itext : paragraph keepTogether property affect sub element indent - java

I use keepTogether property on Paragraph to link on the same page some sub element (Chunk, Paragraph, etc.)
Java code:
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("C:\\hello.pdf"));
PdfDocument pdf = new PdfDocument();
pdf.addWriter(writer);
document.open();
Paragraph mainPara = new Paragraph();
Chunk title = new Chunk();
title.append("My title:");
title.setUnderline(1f, -2f);
mainPara.add(title);
Paragraph subPara = new Paragraph("Hello World!");
mainPara.add(subPara);
mainPara.setIndentationLeft(11f);
mainPara.setKeepTogether(true);
document.add(mainPara);
document.close();
When I activate the keepTogether property, I lost the indentationLeft inherited from mainPara on subPara element.
Without keepTogether property on mainPara object, the pdf result result is :
My title:
Hello World!
With keepTogether property on mainPara object, the pdf result result is :
My title:
Hello World!
I lost the indent inherited from the mainPara on subPara object. I wan't to keep it.

You are only setting indentation for the main paragraph,
For a long text
subPara.setFirstLineIndent(11f);
OR For a short text.
subPara.setIndentationLeft(11f);

Related

Set width of space with iText 7

Is there a way to set the width of all spaces in a Paragraph in iText 7?
So for example when showing the text "Hello world spacetest" I would like to be able to set the space between "Hello" and "world", and the space between "world" and "spacetest" to 3em.
Use Paragraph#setWordSpacing for that: e.g. p.setWordSpacing(10);.
Full code sample:
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFileName));
Document document = new Document(pdfDocument);
Paragraph p = new Paragraph("Hello world spacetest");
p.setWordSpacing(10);
document.add(p);
document.close();
Visual result:

convert html file with Arabic Characters to pdf using java [duplicate]

