How do you add multiple images to a PDF with itext7 Java? - java

First google result takes me to Add multiple images into a single pdf file with iText using java which was posted 5 years ago. I am not sure which version they are using, because the Image object doesn't even have the getInstance method for me. Needless to say I am not getting much help from that link.
Anyways I am trying to create a javaFX application that loops multiple JPG images to create a single PDF document. Below is my code, which successfully creates a PDF from 2 images, but I am having trouble making the second image display on the second page.
In the link I posted above the simple solution I saw was to do document.newPage() then do document.add(img), but my document object doesn't have that method? I am not sure what to do.
PdfWriter writer = new PdfWriter("D:/sample1.pdf");
// Creating a PdfDocument
PdfDocument pdfDoc = new PdfDocument(writer);
// Adding a new page
// I can add multiple pages here, but when I add multiple images they do not
// automatically flow over to the next page.
pdfDoc.addNewPage();
pdfDoc.addNewPage();
// Creating a Document
Document document = new Document(pdfDoc);
String imageFile = "C:/Users/***/Downloads/MAT204/1.3-1.4 HW/test.jpg";
ImageData data = ImageDataFactory.create(imageFile);
Image img = new Image(data);
img.setAutoScale(true);
img.setRotationAngle(-Math.toRadians(90));
// I can add multiple images, but they overlaps each other and only
// appears on the first page.
// Is there a way for me to change the current page to write on?
document.add(img);
document.add(img);
// Closing the document
document.close();
System.out.println("PDF Created");
Anyways, I just want to figure out how to manually add another image before I write a loop to automate the process.

After doing more research I found the answer here.
https://kb.itextpdf.com/home/it7kb/examples/multiple-images
protected void manipulatePdf(String dest) throws Exception {
Image image = new Image(ImageDataFactory.create(IMAGES[0]));
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
Document doc = new Document(pdfDoc, new PageSize(image.getImageWidth(), image.getImageHeight()));
for (int i = 0; i < IMAGES.length; i++) {
image = new Image(ImageDataFactory.create(IMAGES[i]));
pdfDoc.addNewPage(new PageSize(image.getImageWidth(), image.getImageHeight()));
image.setFixedPosition(i + 1, 0, 0);
doc.add(image);
}
doc.close();
}

Related

How to copy one page of a PDFDocument , to another PDFDocument

I have a doubt about PDFDocuments. How can I copy a specific page of a PdfDocument object , to another PdfDocument object.
I've tried with the moveTo method , but It didn't worked , also Ive tried with copyPagesTo method , but I throws an Requested page is out of bounds (when I try to copy for example only one page , from 1 to 1).
Any hint?
List<PdfDocument> pdfDocuments = new ArrayList<>();
PdfDocument pdfWithMultiplePages = here I have a PDF with 3 pages.
for (int i = 0 ; i<pdfWithMultiplePages.getNumberOfPages() ; i++){
final ByteArrayOutputStream byteArrayOutputStream = new
ByteArrayOutputStream();
final PdfWriter pdfWriter = new PdfWriter(byteArrayOutputStream);
PdfDocument pdfDocument = new PdfDocument(pdfWriter);
pdfDocument.copyPagesTo(i+1, i+1,pdfWithMultiplePages);
pdfWriter.close();
byteArrayOutputStream.close();
shippingLabels.add(shippingLabelSplitted);
}
I've tried also with this :
List<PdfDocument> pdfDocuments = new ArrayList<>();
PdfDocument pdfWithMultiplePages = here I have a PDF with 3 pages.
for (int i = 0 ; i<pdfWithMultiplePages.getNumberOfPages() ; i++){
final ByteArrayOutputStream byteArrayOutputStream = new
ByteArrayOutputStream();
final PdfWriter pdfWriter = new PdfWriter(byteArrayOutputStream);
PdfDocument pdfDocument = new PdfDocument(pdfWriter);
pdfDocument.addPage(1,pdfWithMultiplePages.getPage(i+1));
pdfWriter.close();
byteArrayOutputStream.close();
shippingLabels.add(shippingLabelSplitted);
}
But it throws :
com.itextpdf.kernel.PdfException: Page com.itextpdf.kernel.pdf.PdfPage#6576eb4b cannot be added to document com.itextpdf.kernel.pdf.PdfDocument#286ef136, because it belongs to document com.itextpdf.kernel.pdf.PdfDocument#2c74aa66.
A page in a PDF has many relations to other objects in a PDF.
If you could add a page located in one document to another one, the page would reside in both documents. Thus, the page suddenly would have to have all those relations to objects in both documents. This obviously does not work, thus iText prevents this.
Instead you have to create a copy of the page(s) in question for which the relations are switched to documents in the target document.
For this task there are multiple method overloads of PdfDocument.copyPagesTo. Thus, these methods indeed are the ones to use.
Unfortunately you mistake source and target of the operation:
PdfDocument pdfWithMultiplePages = here I have a PDF with 3 pages.
....
PdfDocument pdfDocument = new PdfDocument(pdfWriter);
pdfDocument.copyPagesTo(i+1, i+1,pdfWithMultiplePages);
This tries to copy page i+1 from pdfDocument to pdfWithMultiplePages. But you just created pdfDocument from scratch, so it does not have any pages yet. What you most probably want is:
pdfWithMultiplePages.copyPagesTo(i+1, i+1, pdfDocument);

