[ 
https://issues.apache.org/jira/browse/PDFBOX-3743?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15955249#comment-15955249
 ] 

Tilman Hausherr commented on PDFBOX-3743:
-----------------------------------------

Here's your code modified so that it runs:
{code}
public class PDFBox3743SigProblem
{
    static String dir = "XXXXXXXXXXXXXXXXXXX";

    public static void main(String[] args) throws IOException, 
URISyntaxException
    {
        try (PDDocument doc = PDDocument.load(new File(dir, "xxx.pdf")))
        {
            if (false)
            {
                doc.addSignature(
                        new PDSignature(),
                        is -> new byte[0],
                        getSignatureOptions(doc, new File(dir, "sig.jpg"))
                );
                // IOException when gc(): COSStream has been closed and cannot 
be read. Perhaps its enclosing PDDocument has been closed?
            }
            else
            {
                SignatureOptions signatureOptions = getSignatureOptions(doc, 
new File(dir, "sig.jpg"));
                doc.addSignature(
                        new PDSignature(),
                        is -> new byte[0],
                        signatureOptions
                );
                // works
            }

            System.gc();

            try (FileOutputStream out = new FileOutputStream(new File(dir, 
"xxx-signed.pdf")))
            {
                doc.saveIncremental(out);
            }
        }
    }

    private static SignatureOptions getSignatureOptions(PDDocument doc, File 
signatureImage) throws IOException
    {
        SignatureOptions signatureOptions = new SignatureOptions();

        PDVisibleSignDesigner visibleSignature;
        try (InputStream input = new FileInputStream(signatureImage))
        {
            visibleSignature = new PDVisibleSignDesigner(doc, input, 1);
        }

        PDVisibleSigProperties visibleSignatureProperties = new 
PDVisibleSigProperties();
        
visibleSignatureProperties.setPdVisibleSignature(visibleSignature).buildSignature();
        signatureOptions.setVisualSignature(visibleSignatureProperties);

        return signatureOptions;
    }
}
{code}
Look at the first "if" statement. When the condition is "true", the code fails. 
When it is false, the code succeeds. It is related to signatureOptions falling 
out of scope. You might also have seen this log output:
{quote}
WARN  \[Finalizer] org.apache.pdfbox.cos.COSDocument:478 - Warning: You did not 
close a PDF Document
{quote}
That one means that PDFBox closes a COSDocument object (that is in the 
signatureOptions) for you. I made a modification to SignatureOptions to see if 
finalize is called before things go bad, and yes it is :-(

Your problem reminds me of this
https://stackoverflow.com/questions/42208399/pdfbox-how-to-clone-a-page
see the comment by mkl.

So signatureOptions goes out of scope, and thus COSDocument is also not needed 
anymore either... but the signed PDF keeps references of some of the streams in 
the COSDocument. Because the COSDocument is no longer referenced, it gets 
closed at the gc() moment, which also closes streams that are still needed. So 
the solution in the CreateVisibleSignature example is the correct one: keep 
signatureOptions until done, and close it yourself (i.e. even the "false" 
branch here is not really correct!!!). I will add a comment into the 
CreateVisibleSignature example and improve the javadoc of 
SignatureOptions.close().

Thus, TODO for you: add {{signatureOptions.close();}} as last statement.

Btw your code is incorrect, it doesn't sign anything. Unlike the 
CreateVisibleSignature example, which can sign.


> Running GC between signing and saving document closes stream
> ------------------------------------------------------------
>
>                 Key: PDFBOX-3743
>                 URL: https://issues.apache.org/jira/browse/PDFBOX-3743
>             Project: PDFBox
>          Issue Type: Bug
>    Affects Versions: 2.0.5
>         Environment: Ubuntu 16.04 64-bit, play framework 1.5
>            Reporter: Dmitri Ess
>
> Running GC between signing and saving document closes stream and signing 
> process fails. It happens only if signature image is added via 
> PDVisibleSignDesigner e.g.
> import org.apache.commons.io.IOUtils;
> import org.apache.pdfbox.pdmodel.PDDocument;
> import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
> import 
> org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
> import 
> org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigProperties;
> import 
> org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner;
> import java.io.*;
> import java.net.URISyntaxException;
> import static java.lang.Thread.currentThread;
> public class Foo {
>   public static void main(String[] args) throws IOException, 
> URISyntaxException {
>     byte[] unsignedPdf = getResourceAsBytes("pdf-sample.pdf");
>     try (PDDocument doc = PDDocument.load(unsignedPdf)) {
>       doc.addSignature(
>           new PDSignature(),
>           is -> new byte[0],
>           getSignatureOptions(doc, getFile("util/test-pdf-signature.jpg"))
>       );
>       System.gc();
>       try (FileOutputStream out = new 
> FileOutputStream(File.createTempFile("signed", ".pdf"))) {
>         doc.saveIncremental(out);
>       }
>     }
>   }
>   private static SignatureOptions getSignatureOptions(PDDocument doc, File 
> signatureImage) throws IOException {
>     SignatureOptions result = new SignatureOptions();
>     PDVisibleSignDesigner visibleSignature;
>     try (InputStream input = new FileInputStream(signatureImage)) {
>       visibleSignature = new PDVisibleSignDesigner(doc, input, 1);
>     }
>     PDVisibleSigProperties visibleSignatureProperties = new 
> PDVisibleSigProperties();
>     
> visibleSignatureProperties.setPdVisibleSignature(visibleSignature).buildSignature();
>     result.setVisualSignature(visibleSignatureProperties);
>     return result;
>   }
>   public static byte[] getResourceAsBytes(String filePath) throws 
> IOException, URISyntaxException {
>     return IOUtils.toByteArray(getFile(filePath).toURI());
>   }
>   public static File getFile(String filePath) throws URISyntaxException {
>     return new 
> File(currentThread().getContextClassLoader().getResource(filePath).toURI());
>   }
> }
> constantly fails with:
> Exception in thread "main" java.io.IOException: COSStream has been closed and 
> cannot be read. Perhaps its enclosing PDDocument has been closed?
>       at org.apache.pdfbox.cos.COSStream.checkClosed(COSStream.java:77)
>       at 
> org.apache.pdfbox.cos.COSStream.createRawInputStream(COSStream.java:125)
>       at 
> org.apache.pdfbox.pdfwriter.COSWriter.visitFromStream(COSWriter.java:1203)
>       at org.apache.pdfbox.cos.COSStream.accept(COSStream.java:383)
>       at org.apache.pdfbox.cos.COSObject.accept(COSObject.java:158)
>       at 
> org.apache.pdfbox.pdfwriter.COSWriter.doWriteObject(COSWriter.java:522)
>       at 
> org.apache.pdfbox.pdfwriter.COSWriter.doWriteObjects(COSWriter.java:460)
>       at org.apache.pdfbox.pdfwriter.COSWriter.doWriteBody(COSWriter.java:444)
>       at 
> org.apache.pdfbox.pdfwriter.COSWriter.visitFromDocument(COSWriter.java:1099)
>       at org.apache.pdfbox.cos.COSDocument.accept(COSDocument.java:419)
>       at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1370)
>       at 
> org.apache.pdfbox.pdmodel.PDDocument.saveIncremental(PDDocument.java:1276)
>       at Foo.main(Foo.java:27)



--
This message was sent by Atlassian JIRA
(v6.3.15#6346)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to