Skip to content

Commit

Permalink
Support using PDF, in addition to images, as the signature graphic
Browse files Browse the repository at this point in the history
  • Loading branch information
Alkaid-Benetnash authored and asturio committed Nov 25, 2024
1 parent fc0fb74 commit 28fad7b
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 43 deletions.
113 changes: 70 additions & 43 deletions openpdf/src/main/java/com/lowagie/text/pdf/PdfSignatureAppearance.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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
* <CODE>SignatureRenderGraphicAndDescription</CODE>
Expand All @@ -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
* <CODE>SignatureRenderGraphicAndDescription</CODE>
*
* @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;
}

/**
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -1688,4 +1715,4 @@ public int read(byte[] b, int off, int len) throws IOException {
return -1;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
Expand All @@ -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<PdfName, Integer> exc = new HashMap<>();
exc.put(PdfName.CONTENTS, 10);
Expand Down

0 comments on commit 28fad7b

Please sign in to comment.