Search code examples
javapdfitextpdf-generationpdfbox

Itext and Pdfbox Rotation settings compatibility issues


i have a PDF which is generated by itext and when i'm trying to load it using pdfbox it is getting loaded in landscape mode i.e width and height are interchanged (normally width and height of a PDF which is in portrait mode is 595 and 842(in points) respectively.) but when viewed it is in portrait mode.

it looks like 90 degrees is the portrait value for pdf generated by itext as for pdfbox is 0 degrees. i tried rotating the pdf but still no luck any help would be appreciated.

UPDATED :

i tried adding signature field to this pdf but image is not being shown, i guess i'm not giving the correct cooordinates here . what should i do here ?

void addImageOnlySignatureField(PDDocument pdDocument, PDPage pdPage, PDRectangle rectangle, PDSignature signature) throws IOException {
    PDAcroForm acroForm = pdDocument.getDocumentCatalog().getAcroForm();
    List<PDField> acroFormFields = acroForm.getFields();

    PDSignatureField signatureField = new PDSignatureField(acroForm);
    signatureField.setValue(signature);
    PDAnnotationWidget widget = signatureField.getWidgets().get(0);
    acroFormFields.add(signatureField);

    widget.setRectangle(rectangle);
    widget.setPage(pdPage);

    // from PDVisualSigBuilder.createHolderForm()
    PDStream stream = new PDStream(pdDocument);
    PDFormXObject form = new PDFormXObject(stream);
    PDResources res = new PDResources();
    form.setResources(res);
    form.setFormType(1);
    PDRectangle bbox = new PDRectangle(rectangle.getWidth(), rectangle.getHeight());

    form.setBBox(bbox);

    // from PDVisualSigBuilder.createAppearanceDictionary()
    PDAppearanceDictionary appearance = new PDAppearanceDictionary();
    appearance.getCOSObject().setDirect(true);
    PDAppearanceStream appearanceStream = new PDAppearanceStream(form.getCOSObject());
    appearance.setNormalAppearance(appearanceStream);
    widget.setAppearance(appearance);

    try (   PDPageContentStream cs = new PDPageContentStream(pdDocument, appearanceStream);
            InputStream imageResource = getClass().getResourceAsStream("/mkl/testarea/pdfbox2/content/Willi-1.jpg") )
    {
        cs.saveGraphicsState();
        Matrix m = new Matrix();
        m.rotate(90);
        cs.transform(m);
        PDImageXObject pdImage = PDImageXObject.createFromByteArray(pdDocument, ByteStreams.toByteArray(imageResource), "Willi");
        cs.addComment("This is a comment");
        cs.drawImage(pdImage, 0, 0, rectangle.getWidth(), rectangle.getHeight());
        cs.restoreGraphicsState();

    }

    pdPage.getAnnotations().add(widget);
    
    COSDictionary pageTreeObject = pdPage.getCOSObject(); 
    while (pageTreeObject != null) {
        pageTreeObject.setNeedToBeUpdated(true);
        pageTreeObject = (COSDictionary) pageTreeObject.getDictionaryObject(COSName.PARENT);
    }
}

Solution

  • As already mentioned in comments, you have to counter the page rotation when generating the signature appearance. And when rotating the appearance to do so, one must not forget that a pure rotation also rotates the content to be out of the bounding box of the appearance. Thus, one also has to translate.

    Thus, the original (page rotation un-aware) code

    try (   PDPageContentStream cs = new PDPageContentStream(pdDocument, appearanceStream);
            InputStream imageResource = getClass().getResourceAsStream("/mkl/testarea/pdfbox2/content/Willi-1.jpg") )
    {
        PDImageXObject pdImage = PDImageXObject.createFromByteArray(pdDocument, ByteStreams.toByteArray(imageResource), "Willi");
        cs.addComment("This is a comment");
        cs.drawImage(pdImage, 0, 0, rectangle.getWidth(), rectangle.getHeight());
    }
    

    (CreateMultipleVisualizations helper method addImageOnlySignatureField)

    has to be changed into something like this:

    try (   PDPageContentStream cs = new PDPageContentStream(pdDocument, appearanceStream);
            InputStream imageResource = getClass().getResourceAsStream("/mkl/testarea/pdfbox2/content/Willi-1.jpg") )
    {
        Matrix matrix = new Matrix();
        boolean switchLengths = false;
        switch (pdPage.getRotation() % 360) {
        case 90:
            matrix.translate(rectangle.getWidth(), 0);
            matrix.rotate(Math.PI/2);
            switchLengths = true;
            break;
        case 180: //untested
            matrix.translate(rectangle.getWidth(), rectangle.getHeight());
            matrix.rotate(Math.PI);
            break;
        case 270: //untested
            matrix.translate(0, rectangle.getHeight());
            matrix.rotate(-Math.PI/2);
            switchLengths = true;
            break;
        }
        cs.transform(matrix);
    
        PDImageXObject pdImage = PDImageXObject.createFromByteArray(pdDocument, ByteStreams.toByteArray(imageResource), "Willi");
        cs.addComment("This is a comment");
        if (switchLengths)
            cs.drawImage(pdImage, 0, 0, rectangle.getHeight(), rectangle.getWidth());
        else
            cs.drawImage(pdImage, 0, 0, rectangle.getWidth(), rectangle.getHeight());
    }
    

    (CreateMultipleVisualizations helper method addRotationAwareImageOnlySignatureField)