I am having trouble to display the Arabic Characters from HTML Content in PDF Generation as "?"
I am able to display the Arabic text from String variable. At the same time I am not able to generate the Arabic Text from the HTML String.
I want to display the PDF with two column, left side English and the right side Arabic Text.
when I use the following program to convert into pdf. Please help me in this regard.
try
{
Document document = new Document(PageSize.A4, 50, 50, 50, 50);
ByteArrayOutputStream out = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(document, out);
BaseFont bf = BaseFont.createFont("C:\\arial.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
Font font = new Font(bf, 8);
document.open();
BufferedReader br = new BufferedReader(new FileReader("C:\\style.css"));
StringBuffer fileContents = new StringBuffer();
String line = br.readLine();
while (line != null)
{
fileContents.append(line);
line = br.readLine();
}
br.close();
String styles = fileContents.toString(); //"p { font-family: Arial;}";
Paragraph cirNoEn = null;
Paragraph cirNoAr = null;
String htmlContentEn = null;
String htmlContentAr = null;
PdfPCell contentEnCell = new PdfPCell();
PdfPCell contentArCell = new PdfPCell();
cirNoEn = new Paragraph("Circular No. (" + cirEnNo + ")", new Font(bf, 14, Font.BOLD | Font.UNDERLINE));
cirNoAr = new Paragraph("رقم التعميم (" + cirArNo + ")", new Font(bf, 14, Font.BOLD | Font.UNDERLINE));
htmlContentEn = “< p >< span > Dear….</ span ></ p >”;
htmlContentAr = “< p >< span > رقم التعميم رقم التعميم </ p >< p > رقم التعميم ….</ span ></ p >”;
for (Element e : XMLWorkerHelper.parseToElementList(htmlContentEn, styles))
{
for (Chunk c : e.getChunks())
{
c.setFont(new Font(bf));
}
contentEnCell.addElement(e);
}
for (Element e : XMLWorkerHelper.parseToElementList(htmlContentAr, styles))
{
for (Chunk c:e.getChunks())
{
c.setFont(new Font(bf));
}
contentArCell.addElement(e);
}
PdfPCell emptyCell = new PdfPCell();
PdfPCell cirNoEnCell = new PdfPCell(cirNoEn);
PdfPCell cirNoArCell = new PdfPCell(cirNoAr);
cirNoEnCell.setHorizontalAlignment(Element.ALIGN_CENTER);
cirNoArCell.setHorizontalAlignment(Element.ALIGN_CENTER);
emptyCell.setBorder(Rectangle.NO_BORDER);
emptyCell.setFixedHeight(15);
cirNoEnCell.setBorder(Rectangle.NO_BORDER);
cirNoArCell.setBorder(Rectangle.NO_BORDER);
contentEnCell.setBorder(Rectangle.NO_BORDER);
contentArCell.setBorder(Rectangle.NO_BORDER);
cirNoArCell.setRunDirection(PdfWriter.RUN_DIRECTION_RTL);
contentArCell.setRunDirection(PdfWriter.RUN_DIRECTION_RTL);
contentEnCell.setNoWrap(false);
contentArCell.setNoWrap(false);
PdfPTable circularInfoTable = null;
emptyCell.setColspan(2);
circularInfoTable = new PdfPTable(2);
circularInfoTable.addCell(cirNoEnCell);
circularInfoTable.addCell(cirNoArCell);
circularInfoTable.addCell(emptyCell);
circularInfoTable.addCell(emptyCell);
circularInfoTable.addCell(emptyCell);
circularInfoTable.addCell(contentEnCell);
circularInfoTable.addCell(contentArCell);
circularInfoTable.addCell(emptyCell);
circularInfoTable.getDefaultCell().setBorder(PdfPCell.NO_BORDER);
circularInfoTable.setWidthPercentage(100);
document.add(circularInfoTable);
document.close();
}
catch (Exception e)
{
}
Please take a look at the ParseHtml7 and ParseHtml8 examples. They take HTML input with Arabic characters and they create a PDF with the same Arabic text:
Before we look at the code, allow me to explain that it's not a good idea to use non-ASCII characters in source code. For instance: this is not done:
htmlContentAr = “<p><span> رقم التعميم رقم التعميم</p><p>رقم التعميم ….</span></p>”;
You never know how a Java file containing these glyphs will be stored. If it's not stored as UTF-8, the characters may end up looking like something completely different. Versioning systems are known to have problems with non-ASCII characters and even compilers can get the encoding wrong. If you really want to stored hard-coded String values in your code, use the UNICODE notation. Part of your problem is an encoding problem, and you can read more about this here: Can't get Czech characters while generating a PDF
For the examples shown in the screen shots, I saved the following files using UTF-8 encoding:
This is what you'll find in the file arabic.html:
<html>
<body style="font-family: Noto Naskh Arabic">
<p>رقم التعميم رقم التعميم</p>
<p>رقم التعميم</p>
</body>
</html>
This is what you'll find in the file arabic2.html:
<html>
<body style="font-family: Noto Naskh Arabic">
<table>
<tr>
<td dir="rtl">رقم التعميم رقم التعميم</td>
<td dir="rtl">رقم التعميم</td>
</tr>
</table>
</body>
</html>
The second part of your problem concerns the font. It is important that you use a font that knows how to draw Arabic glyphs. It is hard to believe that you have arial.ttf right at the root of your C: drive. That's not a good idea. I would expect you to use C:/windows/fonts/arialuni.ttf which certainly knows Arabic glyphs.
Selecting the font isn't sufficient. Your HTML needs to know which font family to use. Because most of the examples in the documentation use Arial, I decided to use a NOTO font. I discovered these fonts by reading this question: iText pdf not displaying Chinese characters when using NOTO fonts or Source Hans. I really like these fonts because they are nice and (almost) every language is supported. For instance, I used NotoNaskhArabic-Regular.ttf which means that I need to define the font familie like this:
style="font-family: Noto Naskh Arabic"
I defined the style in the body tag of my XML, it's obvious that you can choose where to define it: in an external CSS file, in the styles section of the <head>, at the level of a <td> tag,... That choice is entirely yours, but you have to define somewhere which font to use.
Of course: when XML Worker encounters font-family: Noto Naskh Arabic, iText doesn't know where to find the corresponding NotoNaskhArabic-Regular.ttf unless we register that font. We can do this, by creating an instance of the FontProvider interface. I chose to use the XMLWorkerFontProvider, but you're free to write your own FontProvider implementation:
XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
fontProvider.register("resources/fonts/NotoNaskhArabic-Regular.ttf");
There is one more hurdle to take: Arabic is written from right to left. I see that you want to define the run direction at the level of the PdfPCell and that you add the HTML content to this cell using an ElementList. That's why I first wrote a similar example, named ParseHtml7:
public void createPdf(String file) throws IOException, DocumentException {
// step 1
Document document = new Document();
// step 2
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
// step 3
document.open();
// step 4
// Styles
CSSResolver cssResolver = new StyleAttrCSSResolver();
XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
fontProvider.register("resources/fonts/NotoNaskhArabic-Regular.ttf");
CssAppliers cssAppliers = new CssAppliersImpl(fontProvider);
// HTML
HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers);
htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
// Pipelines
ElementList elements = new ElementList();
ElementHandlerPipeline pdf = new ElementHandlerPipeline(elements, null);
HtmlPipeline html = new HtmlPipeline(htmlContext, pdf);
CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);
// XML Worker
XMLWorker worker = new XMLWorker(css, true);
XMLParser p = new XMLParser(worker);
p.parse(new FileInputStream(HTML), Charset.forName("UTF-8"));
PdfPTable table = new PdfPTable(1);
PdfPCell cell = new PdfPCell();
cell.setRunDirection(PdfWriter.RUN_DIRECTION_RTL);
for (Element e : elements) {
cell.addElement(e);
}
table.addCell(cell);
document.add(table);
// step 5
document.close();
}
There is no table in the HTML, but we create our own PdfPTable, we add the content from the HTML to a PdfPCell with run direction LTR, and we add this cell to the table, and the table to the document.
Maybe that's your actual requirement, but why would you do this in such a convoluted way? If you need a table, why don't you create that table in HTML and define some cells are RTL like this:
<td dir="rtl">...</td>
That way, you don't have to create an ElementList, you can just parse the HTML to PDF as is done in the ParseHtml8 example:
public void createPdf(String file) throws IOException, DocumentException {
// step 1
Document document = new Document();
// step 2
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
// step 3
document.open();
// step 4
// Styles
CSSResolver cssResolver = new StyleAttrCSSResolver();
XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
fontProvider.register("resources/fonts/NotoNaskhArabic-Regular.ttf");
CssAppliers cssAppliers = new CssAppliersImpl(fontProvider);
HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers);
htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
// Pipelines
PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer);
HtmlPipeline html = new HtmlPipeline(htmlContext, pdf);
CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);
// XML Worker
XMLWorker worker = new XMLWorker(css, true);
XMLParser p = new XMLParser(worker);
p.parse(new FileInputStream(HTML), Charset.forName("UTF-8"));;
// step 5
document.close();
}
There is less code needed in this example, and when you want to change the layout, it's sufficient to change the HTML. You don't need to change your Java code.
One more example: in ParseHtml9, I create a table with an English name in one column ("Lawrence of Arabia") and the Arabic translation in the other column ("لورانس العرب"). Because I need different fonts for English and Arabic, I define the font at the <td> level:
<table>
<tr>
<td>Lawrence of Arabia</td>
<td dir="rtl" style="font-family: Noto Naskh Arabic">لورانس العرب</td>
</tr>
</table>
For the first column, the default font is used and no special settings are needed to write from left to right. For the second column, I define an Arabic font and I set the run direction to "rtl".
The result looks like this:
That's much easier than what you're trying to do in your code.

