Table creation on separate method using iText in Java - java

I'm trying to create an PDF document using iText. I followed to THIS nice tutorial and tried to create single page pdf document which has a table. In the tutorial the author keeps table creation of table on separate method such as addMetaData, addTitlePage and addContent. I also would keep them separately, but I'm new to iText and currently I'm stuck. The current code is:
public static void main(String args[]) {
try {
Document document = new Document(PageSize.A4);
PdfWriter.getInstance(document, new FileOutputStream(FILE));
document.open();
addMetaData(document);
addTitlePage(document);
addContent(document);
document.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void addTitlePage(Document document) throws DocumentException {
Paragraph preface = new Paragraph();
// Add one empty line
addEmptyLine(preface, 1);
// Header of the document
preface.add(new Paragraph("Title here", capFont));
addEmptyLine(preface, 1);
// Report generated by: _name, _date
preface.add(new Paragraph("Report generated by: " + System.getProperty("user.name") + ", " + new Date(), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
normFont));
addEmptyLine(preface, 2);
preface.add(new Paragraph("This document describes some kind of price list which is unknown to me.", normFont));
document.add(preface);
}
private static void addContent(Document document) throws DocumentException {
Paragraph content = new Paragraph();
// Add one empty line
addEmptyLine(content, 1);
// Content of the document
content.add(new Paragraph(createTable(subPart), normFont)); // not working line
addEmptyLine(content, 5);
content.add(new Paragraph("This document is a preliminary version and not subject to the license agreement.", redFont));
document.add(content);
}
private static void createTable(Section subPart) throws BadElementException {
PdfPTable table = new PdfPTable(3);
table.setHorizontalAlignment(Element.ALIGN_CENTER);
// Data
table.addCell("1");
table.addCell("2");
table.addCell("3");
subPart.add(table);
}
Any help would be appreciated.

So, after one day literature reading and api homepage visiting I came to my solution:
Instead of: content.add(new Paragraph(createTable(subPart), normFont));
I have now: createTable(content);
and of course I changed the type of variable in createTable method to the paragraph in order to get it working.

package src.AutosysPolicyWriter.Utility;
import java.util.StringTokenizer;
import com.lowagie.text.Cell;
import com.lowagie.text.Document;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.Phrase;
import com.lowagie.text.Rectangle;
import com.lowagie.text.Table;
/**
* Modification/itext 1.4 - <Modified : September 26, 2013>
* #author Oliver Lundag
* #date 2013-09-06
* Can handle table creation in the PDF
*/
public class PdfTableUtility {
/***
*
* #param titleFont - font of the title of the table
* #param fontHeader - font of the headers
* #param fontData - font of the data
* #param thisReport - Document
* #param tableTitle - Name of the table
* #param headerStrings - headers
* #param data - data
*
* How to use this function;
*
* Example:
*
* // Initialize PdfTableUtility object
* 1. PdfTableUtility tableUtility = new PdfTableUtility();
*
* // Declare the value for headers.
* // Note: Number of columns will depends on how many headers has been declared
* 2. String[] headers = {"Customer Name","Age","Plan","Amount"};
*
* // Declare the data that will be put inside
* // Note that the arrangement of the strings are the actual display in the pdf
* // ; - separator
* 3. String data = "1.Oliver Lundag;26;Plan A;250,000;"+
* "2.Oliver Lundag;26;Plan A;250,000;"+
* "3.Oliver Lundag;26;Plan A;250,000";
*
* //call the function with specified arguments
* //arguments will depend on developers perspective
* 4. tableUtility.displaytable(FontBold11, FontBold9, FontNormal9, thisReport, "Information", 4, headers, data);
*/
public void displaytable(Font titleFont, Font fontHeader, Font fontData, Document thisReport,String tableTitle, String[] headerStrings, String data) {
try{
//START-(Modification/itext 1.4) SR-CS-13035 - OLUND <Modified : September 26, 2013> - title
//1.create table
Table title = new Table(1);
title.setLastHeaderRow(1);
title.setOffset(12f);
title.setSpaceInsideCell(1f);
title.setBorder(Rectangle.NO_BORDER);
//2.create table
Cell celltitle = new Cell(new Phrase(tableTitle, titleFont));
celltitle.setLeading(12);
celltitle.setBorder(Rectangle.NO_BORDER);
celltitle.setHorizontalAlignment(Element.ALIGN_CENTER);
title.addCell(celltitle);
//3.add the title in document
thisReport.add(title);
//END -(Modification/itext 1.4) SR-CS-13035 - OLUND <Modified : September 26, 2013> - title
//START-(Modification/itext 1.4) SR-CS-13035 - OLUND <Modified : September 26, 2013> - data
//1. get the max number of columns
int numColumns = headerStrings.length;
//2. create a table
Table table = new Table(numColumns);
table.setOffset(12f);
table.setLastHeaderRow(1);
table.setSpaceInsideCell(1f);
table.setTableFitsPage(true);
table.setAutoFillEmptyCells(true);
//3.get headers and add it into cells
for (String header : headerStrings) {
Cell headerCell = new Cell(new Phrase(header, fontHeader));
headerCell.setLeading(12);
headerCell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(headerCell);
}
//4.get data and add it into cells
String strToken;
if (data.length() > 0) {
StringTokenizer stStr = new StringTokenizer(data,";",false);
while(stStr.hasMoreTokens()){
strToken = stStr.nextToken().toString();
Cell cell = new Cell(new Phrase(strToken,fontData));
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
cell.setLeading(12);
table.addCell(cell);
}
}
//5. add the table in the document
thisReport.add(table);
//END - (Modification/itext 1.4) SR-CS-13035 - OLUND <Modified : September 26, 2013> - data
}catch (Exception e) {
e.printStackTrace();
}
}
}

Related

IText 5.5.3. 508 Compliance with JAWS 16

I am having issues printing 508 compliant Tagged PDF files that has Tables in them. For some reason, JAWS doesn't read the accessibility text for a PdfPTable.
In the below code snippet, JAWS reads the ALT text for the Chunk but it doesn't read for the PdfPCell and PdfPTable. Please Help!
/**
* Creates a PDF with information about the movies
* #param filename the name of the PDF file that will be created.
* #throws DocumentException
* #throws IOException
*/
public void createPdf(String filename)
throws IOException, DocumentException {
// step 1
Document document = new Document();
// step 2
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(filename));
writer.setPdfVersion(PdfWriter.VERSION_1_7);
writer.setTagged();
writer.setViewerPreferences(PdfWriter.DisplayDocTitle);
document.addLanguage("en-US");
document.addTitle("Some title");
writer.createXmpMetadata();
// step 3
document.open();
// step 4
Paragraph p1 = new Paragraph();
p1.setFont(FontFactory.getFont(
FONT, BaseFont.WINANSI, BaseFont.EMBEDDED, 20));
Chunk c1 = new Chunk("What is this?");
c1.setAccessibleAttribute(PdfName.ALT, new PdfString(" Q1. What is this?"));
p1.add(c1);
document.add(p1);
document.add(createFirstTable());
// step 5
document.close();
}
/**
* Creates our first table
* #return our first table
*/
public static PdfPTable createFirstTable() {
// a table with three columns
PdfPTable table = new PdfPTable(3);
table.setAccessibleAttribute(PdfName.ALT, new PdfString("My Table"));
// the cell object
PdfPCell cell;
// we add a cell with colspan 3
cell = new PdfPCell(new Phrase("Cell with colspan 3"));
cell.setAccessibleAttribute(PdfName.TD, new PdfString("Cell 1"));
cell.setColspan(3);
table.addCell(cell);
// now we add a cell with rowspan 2
cell = new PdfPCell(new Phrase("Cell with rowspan 2"));
cell.setRowspan(2);
table.addCell(cell);
// we add the four remaining cells with addCell()
table.addCell("row 1; caa*");
table.addCell("row 1; c+");
table.addCell("row 2; c-");
table.addCell("row 2; c/");
return table;
}
Wow! 508 can be really frustrating. After a couple of days, i was able to figure out a way out. I stumbled on the method: createTaggedPDF17(). I created a PdfPHeaderSet for the first row and added an header for each of the cells in the table body.
It worked perfectly! JAWS read the alternate text just the way i wanted it.
I dont know why it didnt work before. But this solved my problem.
public static PdfPTable createFirstTable() {
// a table with three columns
PdfPTable table = new PdfPTable(3);
// the cell object
PdfPCell cell;
// we add a cell with colspan 3
//create header cell for first row
PdfPHeaderCell headerCell = new PdfPHeaderCell();
headerCell.setScope(PdfPHeaderCell.ROW);
headerCell.setPhrase(new Phrase("Cell with colspan 3"));
headerCell.setName("header Cell");
headerCell.setAccessibleAttribute(PdfName.TD, new PdfString("Cell 1"));
headerCell.setColspan(3);
table.addCell(headerCell);
// now we add a cell with rowspan 2
cell = new PdfPCell(new Phrase("Cell with rowspan 2"));
//add metadata for each cell in the body.
cell.addHeader(headerCell);
cell.setRowspan(2);
table.addCell(cell);
// we add the four remaining cells with addCell()
table.addCell("row 1; caa*");
table.addCell("row 1; c+");
table.addCell("row 2; c-");
table.addCell("row 2; c/");
//set header row for the table
table.setHeaderRows(1);
return table;
}

Put hyperlink into image in excel (Apache POI)

I can set hyperlink for cell in Apache POI, but I don't know how to put the hyperlink into an image (I'm using XSSF)
Here is the function of putting cell hyperlink :
/**
* Helper function for putting hyperlink into specified cell
* #param label
* #param value
* #param col
* #param row
* #param sheet
*/
private static void putImageHyperlink(Cell cell, CellStyle hyperlinkStyle, String value, Workbook wb) {
try {
CreationHelper createHelper = wb.getCreationHelper();
Hyperlink link = createHelper.createHyperlink(Hyperlink.LINK_URL);
link.setAddress(value);
cell.setHyperlink(link);
cell.setCellStyle(hyperlinkStyle);
// Put hyperlink value
cell.setCellValue(value);
} catch (Exception e) {
log.severe("Can't create hyperlink : " + Utils.exceptionToString(e));
}
}
And here is the function for putting image into specified cell :
/**
* Put image into sheet at position [row,col]
* #param sheet
* #param col
* #param row
* #param imgData
* #throws Exception
*/
private static void putImage(Workbook wb, Sheet sheet, int col, int row, byte[] imgData) throws Exception {
try {
Drawing drawing = sheet.createDrawingPatriarch();
int pictureIdx = wb.addPicture(imgData, Workbook.PICTURE_TYPE_PICT);
CreationHelper helper = wb.getCreationHelper();
ClientAnchor anchor4 = helper.createClientAnchor();
//set top-left corner of the picture,
//subsequent call of Picture#resize() will operate relative to it
anchor4.setCol1(col);
anchor4.setRow1(row);
anchor4.setCol2(col+1);
anchor4.setRow2(row+1);
drawing.createPicture(anchor4, pictureIdx);
} catch (Exception ex) {
log.severe("Exception : " + Utils.exceptionToString(ex));
}
}
=> How to put hyperlink into picture created by command drawing.createPicture(anchor4, pictureIdx); ?
Thanks in advance!
When looking at how Excel stores this it seems to be stored differently for Images in the xl\drawings\_rels\drawing1.xml.rels and xl\drawings\drawing1.xml part of the XLSX file:
<Relationship Id="rId1" Target="http://poi.apache.org" TargetMode="External" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"/>
<xdr:cNvPr descr="Picture" id="2" name="Picture 1">
<a:hlinkClick xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:id="rId1"/>
</xdr:cNvPr>
POI does not support adding such hyperlinks via it's API yet, but you can use the underlying lowlevel-API as follows to first create the relationship for the hyperlink and then set the relation to the hyperlink in the Picture-object:
PackageRelationship rel = ((XSSFDrawing)patriarch).getPackagePart().addRelationship(
new URI("http://poi.apache.org"),
TargetMode.EXTERNAL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink");
((XSSFDrawing)patriarch).addRelation(rel.getId(),new POIXMLDocumentPart());
CTPictureNonVisual nvPicPr = ((XSSFPicture)picture).getCTPicture().getNvPicPr();
CTHyperlink hLinkClick = nvPicPr.getCNvPr().addNewHlinkClick();
hLinkClick.setId(rel.getId());

Reading from a word document using java

I'm trying to read data from a docx file using java. The data is is tables. Is there a way to iterate through the table cells and extract the cell data?
You have two choices:
Write a library that can open, read, and manipulate Word documents, for some definitions of "open", "read", and "manipulate", and some definition of "Word document".
Find a third-party library that can do some or all of what is defined in (1).
Search "java docx library" in your favourite web search and see what comes up.
This should help you.
http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xwpf/usermodel/SimpleTable.java
The above was achieved using Apache POI
Here is the code from the link:
package org.apache.poi.xwpf.usermodel;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.util.List;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHeight;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTShd;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTString;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTrPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVerticalJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STShd;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
/**
* This program creates a simple WordprocessingML table using POI XWPF API, and
* a more complex, styled table using both XWPF and ooxml-schema. It's possible
* that not all referenced wordprocessingml classes are defined in
* poi-ooxml-schemas-3.8-beta4. If this is the case, you'll need to use the full
* ooxml-schemas.jar library.
*
* #author gisella bronzetti (original)
* #author Gregg Morris (styled table)
*/
public class SimpleTable {
public static void main(String[] args) throws Exception {
try {
createSimpleTable();
}
catch(Exception e) {
System.out.println("Error trying to create simple table.");
throw(e);
}
try {
createStyledTable();
}
catch(Exception e) {
System.out.println("Error trying to create styled table.");
throw(e);
}
}
public static void createSimpleTable() throws Exception {
XWPFDocument doc = new XWPFDocument();
XWPFTable table = doc.createTable(3, 3);
table.getRow(1).getCell(1).setText("EXAMPLE OF TABLE");
// table cells have a list of paragraphs; there is an initial
// paragraph created when the cell is created. If you create a
// paragraph in the document to put in the cell, it will also
// appear in the document following the table, which is probably
// not the desired result.
XWPFParagraph p1 = table.getRow(0).getCell(0).getParagraphs().get(0);
XWPFRun r1 = p1.createRun();
r1.setBold(true);
r1.setText("The quick brown fox");
r1.setItalic(true);
r1.setFontFamily("Courier");
r1.setUnderline(UnderlinePatterns.DOT_DOT_DASH);
r1.setTextPosition(100);
table.getRow(2).getCell(2).setText("only text");
FileOutputStream out = new FileOutputStream("simpleTable.docx");
doc.write(out);
out.close();
}
/**
* Create a table with some row and column styling. I "manually" add the
* style name to the table, but don't check to see if the style actually
* exists in the document. Since I'm creating it from scratch, it obviously
* won't exist. When opened in MS Word, the table style becomes "Normal".
* I manually set alternating row colors. This could be done using Themes,
* but that's left as an exercise for the reader. The cells in the last
* column of the table have 10pt. "Courier" font.
* I make no claims that this is the "right" way to do it, but it worked
* for me. Given the scarcity of XWPF examples, I thought this may prove
* instructive and give you ideas for your own solutions.
* #throws Exception
*/
public static void createStyledTable() throws Exception {
// Create a new document from scratch
XWPFDocument doc = new XWPFDocument();
// -- OR --
// open an existing empty document with styles already defined
//XWPFDocument doc = new XWPFDocument(new FileInputStream("base_document.docx"));
// Create a new table with 6 rows and 3 columns
int nRows = 6;
int nCols = 3;
XWPFTable table = doc.createTable(nRows, nCols);
// Set the table style. If the style is not defined, the table style
// will become "Normal".
CTTblPr tblPr = table.getCTTbl().getTblPr();
CTString styleStr = tblPr.addNewTblStyle();
styleStr.setVal("StyledTable");
// Get a list of the rows in the table
List<XWPFTableRow> rows = table.getRows();
int rowCt = 0;
int colCt = 0;
for (XWPFTableRow row : rows) {
// get table row properties (trPr)
CTTrPr trPr = row.getCtRow().addNewTrPr();
// set row height; units = twentieth of a point, 360 = 0.25"
CTHeight ht = trPr.addNewTrHeight();
ht.setVal(BigInteger.valueOf(360));
// get the cells in this row
List<XWPFTableCell> cells = row.getTableCells();
// add content to each cell
for (XWPFTableCell cell : cells) {
// get a table cell properties element (tcPr)
CTTcPr tcpr = cell.getCTTc().addNewTcPr();
// set vertical alignment to "center"
CTVerticalJc va = tcpr.addNewVAlign();
va.setVal(STVerticalJc.CENTER);
// create cell color element
CTShd ctshd = tcpr.addNewShd();
ctshd.setColor("auto");
ctshd.setVal(STShd.CLEAR);
if (rowCt == 0) {
// header row
ctshd.setFill("A7BFDE");
}
else if (rowCt % 2 == 0) {
// even row
ctshd.setFill("D3DFEE");
}
else {
// odd row
ctshd.setFill("EDF2F8");
}
// get 1st paragraph in cell's paragraph list
XWPFParagraph para = cell.getParagraphs().get(0);
// create a run to contain the content
XWPFRun rh = para.createRun();
// style cell as desired
if (colCt == nCols - 1) {
// last column is 10pt Courier
rh.setFontSize(10);
rh.setFontFamily("Courier");
}
if (rowCt == 0) {
// header row
rh.setText("header row, col " + colCt);
rh.setBold(true);
para.setAlignment(ParagraphAlignment.CENTER);
}
else if (rowCt % 2 == 0) {
// even row
rh.setText("row " + rowCt + ", col " + colCt);
para.setAlignment(ParagraphAlignment.LEFT);
}
else {
// odd row
rh.setText("row " + rowCt + ", col " + colCt);
para.setAlignment(ParagraphAlignment.LEFT);
}
colCt++;
} // for cell
colCt = 0;
rowCt++;
} // for row
// write the file
FileOutputStream out = new FileOutputStream("styledTable.docx");
doc.write(out);
out.close();
}
}

How to adjust the page height to the content height?

I'm using iTextPDF + FreeMarker for my project. Basically I load and fill an HTML template with FreeMarker and then render it to pdf with iTextPDF's XMLWorker.
The template is:
<html>
<body style="font-family; ${fontName}">
<table>
<tr>
<td style="text-align: right">${timestampLabel} </td>
<td><b>${timestampValue}</b></td>
</tr>
<tr>
<td style="text-align: right">${errorIdLabel} </td>
<td><b>${errorIdValue}</b></td>
</tr>
<tr>
<td style="text-align: right">${systemIdLabel} </td>
<td><b>${systemIdValue}</b></td>
</tr>
<tr>
<td style="text-align: right">${descriptionLabel} </td>
<td><b>${descriptionValue}</b></td>
</tr>
</table>
</body>
</html>
And this is my code:
SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
String errorId = "ERROR-01";
String systemId = "SYSTEM-01";
String description = "A SHORT DESCRIPTION OF THE ISSUE";
Map<String, String> parametersMap = new HashMap<String, String>();
parametersMap.put("fontName", fontName); //valid font name
parametersMap.put("timestampLabel", " TIMESTAMP:");
parametersMap.put("errorIdLabel", " ERROR ID:");
parametersMap.put("systemIdLabel", " SYSTEM ID:");
parametersMap.put("descriptionLabel", " DESCRIPTION:");
parametersMap.put("timestampValue", DATE_FORMAT.format(new Date()));
parametersMap.put("errorIdValue", errorId);
parametersMap.put("systemIdValue", systemId);
parametersMap.put("descriptionValue", description);
FreeMarkerRenderer renderer = new FreeMarkerRenderer(); //A utility class
renderer.loadTemplate(errorTemplateFile); //the file exists
String rendered = renderer.render(parametersMap);
File temp = File.createTempFile("document", ".pdf");
file = new FileOutputStream(temp);
Document document = new Document();
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
document.setPageSize(new Rectangle(290f, 150f));
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
document.setMargins(10, 10, 10, 10);
PdfWriter writer = PdfWriter.getInstance(document, file);
document.open();
InputStream is = new ByteArrayInputStream(rendered.getBytes());
XMLWorkerFontProvider provider = new XMLWorkerFontProvider();
provider.register(fontFile); //the file exists
FontFactory.setFontImp(provider);
byte[] errorStyle = getErrorStyleByteArray(); //returns a byte array from a css file (works)
XMLWorkerHelper helper = XMLWorkerHelper.getInstance();
helper.parseXHtml(writer, document, is, new ByteArrayInputStream(errorStyle), provider);
document.close();
file.close();
This code works fine, but With the fixed height is a problem.
I.E. Let's say that:
errorId = "ERROR-01"
systemId = "SYSTEM-01"
description = "A SHORT DESCRIPTION OF THE ISSUE"
The produced document is:
If instead I use
errorId = "ERROR-01"
systemId = "SYSTEM-01"
description = "A SHORT DESCRIPTION OF THE ISSUE. THIS IS MULTILINE AND IT SHOULD STAY ALL IN THE SAME PDF PAGE."
The produced document is:
As you can see, in the last document I have two pages. I would like to have only one page which changes its height according to the content height.
Is something like this possible with iText?
You can not change the page size after you have added content to that page. One way to work around this, would be to create the document in two passes: first create a document to add the content, then manipulate the document to change the page size. That would have been my first reply if I had time to answer immediately.
Now that I've taken more time to think about it, I've found a better solution that doesn't require two passes. Take a look at HtmlAdjustPageSize
In this example, I first parse the content to a list of Element objects using this method:
public ElementList parseHtml(String html, String css) throws IOException {
// CSS
CSSResolver cssResolver = new StyleAttrCSSResolver();
CssFile cssFile = XMLWorkerHelper.getCSS(new ByteArrayInputStream(css.getBytes()));
cssResolver.addCss(cssFile);
// HTML
CssAppliers cssAppliers = new CssAppliersImpl(FontFactory.getFontImp());
HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers);
htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
htmlContext.autoBookmark(false);
// Pipelines
ElementList elements = new ElementList();
ElementHandlerPipeline end = new ElementHandlerPipeline(elements, null);
HtmlPipeline htmlPipeline = new HtmlPipeline(htmlContext, end);
CssResolverPipeline cssPipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
// XML Worker
XMLWorker worker = new XMLWorker(cssPipeline, true);
XMLParser p = new XMLParser(worker);
p.parse(new ByteArrayInputStream(html.getBytes()));
return elements;
}
Note: I've been copy/pasting this method so many times that I decided to make it a static method in the XMLWorkerHelper class. It will be available in the next iText release.
Important: I have done what I promised, this method is now available in the XML Worker release.
For testing purposes, I used static String values for HTML and CSS:
public static final String HTML = "<table>" +
"<tr><td class=\"ra\">TIMESTAMP</td><td><b>2014-11-28 11:06:09</b></td></tr>" +
"<tr><td class=\"ra\">ERROR ID</td><td><b>ERROR-01</b></td></tr>" +
"<tr><td class=\"ra\">SYSTEM ID</td><td><b>SYSTEM-01</b></td></tr>" +
"<tr><td class=\"ra\">DESCRIPTION</td><td><b>TEST WITH A VERY, VERY LONG DESCRIPTION LINE THAT NEEDS MULTIPLE LINES</b></td></tr>" +
"</table>";
public static final String CSS = "table {width: 200pt; } .ra { text-align: right; }";
public static final String DEST = "results/xmlworker/html_page_size.pdf";
You can see that I took HTML that looks more or less like the HTML you are dealing with.
I parse this HTML and CSS to an ElementList:
ElementList el = parseHtml(HTML, CSS);
Or, starting with XML Worker 5.5.4:
ElementList el = XMLWorkerHelper.parseToElementList(HTML, CSS);
So far, so good. I haven't told you anything that you didn't already know, except this: I am now
going to use this el twice:
I'll add the list to a ColumnText in simulation mode. This ColumnText isn't tied to any document or writer yet. The sole purpose to do this, is to know how much space I need vertically.
I'll add the list to a ColumnText for real. This ColumnText will fit exactly on a page of a size that I define using the results obtained in simulation mode.
Some code will clarify what I mean:
// I define a width of 200pt
float width = 200;
// I define the height as 10000pt (which is much more than I'll ever need)
float max = 10000;
// I create a column without a `writer` (strange, but it works)
ColumnText ct = new ColumnText(null);
ct.setSimpleColumn(new Rectangle(width, max));
for (Element e : el) {
ct.addElement(e);
}
// I add content in simulation mode
ct.go(true);
// Now I ask the column for its Y position
float y = ct.getYLine();
The above code is useful for only one things: getting the y value that will be used to define the page size of the Document and the column dimension of the ColumnText that will be added for real:
Rectangle pagesize = new Rectangle(width, max - y);
// step 1
Document document = new Document(pagesize, 0, 0, 0, 0);
// step 2
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
// step 3
document.open();
// step 4
ct = new ColumnText(writer.getDirectContent());
ct.setSimpleColumn(pagesize);
for (Element e : el) {
ct.addElement(e);
}
ct.go();
// step 5
document.close();
Please download the full HtmlAdjustPageSize.java code and change the value of HTML. You'll see that this leads to different page sizes.

