Android Printing Framework — альбомный PDF-файл поворачивается вбок и обрезается при предварительном просмотре

У меня есть следующий код для печати PDF-файла с помощью Android Printing Framework:

Вот мой класс PrintDocumentAdapter:

@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();
            }
        }
    }
}

Вот мой метод, который вызывает команду печати PrintManager:

@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);
}

PDF-файл, который я пытаюсь распечатать, имеет альбомную ориентацию. По какой-то причине при отправке на печать файл PDF поворачивается вбок и обрезается. Я хотел бы знать, могу ли я что-нибудь сделать, чтобы обойти это?

ОБНОВЛЕНИЕ: я только что сделал тестовую печать, и она действительно печатается правильно. Однако предварительный просмотр показывает, что он повернут вбок.


person Pink Jazz    schedule 03.09.2015    source источник
comment
Возможно, это ошибка в превью. Вы на самом деле не контролируете это, поэтому, если он печатает правильно, вы мало что можете с этим поделать.   -  person CommonsWare    schedule 03.09.2015
comment
Вы когда-нибудь догадывались об этом? На самом деле я вижу то же самое, и с некоторыми портретными страницами. Я изучаю это больше, чтобы увидеть, есть ли какое-то вращение на странице в самом PDF-файле (я не очень хорошо знаком со спецификацией PDF). Это проблема, потому что я показываю отрендеренное растровое изображение в приложении, и оно выходит боком.   -  person Oded    schedule 31.12.2016


Ответы (1)


В моем случае это произошло потому, что я использую собственное преобразование, и при предоставлении преобразования собственный модуль визуализации не применяет поворот страницы, указанный в атрибутах страницы PDF. Сейчас нет возможности получить этот атрибут через Android API, поэтому я использовал 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);
   }
}

Вот ссылка на исходный код собственного средства визуализации PDF: https://github.com/android/platform_frameworks_base/blob/master/core/jni/android/graphics/pdf/PdfRenderer.cpp

person Oded    schedule 02.01.2017
comment
Если кто-то, кто разбирается в математике лучше меня, знает, почему эти переводы оказались правильными, поделитесь, пожалуйста. Пришлось выяснять опытным путем. - person Oded; 02.01.2017