I'm trying to extract the signature image from a PDF signed with Adobe Sign. Not sure how Adobe adds this image.
I have tested in Java with iText and PDFBox. Normally when you traverse through the PDF structure with some tools e.g iText RUPS you can find the images like the visible signature and even download it directly in the tool. I didn't find it in this case. I did find though the XObject what I think holds the signature image.
The stream looks like this:
q
q
0.07843 0.45098 0.90196 RG
0.07843 0.45098 0.90196 rg
1 w
q
BT
1 0 0 1 0 1.78 Tm
/F1 6 Tf
0.07843 0.45098 0.90196 rg
({0009002000270027002a00010018002a002d0027001f00010497000200300022000104400443047600010441043f044104420001044004410477043f044300010008000e001506d404410498}) Tj
0 g
ET
Q
0 8.28 m
103.55 8.28 l
S
Q
0 0 0 RG
0 0 0 rg
q
1 0 0 1 0 0 cm
/Xf2 Do
Q
Q
And has a reference to Xf2 which looks like this:
1 J
1 j
1.000 w
30.315 10.580 m
30.315 10.580 30.315 10.580 30.315 10.587 c
S
1.000 w
30.315 10.587 m
30.315 10.594 30.315 10.608 30.315 10.627 c
S
1.000 w
30.315 10.627 m
30.315 10.646 30.315 10.670 30.315 10.683 c
S
...
Can this be extracted as an image?
Proof of concept with PDFBox:
try (PDDocument document = PDDocument.load(pdf)) {
PDAnnotation annotation = document.getPage(0).getAnnotations().get(0);
PDResources resources = annotation.getPage().getResources();
Iterator<COSName> names = resources.getXObjectNames().iterator();
PDXObject xi3Object = resources.getXObject(names.next());
PDStream xi3Stream = xi3Object.getStream();
// OR
COSDictionary page = (COSDictionary) document.getDocument().getObjectsByType(COSName.ANNOT).get(0)
.getDictionaryObject(COSName.P);
COSDictionary resources = (COSDictionary) page.getItem(COSName.RESOURCES);
COSDictionary xObject = (COSDictionary) resources.getItem(COSName.XOBJECT);
COSObject xi3Object = (COSObject) xObject.getItem("Xi3");
COSStream xi3Stream = (COSStream) xi3Object.getObject();
PDFormXObject pdFormXObject = new PDFormXObject(xi3Stream);
PDPage page = new PDPage(new PDRectangle(pdFormXObject.getBBox().getWidth(),
pdFormXObject.getBBox().getHeight()));
try (PDDocument tempDocument = new PDDocument()) {
PDPageContentStream contents = new PDPageContentStream(tempDocument, page);
AffineTransform affineTransform = new AffineTransform();
affineTransform.setToTranslation(0, 0);
affineTransform.setToScale(0.75d, 0.75d);
pdFormXObject.setMatrix(affineTransform);
contents.drawForm(pdFormXObject);
contents.restoreGraphicsState();
contents.close();
tempDocument.addPage(page);
PDFRenderer renderer = new PDFRenderer(tempDocument);
BufferedImage image = renderer.renderImageWithDPI(0, 600);
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
ImageIO.write(image, "png", baos);
return baos.toByteArray();
}
}
}
Your Question was can a signature squiggle (vector graphic) be extracted as an image?
So there are more unknows than answers, in such a question, like where do you need the extraction to be or converted into?
Here on left we can see the multiple components of a signature annotation. and once we know what nested object is the artwork (here number 14 0 obj) we can copy the stream data into another PDF. As seen on the right.
since it is a screen graphic we can copy and paste to any graphics application and save in any image format you wish. However to maintain the simplicity of the source it is best copied into an SVG editor like Inkscape.
Or simpler yet since it is now an isolated PDF object simply convert to SVG for forensic use in a web page, or on the bosses debit account, etc.
mutool convert -o output.svg input.pdf