Search code examples
javapdfitextpdf-generationitext7

Java iText There is no associate PdfWriter for making indirects


I have the following method that scales an image to A4

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

This method is invoked/called in this snippet :

  ByteArrayOutputStream mergedPdfStream = new ByteArrayOutputStream();
    PdfDocument mergedPdf = new PdfDocument(new PdfWriter(mergedPdfStream));

    for (PdfDocument doc : pdfDocuments) {
        int n = doc.getNumberOfPages();
      
        for (int i = 1; i <= n; i++) {
       
            PdfPage page = doc.getPage(i).copyTo(mergedPdf);
            mergedPdf.addPage(page);
          
        }
        Rectangle pageSize = PageSize.A4;
        Rectangle pageBodySize = pageSize.clone().applyMargins(72, 72, 72, 72, false);
        scale(doc, pageSize, pageBodySize);
    }

   

    mergedPdf.close();

However , when it performs this code at the end

 new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDocument)
                .concatMatrix(transform);

It throws an PDF Exception There is no associate PdfWriter for making indirects:

 com.itextpdf.kernel.PdfException: There is no associate PdfWriter for making indirects.
at com.itextpdf.kernel.pdf.PdfObject.makeIndirect(PdfObject.java:228) ~[kernel-7.1.1.jar:?]
at com.itextpdf.kernel.pdf.PdfObject.makeIndirect(PdfObject.java:248) ~[kernel-7.1.1.jar:?]
at com.itextpdf.kernel.pdf.PdfPage.newContentStream(PdfPage.java:1186) ~[kernel-7.1.1.jar:?]
at com.itextpdf.kernel.pdf.PdfPage.newContentStreamBefore(PdfPage.java:244) ~[kernel-7.1.1.jar:?]

How can I fix this problem? Am I doing something wrong ?


Solution

  • You call

    scale(doc, pageSize, pageBodySize);
    

    for each PdfDocument doc in pdfDocuments. So after copying the pages to mergedPdf you try to scale the pages in your source documents. You cannot scale the pages in your source PdfDocument instances as they are opened read-only (i.e. only with a PdfReader, without a PdfWriter), and doing so after copying also doesn't make sense as you surely want to scale what's in the result mergedPdf, not in the sources.

    Thus, move the block

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

    out of the outer for loop body, after it, and replace the last line by

    scale(mergedPdf, pageSize, pageBodySize);
    

    to scale the resulting merged PDF.