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

( ScaleToA4 방법 scale)

양쪽에 여백 인치가있는 A4 결과 페이지 크기의 경우 다음과 같이 호출 할 수 있습니다 PdfDocument pdfDocument.

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

( ScaleToA4 테스트 에서 발췌 testFdaRequiresUseOfEctdFormatAndStandardizedStudyDataInFutureRegulatorySubmissionsSept)