diff --git a/openpdf/src/main/java/com/lowagie/text/pdf/PdfSignatureAppearance.java b/openpdf/src/main/java/com/lowagie/text/pdf/PdfSignatureAppearance.java index 99fe57988..94389653e 100755 --- a/openpdf/src/main/java/com/lowagie/text/pdf/PdfSignatureAppearance.java +++ b/openpdf/src/main/java/com/lowagie/text/pdf/PdfSignatureAppearance.java @@ -172,6 +172,7 @@ public class PdfSignatureAppearance { private Certificate[] certChain; private int render = SignatureRenderDescription; private Image signatureGraphic = null; + private PdfImportedPage signaturePDF = null; /** * Holds value of property contact. */ @@ -311,6 +312,24 @@ public Image getSignatureGraphic() { return signatureGraphic; } + /** + * Gets the PDF page to render. + * + * @return the PDF page + */ + public PdfImportedPage getSignaturePDF() { + return signaturePDF; + } + + /** + * Check whether we already have a valid signature graphic (image or PDF). + * + * @return true if we have one valid signature graphic + */ + public boolean hasValidSignatureGraphic() { + return (signatureGraphic != null || signaturePDF != null); + } + /** * Sets the Image object to render when Render is set to * SignatureRenderGraphicAndDescription @@ -320,6 +339,21 @@ public Image getSignatureGraphic() { */ public void setSignatureGraphic(Image signatureGraphic) { this.signatureGraphic = signatureGraphic; + this.signaturePDF = null; + } + + /** + * Sets the PDF page to render as signature when Render is set to + * SignatureRenderGraphicAndDescription + * + * @param sigFile + * The PDF file to be rendered. + * @param pgnum + * The page number in the sigFile to be rendered (start from 1). + */ + public void setSignaturePDF(PdfReader sigFile, int pgnum) { + this.signaturePDF = writer.getImportedPage(sigFile, pgnum); + this.signatureGraphic = null; } /** @@ -632,7 +666,7 @@ public PdfTemplate getAppearance() throws DocumentException { Rectangle signatureRect = null; if (render == SignatureRenderNameAndDescription - || (render == SignatureRenderGraphicAndDescription && this.signatureGraphic != null)) { + || (render == SignatureRenderGraphicAndDescription && hasValidSignatureGraphic())) { // origin is the bottom-left signatureRect = new Rectangle(MARGIN, MARGIN, rect.getWidth() / 2 - MARGIN, rect.getHeight() - MARGIN); @@ -674,48 +708,9 @@ public PdfTemplate getAppearance() throws DocumentException { ct2.go(); } else if (render == SignatureRenderGraphicAndDescription) { - ColumnText ct2 = new ColumnText(t); - ct2.setRunDirection(runDirection); - ct2.setSimpleColumn(signatureRect.getLeft(), signatureRect.getBottom(), - signatureRect.getRight(), signatureRect.getTop(), 0, - Element.ALIGN_RIGHT); - - Image im = Image.getInstance(signatureGraphic); - im.scaleToFit(signatureRect.getWidth(), signatureRect.getHeight()); - - Paragraph p = new Paragraph(); - // must calculate the point to draw from to make image appear in middle - // of column - float x = 0; - // experimentation found this magic number to counteract Adobe's - // signature graphic, which - // offsets the y co-ordinate by 15 units - float y = -im.getScaledHeight() + 15; - - x = x + (signatureRect.getWidth() - im.getScaledWidth()) / 2; - y = y - (signatureRect.getHeight() - im.getScaledHeight()) / 2; - p.add(new Chunk(im, x - + (signatureRect.getWidth() - im.getScaledWidth()) / 2, y, false)); - ct2.addElement(p); - ct2.go(); + renderSignatureGraphic(t, signatureRect); } else if (this.render == SignatureRenderGraphic) { - ColumnText ct2 = new ColumnText(t); - ct2.setRunDirection(this.runDirection); - ct2.setSimpleColumn(signatureRect.getLeft(), signatureRect.getBottom(), signatureRect.getRight(), - signatureRect.getTop(), 0, Element.ALIGN_RIGHT); - - Image im = Image.getInstance(this.signatureGraphic); - im.scaleToFit(signatureRect.getWidth(), signatureRect.getHeight()); - - Paragraph p = new Paragraph(signatureRect.getHeight()); - // must calculate the point to draw from, to make image appear in the middle of the column - float x = (signatureRect.getWidth() - im.getScaledWidth()) / 2f; - float y = (signatureRect.getHeight() - im.getScaledHeight()) / 2f; - - p.add(new Chunk(im, x, y, false)); - - ct2.addElement(p); - ct2.go(); + renderSignatureGraphic(t, signatureRect); } if (this.render != SignatureRenderGraphic) { @@ -800,6 +795,38 @@ public PdfTemplate getAppearance() throws DocumentException { return napp; } + /** + * A helper to render signature graphic (PDF or image) to a give new layer + * + * @param t the new PDF object/layer to render on + */ + private void renderSignatureGraphic(PdfTemplate t, Rectangle signatureRect) { + if (this.signatureGraphic != null) { + ColumnText ct2 = new ColumnText(t); + ct2.setRunDirection(this.runDirection); + ct2.setSimpleColumn(signatureRect.getLeft(), signatureRect.getBottom(), signatureRect.getRight(), + signatureRect.getTop(), 0, Element.ALIGN_RIGHT); + + Image im = Image.getInstance(this.signatureGraphic); + im.scaleToFit(signatureRect.getWidth(), signatureRect.getHeight()); + + Paragraph p = new Paragraph(signatureRect.getHeight()); + // must calculate the point to draw from, to make image appear in the middle of the column + float x = (signatureRect.getWidth() - im.getScaledWidth()) / 2f; + float y = (signatureRect.getHeight() - im.getScaledHeight()) / 2f; + + p.add(new Chunk(im, x, y, false)); + + ct2.addElement(p); + ct2.go(); + } else if (this.signaturePDF != null) { + float scale = Math.min(signatureRect.getWidth() / signaturePDF.getWidth(), + signatureRect.getHeight() / signaturePDF.getHeight()); + t.addTemplate(signaturePDF, scale, 0, 0, scale, 0, 0); + } + } + + /** * Sets the digest/signature to an external calculated value. * @@ -1688,4 +1715,4 @@ public int read(byte[] b, int off, int len) throws IOException { return -1; } } -} +} \ No newline at end of file diff --git a/openpdf/src/test/java/com/lowagie/text/pdf/PdfSignatureAppearanceTest.java b/openpdf/src/test/java/com/lowagie/text/pdf/PdfSignatureAppearanceTest.java index c513a6867..61fe4b6db 100644 --- a/openpdf/src/test/java/com/lowagie/text/pdf/PdfSignatureAppearanceTest.java +++ b/openpdf/src/test/java/com/lowagie/text/pdf/PdfSignatureAppearanceTest.java @@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import com.lowagie.text.DocumentException; +import com.lowagie.text.Image; import com.lowagie.text.Rectangle; import com.lowagie.text.Utilities; import java.io.ByteArrayInputStream; @@ -103,6 +104,8 @@ void visibleExternalSignature() throws DocumentException, IOException, NoSuchAlg byte[] expectedDigestClose = null; Calendar signDate = Calendar.getInstance(); + Image sigImg = Image.getInstance(getClass().getClassLoader().getResource("GitHub-Mark-32px.png")); + PdfReader sigPdf = new PdfReader(getClass().getClassLoader().getResource("SimulatedBoldAndStrokeWidth.pdf")); byte[] originalDocId = null; PdfObject overrideFileId = new PdfLiteral("<123><123>".getBytes()); @@ -129,6 +132,17 @@ void visibleExternalSignature() throws DocumentException, IOException, NoSuchAlg sap.setSignDate(signDate); sap.setVisibleSignature(new Rectangle(100, 100), 1); sap.setLayer2Text("Hello world"); + if (i < 5) { + // Test image signature in the first half of the tests + sap.setSignatureGraphic(sigImg); + } else { + // Test PDF signature in the second half of the tests + if (i == 5) { + expectedDigestPreClose = null; + expectedDigestClose = null; + } + sap.setSignaturePDF(sigPdf, 1); + } Map exc = new HashMap<>(); exc.put(PdfName.CONTENTS, 10);