1

I have the following code for to print a PDF file using the Android Printing Framework:

Here is my PrintDocumentAdapter class:

@TargetApi(Build.VERSION_CODES.KITKAT)
public class PrintPDFAdapter extends PrintDocumentAdapter {
    private File pdfFile;
    private String fileName;

    public PrintPDFAdapter(File pdfFile, String fileName) {
        this.pdfFile = pdfFile;
        this.fileName = fileName;
    }


    @Override
    public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) {
        if (cancellationSignal.isCanceled()) {
            callback.onLayoutCancelled();
            return;
        }

        PrintDocumentInfo pdi = new PrintDocumentInfo.Builder(fileName).setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).build();

        callback.onLayoutFinished(pdi, true);
    }

    @Override
    public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) {
        InputStream input = null;
        OutputStream output = null;

        try {

            input = new FileInputStream(pdfFile);
            output = new FileOutputStream(destination.getFileDescriptor());

            byte[] buf = new byte[1024];
            int bytesRead;

                while ((bytesRead = input.read(buf)) > 0) {
                output.write(buf, 0, bytesRead);
            }

            callback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES});

        } catch (FileNotFoundException ee){
            //Catch exception
        } catch (Exception e) {
            //Catch exception
        } finally {
            try {
                input.close();
                output.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Here is my method that calls the PrintManager print command:

@TargetApi(Build.VERSION_CODES.KITKAT)
private void doPDFPrint(File pdfFile, String filename) {
    PrintManager printManager = (PrintManager) this.getSystemService(Context.PRINT_SERVICE);
    String jobName = this.getString(R.string.app_name) + " Report";
    PrintPDFAdapter pda = new PrintPDFAdapter(pdfFile, filename);
    PrintAttributes attrib = new PrintAttributes.Builder().
            setMediaSize(PrintAttributes.MediaSize.NA_LETTER.asLandscape()).
            setMinMargins(PrintAttributes.Margins.NO_MARGINS).
            build();
    printManager.print(jobName, pda, attrib);
}

The PDF that I am trying to print is in landscape orientation. For some reason, when sending it to print, the PDF file gets rotated sideways and gets clipped. I would like to know, is there anything I can do to get around this?

UPDATE: I just did a test print, and it actually prints properly. However, the preview shows it rotated sideways.

Pink Jazz
  • 784
  • 4
  • 13
  • 34
  • It's possible that this is a bug in the preview stuff. You don't really control that, so if it is printing properly, there may not be much you can do about it. – CommonsWare Sep 03 '15 at 18:28
  • Did you ever figure this out? I am actually seeing the same thing, and with some portrait pages, as well. I'm looking into it more to see if there's some rotation on the page in the PDF itself somehow (I'm not very familiar with the PDF spec). It's a problem because I'm displaying the rendered bitmap in the app and it's coming out sideways. – Oded Dec 31 '16 at 17:07

1 Answers1

0

In my case it was because I'm using my own transform, and when supplying a transform, the native renderer does not apply the page rotation specified in the PDF page's attributes. There is no way to get this attribute via the Android API right now, so I used iText:

private PdfReader _iTextReader;

...

_iTextReader = new PdfReader(file.getAbsolutePath());

...

// iText uses 1-indexed pages
PdfDictionary iTextPage = _iTextReader.getPageN(pageNumber + 1);
PdfNumber rotate = iTextPage.getAsNumber(PdfName.ROTATE);
if (rotate != null && rotate.intValue() % 360 != 0) {
   // getPageSize returns media box
   float mediaBoxWidth = _iTextReader.getPageSize(pageNumber + 1).getWidth();
   float mediaBoxHeight = _iTextReader.getPageSize(pageNumber + 1).getHeight();
   float iTextCenterX = mediaBoxWidth / 2;
   float iTextCenterY = mediaBoxHeight / 2;
   Util.Log("Applying " + rotate.intValue() + " degree rotation per PDF page attributes.");
   pdfMatrix.postRotate(rotate.intValue(), iTextCenterX, iTextCenterY);
   /*
    * Transform it back to the top-left corner.
    * For the life of me, I do not know why these translations are right. But I've
    * test both portrait->landscape and landscape->portrait on all rotation angles.
    */
   if (rotate.intValue() == 90) {
      pdfMatrix.postTranslate(iTextCenterX - iTextCenterY, iTextCenterX - iTextCenterY);
   } else if (rotate.intValue() == 270) {
      pdfMatrix.postTranslate(3 * iTextCenterY - 3 * iTextCenterX, iTextCenterX - iTextCenterY);
   }
}

Here's the link to the source code of the native PDF renderer: https://github.com/android/platform_frameworks_base/blob/master/core/jni/android/graphics/pdf/PdfRenderer.cpp

Oded
  • 954
  • 12
  • 16
  • If anyone who can math better than me knows why those translations ended up being right, please share. I had to figure it out empirically. – Oded Jan 02 '17 at 04:18