We have a number of dynamically generated printable forms files on our site that use iText 4.2.0. However, we also have a large number of users that have print disabilities and use screen readers, like JAWS, to render our PDFs. We use the .setTagged() method to tag the PDFs, but some elements of the PDF appear out of order. Some even become more jumbled after calling setTagged!
I read about PDF/UA in a 2013 interview about iText with Bruno Lowagie, and this seems like something that might help with our problem. However, I have not been able to find a good example of how to generate a PDF/UA document. Can you provide an example? Also, what is the minimum version of iText we will need to generate a PDF/UA compliant PDF document?
Please take a look at the PdfUA example. It explains step by step what is needed to be compliant with PDF/UA. A similar example was presented at the iText Summit in 2014 and at JavaOne. Watch the iText Summit video tutorial.
public void createPdf(String dest) throws IOException, DocumentException {
Document document = new Document(PageSize.A4.rotate());
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
writer.setPdfVersion(PdfWriter.VERSION_1_7);
//TAGGED PDF
//Make document tagged
writer.setTagged();
//===============
//PDF/UA
//Set document metadata
writer.setViewerPreferences(PdfWriter.DisplayDocTitle);
document.addLanguage("en-US");
document.addTitle("English pangram");
writer.createXmpMetadata();
//=====================
document.open();
Paragraph p = new Paragraph();
//PDF/UA
//Embed font
Font font = FontFactory.getFont(FONT, BaseFont.WINANSI, BaseFont.EMBEDDED, 20);
p.setFont(font);
//==================
Chunk c = new Chunk("The quick brown ");
p.add(c);
Image i = Image.getInstance(FOX);
c = new Chunk(i, 0, -24);
//PDF/UA
//Set alt text
c.setAccessibleAttribute(PdfName.ALT, new PdfString("Fox"));
//==============
p.add(c);
p.add(new Chunk(" jumps over the lazy "));
i = Image.getInstance(DOG);
c = new Chunk(i, 0, -24);
//PDF/UA
//Set alt text
c.setAccessibleAttribute(PdfName.ALT, new PdfString("Dog"));
//==================
p.add(c);
document.add(p);
p = new Paragraph("\n\n\n\n\n\n\n\n\n\n\n\n", font);
document.add(p);
List list = new List(true);
list.add(new ListItem("quick", font));
list.add(new ListItem("brown", font));
list.add(new ListItem("fox", font));
list.add(new ListItem("jumps", font));
list.add(new ListItem("over", font));
list.add(new ListItem("the", font));
list.add(new ListItem("lazy", font));
list.add(new ListItem("dog", font));
document.add(list);
document.close();
}
You make the document tagged with the setTagged document, but that's not sufficient. You also need to set document data: the document title needs to be displayed and you need to indicate the language used in the document. XMP metadata is mandatory.
Furthermore you need to embed all fonts. When you have images, you need a alternate description. In the example, we replace the words "dog" and "fox" by an image. To make sure that these images are "read out loud" correctly, we need to use the setAccessibleAttribute() method.
At the end of the example, I added a numbered list. In your duplicate question https://stackoverflow.com/questions/28222490/numbered-list-across-a-page-break-causes-jaws-to-read-numbers-out-of-order-in-it, you claim that the list is not read out loud correctly by JAWS. If you check the PDF file created with the above example, more specifically pdfua.pdf, you'll discover that JAWS reads the document as expected, with the numbers and the text in the right order.
The reason why "it doesn't work" when you try this, is simple. You claim that you are using iText, but you are not. You are using a "gork" of iText. A "gork" is an unofficial "fork" of which God Only Really Knows what's inside. You need the latest iText version to achieve what you want because PDF/UA is a standard dating from 2012 and you are using a version of iText that dates from 2009.
I suggest that you delete that other question because:
it is a duplicate of this question (if you disagree, read my answer: isn't it exactly what you're asking in both questions?),
it is off-topic in the sense that it sounds like "I am using an ancient DVD player and it doesn't want to play my blue ray disks." (I know that you downvoted my correct answer because you don't believe this to be true. So be it. Other people will find this answer valuable and understand that your vote was unfair.)
Please read the final question in The Best iText Questions on StackOverflow to find out what I think about people using unofficial, rogue, obsolete versions of iText.
See also https://stackoverflow.com/questions/25696851/can-itext-2-1-7-or-earlier-can-be-used-commercially
Related
I have a pdf document already created with some textfields.I can fill those text fields using Adobe reader and save those values with that file.
My problem is ,can i do that programmatically using iText?If it is possible ,please tell me where i can find some examples?
That's explained in the iText 7 Jump-start tutorial, more specifically in chapter 4:
This form:
Can be filled out like this:
PdfDocument pdf =
new PdfDocument(new PdfReader(src), new PdfWriter(dest));
PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
Map<String, PdfFormField> fields = form.getFormFields();
fields.get("name").setValue("James Bond");
fields.get("language").setValue("English");
fields.get("experience1").setValue("Off");
fields.get("experience2").setValue("Yes");
fields.get("experience3").setValue("Yes");
fields.get("shift").setValue("Any");
fields.get("info").setValue("I was 38 years old when I became an MI6 agent.");
// form.flattenFields();
pdf.close();
The result looks like this:
If you uncomment the line form.flattenFields(); then you get this:
When the form is flattened, the fields are removed, and only the content is left.
If by any chance the PDF is a dynamic XFA form, then you should provide an XML stream, and you should read the FAQ: How to fill out a pdf file programmatically? (Dynamic XFA)
As you seem to be new to iText, it is assumed that you'll use the latest version of iText (which is iText 7) as opposed to a version that is being phased out (iText 5) or obsolete (all versions prior to iText 2). However, if for any reason you choose to use iText 5, then your question is a duplicate of How to fill out a pdf file programatically? (in which case your question should be closed as a duplicate).
i try to print invoices on a pre defined template on a piece of paper.
Because of that template i need some placeholders before the invoice is printed to avoid overplap. Sometimes the invoices get a little bit longer so that i need a second invoice page. If the invoice just has one page everything works fine.
My issue:
If the invoice gets longer (second page) the placeholder has to be on the beginning of the second page as well. I was not able to figure out how to do this.
Here is how i do it on first page:
PdfPTable placeholderTable = new PdfPTable(1);
placeholderTable.setHorizontalAlignment(PdfPTable.ALIGN_RIGHT);
placeholderTable.setWidthPercentage(91f);
PdfPCell placeholderCell = new PdfPCell(new Phrase(" ", font4GroßFett));
placeholderCell.setBorder(0);
placeholderTable.addCell(placeholderCell);
document.add(placeholderTable);
I tried a lot of things but especially i think the following is important (maybe i just use it in a wrong way)
writer.setPageEvent(new PdfPageEventHelper() {
#Override
public void onStartPage(final PdfWriter writer, final Document document) {
//add the placeholder here?
}
});
This seemed to be the best solution but i cant add elements to the document in this method (see offical documentation of itext)
My question is now: How can i set some placeholders (space) to the top of EVERY new page?
Thank you very much for helping!
I am creating a PDF with Arabic & latin mixed data. The arabic comes out unshaped. The code i have is like the Ligatures2 example:
PdfPTable table = new PdfPTable(1);
table.setWidthPercentage(100);
table.getDefaultCell().setBorder(0);
table.setRunDirection(PdfWriter.RUN_DIRECTION_RTL);
ColumnText column = new ColumnText(writer.getDirectContent());
column.setSimpleColumn(0, 0, 1500, 1500);
column.setRunDirection(PdfWriter.RUN_DIRECTION_RTL);
document.add(new Paragraph(line, font));
column.go();
I'm sorry to disagree with you, but your code is nothing like the Ligatures2 example:
You create a PdfPTable object, but you don't add any content to it. You don't add the table to the document.
You create a ColumnText object, but you don't add any content to it. When you perform go() nothing happens.
If we remove all the unused lines from your code snippet, this is what remains:
document.add(new Paragraph(line, font));
As documented in the book that comes with the Ligatures2 example you refer to, this code, this is insufficient to render Arabic.
One way to fix your code would be to do something like this:
ColumnText column = new ColumnText(writer.getDirectContent());
column.setSimpleColumn(36, 36, 559, 806);
column.setRunDirection(PdfWriter.RUN_DIRECTION_RTL);
document.addElement(new Paragraph(line, font));
column.go();
Note that I am making an assumption here: I assume that your page size is A4. In your code, you defined the rectangle of the column like this:
column.setSimpleColumn(0, 0, 1500, 1500);
That's a very strange size.
Side-note:
Please avoid to copy/paste code from examples and then break those examples without reading the documentation that comes with the examples.
I see that (1.) this question isn't the first example of this behavior, and (2.) you don't provide feedback when somebody answers your question. If a question is solved correctly, you should do the right thing and accept the answer!
https://stackoverflow.com/questions/27941538/illegalpdfsyntaxexception-unbalanced-begin-end-operators: no feedback whatsoever on the counter-question. The question can't be answered due to lack of information.
IText font not subsetting or embedding: question reveals a lack of respect for the documentation. It was answered correctly, but the answer was not accepted.
JZOS and iText on z/OS: strange question and no feedback on the answer that was given. Did it solve the problem? One can only guess.
I am using iTextSharp 5.5.3 i have a PDF with named fields i created with Adobe lifecycle I am able to fill the fields using iTextSharp but when i change the textcolor for a field it does not change. i really dont know why this is so. here is my code below
form.SetField("name", "Michael Okpara");
form.SetField("session", "2014/2015");
form.SetField("term", "1st Term");
form.SetFieldProperty("name", "textcolor", BaseColor.RED, null);
form.RegenerateField("name");
If your form is created using Adobe LifeCycle, then there are two options:
You have a pure XFA form. XFA stands for the XML Forms Architecture and your PDF is nothing more than a container of an XML stream. There is hardly any PDF syntax in the document and there are no AcroForm fields. I don't think this is the case, because you are still able to fill out the fields (which wouldn't work if you had a pure XFA form).
You have a hybrid form. In this case, the form is described twice inside the PDF file: once using an XML stream (XFA) and once using PDF syntax (AcroForm). iText will fill out the fields in both descriptions, but the XFA description gets preference when rendering the document. Changing the color of a field (or other properties) would require changing the XML and iText(Sharp) can not do that.
If I may make an educated guess, I would say that you have a hybrid form and that you are only changing the text color of the AcroForm field without changing the text color in the XFA field (which is really hard to achieve).
Please try adding this line:
form.RemoveXfa();
This will remove the XFA stream, resulting in a form that only keeps the AcroForm description.
I have written a small example named RemoveXFA using the form you shared to demonstrate this. This is the C#/iTextSharp version of that example:
public void ManipulatePdf(String src, String dest)
{
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileStream(dest, FileMode.Create));
AcroFields form = stamper.AcroFields;
form.RemoveXfa();
IDictionary<String, AcroFields.Item> fields = form.Fields;
foreach (String name in fields.Keys)
{
if (name.IndexOf("Total") > 0)
form.SetFieldProperty(name, "textcolor", BaseColor.RED, null);
form.SetField(name, "X");
}
stamper.Close();
reader.Close();
}
In this example, I remove the XFA stream and I look over all the remaining AcroFields. I change the textcolor of all the fields with the word "Total" in their name, and I fill out every field with an "X".
The result looks like this: reportcard.pdf
All the fields show the letter "X", but the fields in the TOTAL column are written in red.
I finally found a way, guess the problem was coming from using Adobe LC, so i switched to Open Office it all worked but when i flatten the form everything disappears. I found a solution to that here ITextSharp PDFTemplate FormFlattening removes filled data
Thanks Mr Lowagie for your help
I'm pretty sure I'm missing something simple, but since I've been breaking my head on this for a while, I'm just going to ask.
I'm using JavaScript to access the iText (Java) library to take a filable PDF and serve it up via a browser. The process has worked for my first one, and now I'm doing one where the original fillable PDF has 2 pages. I've been trying to get the second page for a while now. I'm using the PdfContentByte to get it to the browser, and it works except I can't seem to get the PdfContentByte to have a second page. My relevant code is below. When I add the second template (page2) they way I do, it moves what I'm writing, but I'm still just getting one (US letter) page.
This may not be the most efficient code, but like I said, I've been trying a few things on this. If someone has a pointer, I would be very grateful.
var cb:com.itextpdf.text.pdf.PdfContentByte = writer.getDirectContent();
var cb2:com.itextpdf.text.pdf.PdfContentByte = writer.getDirectContent();
var reader2:com.itextpdf.text.pdf.PdfReader = new com.itextpdf.text.pdf.PdfReader(os.toByteArray());
var page:com.itextpdf.text.pdf.PdfImportedPage = writer.getImportedPage(reader2, 1);
cb.addTemplate(page, 0, 0); //this works as expected
var page2:com.itextpdf.text.pdf.PdfImportedPage = writer.getImportedPage(reader2, 2);
// this will add, and with the 100 do an offset, but the
// "physical size" of the paper is the same
cb2.addTemplate(page2, 0, 100);
Have a look at chapter 6 of iText in Action, 2nd edition, especially at subsection 6.4.1: Concatenating and splitting PDF documents.
Listing 6.22, ConcatenateStamp.java, shows you how you should create a PDF from copies of pages of multiple other PDFs; the sample actually additionally adds a new "Page X of Y" footer which you may keep or remove from the sample.