[ 
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]

Reply via email to