iText add image to pdf - setAbsolutePosition [duplicate]

I am trying to read one PDF and copy its data into another PDF. The first PDF contains some text and images and I wish to write an image in the second PDF exactly where the text ends(which is basically the end of the PDF file). RIght now it just prints at the top. How can I make this change?
PdfReader reader = null;
reader = new PdfReader(Var.input);
Document document=new Document();
PdfWriter writer = null;
writer = PdfWriter.getInstance(document,new FileOutputStream(Var.output));
PdfImportedPage page = writer.getImportedPage(reader, 1);
reader.close();
document.open();
PdfContentByte cb = writer.getDirectContent();
// Copy first page of existing PDF into output PDF
document.newPage();
cb.addTemplate(page, 0, 0);
// Add your new data / text here
Image image = null;
image = Image.getInstance (Var.qr);
document.add(image);
document.close();
Try this:
First get the location/co-ords of where the image needs to go, then simply add the second line from below to your code so the image is inserted at that location "X, Y"
Image image = Image.getInstance(String RESOURCE);
image.setAbsolutePosition(X, Y);
writer.getDirectContent().addImage(image);
Take a look here for some examples in iText 5: https://itextpdf.com/en/resources/examples/itext-5-legacy/chapter-3-adding-content-absolute-positions
You should use a PdfStamper instead of a PdfWriter with imported pages. Your approach throws away all interactive contents. You can use sorifiend's idea there, too.
To determine where the text on the given page ends, have a look at the iText in Action, 2nd edition example ShowTextMargins which parses a PDF and ads a rectangle showing the text margin.

iText: Importing styled Text and informations from an existing PDF

