I can't value fields iText 2.1.7 - java

We have created PDF files via a template and we fill the fields with values from the database. "Name field" = "value".
Now we want to read the value of one of the fields in the PDF file we created earlier.
CODE
reader = new PdfReader("C:\\temp\\letter.pdf");
baos = new ByteArrayOutputStream();
stamper = new PdfStamper(reader, baos);
form = stamper.getAcroFields();
System.out.println(form.getField("CUSTOMER-NAME"));
But when I do that returns "null" and it does not recognize any field. It is as if the fields does not exist.
Any help would appreciated. Thanks.
Hi,
I have 2 file types. One has been flattened :-( and another one no.
For the last file, i am using this code and it work:
PdfReader reader = new PdfReader(FILE);
PdfDictionary root = reader.getCatalog();
PdfDictionary form1 = root.getAsDict(PdfName.ACROFORM);
PdfArray fields = form1.getAsArray(PdfName.FIELDS);
PdfDictionary page;
PdfArray annots;
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
page = reader.getPageN(i);
annots = page.getAsArray(PdfName.ANNOTS);
for (int j = 0; j < annots.size(); j++) {
fields.add(annots.getAsIndirectObject(j));
}
}
AcroFields form2 = reader.getAcroFields();
Thanks a lot!!!
Regards,
Muni

As bruno suggested - if you only want to read, only use the PdfReader...
Try the following code and see whether something is printed out:
PdfReader reader = new PdfReader("C:\\temp\\letter.pdf");
AcroFields acroFields = reader.getAcroFields();
Map<String, AcroFields.Item> fields = acroFields.getFields();
Iterator<Entry<String, Item>> it = fields.entrySet().iterator();
while (it.hasNext()) {
Entry<String, Item> entry = it.next();
String value = acroFields.getField(entry.getKey());
System.out.println(entry.getKey()+":"+value);
}
There could be many reasons why your field is not found:
the PDF doesn't contain PDF form fields at all (pdf has been flattened)
the field name is a different one (e.g. Customer-Name)
you field has a parent (so the name is parent.CUSTOMER-NAME)
the form fields were not correctly inserted
...
Can you see the fields in e.g. adobe reader?

Related

How to use iText to parse paths (such as lines in the document)

I am using iText to parse text in a PDF document, and i am using PdfContentStreamProcessor with a RenderListener. Such as:
PdfReader reader = new PdfReader(file.toURI().toURL());
int numberOfPages = reader.getNumberOfPages();
MyRenderListener listener = new MyRenderListener ();
PdfContentStreamProcessor processor = new PdfContentStreamProcessor(listener);
for (int pageNumber = 1; pageNumber <= numberOfPages; pageNumber++) {
PdfDictionary pageDic = reader.getPageN(pageNumber);
PdfDictionary resourcesDic = pageDic.getAsDict(PdfName.RESOURCES);
Rectangle pageSize = reader.getPageSize(pageNumber);
listener.startPage(pageNumber, pageSize);
processor.processContent(ContentByteUtils.getContentBytesForPage(reader, pageNumber), resourcesDic);
}
I have no problem to get the text with the renderText(TextRenderInfo) method, but how do I parse the graphic content appart from images? For example in my case I would like to get:
Text content which is in a box
Horizontal lines
Per mkl comment, by using ExtRenderListener I am able to get the geometries. I used How to extract the color of a rectangle in a PDF, with iText for reference

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();
}

how to make pdf annotation as read only using itext?

I am trying to make a program that multiple users can share one PDF document , and every one can put his comments on the PDF using add sticky note without changing/modifying other notes.
For example ,
The program will transfer that PDF file to another person for review and checking , the reviewer will put his comments on the PDF and send it to Approver person . The approver can't edit reviewer comments and change it at all , he can add new sticky note to it for his comments.
if I use the security on the PDF ( ~ PdfWriter.AllowModifyAnnotations ) , I will disable entering new sticky note.
is there any solution for that ?
please help me and thanks in advance
PDF annotation objects can have flags; one of these flags is a read-only flag. Thus, you only have to iterate over all annotations on all pages and set their respective read-only flag.
In iText 5.5.x this can be done like this:
PdfReader reader = new PdfReader(resourceStream);
PdfStamper stamper = new PdfStamper(reader, outputStream);
for (int page = 1; page <= reader.getNumberOfPages(); page++)
{
PdfDictionary pageDictionary = reader.getPageN(page);
PdfArray annotationArray = pageDictionary.getAsArray(PdfName.ANNOTS);
if (annotationArray == null)
continue;
for (PdfObject object : annotationArray)
{
PdfObject directObject = PdfReader.getPdfObject(object);
if (directObject instanceof PdfDictionary)
{
PdfDictionary annotationDictionary = (PdfDictionary) directObject;
PdfNumber flagsNumber = annotationDictionary.getAsNumber(PdfName.F);
int flags = flagsNumber != null ? flagsNumber.intValue() : 0;
flags |= PdfAnnotation.FLAGS_READONLY;
annotationDictionary.put(PdfName.F, new PdfNumber(flags));
}
}
}
stamper.close();
(iText 5 MarkAnnotationReadOnly.java)
In iText 7.0.x it can be done like this
try ( PdfReader pdfReader = new PdfReader(resourceStream);
PdfWriter pdfWriter = new PdfWriter(outputStream);
PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter) )
{
for (int page = 1; page <= pdfDocument.getNumberOfPages(); page++)
{
PdfPage pdfPage = pdfDocument.getPage(page);
for (PdfAnnotation pdfAnnotation : pdfPage.getAnnotations())
{
pdfAnnotation.setFlag(PdfAnnotation.READ_ONLY);
}
}
}
(iText 7 MarkAnnotationReadOnly.java)
Only the kernel iText 7 artifact is required.

