Масштабирование документа Java iText до формата A4

Aug 20 2020

У меня есть следующий метод, который "изменяет размер" всех страниц документа до размеров страницы A4:

  for (PdfDocument doc : pdfDocuments) {
        int n = doc.getNumberOfPages();
     
        for (int i = 1; i <= n; i++) {
         
            PdfPage page = doc.getPage(i);
        
            Rectangle media = page.getCropBox();
            if (media == null) {
                media = page.getMediaBox();
            }
          
            Rectangle crop = new Rectangle(0, 0, 210, 297);
            page.setMediaBox(crop);
            page.setCropBox(crop);

            // The content, placed on a content stream before, will be rendered before the other content
            // and, therefore, could be understood as a background (bottom "layer")
            new PdfCanvas(page.newContentStreamBefore(),
                    page.getResources(), doc).writeLiteral("\nq 0.5 0 0 0.5 0 0 cm\nq\n");

            // The content, placed on a content stream after, will be rendered after the other content
            // and, therefore, could be understood as a foreground (top "layer")
            new PdfCanvas(page.newContentStreamAfter(),
                    page.getResources(), doc).writeLiteral("\nQ\nQ\n");
        }
    }

Однако это не работает должным образом, страницы преобразуются в формат A4 (297x210), НО содержимое не помещается внутрь (масштабируется), содержимое кажется обрезанным, поскольку исходные страницы больше 297X210. Как я могу это исправить ?

Ответы

1 mkl Aug 24 2020 at 13:47

В комментарии вы уточнили

Я хочу, чтобы ограничивающая рамка прежнего содержимого была масштабирована, а поле цели было добавлено

Итак, сначала нам нужно определить ограничивающую рамку исходного содержимого страницы. Это можно сделать с помощью MarginFinderкласса из этого ответа . Осторожно: этот класс определяет ограничивающую рамку всего содержимого, даже если это просто белый прямоугольник, визуально не отличающийся от содержимого или чего-то, что раньше находилось вне рамки кадрирования ... Если этого требует ваш вариант использования, вам, возможно, придется расширить этот класс принять во внимание и такие обстоятельства.

После определения ограничивающей рамки содержимого все, что осталось сделать, - это немного вычислить.

Следующий метод определяет ограничивающую рамку, используя приведенный выше класс, соответствующим образом преобразует содержимое и изменяет рамку обрезки результата.

void scale(PdfDocument pdfDocument, Rectangle pageSize, Rectangle pageBodySize) {
    int n = pdfDocument.getNumberOfPages();

    for (int i = 1; i <= n; i++) {
        PdfPage page = pdfDocument.getPage(i);

        MarginFinder marginFinder = new MarginFinder();
        PdfCanvasProcessor pdfCanvasProcessor = new PdfCanvasProcessor(marginFinder);
        pdfCanvasProcessor.processPageContent(page);
        Rectangle boundingBox = marginFinder.getBoundingBox();
        if (boundingBox == null || boundingBox.getWidth() == 0 || boundingBox.getHeight() == 0) {
            System.err.printf("Cannot scale page %d contents with bounding box %s\n", i , boundingBox);
            continue;
        } else {
            // Scale and move content into A4 with margin
            double scale = 0, xDiff= 0, yDiff = 0;
            double xScale = pageBodySize.getWidth()/boundingBox.getWidth();
            double yScale = pageBodySize.getHeight()/boundingBox.getHeight();
            if (xScale < yScale) {
                yDiff = boundingBox.getHeight() * (yScale / xScale - 1) / 2;
                scale = xScale;
            } else {
                xDiff = boundingBox.getWidth() * (xScale / yScale - 1) / 2;
                scale = yScale;
            }

            AffineTransform transform = AffineTransform.getTranslateInstance(pageBodySize.getLeft() + xDiff, pageBodySize.getBottom() + yDiff);
            transform.scale(scale, scale);
            transform.translate(-boundingBox.getLeft(), -boundingBox.getBottom());
            new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDocument)
                    .concatMatrix(transform);
        }
        page.setMediaBox(pageSize);
        page.setCropBox(pageSize);
    }
}

( Метод ScaleToA4scale )

Для размера страницы результатов A4 с полем в дюйм с каждой стороны вы можете назвать это следующим образом PdfDocument pdfDocument:

Rectangle pageSize = PageSize.A4;
Rectangle pageBodySize = pageSize.clone().applyMargins(72, 72, 72, 72, false);
scale(pdfDocument, pageSize, pageBodySize);

(отрывок из теста ScaleToA4testFdaRequiresUseOfEctdFormatAndStandardizedStudyDataInFutureRegulatorySubmissionsSept )