Java Set local file Hyperlink in existing pdf using itext - java

I am trying to provide a hyper link in a existing PDF, which when clicked will open the file. How can this be done?
I have try following Code it work fine for external hyper link like http://www.google.com but not working for local file hyperlink like D:/intro.pdf .
i am using itext pdf library.
Code :
String in = "D:/introduction.pdf";
String out = "D:/introduction.pdf";
try {
PdfReader reader = new PdfReader(in);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, baos);
PdfContentByte canvas=stamper.getOverContent(6);
Chunk imdb = new Chunk("Local Link");
imdb.setAnchor("http://www.google.com"); // this work
// imdb.setAnchor("D://intro.pdf"); // this does not work
ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, new Phrase(imdb), 100, 10, 0);
stamper.close();
FileOutputStream fileOutputStream = new FileOutputStream(out);
IOUtils.write(baos.toByteArray(), fileOutputStream);
} catch (Exception e) {
}
i have also try using Annotation as below :
PdfAnnotation annotation;
PdfName aa=new PdfName("test test");
annotation = PdfAnnotation.createLink(stamper.getWriter(),
new Rectangle(50f, 750f, 180f, 800f),aa,PdfAction.gotoRemotePage("file:///D:/intro.pdf","1", false, true));
annotation.setTitle("Click Here");
stamper.addAnnotation(annotation, 1);
I have also try below code comment by #Bruno Lowagie : [ it create link on given page but in intro.pdf file and when i click on link it on same page (intro.pdf)]
as per above image ( image of intro.pdf page number-2 )
PdfReader reader1 = new PdfReader("D://introduction.pdf");
PdfStamper stamper1 = new PdfStamper(reader1, new FileOutputStream("D://intro.pdf"));
PdfAnnotation link1 = PdfAnnotation.createLink(stamper1.getWriter(),
new Rectangle(136, 780, 559, 806), PdfAnnotation.HIGHLIGHT_INVERT,
new PdfAction("D://introduction.pdf", 1));
link1.setTitle("Click Here");
stamper1.addAnnotation(link1, 2);
stamper1.close();
Thanks in advance.

You need to specify the protocol. For web pages, your URI starts with http://; for files your URI should start with file://.
However, as the file you want to link to is also a PDF file, you probably don't want to use the setAnchor() method. You should use the setRemoteGoto() method instead. See the MovieLinks2 example.
If you want to add a link to an existing document, this is how to do it:
PdfReader reader = new PdfReader("hello.pdf");
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("hello_link.pdf"));
PdfAnnotation link = PdfAnnotation.createLink(stamper.getWriter(),
new Rectangle(36, 790, 559, 806), PdfAnnotation.HIGHLIGHT_INVERT,
new PdfAction("hello.pdf", 1));
stamper.addAnnotation(link, 1);
stamper.close();
If you look inside the PDF document, you'll see that the new file named hello_link.pdf contains a Link annotation that refers to the old file hello.pdf:

Related

iText PdfCopy creates editable pdf document