Retrieve the page number of an image in pdf- IText

I am using the code from the below link to render the images
MyImageRenderListener - IText
Below is my try block of the Code. What I am actually doing is finding the DPI of the image and if the dpi of the image is below 300 then writing it in a text file.
NOW, I also want to write the page numbers where these images are located in the PDF. How can I obtain the Page Number of that image?
try {
String filename;
FileOutputStream os;
PdfImageObject image = renderInfo.getImage();
BufferedImage img = null;
String txtfile = "results/results.txt";
PdfDictionary imageDict = renderInfo.getImage().getDictionary();
float widthPx = imageDict.getAsNumber(PdfName.WIDTH).floatValue();
float heightPx = imageDict.getAsNumber(PdfName.HEIGHT).floatValue();
float widthUu = renderInfo.getImageCTM().get(Matrix.I11);
float heigthUu = renderInfo.getImageCTM().get(Matrix.I22);
float widthIn = widthUu/72;
float heightIn = heigthUu/72;
float imagepdi = widthPx/widthIn;
filename = String.format(path, renderInfo.getRef().getNumber(), image.getFileType());
System.out.println(filename+"-->"+imagepdi);
if(imagepdi < 300){
File file = new File("C:/Users/Abhinav/workspace/itext/results/result.txt");
if(filename != null){
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file.getAbsoluteFile(),true);
file.setReadable(true, false);
file.setExecutable(true, false);
file.setWritable(true, false);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(filename);
bw.write("\r\n");
bw.close();
}
}
This is a strange question, because it is incomplete and illogical.
Why is your question incomplete?
You are using MyImageRenderListener in the context of another example, ExtractImages:
PdfReader reader = new PdfReader(filename);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
MyImageRenderListener listener = new MyImageRenderListener(RESULT);
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
parser.processContent(i, listener);
}
reader.close();
In this example, you loop over every page number to examine every separate page. Hence you know the page number whenever MyImageRenderListener returns an image.
Images are stored inside a PDF as external objects (aka XObject). MyImageRenderListener returns what's stored in such a stream object (containing the bytes of the image). So far, so good.
Why is your question illogical?
Because the whole purpose of storing images in XObject is to be able to reuse the same image stream. Imagine an image of a logo. That image can be present on every page of the document. In this case, MyImageRenderListener will give you the same image (from the same stream) as many times as there are pages, but in reality, there is only one image, and it's external to the page content. It doesn't make sense for that image to "know" the page it is on: it is on every page. The same logic applies even when the image is only used on one page. That is inherent to the design of PDF: an image stream doesn't know which page it belongs to. The link between the image stream and the page exists through the /XObject entry in the /Resources of the page dictionary.
What would be an elegant way to solve this?
Create a member-variable in MyImageRenderListener, e.g.:
protected int pagenumber;
public void setPagenumber(int pagenumber) {
this.pagenumber = pagenumber;
}
Use the setter from your loop:
PdfReader reader = new PdfReader(filename);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
MyImageRenderListener listener = new MyImageRenderListener(RESULT);
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
listener.setPagenumber(i);
parser.processContent(i, listener);
}
reader.close();
Now you can use pagenumber in the renderImage(ImageRenderInfo renderInfo) method. This way, you'll always know which page is being examined when this method is triggered.

Changing UserUnit of existing pdf with itext in java

i didn't found anything specific to that topic, therefore i'm using this board and hope to get a question/help.
What i have: i have a pdf-document, which is very big (adobe reader says: 21.399,4 x 15.123,7 mm, zoom-factory, when opened is ~1,64% screen-filling!). It's a construction drawing, but this doesn't matter. When i'm using sublime to analyze the structure, i can find the following:
pdf-Version is: 1.6
CropBox[0.0 0.0 14400.0 10177.0]
/Rotate 0/Type/Page/UserUnit 4.2125
What i need: a smaller document, because of the big size, i can't go on with processing the file
What i tried: using iText to reduce the UserUnit to default "1" for the first step. This should make some things easier. My code in the java-programm looks like this:
PdfReader reader = new PdfReader(inFile.getAbsolutePath());
try (FileOutputStream outStream = new FileOutputStream(outFile)) {
PdfStamper pdfStamper = new PdfStamper(reader, outStream);
PdfWriter writer = pdfStamper.getWriter();
writer.setUserunit(1f);
pdfStamper.close();
}
another thing, which i tried, was:
PdfDictionary pageDict;
pageDict = reader.getCatalog();
pageDict.put(PdfName.USERUNIT, new PdfNumber(1f));
Both things didn't work, so my questions are:
Is it possible to change UserUnits of an existing file? Or do i need to create a new one with the properties i want to have and then writing the content of the existing pdf in my new one?
if it's possible: what else do i need to do to change the UserUnits?
With greetings from Heidelberg,
sincerly
D. Pfizenmaier
Please take a look at the ScaleRotate example. It was written in answer to the question Rotating in Itextsharp while preserving comment location & orientation where you'll find more info about the user unit.
This is the code that is relevant:
PdfReader reader = new PdfReader(src);
int n = reader.getNumberOfPages();
PdfDictionary page;
for (int p = 1; p <= n; p++) {
page = reader.getPageN(p);
page.put(PdfName.USERUNIT, new PdfNumber(1f));
}
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
stamper.close();
reader.close();
Note that you are getting the root of the document using getCatalog() but the name you give to the variable sounds as if you assume that it is a page dictionary. That won't work...

Categories