Why on splitting table to new page page padding is changed?

Why on splitting table to new page page padding/margins is/are changed?
See what I mean:
Code:
//Some logic to get data.
PdfPTable table = new PdfPTable(cols);
table.setWidthPercentage(100);
table.setHorizontalAlignment(Element.ALIGN_JUSTIFIED_ALL);
Phrase headerText = new Phrase(header);
headerText.setFont(FontFactory.getFont(FontFactory.COURIER_BOLD,14.6f));
PdfPCell headerRow = new PdfPCell(headerText);
headerRow.setColspan(7);
headerRow.setBackgroundColor(BaseColor.LIGHT_GRAY);
headerRow.setHorizontalAlignment(Element.ALIGN_CENTER);
headerRow.setPadding(5);
table.addCell(headerRow);
Set<Integer> keys = data.keySet();
double sum = 0;
for (Integer key : keys) {
//There data is added in table...
}
//generate pdf
Document document = new Document();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PdfWriter.getInstance(document,byteArrayOutputStream);
document.open();
document.setMargins(5,5,5,5);
document.add(table);
document.add(p);
document.add(paragraph);
document.addCreationDate();
document.addTitle("Tenant activity");
document.close();
logger.debug("Pdf generated");
File f = new File("activity.pdf");
logger.debug("File path: " + f.getAbsolutePath());
How can I set padding for page / margin for table same as on first page, to each page?
This is the wrong order:
document.open();
document.setMargins(5,5,5,5);
This is the right order:
document.setMargins(5,5,5,5);
document.open();
When you open the document, or when you invoke document.newPage(), the next page is initialized, and you can't change page properties such as size or margins of that page.
So if you change the page size or margins, those changes will only be valid on the next page, not on the current page.
Why is this? Well, this is PDF, everything is page based, and once a page has been initialized, you'd get some really weird side-effects if you change those properties while adding content.

iTextPDF - Cannot use writeSelectedRows() on a table where an anchor has been inserted