I have a template pdf file which is used in a spring boot application. I need to update values in this template based on user input per request. Also in the request i will get multiple pdf files I need to merge those files along with updated file which is first page of final pdf.
I am using iText with Spring Boot. I am able to update the values in template and merge file content as well but final pdf is coming as editable with files are hidden. If i click on that filed i can able to see my values also can able to edit.
public void mergefiles(Map<String, String> tempData,MultipartFile[] userInfoFiles)
throws Exception{
FileOutputStream mergeOutStream = new FileOutputStream(new File("C:\\UpdateFile\\mergepath\\updatetem.pdf")); //To update user content to Template
PdfReader reader = new PdfReader(new FileInputStream(new File("C:\\UpdateFile\\template\\template.pdf"))); //Template File Stream
PdfStamper stamper = new PdfStamper(reader, mergeOutStream);
stamper.setFormFlattening(false);
AcroFields form = stamper.getAcroFields();
Map<String, Item> fieldMap = form.getFields();
for (String key : fieldMap.keySet()) {
String fieldValue = dataMap.get(key);
if (fieldValue != null) {
form.setField(key, fieldValue);
}
}
//Above part creates updated pdf with read only
//Below section creates merged file but first page is editable with
//filed values are hidden.
Document mergePdfDoc = new Document();
PdfCopy pdfCopy;
boolean smartCopy = false;
FileOutputStream newmergeOutStream = new FileOutputStream(new File("C:\\UpdateFile\\mergepath\\newmerged.pdf"));
if(smartCopy)
pdfCopy = new PdfSmartCopy(mergePdfDoc, newmergeOutStream);
else
pdfCopy = new PdfCopy(mergePdfDoc, newmergeOutStream);
mergePdfDoc.open();
pdfCopy.addDocument(stamper.getReader());
pdfCopy.freeReader(stamper.getReader());
PdfReader[] pdfReader = new PdfReader[userInfoFiles.length];
for(int i=0; i<=userInfoFiles.length-1;i++) {
pdfReader[i] = new PdfReader(userInfoFiles[i].getInputStream());
pdfCopy.addDocument(pdfReader[i]);
pdfCopy.freeReader(pdfReader[i]);
pdfReader[i].close();
}
stamper.close();
mergeOutStream.close();
mergePdfDoc.close();
}
Any input why final pdf is in editable form and filed values are hidden. I have to create a merged document and get ByteArray stream of the final document as its input to another function call.I am Using iText5.
The problem is that you add the PdfReader the PdfStamper is based on as input to your PdfCopy:
pdfCopy.addDocument(stamper.getReader());
The reader a stamper works on is dirty: some changes applied via the stamper are made to the objects the reader holds, some are only in the stamper or its output.
E.g. in your case the form fields are already defined in the original pdf. The field value is added to this field directly. Thus, it gets changed in the reader. But the appearance, the field visualization including a drawing of its current value, gets generated in a new indirect object which is added to the stamper output. Thus, there still is the original, empty visualization in the reader.
In a pdf viewer, therefore, the PdfCopy result at first has the looks of empty fields (as the appearances have been generated in the stamper only) but when editing a field, the changed value becomes visible (because the field editor is initialized with the field value).
To fix this, don't use the dirty reader but instead create a new, clean reader from the stamping result.
First create the stamped file:
FileOutputStream mergeOutStream = new FileOutputStream(new File("C:\\UpdateFile\\mergepath\\updatetem.pdf")); //To update user content to Template
PdfReader reader = new PdfReader(new FileInputStream(new File("C:\\UpdateFile\\template\\template.pdf"))); //Template File Stream
PdfStamper stamper = new PdfStamper(reader, mergeOutStream);
stamper.setFormFlattening(false);
AcroFields form = stamper.getAcroFields();
Map<String, Item> fieldMap = form.getFields();
for (String key : fieldMap.keySet()) {
String fieldValue = dataMap.get(key);
if (fieldValue != null) {
form.setField(key, fieldValue);
}
}
stamper.close();
And then merge:
Document mergePdfDoc = new Document();
PdfCopy pdfCopy;
boolean smartCopy = false;
FileOutputStream newmergeOutStream = new FileOutputStream(new File("C:\\UpdateFile\\mergepath\\newmerged.pdf"));
if(smartCopy)
pdfCopy = new PdfSmartCopy(mergePdfDoc, newmergeOutStream);
else
pdfCopy = new PdfCopy(mergePdfDoc, newmergeOutStream);
mergePdfDoc.open();
PdfReader reader = new PdfReader(new FileInputStream(new File("C:\\UpdateFile\\mergepath\\updatetem.pdf")));
pdfCopy.addDocument(reader);
pdfCopy.freeReader(reader);
PdfReader[] pdfReader = new PdfReader[userInfoFiles.length];
for(int i=0; i<=userInfoFiles.length-1;i++) {
pdfReader[i] = new PdfReader(userInfoFiles[i].getInputStream());
pdfCopy.addDocument(pdfReader[i]);
pdfCopy.freeReader(pdfReader[i]);
pdfReader[i].close();
}
mergeOutStream.close();
mergePdfDoc.close();
}

Printing a PDF enters a long and slow flattening process

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.

how to set attributes for existing pdf that contains only images using java itext?

I would like to set attributes to pdf before uploading it into a server.
Document document = new Document();
try
{
OutputStream file = new FileOutputStream({Localpath});
PdfWriter.getInstance(document, file);
document.open();
//Set attributes here
document.addTitle("TITLE");
document.close();
file.close();
} catch (Exception e)
{
e.printStackTrace();
}
But its not working. The file is getting corrupted
In a comment to another answer the OP clarified:
I want to set attributes to an existing pdf(not to create new pdf)
Obviously, though, his code creates a new document from scratch (as is obvious from the fact that a mere FileOutputStream is used to access the file, no reading, only writing).
To manipulate an existing PDF, one has to use a PdfReader / PdfWriter couple. Bruno Lowagie provided an example for that in his answer to the stack overflow question "iText setting Creation Date & Modified Date in sandbox.stamper.SuperImpose.java":
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
Map info = reader.getInfo();
info.put("Title", "New title");
info.put("CreationDate", new PdfDate().toString());
stamper.setMoreInfo(info);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XmpWriter xmp = new XmpWriter(baos, info);
xmp.close();
stamper.setXmpMetadata(baos.toByteArray());
stamper.close();
reader.close();
}
(ChangeMetadata.java)
As you see the code sets the metadata both in the ol'fashioned PDF info dictionary (stamper.setMoreInfo) and in the XMP metadata (stamper.setXmpMetadata).
Obviously src and dest should not be the same here.
Without a second file
In yet another comment the OP clarified that he had already tried a similar solution but that he wants to prevent the
Temporary existence of second file
This can easily be prevented by first reading the original PDF into a byte[] and then stamping to it as the target file. E.g. if File singleFile references the original file which is also to be the target file, you can implement:
byte[] original = Files.readAllBytes(singleFile.toPath());
PdfReader reader = new PdfReader(original);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(singleFile));
Map<String, String> info = reader.getInfo();
info.put("Title", "New title");
info.put("CreationDate", new PdfDate().toString());
stamper.setMoreInfo(info);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XmpWriter xmp = new XmpWriter(baos, info);
xmp.close();
stamper.setXmpMetadata(baos.toByteArray());
stamper.close();
reader.close();
(UpdateMetaData test testChangeTitleWithoutTempFile)

