Pdfbox - Signature Validity Checkmark Not Visible in Acrobat Reader

Pdf Signature Validity Check Mark Not Visible on Acrobat Reader

it turns out I only needed to set Acro6Layers to false and not set any image with setImage method... instead of setImage, I used setSignatureGraphic method...

pdfSignatureAppearance.setAcro6Layers(false);
pdfSignatureAppearance.setImage(null);
pdfSignatureAppearance.setSignatureGraphic(Image...);

How to display different images based on validity of digital signature using pdfbox api?

Such variable graphics have been deprecated more than a decade ago; Adobe Reader probably still supports them but there is no telling for how long. Depending on your signature profile they actually are forbidden!

Please use a neutral graphic (no check mark, no cross, no question mark icon) for your signature and determine the validation state from the signature tab of the PDF viewer.


As it turns out after a bit of searching, I had already answered a similar question a year ago and included the relevant references in there. Thus, I marked this question a duplicate of that older one.

Some notes, though:

  • The answer contains a link to "Adobe Acrobat 9 Digital Signatures, Changes and Improvements" (Updated for Adobe Acrobat and Adobe Reader 9.1), an Adobe Technical Whitepaper dated 1 April 2009. Adobe seems to have removed that paper from its site, though, but copies can be found elsewhere.

  • The answer does not illuminate the situation in ISO 32000-2 as that part 2 has only been published 2017, this year. But just like in part 1, there is no mentioning of those "layers" n1, n3, and n4 in it either.

Programmatically signed PDF document does not get the green checkmark after being signed using Acrobat Reader

You change the AcroForm dictionary DA default appearance entry.

In the document signed by Adobe the AcroForm dictionary looks like this:

<</DA(/Helv 0 Tf 0 g )/DR<</Encoding<</PDFDocEncoding 8 0 R>>/Font<</Helv 6 0 R/MyriadPro-Regular 27 0 R/ZaDb 7 0 R>>>>/Fields[26 0 R]/SigFlags 3>>

After you signed that document it becomes this:

<</DA(/Helv 0 Tf 0 g)/DR<</Encoding<</PDFDocEncoding 8 0 R>>/Font<</Helv 6 0 R/MyriadPro-Regular 27 0 R/ZaDb 7 0 R>>>>/Fields[26 0 R 35 0 R]/SigFlags 3>>

I.e. you removed the trailing space character in the DA entry.

PDFBox : Signature fails Can't write signature, not enough space

In a comment you mention that you get

signature length = 10721

in the log files and that you

didn't set any preferred size

By default PDFBox reserves 0x2500 bytes for the signature. That's 9472 bytes decimally. Thus, just like the exception says, there's not enough space.

You can set the size PDFBox reserves for the signature by using a SignatureOptions object during document.addSignature:

SignatureOptions signatureOptions = new SignatureOptions();
signatureOptions.setPreferredSignatureSize(20000);
document.addSignature(signature, signatureOptions);

PDFBOX acroForm filled but when opened in Acrobat reader values disappears

The page /AA/O entry ("An action that shall be performed when the page is opened") has this:

if (!bReset)
{
this.resetForm();
bReset = true;
}

So the form is reset.

This happens even if the form is filled manually and saved, closed and reopened. Maybe this is a demo version of "formupack" that does this on purpose.

You could prevent this by removing the page /AA entry like this

document.getPage(0).setActions(null);

or just remove the /O entry

document.getPage(0).getActions().setO(null);

Get Visible Signature from a PDF using PDFBox?

As no one came up to answer, I tried my proposal in the comments to your question myself. A first result:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdfviewer.PageDrawer;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.PDGraphicsState;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;

public class AnnotationDrawer extends PageDrawer
{
public AnnotationDrawer(int imageType, int resolution) throws IOException
{
super();
this.imageType = imageType;
this.resolution = resolution;
}

public Map<String, BufferedImage> convertToImages(PDPage p) throws IOException
{
page = p;
final Map<String, BufferedImage> result = new HashMap<String, BufferedImage>();

List<PDAnnotation> annotations = page.getAnnotations();
for (PDAnnotation annotation: annotations)
{
String appearanceName = annotation.getAppearanceStream();
PDAppearanceDictionary appearDictionary = annotation.getAppearance();
if( appearDictionary != null )
{
if( appearanceName == null )
{
appearanceName = "default";
}
Map<String, PDAppearanceStream> appearanceMap = appearDictionary.getNormalAppearance();
if (appearanceMap != null)
{
PDAppearanceStream appearance =
(PDAppearanceStream)appearanceMap.get( appearanceName );
if( appearance != null )
{
BufferedImage image = initializeGraphics(annotation);
setTextMatrix(null);
setTextLineMatrix(null);
getGraphicsStack().clear();
processSubStream( page, appearance.getResources(), appearance.getStream() );

String name = annotation.getAnnotationName();
if (name == null || name.length() == 0)
{
name = annotation.getDictionary().getString(COSName.T);
if (name == null || name.length() == 0)
{
name = Long.toHexString(annotation.hashCode());
}
}

result.put(name, image);
}
}
}
}

return result;
}

BufferedImage initializeGraphics(PDAnnotation annotation)
{
PDRectangle rect = annotation.getRectangle();
float widthPt = rect.getWidth();
float heightPt = rect.getHeight();
float scaling = resolution / (float)DEFAULT_USER_SPACE_UNIT_DPI;
int widthPx = Math.round(widthPt * scaling);
int heightPx = Math.round(heightPt * scaling);
//TODO The following reduces accuracy. It should really be a Dimension2D.Float.
Dimension pageDimension = new Dimension( (int)widthPt, (int)heightPt );
BufferedImage retval = new BufferedImage( widthPx, heightPx, imageType );
Graphics2D graphics = (Graphics2D)retval.getGraphics();
graphics.setBackground( TRANSPARENT_WHITE );
graphics.clearRect( 0, 0, retval.getWidth(), retval.getHeight() );
graphics.scale( scaling, scaling );
setGraphics(graphics);
pageSize = pageDimension;
graphics.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
graphics.setRenderingHint( RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON );
setGraphicsState(new PDGraphicsState(new PDRectangle(widthPt, heightPt)));

return retval;
}

void setGraphics(Graphics2D graphics)
{
try {
Field field = PageDrawer.class.getDeclaredField("graphics");
field.setAccessible(true);
field.set(this, graphics);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

private static final int DEFAULT_USER_SPACE_UNIT_DPI = 72;
private static final Color TRANSPARENT_WHITE = new Color( 255, 255, 255, 0 );

private int imageType;
private int resolution;
}

If you want to render the annotations of a given PDPage page, you merely do:

AnnotationDrawer drawer = new AnnotationDrawer(8, 288);
Map<String, BufferedImage> images = drawer.convertToImages(page);

The constructor arguments correspond to those of PDPage.convertToImage(int imageType, int resolution).

Beware, this has

a. been hacked together based on PDFBox 1.8.2; it may contain version-specific code;
b. merely been checked for some visible signature annotations I have here; it may be incomplete, and it may especially fail for other annotation types.



Related Topics



Leave a reply



Submit