如何调整页面高度到内容高度?
我正在为我的项目使用iTextPDF + FreeMarker。 基本上我使用FreeMarker加载和填充HTML模板,然后使用iTextPDF的XMLWorker
将其渲染为pdf。
该模板是:
<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>
这是我的代码:
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();
此代码工作正常,但与固定的高度是一个问题。
IE让我们这样说:
errorId = "ERROR-01" systemId = "SYSTEM-01" description = "A SHORT DESCRIPTION OF THE ISSUE"
生成的文件是:
如果相反,我使用
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."
生成的文件是:
正如你所看到的,在最后一份文件中,我有两页。 我想只有一个页面根据内容的高度来改变它的高度。
是这样的iText可能吗?
将内容添加到该页面后,您无法更改页面大小。 解决这个问题的一种方法是创build两个文档:首先创build一个文档来添加内容,然后操作文档来改变页面大小。 如果我有时间立即回答,这将是我的第一个答复。
现在我花了更多的时间来思考,我find了一个更好的解决scheme,不需要两次通过。 看看HtmlAdjustPageSize
在这个例子中,我首先使用这个方法将内容parsing为一个Element
对象列表:
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; }
注意:我已经复制/粘贴这个方法很多次了,所以我决定在XMLWorkerHelper
类中使它成为一个静态方法。 它将在下一个iText版本中提供。
重要说明:我已经完成了我所承诺的内容,现在可以在XML Worker版本中使用此方法。
出于testing目的,我为HTML和CSS使用了静态String
值:
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";
你可以看到,我把HTML看起来或多或less像你正在处理的HTML。
我将这个HTML和CSSparsing为一个ElementList
:
ElementList el = parseHtml(HTML, CSS);
或者,从XML Worker 5.5.4开始:
ElementList el = XMLWorkerHelper.parseToElementList(HTML, CSS);
到现在为止还挺好。 我没有告诉你任何你不知道的事情,除了这个:我现在要使用这个el
两次:
- 我将在模拟模式下将列表添加到
ColumnText
。 这个ColumnText
没有绑定到任何文档或者作者。 这样做的唯一目的是要知道我需要多less空间垂直。 - 我会将列表添加到
ColumnText
中。 这个ColumnText
将精确地放在我使用在模拟模式下获得的结果定义的大小的页面上。
一些代码将阐明我的意思:
// 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();
上面的代码对于只有一件事是有用的:获取将用于定义Document
的页面大小的y
值以及将被添加为实际的ColumnText
的列维度:
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();
请下载完整的HtmlAdjustPageSize.java代码并更改HTML
的值。 你会看到这会导致不同的页面大小。