I seem to have a workaround. The solution is that when a PDF page has markup, use PDFRenderer to create a BufferedImage of the page at 300dpi, add the markup to the image (adjusting the markup to 300dpi), add the image to a new PDpage, and add that new page to outDocument. If there is no markup, I just add the inDocument PDPage to outDocument.
There's a time-image quality tradeoff, but I don't know if working Overlay would be faster. 300dpi seems to be good enough for my purposes. On Thu, Oct 21, 2021 at 11:21 AM Thad Humphries <thad.humphr...@gmail.com> wrote: > Yes, I can do that. It was meant as a simple illustration. The problem > returns when there are intermediate PDDocuments inside the for-loop > > I must create intermediary PDDocuments in order to Overlay a BufferedImage > onto each page. Even that can work if the overlay is the same for each page > *and* I don't close the overlay in the for-loop. But in my case the image > will change with each page. > > So this function works: > > @Test > > *public* *void* testCopyAnnotationOverlay() *throws* Exception { > > File inPdfFile = *new* File(*this*.getClass().getResource( > "/patent-3_139_857.pdf").toURI()); > > PDDocument inDocument = PDDocument.*load*(inPdfFile); > > > BufferedImage imageOverlay = ImageIO.*read*(*new* File(*this* > .getClass().getResource("/sample-annotation.png").toURI())); > > > PDDocument outDocument = *new* PDDocument(); > > *int* pages = inDocument.getNumberOfPages(); > > > > PDDocument overlayDocument; > > *for* (*int* page = 0; page < pages; page++) { > > PDPage pdPage = inDocument.getPage(page); > > > // Draw an image into a PDF page. > > PDPage imagePage = *new* PDPage(pdPage.getCropBox()); > > PDDocument imageDocument = *new* PDDocument(); > > imageDocument.addPage(imagePage); > > PDPageContentStream cos = *new* PDPageContentStream(imageDocument, > imagePage); > > PDImageXObject ximage = LosslessFactory.*createFromImage*( > imageDocument, imageOverlay); > > cos.drawImage(ximage, 0, 0); > > cos.close(); // this also close imageDocument > > > > overlayDocument = *new* PDDocument(); > > overlayDocument.addPage(pdPage); > > Overlay overlay = *new* Overlay(); > > overlay.setInputPDF(overlayDocument); > > overlay.setOverlayPosition(Overlay.Position.*FOREGROUND*); > > overlay.setAllPagesOverlayPDF(imageDocument); > > HashMap<Integer, String> overlayProps = *new* HashMap<Integer, > String>(); > > overlay.overlay(overlayProps); > > > > outDocument.importPage(overlayDocument.getPage(0)); > > // overlay.close(); > > } > > outDocument.save(*OUT_DIR* + "/out-pdf-patent.pdf"); > > inDocument.close(); > > outDocument.close(); > > Assert.*assertTrue*(*true*); > > } > > Note the commented out "overlay.close()". Leave that in and there will be > a COSStream error on save(). (Let the JVM clean it up.) > > Now alter the function so that "imageOverlay" is created inside the > for-loop (because I'll have a different markup on each page). There will be > a COSStream error on save(), even if I also comment out "cos.close()". > > On Thu, Oct 21, 2021 at 2:06 AM Tilman Hausherr <thaush...@t-online.de> > wrote: > >> close inDocument after saving the other. >> >> Tilman >> >> Am 20.10.2021 um 21:15 schrieb Thad Humphries: >> > I am using PDFBox 2.0.24. I am attempting to copy a PDF file to a new >> > PDDocument and save that new document. The eventual goal is to use >> Overlay >> > to overlay various images onto pages of the old document before >> > adding them to the new document. >> > >> > >> > The problem I'm having is that when I close the old document or any >> > intermediary document (like one created when making the Overlay), I get >> an >> > error "COSStream has been closed and cannot be read" when I save the new >> > document. >> > >> > >> > I can demonstrate this error simply with just a simple function: >> > >> > >> > @Test >> > >> > *public* *void* testCopyAnnotation() *throws* Exception { >> > >> > File inPdfFile = *new* File(*this*.getClass().getResource( >> > "/patent-3_139_857.pdf").toURI()); >> > >> > PDDocument inDocument = PDDocument.*load*(inPdfFile); >> > >> > PDDocument outDocument = *new* PDDocument(); >> > >> > *int* pages = inDocument.getNumberOfPages(); >> > >> > *for* (*int* page = 0; page < pages; page++) { >> > >> > PDPage pdPage = inDocument.getPage(page); >> > >> > outDocument.importPage(pdPage); >> > >> > } >> > >> > inDocument.close(); >> > >> > outDocument.save(*OUT_DIR* + "/out-pdf-patente.pdf"); >> > >> > outDocument.close(); >> > >> > Assert.*assertTrue*(*true*); >> > >> > } >> > >> > >> > The stack trace below is triggered by the line >> "outDocument.save(*OUT_DIR* >> > + "/out-pdf-patente.pdf");". >> > >> > >> > What is wrong here and how might I correct this? >> > >> > >> > *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:83) >> > >> > at >> org.apache.pdfbox.cos.COSStream.createRawInputStream(COSStream.java:133) >> > >> > at >> org.apache.pdfbox.pdfwriter.COSWriter.visitFromStream(COSWriter.java:1268 >> > ) >> > >> > at org.apache.pdfbox.cos.COSStream.accept(COSStream.java:416) >> > >> > at org.apache.pdfbox.cos.COSObject.accept(COSObject.java:158) >> > >> > at >> org.apache.pdfbox.pdfwriter.COSWriter.doWriteObject(COSWriter.java:572) >> > >> > at >> org.apache.pdfbox.pdfwriter.COSWriter.doWriteObjects(COSWriter.java:497) >> > >> > at org.apache.pdfbox.pdfwriter.COSWriter.doWriteBody(COSWriter.java:481) >> > >> > at org.apache.pdfbox.pdfwriter.COSWriter.visitFromDocument( >> > COSWriter.java:1162) >> > >> > at org.apache.pdfbox.cos.COSDocument.accept(COSDocument.java:452) >> > >> > at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1435) >> > >> > at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1322) >> > >> > at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1375) >> > >> > at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1342) >> > >> > at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1326) >> > >> > -->> at com.optix.server.rest.TestFileServlet.testCopyAnnotation( >> > TestFileServlet.java:152) >> > >> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) >> > >> > at sun.reflect.NativeMethodAccessorImpl.invoke( >> > NativeMethodAccessorImpl.java:62) >> > >> > at sun.reflect.DelegatingMethodAccessorImpl.invoke( >> > DelegatingMethodAccessorImpl.java:43) >> > >> > at java.lang.reflect.Method.invoke(Method.java:498) >> > >> > at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall( >> > FrameworkMethod.java:50) >> > >> > at org.junit.internal.runners.model.ReflectiveCallable.run( >> > ReflectiveCallable.java:12) >> > >> > at org.junit.runners.model.FrameworkMethod.invokeExplosively( >> > FrameworkMethod.java:47) >> > >> > at org.junit.internal.runners.statements.InvokeMethod.evaluate( >> > InvokeMethod.java:17) >> > >> > at org.junit.internal.runners.statements.RunBefores.evaluate( >> > RunBefores.java:26) >> > >> > at org.junit.internal.runners.statements.RunAfters.evaluate( >> > RunAfters.java:27) >> > >> > at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55) >> > >> > at org.junit.rules.RunRules.evaluate(RunRules.java:20) >> > >> > at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) >> > >> > at org.junit.runners.BlockJUnit4ClassRunner.runChild( >> > BlockJUnit4ClassRunner.java:78) >> > >> > at org.junit.runners.BlockJUnit4ClassRunner.runChild( >> > BlockJUnit4ClassRunner.java:57) >> > >> > at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) >> > >> > at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) >> > >> > at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) >> > >> > at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) >> > >> > at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) >> > >> > at org.junit.runners.ParentRunner.run(ParentRunner.java:363) >> > >> > at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run( >> > JUnit4TestReference.java:93) >> > >> > at org.eclipse.jdt.internal.junit.runner.TestExecution.run( >> > TestExecution.java:40) >> > >> > at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests( >> > RemoteTestRunner.java:529) >> > >> > at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests( >> > RemoteTestRunner.java:756) >> > >> > at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run( >> > RemoteTestRunner.java:452) >> > >> > at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main( >> > RemoteTestRunner.java:210) >> > >> > >> > >> > >> >> >> --------------------------------------------------------------------- >> To unsubscribe, e-mail: users-unsubscr...@pdfbox.apache.org >> For additional commands, e-mail: users-h...@pdfbox.apache.org >> >> > > -- > "Hell hath no limits, nor is circumscrib'd In one self-place; but where we > are is hell, And where hell is, there must we ever be" --Christopher > Marlowe, *Doctor Faustus* (v. 111-13) > -- "Hell hath no limits, nor is circumscrib'd In one self-place; but where we are is hell, And where hell is, there must we ever be" --Christopher Marlowe, *Doctor Faustus* (v. 111-13)