I am having problem while merging documents of different width using iText.
Below is the code I'm using to merge.
public static void doMerge(List<InputStream> list, OutputStream outputStream) throws Exception {
Rectangle pagesize = new Rectangle(1700f, 20f);
com.itextpdf.text.Document document = new com.itextpdf.text.Document(pagesize);
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
document.setPageSize(pagesize);
com.itextpdf.text.pdf.PdfContentByte cb = writer.getDirectContent();
for (InputStream in : list){
PdfReader reader = new PdfReader(in);
for (int i = 1; i <= reader.getNumberOfPages(); i++){
document.newPage();
//import the page from source pdf
com.itextpdf.text.pdf.PdfImportedPage page = writer.getImportedPage(reader, i);
//calculate the y for merging it from top
float y = document.getPageSize().getHeight() - page.getHeight();
//add the page to the destination pdf
cb.addTemplate(page, 0, y);
}
reader.close();
in.close();
}
outputStream.flush();
document.close();
outputStream.close();
}
First page of pdf will be of 14 inch of width and 13 inch of height. All the other pages on document will be always smaller than it.
I want to merge all the documents altogether in a single document.
I don't know how to set a width and height of a single merged document.
I think Rectangle pagesize = new Rectangle(1700f, 20f); should do it but it's not working means if change it to Rectangle pagesize = new Rectangle(1700f, 200f);, document has no effect.
Please guide me further.
Using the PdfWriter class to merge documents goes against all the recommendations given in the official documentation, though there are unofficial examples that may have lured you into writing bad code. I hope that you understand that I find these bad examples even more annoying than you do.
Please take a look at Table 6.1 in chapter 6 of my book. It gives you an overview showing when to use which class. In this case, you should use PdfCopy:
String[] files = { MovieLinks1.RESULT, MovieHistory.RESULT };
// step 1
Document document = new Document();
// step 2
PdfCopy copy = new PdfCopy(document, new FileOutputStream(RESULT));
// step 3
document.open();
// step 4
PdfReader reader;
int n;
// loop over the documents you want to concatenate
for (int i = 0; i < files.length; i++) {
reader = new PdfReader(files[i]);
// loop over the pages in that document
n = reader.getNumberOfPages();
for (int page = 0; page < n; ) {
copy.addPage(copy.getImportedPage(reader, ++page));
}
copy.freeReader(reader);
reader.close();
}
// step 5
document.close();
If you are using a recent version of iText, you can even use the addDocument() method in which case you don't need to loop over all the pages. You also need to take special care if forms are involved. There are several examples demonstrating the new functionality (dating from after the book was written) in the Sandbox.
with the itext version 5.5 we can merge pdf more easly using the method PdfCopy.addDocument :
package tn.com.sf.za.rd.controller;
import java.io.FileOutputStream;
import java.io.IOException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
public class ReportMerging {
public static void main(String[] args) throws DocumentException, IOException {
String DOC_ONE_PATH = "D:/s.zaghdoudi/tmp/one.pdf";
String DOC_TWO_PATH = "D:/s.zaghdoudi/tmp/two.pdf";
String DOC_THREE_PATH = "D:/s.zaghdoudi/tmp/three.pdf";
Document document = new Document();
PdfCopy copy = new PdfCopy(document, new FileOutputStream(DOC_THREE_PATH));
document.open();
PdfReader readerOne = new PdfReader(DOC_ONE_PATH);
PdfReader readerTwo = new PdfReader(DOC_TWO_PATH);
copy.addDocument(readerOne);
copy.addDocument(readerTwo);
document.close();
}
}
Related
I need to generate large size PDF by adding multiple images to it. In itext 5 if I add a image to the document it is immediately flushed to disk. But in itext 7 it stays in memory and is written to disk only after closing the document.
Itext 7 docs says about using large tables concept https://kb.itextpdf.com/home/it7kb/examples/large-tables , which I tried but it also doesnt flush the images to disk.
Anyone know why ? Thanks in advance for help.
itext 5 code (java)
Document document = new Document(PageSize.A4, 36, 36, 36, 72);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("test.pdf"));
document.open();
Image image1 = null;
for (int i = 0; i < 1000; i++) {
File f = new File("big_image.png");
InputStream is = new FileInputStream(f);
image1 = Image.getInstance(IOUtils.toByteArray(is));
document.add(image1);
}
document.close();
writer.close();
itext 7 code (java)
PdfDocument pdfDoc = new PdfDocument(new PdfWriter("test.pdf"));
Document doc = new Document(pdfDoc);
for (int i = 0; i < 1000; i++) {
File f = new File("big_image.png");
doc.add(new Image(ImageDataFactory.create(f.getPath())));
}
doc.close();
It seems this is not working as intended in iText 7. We'll need to look into it further (disclosure: I'm an iText Software employee).
In the meantime, as a simple workaround, you can flush the images explicitly:
for (int i = 0; i < 1000; i++) {
File f = new File("big_image.png");
Image image = new Image(ImageDataFactory.create(f.getPath()));
image.getXObject().makeIndirect(pdfDoc).flush();
doc.add(image);
}
I am using iText 2.1.7 to merge some document PDFs into a single PDF. The code below seems to work just fine, however it appears in some instances the rendered PDF is scaled slightly smaller, like at 90% of the PDF if printed directly before processing.
Is there a way to keep the current size?
private void doMerge(List<InputStream> list, OutputStream outputStream) throws DocumentException, IOException {
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
PdfContentByte cb = writer.getDirectContent();
for (InputStream in : list) {
PdfReader reader = new PdfReader(in);
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
document.newPage();
//import the page from source pdf
PdfImportedPage page = writer.getImportedPage(reader, i);
//add the page to the destination pdf
cb.addTemplate(page, 0, 0);
}
}
outputStream.flush();
document.close();
outputStream.close();
}
The API was already available with that version. I would even suggest to use PdfSmartCopy instead of PdfCopy (or PdfCopyFields if form fields are inside).
private PdfSmartCopy copier;
public void SomeMainMethod(){
Document finalPdf = new Document();
copier = new PdfSmartCopy(finalPdf, outputstream);
//Start adding pdfs
finalPdf.open();
//add n documents
addDocuments(...);
finalPdf.close();
formCopier.close();
}
public void addDocument(InputStream pdfDocument, int startPage, int endPage){
PdfReader reader= new PdfReader(pdfDocument);
int startPage = 1;
int endPage = reader.getNumberOfPages();
for (int i = startPage; i <= endPage; i++) {
copier.addPage(this.copier.getImportedPage(reader,i));
}
if(copier!=null){
//Important: Free Memory!
copier.flush();
copier.freeReader(reader);
}
if (reader!=null) {
reader.close();
reader=null;
}
pdfDocument.close();
}
I am programmatically trying to create an pdf by superimposing two pdf files using itextpdf. The PDF that was made goes into this flattening process for some reason, how do I skip flattening or make the process faster.
PdfReader reader = new PdfReader(template);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
PdfReader r;
PdfImportedPage page;
int i=1;
for (String path : patterns) {
r = new PdfReader(path);
for(int j=1;j<=r.getNumberOfPages();j++) {
page = stamper.getImportedPage(r, j);
PdfContentByte canvas = stamper.getUnderContent(i++);
canvas.addTemplate(page, 0, 0);
stamper.getWriter().freeReader(r);
}
r.close();
}
stamper.close();
The PDF that was generated from Adobe Illustrator had an masked image instead of a proper component. I am sorry if the answer seems vague but I am not a designer but the flattening process happens when the one or more of the original PDFs that are being merged aren't proper.
I was thinking about using a library such as PDFBox but I would like your input.
I can recommend iText, it works pretty well for manipulating PDFs or even constructing them from scratch.
There is also a tutorial on how to manipulate PDFs. I didn't see a way to delete pages, but the tool supports creating a new PDF by copying content from another one. So you could just copy all the pages but the first.
With IText
public void removeFirstPage(String input_filename, String output_filename) throws DocumentException, IOException {
File outFile = new File(output_filename);
PdfReader reader = new PdfReader(input_filename);
int pages_number = reader.getNumberOfPages();
if(pages_number > 0) {
Document document = new Document(reader.getPageSizeWithRotation(1));
PdfCopy copy = new PdfCopy(document, new FileOutputStream(outFile));
document.open();
for(int i=2; i <= pages_number;i++) {
PdfImportedPage page = copy.getImportedPage(reader, i);
copy.addPage(page);
}
document.close();
}
}
I have 3 PDF documents that are generated on the fly by a legacy library that we use, and written to disk. What's the easiest way for my JAVA server code to grab these 3 documents and turn them into one long PDF document where it's just all the pages from document #1, followed by all the pages from document #2, etc.
Ideally I would like this to happen in memory so I can return it as a stream to the client, but writing it to disk is also an option.
#J D OConal, thanks for the tip, the article you sent me was very outdated, but it did point me towards iText. I found this page that explains how to do exactly what I need:
http://java-x.blogspot.com/2006/11/merge-pdf-files-with-itext.html
Thanks for the other answers, but I don't really want to have to spawn other processes if I can avoid it, and our project already has itext.jar, so I'm not adding any external dependancies
Here's the code I ended up writing:
public class PdfMergeHelper {
/**
* Merges the passed in PDFs, in the order that they are listed in the java.util.List.
* Writes the resulting PDF out to the OutputStream provided.
*
* Sample Usage:
* List<InputStream> pdfs = new ArrayList<InputStream>();
* pdfs.add(new FileInputStream("/location/of/pdf/OQS_FRSv1.5.pdf"));
* pdfs.add(new FileInputStream("/location/of/pdf/PPFP-Contract_Genericv0.5.pdf"));
* pdfs.add(new FileInputStream("/location/of/pdf/PPFP-Quotev0.6.pdf"));
* FileOutputStream output = new FileOutputStream("/location/to/write/to/merge.pdf");
* PdfMergeHelper.concatPDFs(pdfs, output, true);
*
* #param streamOfPDFFiles the list of files to merge, in the order that they should be merged
* #param outputStream the output stream to write the merged PDF to
* #param paginate true if you want page numbers to appear at the bottom of each page, false otherwise
*/
public static void concatPDFs(List<InputStream> streamOfPDFFiles, OutputStream outputStream, boolean paginate) {
Document document = new Document();
try {
List<InputStream> pdfs = streamOfPDFFiles;
List<PdfReader> readers = new ArrayList<PdfReader>();
int totalPages = 0;
Iterator<InputStream> iteratorPDFs = pdfs.iterator();
// Create Readers for the pdfs.
while (iteratorPDFs.hasNext()) {
InputStream pdf = iteratorPDFs.next();
PdfReader pdfReader = new PdfReader(pdf);
readers.add(pdfReader);
totalPages += pdfReader.getNumberOfPages();
}
// Create a writer for the outputstream
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
PdfContentByte cb = writer.getDirectContent(); // Holds the PDF
// data
PdfImportedPage page;
int currentPageNumber = 0;
int pageOfCurrentReaderPDF = 0;
Iterator<PdfReader> iteratorPDFReader = readers.iterator();
// Loop through the PDF files and add to the output.
while (iteratorPDFReader.hasNext()) {
PdfReader pdfReader = iteratorPDFReader.next();
// Create a new page in the target for each source page.
while (pageOfCurrentReaderPDF < pdfReader.getNumberOfPages()) {
document.newPage();
pageOfCurrentReaderPDF++;
currentPageNumber++;
page = writer.getImportedPage(pdfReader, pageOfCurrentReaderPDF);
cb.addTemplate(page, 0, 0);
// Code for pagination.
if (paginate) {
cb.beginText();
cb.setFontAndSize(bf, 9);
cb.showTextAligned(PdfContentByte.ALIGN_CENTER, "" + currentPageNumber + " of " + totalPages,
520, 5, 0);
cb.endText();
}
}
pageOfCurrentReaderPDF = 0;
}
outputStream.flush();
document.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (document.isOpen()) {
document.close();
}
try {
if (outputStream != null) {
outputStream.close();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
I've used pdftk to great effect. It's an external application that you'll have to run from your java app.
iText seems to have changed and now has commercial licencing requirements, along with not that good help (Want documentation? Buy our book!).
We ended up finding PDFSharp http://www.pdfsharp.net/ and using that. The sample for concatenating multiple pdf documents together is simple and easy to follow: http://www.pdfsharp.net/wiki/ConcatenateDocuments-sample.ashx
Enjoy
Random
Take a look at this list of Java open source PDF libraries.
Also check out this article.
[Edit: There's always Ghostscript, which is easy to use, but who wants more dependencies?]
iText PdfCopy
PDFBox is by far the easiest way to achieve this, there is a utility called PDFMerger within the code which makes things very easy, all it took me was a for loop and 2 lines of code in it and all done :)