如何调整页面高度到内容高度?

我正在为我的项目使用iTextPDF + FreeMarker。 基本上我使用FreeMarker加载和填充HTML模板,然后使用iTextPDF的XMLWorker将其渲染为pdf。

该模板是:

 <html> <body style="font-family; ${fontName}"> <table> <tr> <td style="text-align: right">${timestampLabel}&nbsp;</td> <td><b>${timestampValue}</b></td> </tr> <tr> <td style="text-align: right">${errorIdLabel}&nbsp;</td> <td><b>${errorIdValue}</b></td> </tr> <tr> <td style="text-align: right">${systemIdLabel}&nbsp;</td> <td><b>${systemIdValue}</b></td> </tr> <tr> <td style="text-align: right">${descriptionLabel}&nbsp;</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两次:

  1. 我将在模拟模式下将列表添加到ColumnText 。 这个ColumnText没有绑定到任何文档或者作者。 这样做的唯一目的是要知道我需要多less空间垂直。
  2. 我会将列表添加到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的值。 你会看到这会导致不同的页面大小。