I'm not actively working with the old iText versions anymore but some things have not changed since then. Thus, here some issues in your code and pointers helping to resolve them:
Your main issues in your current code are that you
reuse the Document
instance (which you already use for your PdfWriter
and already have opened) for a PdfCopy
; while a Document
can support multiple listeners, they all need to be registered before calling open
; the use case of this construct is to create the same document in parallel in two different formats; and you
use the same output stream for both your PdfWriter
and your PdfCopy
; the result is not one valid PDF but byte ranges from two different PDFs wildly mixed together, i.e. something that definitely won't be a valid PDF.
Using PdfCopy
correctly
You can restructure your code by first creating a new PDF containing you new paragraphs in a ByteArrayOutputStream
(closing the Document
involved) and then copy this PDF and the other pages you want to add into a new PDF.
E.g. like this:
ByteArrayOutputStream os = new ByteArrayOutputStream();
Document bigDoc = new Document(PageSize.LETTER, 50, 50, 110, 60);
PdfWriter writer = PdfWriter.getInstance(bigDoc, os);
bigDoc.open();
Paragraph par = new Paragraph("one");
bigDoc.add(par);
bigDoc.add(new Paragraph("three"));
bigDoc.close();
ByteArrayOutputStream os2 = new ByteArrayOutputStream();
Document finalDoc = new Document();
PdfCopy copy = new PdfCopy(finalDoc, new FileOutputStream(RESULT2));
finalDoc.open();
PdfReader reader = new PdfReader(os.toByteArray());
for (int i = 0; i < reader.getNumberOfPages();) {
copy.addPage(copy.getImportedPage(reader, ++i));
}
PdfReader pdfReader = new PdfReader("c:/insertable.pdf");
copy.addPage(copy.getImportedPage(pdfReader, 1));
finalDoc.close();
reader.close();
pdfReader.close();
// result PDF
byte[] result = os2.toByteArray();
Using only PdfWriter
You can alternatively change your code by directly importing the page into your PdfWriter
, e.g. like this:
ByteArrayOutputStream os = new ByteArrayOutputStream();
Document bigDoc = new Document(PageSize.LETTER, 50, 50, 110, 60);
PdfWriter writer = PdfWriter.getInstance(bigDoc, os);
bigDoc.open();
Paragraph par = new Paragraph("one");
bigDoc.add(par);
bigDoc.add(new Paragraph("three"));
PdfReader pdfReader = new PdfReader("c:/insertable.pdf");
PdfImportedPage page = writer.getImportedPage(pdfReader, 1);
bigDoc.newPage();
PdfContentByte canvas = writer.getDirectContent();
canvas.addTemplate(page, 1, 0, 0, 1, 0, 0);
bigDoc.close();
pdfReader.close();
// result PDF
byte[] result = os.toByteArray();
This approach appears better because no intermediary PDF is required. Unfortunately this appearance is deceiving, this approach as some disadvantages.
Here not the whole original page is copied and added as is to the document but instead only its content stream is used as the content of a template which then is referenced from the actual new document page. This in particular means:
If the imported page has different dimensions than your new target document, some parts of it might be cut of while some parts of the new page remain empty. Because of this you will often find variants of the code above which by scaling and rotating try to make the imported page and target page fit.
The original page contents are now in a template which is referenced from the new page. If you import this new page into yet another document using the same mechanism, you get a page which references a template which again merely references a template which has the original contents. If you import this page into another document, you get another level of indirectness. Etc. etc..
Unfortunately conforming PDF viewers only need to support this indirectness to a limited degree. If you continue this process, your page contents suddenly may not be visible anymore. If the original page already brings along its own hierarchy of referenced templates, this may happen sooner rather than later.
As only the contents are copied, properties of the original page not in the content stream will be lost. This in particular concerns annotations like form fields or certain types of highlight markings or even certain types of free text.
(By the way, these templates in generic PDF specification lingo are called Form XObjects.)
This answer explicitly deals with the use of PdfCopy
and PdfWriter
in the context of merging PDFs.