[
https://issues.apache.org/jira/browse/PDFBOX-4556?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16866815#comment-16866815
]
Tilman Hausherr commented on PDFBOX-4556:
-----------------------------------------
You did pass a PNG image. It is a green checkmark. Open the PDF file with an
editor you'll see "‰PNG" at offset 9809.
The IllegalStateException message is poorly done, I'll improve it. It means
that the image has neither 3 (RGB) nor 1 (B/W) color components. Here's the
current source code of {{PDJpeg.setPropertiesFromAWT}}:
{code:java}
private void setPropertiesFromAWT(BufferedImage image) throws
IllegalStateException
{
setBitsPerComponent( 8 );
if (image.getColorModel().getNumComponents() == 3)
{
setColorSpace( PDDeviceRGB.INSTANCE );
}
else
{
if (image.getColorModel().getNumComponents() == 1)
{
setColorSpace( new PDDeviceGray() );
}
else
{
throw new IllegalStateException("");
}
}
setHeight( image.getHeight() );
setWidth( image.getWidth() );
}
{code}
To find out how many color components your image has, try this:
{code:java}
BufferedImage bim = ImageIO.read(....);
System.out.println("color component count: " +
bim.getColorModel().getNumComponents());
System.out.println("color model: " + bim.getColorModel());
System.out.println("image: " + bim);
{code}
It could be the image has transparency (ARGB) or CMYK.
The other problem (NPE) happens when calling save(). You had that one before,
see my earlier comments.
I did some more research... You use the existing PDDocument, but should have
created a new PDDocument. You wrote into the page content stream, but should
have written into the appearance stream (this "emptiness" resulted in the NPE).
Sadly there are no methods to write PDF operators into an appearance stream in
1.8, so you have to do it the hard way. (Or write into a page content stream
and then read the result, and write it back into the appearance stream).
The code below works, although many things are hard-wired, and the exception
handling is not "best practice". And your text is all in one line.
{code:java}
private static InputStream createVisualSignatureTemplate(PDDocument
signedDoc, int stampingPage, String tickImagePath, String name, String
location, String reason, int xCo_ordinates, int yCo_ordinates, int
signatureHeight, int signatureWidth)
{
File imageFile = new File(tickImagePath);
//PDPage page = (PDPage)
signedDoc.getDocumentCatalog().getAllPages().get(stampingPage - 1);
PDPage page = new PDPage(((PDPage)
(signedDoc.getDocumentCatalog().getAllPages().get(stampingPage-1))).findMediaBox());
//NEW! Don't use "signedDoc" except to get page dimensions
PDDocument doc = new PDDocument();
doc.addPage(page); // dummy page, just to hold the annotation
float x = (float) xCo_ordinates;
float y = (float) yCo_ordinates;
float sigWidth = (float) signatureWidth;
float sigheight = (float) signatureHeight;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try
{
Rectangle2D humanRectangle = new Rectangle2D.Float(xCo_ordinates,
yCo_ordinates, signatureWidth, signatureHeight);
// create signature rectangle
PDRectangle pdRectangle = null;
if (pdRectangle == null)
{
// quick solution now
//pdRectangle = createSignatureRectangle(signedDoc,
humanRectangle, stampingPage);
pdRectangle = new PDRectangle((int) humanRectangle.getWidth(),
(int) humanRectangle.getHeight());
}
PDAcroForm acroForm = new PDAcroForm(doc);
// signedDoc.getDocumentCatalog().setAcroForm(acroForm); // wrong
doc.getDocumentCatalog().setAcroForm(acroForm);
//signedDoc.getDocumentCatalog().getCOSObject().setNeedToBeUpdate(true); //
wrong
doc.getDocumentCatalog().getCOSObject().setNeedToBeUpdate(true);
PDSignatureField signatureField = new PDSignatureField(acroForm);
//List<PDField> acroFormFields = new List<PDField>(); // maybe
works in C++
List<PDField> acroFormFields = new ArrayList<PDField>();
acroForm.getCOSObject().setDirect(true);
acroForm.getCOSObject().setNeedToBeUpdate(true);
acroFormFields.add(signatureField);
signatureField.getCOSObject().setNeedToBeUpdate(true);
acroForm.setFields(acroFormFields); //NEW
//PDAnnotationWidget Widget = new PDAnnotationWidget(); // wrong!!!
PDAnnotationWidget Widget = signatureField.getWidget();
//PDAnnotation Widget =
PDAnnotation.createAnnotation(signedDoc.getDocumentCatalog().getCOSObject());
Widget.getCOSObject().setNeedToBeUpdate(true);
Widget.setRectangle(pdRectangle);
Widget.setPage(page);
//PDStream pdfstream = new PDStream(signedDoc); // wrong!!!
PDStream pdfstream = new PDStream(doc);
pdfstream.getCOSObject().setNeedToBeUpdate(true);
PDXObjectForm form = new PDXObjectForm(pdfstream);
form.getCOSObject().setNeedToBeUpdate(true);
// set resources to xobj
PDResources resources = new PDResources();
resources.getCOSObject().setNeedToBeUpdate(true);
PDFont font = PDType1Font.HELVETICA;
form.setResources(resources);
form.setFormType(1);
PDRectangle bbox = new PDRectangle(pdRectangle.getWidth(),
pdRectangle.getHeight());
float height = bbox.getHeight();
form.setBBox(pdRectangle);
//PDAppearanceDictionary appearanceDictionary = new
PDAppearanceDictionary(signedDoc.getDocumentCatalog().getCOSDictionary()); //
wrong!!!
PDAppearanceDictionary appearanceDictionary = new
PDAppearanceDictionary();
appearanceDictionary.getCOSObject().setDirect(true);
appearanceDictionary.getCOSObject().setNeedToBeUpdate(true);
PDAppearanceStream appearanceStream = new
PDAppearanceStream(form.getCOSStream());
appearanceStream.getCOSObject().setNeedToBeUpdate(true);
appearanceDictionary.setNormalAppearance(appearanceStream);
OutputStream os = form.getCOSStream().createFilteredStream();
// appearance content stream must be written the hard way :-(
// see "operator summary" in the PDF specification
os.write(("0 0 0 rg\n" +
"0 0 100 100 re\n" + // assumed 100 x 100 at position 0,0
// replace with x y sigWidth
sigheight);
"f\n" +
"q\n" +
" 163 0 0 39 0 0 cm\n" + // my image size 163 x 39
" /Im0 Do\n" +
"Q\n" +
"q\n" +
"Q\n" +
"/F0 10 Tf\n" +
"BT\n" +
" (signed By:) Tj\n" + // all on the same line :-(
" (Name:name) Tj\n" +
" (Location:location) Tj\n" +
" (Reason:reason) Tj\n" +
"ET").getBytes());
os.close();
resources.addFont(font, "F0"); // exact key
resources.addXObject(new PDJpeg(doc, new
FileInputStream(tickImagePath)), "Im"); // just prefix
Widget.setAppearance(appearanceDictionary);
try
{
if (false) // disabled. This was just to see what ends in the
content stream. We need to write into the appearance stream.
{
//PDPageContentStream pagecontentStream = new
PDPageContentStream(signedDoc, page, true, false); // wrong!!!
PDPageContentStream pagecontentStream = new
PDPageContentStream(doc, page, true, false);
pagecontentStream.setNonStrokingColor(java.awt.Color.black);
pagecontentStream.addRect(x, y, sigWidth, sigheight);
int windingRule = PathIterator.WIND_NON_ZERO;
pagecontentStream.fill(windingRule);
PDXObjectImage imgobj = null;
//imgobj = new PDJpeg(signedDoc, new
FileInputStream(tickImagePath)); // wrong!!!
imgobj = new PDJpeg(doc, new
FileInputStream(tickImagePath));
//imgobj = createImageobject(tickImagePath, signedDoc,
stampingPage);
// draw xobject with coordinates
pagecontentStream.drawImage(imgobj, x, y);
pagecontentStream.saveGraphicsState();
pagecontentStream.restoreGraphicsState();
float fontSize = 8;
float leading = fontSize * 1.0f;
pagecontentStream.setFont(font, 10);
pagecontentStream.beginText();
//if (!string.IsNullOrEmpty(name)) // can't use this one in
java
{
pagecontentStream.drawString("signed By:");
pagecontentStream.drawString("Name:" + name);
}
//if (!string.IsNullOrEmpty(location))
{
pagecontentStream.drawString("Location:" + location);
}
//if (!string.IsNullOrEmpty(reason))
{
pagecontentStream.drawString("Reason:" + reason);
}
pagecontentStream.endText();
pagecontentStream.close();
}
}
catch (IOException ex)
{
ex.printStackTrace();
return null;
}
// NEW must add widget to page
List<PDAnnotation> annotations = new ArrayList<PDAnnotation>();
annotations.add(Widget);
page.setAnnotations(annotations);
//signedDoc.save(baos); // wrong
doc.save(baos);
doc.close(); // new
return new ByteArrayInputStream(baos.toByteArray());
}
catch (Exception ex)
{
ex.printStackTrace();
return null;
}
}
{code}
> how the visual representation of the signature is achieved
> ------------------------------------------------------------
>
> Key: PDFBOX-4556
> URL: https://issues.apache.org/jira/browse/PDFBOX-4556
> Project: PDFBox
> Issue Type: Wish
> Components: .NET
> Affects Versions: 1.8.16
> Reporter: bal
> Priority: Major
> Attachments: image error stacktrace.txt, npe at adappearence
> dictionary.txt, pdfAnnotation.pdf, visibleSignature.pdf
>
>
--
This message was sent by Atlassian JIRA
(v7.6.3#76005)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]