We have been trying to add annotation/stamp to an existing SIGNED PDF without invalidating the Signature but unfortunately browsers wont show the stamp/annotation. When opened in Adobe Reader the annotation can be seen there.
Any other idea is welcome. All we want is a little text on existing signed PDF that wont invalidate the signature.
Here is our code:
PdfReader reader = new PdfReader(pdf1);
PdfStamper pdfStamper = new PdfStamper(reader, new FileOutputStream(RESULT), '\0', true);
PdfContentByte pcb = new PdfContentByte(pdfStamper.getWriter());
PdfAnnotation annot = PdfAnnotation.createFreeText(pdfStamper.getWriter(), new Rectangle(150, 150, 200, 200), "Annotation 1", pcb);
annot.setFlags(PdfAnnotation.FLAGS_PRINT);
pdfStamper.addAnnotation(annot, 1);
pdfStamper.close();
You use the incremental update mode ('\0', true) thus (certain) additions to PDF documents are possible. That is the correct way
WebBrowsers provide only limited support for certain PDF features like Formfields or annotions. If you can see the annotation in the adobe reader but not in some webbrowers than those browsers do not support it. You have limited options to change that.
One possibility you might have is to not add the stamp as an annotation but as an image. But you have to test afterwards if acrobat reader still considers the signature as intact. (As mentioned only certain additions are allowed)
PdfReader reader = new PdfReader(pdf1);
PdfStamper pdfStamper = new PdfStamper(reader, new FileOutputStream(RESULT), '\0', true);
Image img = Image.getInstance("URL or Filename.PathToImage.png");
//position on the page x,y
img.setAbsolutePosition(380f, 750f);
img.scalePercent(20);
//1=pagenumber and you might also try getOverContent(1)
PdfContentByte underContent = super.stamper.getUnderContent(1);
underContent.addImage(img);
pdfStamper.close();
Related
I have 2 PDF Files, One PDF File is created using Apache FOP and another PDF File is created by converting a word document. I need to merge both these PDF's into single PDF File using IText, which is already been done. In addition to that i need to create a link in my first PDF which has to take me to the first page of the second PDF which has been merged.
The Problem here is i need to create the link from the first PDF by looking for a string/text like "Go To Page", if i find that string in my first PDF , i need to replace that string as a link , and on clicking on that link needs to take me to the desired page.
The below code actually does the page navigating job for me, but i'm not able to do that by creating a link as per my requirement.
Is it possible to find the rectangle coordinates of the string/text, so that i can pass those coordinates to create the link? Or Is there any way to replace my string as a link using itext?
I'm using IText 5.x
public void pdfNavigation(String src, String dest) throws IOException, DocumentException
{
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
PdfDestination d1 = new PdfDestination(PdfDestination.FIT);
Rectangle rect = new Rectangle(0, 806, 595, 842);
PdfAnnotation annotation1= PdfAnnotation.createLink(stamper.getWriter(),
rect,
PdfAnnotation.HIGHLIGHT_INVERT, 10, d1);
stamper.addAnnotation(annotation1, 1);
PdfDestination d2 = new PdfDestination(PdfDestination.FIT);
PdfAnnotation annotation2= PdfAnnotation.createLink(stamper.getWriter(),
rect,
PdfAnnotation.HIGHLIGHT_PUSH, 1, d2);
stamper.addAnnotation(annotation2, 4);
stamper.close();
}
Thanks for Help in advance !
You can use Chunk class for this. I think you will get your answer from this link.
You can also use named actions for this like the below code which you can find in iTEXT documentation (Link is given below).
Paragraph p = new Paragraph()
.add("Go to last page")
.setAction(PdfAction.createNamed(PdfName.LastPage));
document.add(p);
p = new Paragraph()
.add("Go to first page")
.setAction(PdfAction.createNamed(PdfName.FirstPage));
document.add(p);
https://itextpdf.com/en/resources/books/itext-7-building-blocks/chapter-6-creating-actions-destinations-and-bookmarks
https://itextpdf.com/en/resources/examples/itext-7/chapter-6-actions-destinations-bookmarks#2568-c06e02_namedaction.java
I created a pdf with iText and I want to open it, but when I do that Adobe Reader says me "Error opening document. This file is already open or is used by another application".
How can I resolve?
This is my code (sorry for the Houston println exception ;)):
try {
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document,new FileOutputStream("c:/Users/Gabriel/Desktop/"+txtName.getText().toString()+".pdf"));
PdfReader reader = new PdfReader("src/file.pdf");
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("c:/Users/Gabriel/Desktop/"+txtName.getText().toString()+".pdf"));
AcroFields form = stamper.getAcroFields();
..code..
stamper.close();
//document.close();
Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + "c:/Users/Gabriel/Desktop/"+txtName.getText().toString()+".pdf");
}catch (Exception exc) {
System.out.println("Houston we got a problem! : "+exc);
}
}
You are using an old iText version. In the old days, we had PdfWriter to create documents from scratch and we had PdfStamper to manipulate existing documents.
It seems that you want to fill out a form, which requires PdfStamper, but for some mysterious reason you also use PdfWriter as if you want to create a new PDF from scratch.
If you insist on using that old iText version, you shoild drop a couple of lines:
try {
PdfReader reader = new PdfReader("src/file.pdf");
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("c:/Users/Gabriel/Desktop/"+txtName.getText().toString()+".pdf"));
AcroFields form = stamper.getAcroFields();
..code..
stamper.close();
}
In the old iText, there's really no reason for you to use the Document and PdfWriter class for form filling.
To avoid the confusion you're in, we rewrote iText from scratch, and we released this rewrite about 2 years ago. It's amazing to see that you chose an old version being new at iText. Moreover: iText 5 is no longer supported, so why not use iText 7?
Please read the iText 7 jump-start tutorial to see how form filling is done today: https://developers.itextpdf.com/content/itext-7-jump-start-tutorial-net/chapter-4-making-pdf-interactive
I want to add a image or text watermark to pdf file. I found some examples online, but my case is a little bit different.
I have an existing pdf template which is already populated with dynamic data and converted to byte[]. This generated bytes are later exported to pdf.
I would like to add the watermark to that generated bytes.
Something like:
byte[] addWatermark(byte[] generatedBytes){
byte[] bytesWithWatermark;
//add watermark to bytes
return bytesWithWatermark;
}
I just can't seem to figure out how to do this with iText.
You say you already have examples for applying watermarks using iText. As you already have a PDF, you should use code from an example that adds watermarks to existing PDFs. This should be an example that works with a PdfReader / PdfStamper pair, e.g. those here, which all have the structure
PdfReader reader = new PdfReader(SOME_SOURCE);
PdfStamper stamper = new PdfStamper(reader, SOME_TARGET_STREAM);
[... add watermark to all pages in stamper ...]
stamper.close();
reader.close();
To make these example fit into your addWatermark method, simply use your byte[] instead of SOME_SOURCE and a ByteArrayOutputStream instead of SOME_TARGET_STREAM:
byte[] addWatermark(byte[] generatedBytes) {
try (ByteArrayOutputStream target = new ByteArrayOutputStream()) {
PdfReader reader = new PdfReader(generatedBytes);
PdfStamper stamper = new PdfStamper(reader, target);
[... add watermark to all pages in stamper ...]
stamper.close();
reader.close();
return target.toByteArray();
}
}
PS As you used only the tag itext and not the tag itext7, I assumed you were looking for a solution for iText 5.5.x. But the same principle as applied here, i.e. using your byte[] as source argument and a ByteArrayOutputStream as target argument, will also allow you to make iText 7.x examples fit into your method frame.
I create a pdf document and specify few acro-fields. These acro-fields used to be filled by java itext library. This document is digitally signed after adding all required acro-fields.
We already set form filling property in digital signature but we have requirement to fill these acro-fields and make them read only after one time filling without invalidating digital signature.
Here is the code that I am using to fill this document -
String FILE = "/Users/xyz/Desktop/test1.pdf";
PdfReader reader = new PdfReader(pdfReader, new FileOutputStream(pdfTemplatePath), '\0', true);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(FILE), );
AcroFields form = stamper.getAcroFields();
form.setField("Name", "test 123");
stamper.close();
reader.close();
I am using lowagie itext library for filling pdf form.
Is there any way to fix this issue.
Thanks.
I have a PDF previously created with FOP, and I need to add some named destinations to it so later another program can open and navigate the document with the Adobe PDF open parameters, namely the #namedest=destination_name parameter.
I don't need to add bookmarks or other dynamic content but just some destinations with a name and thus injecting a /Dests collection with names defined in the resulting PDF.
I use iText 5.3.0 and I read the chapter 7 of iText in Action (2nd edition), but still I cannot figure it out how to add the destinations and so use them with #nameddest in a browser.
I'm reading and manipulating the document with PdfReader and PdfStamper. I already know in advance where to put every destination after having parsed the document with a customized Listener and a PdfContentStreamProcessor, searching for a specific text marker on each page.
This is a shortened version of my code:
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new BufferedOutputStream(dest));
// search text markers for destinations, page by page
for (int i=1; i<reader.getNumberOfPages(); i++) {
// get a list of markers for this page, as obtained with a custom Listener and a PdfContentStreamProcessor
List<MyDestMarker> markers = ((MyListener)listener).getMarkersForThisPage();
// add a destination for every text marker in the current page
Iterator<MyDestMarker> it = markers.iterator();
while(it.hasNext()) {
MyDestMarker marker = it.next();
String name = marker.getName();
String x = marker.getX();
String y = marker.getY();
// create a new destination
PdfDestination dest = new PdfDestination(PdfDestination.FITH, y); // or XYZ
// add as a named destination -> does not work, only for new documents?
stamper.getWriter().addNamedDestination(name, i /* current page */, dest);
// alternatives
PdfContentByte content = stamper.getOverContent(i);
content.localDestination(name, dest); // doesn't work either -> no named dest found
// add dest name to a list for later use with Pdf Open Parameters
destinations.add(name);
}
}
stamper.close();
reader.close();
I also tried creating a PdfAnnotation with PdfFormField.createLink() but still, I just manage to get the annotation but with no named destination defined it does not work.
Any solution for this? Do I need to add some "ghost" content over the existing one with Chunks or something else?
Thanks in advance.
edit 01-27-2016:
I recently found an answer to my question in the examples section of iText website, here.
Unfortunately the example provided does not work for me if I test it with a pdf without destinations previously defined in it, as it is the case with the source primes.pdf which already contains a /Dests array. This behaviour appears to be consistent with the iText code, since the writer loads the destinations in a map attribute of PdfDocument which is not "inherited" by the stamper on closing.
That said, I got it working using the method addNamedDestination() of PdfStamper added with version 5.5.7; this method loads a named destination in a local map attribute of the class which is later processed and consolidated in the document when closing the stamper.
This approach reaised a new issue though: the navigation with Pdf Open Parameters (#, #nameddest=) works fine with IE but not with Chrome v47 (and probably Firefox, too). I tracked the problem down to the order in which the dests names are defined and referenced inside the document; the stamper uses a HashMap as the container for the destinations, which of course does not guarantee the order of its objects and for whatever reason Chrome refuse to recognise destinations not listed in "natural" order. So, the only way I got it to work is replacing the namedDestinations HashMap with a natural-ordered TreeMap.
Hope this help others with the same issue.
I 've been in the same need for my project previously. Had to display and navigate pdf document with acrobat.jar viewer. To navigate i needed the named destinations in the pdf. I have looked around the web for a possible solution, but no fortunate for me. Then I this idea strikes my mind.
I tried to recreate the existing pdf with itext, navigating through each page and adding localdestinations to each page and i got what I wanted. below is the snip of my code
OutputStream outputStream = new FileOutputStream(new File(filename));
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
PdfContentByte cb = writer.getDirectContent();
PdfOutline pol = cb.getRootOutline();
PdfOutline oline1 = null;
InputStream in1 = new FileInputStream(new File(inf1));
PdfReader reader = new PdfReader(in1);
for (int i = 1; i <= reader.getNumberOfPages(); i++)
{
document.newPage();
document.setMargins(0.0F, 18.0F, 18.0F, 18.0F);
PdfImportedPage page = writer.getImportedPage(reader, i);
document.add(new Chunk(new Integer(i).toString()).setLocalDestination(new Integer(i).toString()));
System.out.println(i);
cb.addTemplate(page, 0.0F, 0.0F);
}
outputStream.flush();
document.close();
outputStream.close();
Thought it would help you.