I am in the process of converting the contents page of my PDF from using page numbers as a hyperlink, to anchors because of a few circumstantial limitations and the linking needs to be more dynamic.
I have omitted outer-loop code, but I am attempting to create a hyperlinked entry in the contents page using the following:
PdfPCell cell = new PdfPCell();
Paragraph p = new Paragraph();
Anchor anchor = new Anchor("page18 link");
anchor.setReference("#page18");
p.add(anchor);
cell.addElement(p);
table.addCell(cell);
Once the contents page has been generated (i.e. all the rows have been added), I then use the writeSelectedRows on the table:
table.writeSelectedRows(0, -1, PageSize.A4.getWidth()*.05f, PageSize.A4.getHeight()-100, stamper.getOverContent(prevSectionPageCount+currentIndexPage+1));
On doing this, I get the following exception:
Cause Exception was: Error in StamperPDFPlugin. null
java.lang.NullPointerException at
com.itextpdf.text.pdf.internal.PdfAnnotationsImp.addPlainAnnotation(PdfAnnotationsImp.java:125)
at com.itextpdf.text.pdf.PdfDocument.localGoto(PdfDocument.java:2115)
at
com.itextpdf.text.pdf.PdfDocument.writeLineToContent(PdfDocument.java:1612)
at com.itextpdf.text.pdf.ColumnText.go(ColumnText.java:1025) at
com.itextpdf.text.pdf.ColumnText.go(ColumnText.java:877) at
com.itextpdf.text.pdf.ColumnText.goComposite(ColumnText.java:1381) at
com.itextpdf.text.pdf.ColumnText.go(ColumnText.java:882) at
com.itextpdf.text.pdf.ColumnText.go(ColumnText.java:877) at
com.itextpdf.text.pdf.ColumnText.go(ColumnText.java:866) at
com.itextpdf.text.pdf.PdfPRow.writeCells(PdfPRow.java:549) at
com.itextpdf.text.pdf.PdfPTable.writeSelectedRows(PdfPTable.java:767)
at
com.itextpdf.text.pdf.PdfPTable.writeSelectedRows(PdfPTable.java:897)
at
com.itextpdf.text.pdf.PdfPTable.writeSelectedRows(PdfPTable.java:845)
at
com.itextpdf.text.pdf.PdfPTable.writeSelectedRows(PdfPTable.java:823)
at
com.ems.rendition.cts.plugin.StamperPDFPlugin.transform(StamperPDFPlugin.java:584)
at
com.ems.rendition.cts.plugin.StamperPDFPlugin.transform(StamperPDFPlugin.java:328)
at
com.ems.rendition.cts.plugin.StamperPDFPlugin.executeProfile(StamperPDFPlugin.java:171)
On seeing the stack trace entry for localGoto, I took out the line anchor.setReference("#18.pdf"); and it completed fine without error (but obviously with the absence of the hyperlinks - only plain text).
What is going wrong here? Am I adding the anchor to the cell incorrectly?
Thanks
Please take a look at LinkInPositionedTable:
public void createPdf(String dest) throws IOException, DocumentException {
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
Anchor target = new Anchor("top");
target.setName("page18");
document.add(target);
PdfPTable table = new PdfPTable(1);
table.setTotalWidth(500);
PdfPCell cell = new PdfPCell();
Paragraph p = new Paragraph();
Anchor anchor = new Anchor("page18 link");
anchor.setReference("#page18");
p.add(anchor);
cell.addElement(p);
table.addCell(cell);
table.writeSelectedRows(0, -1, 36, 700, writer.getDirectContent());
document.close();
}
In this example, I create an anchor with name page18 (although it just refers to the top of the page) and a reference to that anchor added to a PdfPTable using your code snippet.
You can find the result here: link_in_positioned_table.pdf
This works for me, when using iText 5.5.7 (which is the most recent version).

Making a paragraph in iText pdf not divided in two pages

I'm writing a pdf file with iText and I want the paragraphs divided across two different pages. How can I do this?
It is a lot easier to help if you could provide a more accurate example of the paragraphs and the document you are creating, but as far as I understand it is something like this:
Generate an ArrayList or other weapon of choise in making an iterable list of the paragraphs. Iterate through that list and call newPage() before adding content to page 2
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream([file]));
for (ArrayList<Paragraph> : theParagraph ) {
document.addElement(theParagraph)
document.newPage();
}
document.close();
This will automaticaly add new pages as content is added on the pdf-document, but with less controle over when the pagebreak occurs:
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream([file]));
document.open();
for(int i=0 ; i<100; i++){
document.add(new Paragraph("This is a very important message"));
}
document.close();

Categories