How to make a report page direction to change to "rtl"?

I am creating a report with JasperReports, using iReport generated jrxml file.
My application is multilingual, (English (LTR) and Persian (RTL)). In tables generated, regarding to the direction of text I need to swap the whole page direction. Plus I use locale feature.
I googled a lot and finally found an attribute JRXlsAbstractExporter.PROPERTY_SHEET_DIRECTION, "RTL" but setting this attribute in excel generated formats don't have any impact on my report.
params.put(JRXlsAbstractExporter.PROPERTY_SHEET_DIRECTION, "RTL");
JasperPrint jasperPrint = JasperFillManager.fillReport(report,params,
dataSource != null ? new JRMapArrayDataSource(dataSource) : new JREmptyDataSource());
another thing I tried is setting this in exporter parameters as following:
JRExporter exporter = new JRXlsxExporter();
exporter.setParameter(JRXlsAbstractExporter.PROPERTY_SHEET_DIRECTION, "RTL");
exporter.exportReport();
but setting this parameter is not allowed and I get error.
If you have any experience for how to make a report page direction (or in other words mirror the whole report in specific locale) to change please help.
As far as I searched there is no property, you can use below util class:
package foo.bar.utils.export;
import java.util.Iterator;
import java.util.List;
import net.sf.jasperreports.engine.JRPrintElement;
import net.sf.jasperreports.engine.JRPrintFrame;
import net.sf.jasperreports.engine.JRPrintPage;
import net.sf.jasperreports.engine.JasperPrint;
/**
* Report utilities
* Please refer to: http://community.jaspersoft.com/questions/523041/right-left-arabic-reports
* There is another solution at: http://jaspermirror.sourceforge.net/
* which is not used here
* #author AFattahi
*
*/
public class ReportUtils {
private ReportUtils(){
}
/**
* mirror each page layout
* #param print
*/
public static void mirrorLayout(JasperPrint print) {
int pageWidth = print.getPageWidth();
for (Object element : print.getPages()) {
JRPrintPage page = (JRPrintPage) element;
mirrorLayout(page.getElements(), pageWidth);
}
}
/**
* mirror a list of elements
* #param print
*/
protected static void mirrorLayout(List<?> elements, int totalWidth) {
for (Iterator<?> it = elements.iterator(); it.hasNext();) {
JRPrintElement element = (JRPrintElement) it.next();
int mirrorX = totalWidth - element.getX() - element.getWidth();
element.setX(mirrorX);
if (element instanceof JRPrintFrame) {
JRPrintFrame frame = (JRPrintFrame) element;
mirrorLayout(frame.getElements(), frame.getWidth());
}
}
}
}
Please consider that the JRXlsxExporter does not support RTL (seems to be a bug in version 6) and you must JRXlsExporter
exporter = new JRXlsExporter();
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(out));
SimpleXlsReportConfiguration xlsReportConfig = new SimpleXlsReportConfiguration();
xlsReportConfig.setSheetDirection(RunDirectionEnum.RTL);
exporter.setConfiguration(xlsReportConfig);

Categories