I´m generating PDFs using iText and it works fine. But I need a way to import html styled informations from an existing PDF at some point.
I know i could just use the XMLWorker class to generate the text directly from html in my own document. But cause I´m not sure whether it actually supports all html features I´m looking to work around this.
Therefore a PDF is generated from html using XSLT. The content of this PDF then should be copied to my document.
There are two ways discribed in the book ("iText in Action").
One that parses the PDF and gets you the text (or other informations) from the document using PdfReaderContentParser and TextExtractionStrategy.
It looks like this:
PdfReader reader = new PdfReader(pdf);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
TextExtractionStrategy strategy;
for(int i=1;i<=reader.getNumberOfPages();i++){
strategy = parser.processContent(i, new LocationTextExtractionStrategy());
document.add(new Chunk(strategy.getResultantText()));
}
But this only prints plain text to the document. Obviously there are more ExtractionStrategys and maybe one of them does exactly what i want but i couldn´t find it yet.
The second way is to copy an itextpdf.text.Image of each side of the PDF to your document. This is obviously not a good idea, cause it will add the entire page to your document even if there is only one line of text in the existing PDF. Its done like this:
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
PdfReader reader = new PdfReader(pdf);
PdfImportedPage page;
for(int i=1;i<=reader.getNumberOfPages();i++){
page = writer.getImportedPage(reader,i);
document.add(Image.getInstance(page));
}
Like I said this copys all the empty lines at the end of the PDF aswell, but i need to continue my text immediatly after the last line of text.
If I could convert this itext.text.Image into a java.awt.BufferedImage I could use getSubImage(); and informations i can extract from the PDF to cut away all the empty lines. But i wasn´t able to find a way to to this.
This are the two ways i found. But cause none of them is suitable for my purpose as they are my question is:
Is there a way to import everything except the empty lines at the end, but including text-style informations, tables and everything else from a PDF to my document using iText?
You can trim away empty space of the XSLT generated PDF and then import the trimmed pages as in your code.
Example code
The following code borrows from the code in my answer to Using iTextPDF to trim a page's whitespace. In contrast to the code there, though, we have to manipulate the media box, not the crop box, because this is the only box respected by PdfWriter.getImportedPage.
Before importing a page from a given PdfReader, crop it using this method:
static void cropPdf(PdfReader reader) throws IOException
{
int n = reader.getNumberOfPages();
for (int i = 1; i <= n; i++)
{
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
MarginFinder finder = parser.processContent(i, new MarginFinder());
Rectangle rect = new Rectangle(finder.getLlx(), finder.getLly(), finder.getUrx(), finder.getUry());
PdfDictionary page = reader.getPageN(i);
page.put(PdfName.MEDIABOX, new PdfArray(new float[]{rect.getLeft(), rect.getBottom(), rect.getRight(), rect.getTop()}));
}
}
(excerpt from ImportPageWithoutFreeSpace.java)
The extended render listener MarginFinder is taken as is from the question linked to above. You can find a copy here: MarginFinder.java.
Example run
Using this code
PdfReader readerText = new PdfReader(docText);
cropPdf(readerText);
PdfReader readerGraphics = new PdfReader(docGraphics);
cropPdf(readerGraphics);
try ( FileOutputStream fos = new FileOutputStream(new File(RESULT_FOLDER, "importPages.pdf")))
{
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, fos);
document.open();
document.add(new Paragraph("Let's import 'textOnly.pdf'", new Font(FontFamily.HELVETICA, 12, Font.BOLD)));
document.add(Image.getInstance(writer.getImportedPage(readerText, 1)));
document.add(new Paragraph("and now 'graphicsOnly.pdf'", new Font(FontFamily.HELVETICA, 12, Font.BOLD)));
document.add(Image.getInstance(writer.getImportedPage(readerGraphics, 1)));
document.add(new Paragraph("That's all, folks!", new Font(FontFamily.HELVETICA, 12, Font.BOLD)));
document.close();
}
finally
{
readerText.close();
readerGraphics.close();
}
(excerpt from unit test method testImportPages in ImportPageWithoutFreeSpace.java)
I imported both the page from the docText document
and the page from the docGraphics document
into a new document with some text before, between, and after. The result:
As you can see, source styles are preserved but free space around is discarded.

Is it possible to mark a string in pdf document?