Extract pdf page and insert into existing pdf

I have below iText code, I want to copy one page from src pdf file to other pdf file(I have existing PdfStamper, here it is mainPdfStamper).
PdfReader srcReader = new PdfReader(new FileInputStream("source.pdf"));
File file = File.createTempFile("temporary", ".pdf");
PdfStamper pdfStamper = new PdfStamper(srcReader, new FileOutputStream(file));
PdfImportedPage importedPage = pdfStamper.getImportedPage(srcReader, 1);
// copying extracted page from src pdf to existing pdf
mainPdfStamper.getOverContent(1).addTemplate(importedPage, 10,10);
pdfStamper.close();
srcReader.close();
This is not working and I am not aware of how to achieve this. In short, I want to copy one page from source pdf to existing pdf. Please help.
UPDATE
Below code worked as per the answer from Bruno.
PdfReader reader2 = new PdfReader(srcPdf.getAbsolutePath());
PdfImportedPage page = pdfStamper.getImportedPage(reader2, 1);
stamper.insertPage(1, reader2.getPageSize(1));
pdfStamper.getUnderContent(1).addTemplate(page, 100, 100);
// Close the stamper and the readers
pdfStamper.close();
reader2.close();
Please read the documentation, for instance chapter 6 of iText in Action. If you go to section 6.3.4 ("Inserting pages into an existing document"), you'll find the InsertPages example.
You only need this code if p is the page number indicating where you want to insert the page, main_file is the path to your main file and to_be_inserted the path to the file that needs to be inserted (dest is the path to the resulting file):
PdfReader reader = new PdfReader(main_file);
PdfReader reader2 = new PdfReader(to_be_inserted);
// Create a stamper
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
// Create an imported page to be inserted
PdfImportedPage page = stamper.getImportedPage(reader2, 1);
stamper.insertPage(p, reader2.getPageSize(1));
stamper.getUnderContent(i).addTemplate(page, 0, 0);
// Close the stamper and the readers
stamper.close();
reader.close();
reader2.close();
This is only one way to combine pages from two files. You can also use PdfCopy for this purpose. The advantage of using PdfCopy is the fact that you'll preserve the interactive features of the interactive page. When using PdfStamper, you'll lose any interactive feature (e.g. all links) that were present in the inserted page.

How to add an image in the last page of pdf using iText?

How do i add an image on the last page of existing PDF document. Please help me.
The following example adds an image to the second page of an existing pdf using Itext 5.
String src = "c:/in.pdf;
String dest = "c:/out.pdf";
String IMG = "C:/image.jpg";
try {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(IMG);
image.setAbsolutePosition(36, 400);
PdfContentByte over = stamper.getOverContent(2);
over.addImage(image);
stamper.close();
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
You can read the text from the PDF using the same ITEXT library.Try this
PdfReader reader = new PdfReader(INPUTFILE);
int n = reader.getNumberOfPages();
PdfTextExtractor parser =new PdfTextExtractor(new PdfReader("C:/Text.pdf"));
parser.getTextFromPage(3); // Extracting the content from a particular page.
After you have add your data ,You can load images either from file or from a URL, like this:
Image image1 = Image.getInstance("watermark.png");
document.add(image1);
String imageUrl = "http://applause-voice.com/wp-content/uploads/2011/04/1hello.jpg";
Image image2 = Image.getInstance(new URL(imageUrl));
document.add(image2);
If you will add this code at the end of your Java Program , then the image will automatically comes at the end of your page.
The best solution for me was to create a new in-memory PDF document with the image I want to add, then copy this page to the original document.
// Create a separate doc for image
var pdfDocWithImageOutStream = new ByteArrayOutputStream();
var pdfDocWithImage = new PdfDocument(new PdfWriter(pdfDocWithImageOutStream).setSmartMode(true));
var docWithImage = new Document(pdfDocWithImage, destinationPdf.getDefaultPageSize());
// Add image to the doc
docWithImage.add(image);
// Close the doc to save data
docWithImage.close();
pdfDocWithImage.close();
// Open the same doc for reading
pdfDocWithImage = new PdfDocument(new PdfReader(new ByteArrayInputStream(pdfDocWithImageOutStream.toByteArray())));
docWithImage = new Document(pdfDocWithImage, destinationPdf.getDefaultPageSize());
// Copy page to original (destinationPdf)
pdfDocWithImage.copyPagesTo(1, pdfDocWithImage.getNumberOfPages(), destinationPdf);
docWithImage.close();
pdfDocWithImage.close();

Categories