java height itext itextpdf

java - ¿Cómo ajustar la altura de la página a la altura del contenido?



height itext (1)

No puede cambiar el tamaño de la página después de haber agregado contenido a esa página. Una forma de evitar esto sería crear el documento en dos pasadas: primero cree un documento para agregar el contenido, luego manipule el documento para cambiar el tamaño de la página. Esa habría sido mi primera respuesta si hubiera tenido tiempo de responder de inmediato.

Ahora que me he tomado más tiempo para pensarlo, he encontrado una mejor solución que no requiere dos pases. Echa un vistazo a HtmlAdjustPageSize

En este ejemplo, primero analizo el contenido en una lista de objetos Element usando este método:

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; }

Nota: He copiado / pegado este método tantas veces que decidí convertirlo en un método estático en la clase XMLWorkerHelper . Estará disponible en la próxima versión de iText.

Importante: he hecho lo que prometí, este método ahora está disponible en la versión XML Worker.

Para fines de prueba, utilicé valores de String estáticos para HTML y 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";

Puedes ver que tomé HTML que se parece más o menos al HTML con el que estás tratando.

Analizo este HTML y CSS en una ElementList :

ElementList el = parseHtml(HTML, CSS);

O, comenzando con XML Worker 5.5.4:

ElementList el = XMLWorkerHelper.parseToElementList(HTML, CSS);

Hasta aquí todo bien. No te he dicho nada que no supieras, excepto esto: ahora voy a usar este el dos veces:

  1. Agregaré la lista a un ColumnText en modo de simulación. Este ColumnText no está vinculado a ningún documento o escritor. El único propósito de hacer esto es saber cuánto espacio necesito verticalmente.
  2. Agregaré la lista a un ColumnText de verdad. Este ColumnText se ajustará exactamente en una página de un tamaño que defino utilizando los resultados obtenidos en modo de simulación.

Algún código aclarará lo que quiero decir:

// 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();

El código anterior es útil solo para una cosa: obtener el valor y que se utilizará para definir el tamaño de página del Document y la dimensión de la columna de ColumnText que se agregará de forma 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();

Descargue el código completo HtmlAdjustPageSize.java y cambie el valor de HTML . Verá que esto conduce a diferentes tamaños de página.

Estoy usando iTextPDF + FreeMarker para mi proyecto. Básicamente, cargo y lleno una plantilla HTML con FreeMarker y luego la renderizo a PDF con XMLWorker de XMLWorker .

La plantilla es:

<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>

Y este es mi código:

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();

Este código funciona bien, pero con la altura fija es un problema.

IE Digamos que:

errorId = "ERROR-01" systemId = "SYSTEM-01" description = "A SHORT DESCRIPTION OF THE ISSUE"

El documento producido es:

Si en cambio uso

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."

El documento producido es:

Como puede ver, en el último documento tengo dos páginas. Me gustaría tener solo una página que cambie su altura de acuerdo con la altura del contenido.

¿Es posible algo así con iText?