0

I have the following method that "resizes" all the pages of a document to A4 page dimensions:

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

However , this is not working as expected , the pages are being transformed to A4 (297x210) BUT the content is not being fitted inside (scaled) , the content appears cutted because the original pages are larger than 297X210 . How can I fix this ?

Nexussim Lements
  • 535
  • 1
  • 15
  • 47
  • *"the pages are being transformed to A4 (297x210)"* - that would surprise me. The media box and the crop box are given in default user space units. Unless you change their value somewhere, they are 1/72 inch. And A4 certainly is not 210×297 of such units but 210mm×297mm. – mkl Aug 20 '20 at 13:10
  • How do you want the content to be resized? Shall the whole original crop box be resized into the new one? Or shall a bounding box of the former content be scaled, and if so, shall a margin be added in the target? Shall the aspect ration remain? Are annotations involved (which also would have to be relocated and resized)? Do links in your file target the pages at specific coordinates (which also would have to be adjusted)? – mkl Aug 24 '20 at 08:43
  • I want the bounding box of the former content be scaled and a margin be added in the target , also there aren't anotations involved nor links . – Nexussim Lements Aug 24 '20 at 08:56

1 Answers1

1

In a comment you clarified

I want the bounding box of the former content be scaled and a margin be added in the target

So, we first have to determine the bounding box of the original page content. This can be done using the MarginFinder class from this answer. Beware: That class determines the bounding box of all content, even if it is merely a white rectangle visually not distinct from no content or something formerly outside the crop box... If your use case requires it, you may have to extend that class to take such circumstances into consideration, too.

With the content bounding box determined all that remains to do is a bit of calculation.

The following method determines the bounding box using the class above, transforms the content accordingly, and changes the result crop box.

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

(ScaleToA4 method scale)

For an A4 result page size with an inch of margin on each side you can call it like this for a PdfDocument pdfDocument:

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

(excerpt from ScaleToA4 test testFdaRequiresUseOfEctdFormatAndStandardizedStudyDataInFutureRegulatorySubmissionsSept)

mkl
  • 90,588
  • 15
  • 125
  • 265
  • Check my new post please https://stackoverflow.com/questions/63576068/java-itext-there-is-no-associate-pdfwriter-for-making-indirects – Nexussim Lements Aug 25 '20 at 09:39