Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rotate a PdfSignatureAppearance with iText

I'm with a big problem trying to rotate a PdfSignatureAppearance in iText (90 degrees, for instance). I'm signing a PDF using the MakeSignature.signDetached method, and setting my own text and image for the appearance.

Here is some code:

PdfReader reader = new PdfReader("my input file");
FileOutputStream fout = new FileOutputStream("my output file");

PdfStamper stamper = PdfStamper.createSignature(reader, fout, '\0');
PdfSignatureAppearance sap = stamper.getSignatureAppearance();

sap.setLayer2Text("Signed by someone");
sap.setAcro6Layers(true);
sap.setSignatureGraphic("my signature image", null));
sap.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION);

Rectangle pageSize = reader.getPageSize(1); //the page to sign: 1 is the 1st one

Rectangle rect = new Rectangle(llx, lly, urx, ury, rotation);
//llx, lly ... come from a GUI. They are working fine, but the rotation is not considered

sap.setVisibleSignature(rect, 1, null); //1 is the page to sign

MakeSignature.signDetached(sap, ...); //sign the document

My problem is the "rotation" argument. No matter what I set, the text and the image never rotate. Looking at iText code (I'm using iText 5.3.2), the rotation argument of the bounding box of the signature layer is discarded, so, well, setting the rotation this way have no effect at all.

Now the question: Is there a way to rotate my signature layer without rewriting the entire PdfSignatureAppearance and MakeSignature classes?

Just to clarify: the code that digitally signs the document is working fine. My only problem is with the visual layer of the signature: I can't rotate it.

Thanks.

like image 739
Gilberto Torrezan Avatar asked Dec 13 '25 04:12

Gilberto Torrezan


1 Answers

A working example that allows for reuse of the code in com.itextpdf.text.pdf.PdfSignatureAppearance (e.g. to calculate font size automatically):

public class RotateVisualSignature {
    public static void main(String[] args) throws IOException, DocumentException, GeneralSecurityException {
        // Loading private key and certificates.
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(new FileInputStream("signer.p12"), "secret".toCharArray());
        String alias = keyStore.aliases().nextElement();
        PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, "secret".toCharArray());
        Certificate[] certificateChain = keyStore.getCertificateChain(alias);

        PdfReader reader = new PdfReader("sample.pdf");
        FileOutputStream os = new FileOutputStream("sample-signed.pdf");
        PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
        PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
        appearance.setCertificate(certificateChain[0]);

        // This method has to be called as an alternative to 'com.itextpdf.text.pdf.PdfSignatureAppearance.setVisibleSignature'.
        setVisibleSignatureRotated(stamper, appearance, new Rectangle(120, 650, 170, 770), 1, null);

        // Perform the signature.
        ExternalSignature externalSignature = new PrivateKeySignature(privateKey, "SHA-256", null);
        ExternalDigest externalDigest = new BouncyCastleDigest();
        MakeSignature.signDetached(appearance, externalDigest, externalSignature, certificateChain, null, null, null, 0, MakeSignature.CryptoStandard.CMS);
    }

    private static void setVisibleSignatureRotated(PdfStamper stamper, PdfSignatureAppearance appearance, Rectangle pageRect, int page, String fieldName) throws DocumentException, IOException {
        float height = pageRect.getHeight();
        float width = pageRect.getWidth();
        float llx = pageRect.getLeft();
        float lly = pageRect.getBottom();
        // Visual signature is configured as if it were going to be a regular horizontal visual signature.
        appearance.setVisibleSignature(new Rectangle(llx, lly, llx + height, lly + width), page, null);
        // We trigger premature appearance creation, so independent parts of it can be modified right away.
        appearance.getAppearance();
        // Now we correct the width and height.
        appearance.setVisibleSignature(new Rectangle(llx, lly, llx + width, lly + height), page, fieldName);
        appearance.getTopLayer().setWidth(width);
        appearance.getTopLayer().setHeight(height);
        PdfTemplate n2Layer = appearance.getLayer(2);
        n2Layer.setWidth(width);
        n2Layer.setHeight(height);
        // Then we rotate the n2 layer. See http://developers.itextpdf.com/question/how-rotate-paragraph.
        PdfTemplate t = PdfTemplate.createTemplate(stamper.getWriter(), height, width);
        ByteBuffer internalBuffer = t.getInternalBuffer();
        internalBuffer.write(n2Layer.toString().getBytes());
        n2Layer.reset();
        Image textImg = Image.getInstance(t);
        textImg.setInterpolation(true);
        textImg.scaleAbsolute(height, width);
        textImg.setRotationDegrees((float) 90);
        textImg.setAbsolutePosition(0, 0);
        n2Layer.addImage(textImg);
    }
}

Where the result would be something like this:

rotated visual signature

For using this, you just need to copy the setVisibleSignatureRotated method as is and replace calls to com.itextpdf.text.pdf.PdfSignatureAppearance#setVisibleSignature with calls to setVisibleSignatureRotated.

like image 105
Jaime Hablutzel Avatar answered Dec 15 '25 16:12

Jaime Hablutzel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!