I was wondering if it was possible to mark strings in pdf with different color or underline them while looping through the pdf document ?
It's possible on creating a document. Just use different chunks to set the style. Here's an example:
Document document = new Document();
PdfWriter.getInstance(document, outputStream);
document.open();
document.add(new Chunk("This word is "));
Chunk underlined = new Chunk("underlined");
underlined.setUnderline(1.0f, -1.0f); //We can customize thickness and position of underline
document.add(underlined);
document.add(new Chunk(". And this phrase has "));
Chunk background = new Chunk("yellow background.");
background.setBackground(BaseColor.YELLOW);
document.add(background);
document.add(Chunk.NEWLINE);
document.close();
However, it's almost impossible to edit an existing PDF document. The author of iText writes in his book:
In a PDF document, every character or glyph on a PDF page has its
fixed position, regardless of the application that’s used to view the
document. This is an advantage, but it also comes with a disadvantage.
Suppose you want to replace the word “edit” with the word “manipulate”
in a sentence, you’d have to reflow the text. You’d have to reposition
all the characters that follow that word. Maybe you’d even have to
move a portion of the text to the next page. That’s not trivial, if
not impossible.
If you want to “edit” a PDF, it’s advised that you change the original
source of the document and remake the PDF.
Aspose.PDF APIs support to create new PDF document and manipulate existing PDF documents without Adobe Acrobat dependency. You can search and add Highlight Annotation to mark PDF text.
REST API Solution using Aspose.PDF Cloud SDK for Java:
// For complete examples and data files, please go to https://github.com/aspose-pdf-cloud/aspose-pdf-cloud-java
String name = "02_pages.pdf";
String folder="Temp";
String remotePath=folder+"/"+name;
// File to upload
File file = new File("C:/Temp/"+name);
// Storage name is default storage
String storage = null;
// Get App Key and App SID from https://dashboard.aspose.cloud/
PdfApi pdfApi = new PdfApi("xxxxxxxxxxxxxxxxxxxx", "xxxxx-xxxx-xxxx-xxxx-xxxxxxxxx");
//Upload file to cloud storage
pdfApi.uploadFile(remotePath,file,storage);
//Text Position
Rectangle rect = new Rectangle().LLX(259.27580539703365).LLY(743.4707997894287).URX(332.26148873138425).URY(765.5148007965088);
List<AnnotationFlags> flags = new ArrayList<>();
flags.add(AnnotationFlags.DEFAULT);
HighlightAnnotation annotation = new HighlightAnnotation();
annotation.setName("Name Updated");
annotation.rect(rect);
annotation.setFlags(flags);
annotation.setHorizontalAlignment(HorizontalAlignment.CENTER);
annotation.setRichText("Rich Text Updated");
annotation.setSubject("Subj Updated");
annotation.setPageIndex(1);
annotation.setZindex(1);
annotation.setTitle("Title Updated");
annotation.setModified("02/02/2018 00:00:00.000 AM");
List<HighlightAnnotation> annotations = new ArrayList<>();
annotations.add(annotation);
//Add Highlight Annotation to the PDF document
AsposeResponse response = pdfApi.postPageHighlightAnnotations(name,1, annotations, storage, folder);
//Download annotated PDF file from Cloud Storage
File downloadResponse = pdfApi.downloadFile(remotePath, null, null);
File dest = new File("C:/Temp/HighlightAnnotation.pdf");
Files.copy(downloadResponse.toPath(), dest.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
System.out.println("Completed......");
On-Premise Solution using Aspose.PDF for Java:
// For complete examples and data files, please go to https://github.com/aspose-pdf/Aspose.Pdf-for-Java
// Instantiate Document object
Document document = new Document("C:/Temp/Test.pdf");
// Create TextFragment Absorber instance to search particular text fragment
TextFragmentAbsorber textFragmentAbsorber = new TextFragmentAbsorber("Estoque");
// Iterate through pages of PDF document
for (int i = 1; i <= document.getPages().size(); i++) {
// Get first page of PDF document
Page page = document.getPages().get_Item(i);
page.accept(textFragmentAbsorber);
}
// Create a collection of Absorbed text
TextFragmentCollection textFragmentCollection = textFragmentAbsorber.getTextFragments();
// Iterate on above collection
for (int j = 1; j <= textFragmentCollection.size(); j++) {
TextFragment textFragment = textFragmentCollection.get_Item(j);
// Get rectangular dimensions of TextFragment object
Rectangle rect = new Rectangle((float) textFragment.getPosition().getXIndent(), (float) textFragment.getPosition().getYIndent(), (float) textFragment.getPosition().getXIndent() + (float) textFragment.getRectangle().getWidth(), (float) textFragment.getPosition().getYIndent() + (float) textFragment.getRectangle().getHeight());
// Instantiate HighLight Annotation instance
HighlightAnnotation highLight = new HighlightAnnotation(textFragment.getPage(), rect);
// Set opacity for annotation
highLight.setOpacity(.80);
// Set the color of annotation
highLight.setColor(Color.getYellow());
// Add annotation to annotations collection of TextFragment
textFragment.getPage().getAnnotations().add(highLight);
}
// Save updated document
document.save("C:/Temp/HighLight.pdf");
P.S: I work as support/evangelist developer at Aspose.

Image positioning in iText - Java

I am trying to read one PDF and copy its data into another PDF. The first PDF contains some text and images and I wish to write an image in the second PDF exactly where the text ends(which is basically the end of the PDF file). RIght now it just prints at the top. How can I make this change?
PdfReader reader = null;
reader = new PdfReader(Var.input);
Document document=new Document();
PdfWriter writer = null;
writer = PdfWriter.getInstance(document,new FileOutputStream(Var.output));
PdfImportedPage page = writer.getImportedPage(reader, 1);
reader.close();
document.open();
PdfContentByte cb = writer.getDirectContent();
// Copy first page of existing PDF into output PDF
document.newPage();
cb.addTemplate(page, 0, 0);
// Add your new data / text here
Image image = null;
image = Image.getInstance (Var.qr);
document.add(image);
document.close();
Try this:
First get the location/co-ords of where the image needs to go, then simply add the second line from below to your code so the image is inserted at that location "X, Y"
Image image = Image.getInstance(String RESOURCE);
image.setAbsolutePosition(X, Y);
writer.getDirectContent().addImage(image);
Take a look here for some examples in iText 5: https://itextpdf.com/en/resources/examples/itext-5-legacy/chapter-3-adding-content-absolute-positions
You should use a PdfStamper instead of a PdfWriter with imported pages. Your approach throws away all interactive contents. You can use sorifiend's idea there, too.
To determine where the text on the given page ends, have a look at the iText in Action, 2nd edition example ShowTextMargins which parses a PDF and ads a rectangle showing the text margin.

Categories