Document à l'échelle Java iText au format A4

Aug 20 2020

J'ai la méthode suivante qui "redimensionne" toutes les pages d'un document aux dimensions de la page 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");
        }
    }

Cependant, cela ne fonctionne pas comme prévu, les pages sont transformées en A4 (297x210) MAIS le contenu n'est pas inséré à l'intérieur (mis à l'échelle), le contenu semble coupé car les pages d'origine sont plus grandes que 297X210. Comment puis-je réparer cela ?

Réponses

1 mkl Aug 24 2020 at 13:47

Dans un commentaire que vous avez clarifié

Je veux que le cadre de délimitation de l'ancien contenu soit mis à l'échelle et qu'une marge soit ajoutée dans la cible

Nous devons donc d'abord déterminer la zone de délimitation du contenu de la page d'origine. Cela peut être fait en utilisant la MarginFinderclasse de cette réponse . Attention: cette classe détermine la boîte englobante de tout le contenu, même s'il s'agit simplement d'un rectangle blanc visuellement non distinct de l'absence de contenu ou de quelque chose qui se trouvait auparavant en dehors de la zone de recadrage ... Si votre cas d'utilisation l'exige, vous devrez peut-être étendre cette classe prendre également en considération ces circonstances.

Une fois la zone de délimitation du contenu déterminée, il ne reste plus qu'à faire un peu de calcul.

La méthode suivante détermine la zone de délimitation à l'aide de la classe ci-dessus, transforme le contenu en conséquence et modifie la zone de recadrage de résultat.

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

( Méthode ScaleToA4scale )

Pour une page de résultat A4 avec un pouce de marge de chaque côté, vous pouvez l'appeler comme ceci pour un PdfDocument pdfDocument:

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

(extrait du test ScaleToA4testFdaRequiresUseOfEctdFormatAndStandardizedStudyDataInFutureRegulatorySubmissionsSept )