3

我在尝试在 iText 中旋转 PdfSignatureAppearance 时遇到了一个大问题(例如 90 度)。我正在使用 MakeSignature.signDetached 方法签署 PDF,并为外观设置我自己的文本和图像。

这是一些代码:

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

我的问题是“轮换”论点。无论我设置什么,文本和图像都不会旋转。查看iText代码(我使用的是iText 5.3.2),签名层边界框的旋转参数被丢弃,所以,这样设置旋转根本没有效果。

现在的问题是:有没有办法在不重写整个 PdfSignatureAppearance 和 MakeSignature 类的情况下旋转我的签名层?

只是为了澄清:对文档进行数字签名的代码工作正常。我唯一的问题是签名的可视层:我无法旋转它。

谢谢。

4

2 回答 2

3

一个允许重用代码的工作示例com.itextpdf.text.pdf.PdfSignatureAppearance(例如,自动计算字体大小):

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

结果将是这样的:

旋转视觉签名

要使用它,您只需按setVisibleSignatureRotated原样复制方法并将调用替换为com.itextpdf.text.pdf.PdfSignatureAppearance#setVisibleSignature调用setVisibleSignatureRotated

于 2017-04-27T23:52:38.757 回答
1

目前不支持在使​​用便捷方法(例如 setRenderingMode()、setLayer2Text()、setSignatureGraphic() 等)创建签名时设置旋转...

因此,您有两个选择: 1. 要求我们提供该功能。数字签名白皮书前 90 页的草稿刚刚发布给新闻信的订阅者,因此我们正在研究这些课程。但是:使用智能卡签名、重构验证过程等……目前是绝对优先的,所以你可能需要等待一段时间。2. 使用 getLayer() 方法沿您想要的任何方向绘制内容。对于背景中的图像,那将是 getLayer(0);和 getLayer(2) 用于文本。

请注意,以前也有第 1、3、4 层,但它们只有在 acro6Layers 等于 true 时才会起作用;这就是你的情况,但不鼓励使用 acro6Layers(它已经过时了:你不应该再使用它了)。事实上,我现在将弃用该方法并将该值默认设置为 false。

于 2012-08-24T11:53:43.887 回答