Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support using PDF, in addition to images, as the signature graphic #1181

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Block 1

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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is some kind of weird initialization.


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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Block 2

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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Content of Block 2 only

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