【问题标题】:How to get page size of pdf document iText 7如何获取 pdf 文档 iText 7 的页面大小
【发布时间】:2020-06-27 03:04:14
【问题描述】:

我在 iText 7 中有一个 java 程序,它接收 JSON 数据并生成一个 PDF 文档(带有页眉和页脚),该文档适用于注释中变量 clientData 中的数据,但在没有 cmets clientData 中使用该变量时不起作用,我收到此错误java.lang.NullPointerException,在构建页眉和页脚时出现错误(在此行Rectangle pageSize = document.getPdfDocument().getPage(i).getPageSize();),但不知道什么数据为空,因为 JSON 数据和结构PDF的相同,我做错了什么?

这是所有代码:

import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.extgstate.PdfExtGState;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.element.Text;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.colors.Color;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.List;
import com.itextpdf.layout.element.ListItem;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.VerticalAlignment;
import java.io.File;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.Locale;

import org.json.JSONArray;
import org.json.JSONObject;

public class PDFGenerator {
public static final String DESTINATION = "path/exampleSMA.pdf";

public static void main(String[] args) throws Exception {
    File file = new File(DEST);
    file.getParentFile().mkdirs();
    //WORK
    //String clientData = "'{\"nombre_cliente\":\"Postobon\",\"contacto\":\"Kelly Paz\",\"email\":\"ventas@test.com\",\"telefono\":\"233774983\",\"observaciones\":\"\",\"totalizar\":true,\"mostrar_impuesto\":false,\"credito\":true,\"creador\":\"jplata\",\"creador_nombre\":\"JAIME ANTONIO\",\"creador_apellido\":\"PLATA BOGOYA\",\"cargo_asesor\":\"GERENTE\",\"email_asesor\":\"dyehuty@gmail.com\",\"productos\":[{\"modelo\":\"BOLSA ACCESORIOS ESTANDAR\",\"tela\":\"KAMBREL O POLITEX DE 70GR\",\"cantidad\":\"3000\",\"destino\":186,\"destino_label\":\"CALDAS - NEIRA\",\"ancho\":22,\"alto\":33,\"fuelle\":0,\"manija\":0,\"estampado_cara_frontal\":\"1 TINTA MATE\",\"estampado_cara_posterior\":\"2 TINTAS MATE\",\"valor_bolsa\":\"1605\",\"valor_iva\":\"304\",\"iva\":19,\"accesorios_modelo\":[{\"id\":\"1\",\"nombre\":\"CORDON ESTANDAR SENCILLO; PARA BOLSAS CIERRE CORDON O BOLERO.\",\"ancho\":0,\"alto\":0}],\"accesorios_adicionales\":[{\"id\":\"37\",\"nombre\":\"ESTE ACCESORIO SE USA PARA COLOCARLE BASE DE CARTON FORRADA EN EL MISMO MATERIAL A LA BOLSA. NORMALMENTE SE USA PARA LA BOLSA ANCHETA; PERO SE LE PUEDE COLOCAR A CUALQUIER BOLSA.\",\"ancho\":0,\"alto\":0},{\"id\":\"23\",\"nombre\":\"BOLSILLO EN EL MISMO MATERIAL DE LA BOLSA; SE USA PARA LA BOLSA AUTOGUARDABLE TIPO BILLETERA; O PARA CUALQUIER BOLSA QUE SE DESEE LLEVE UN BOLSILLO.  EN LOS CAMPOS ALTO Y ANCHO; INDIQUE LAS DIMENSIONES DE ÉSTE BOLSILLO.\",\"ancho\":20,\"alto\":20},{\"id\":\"36\",\"nombre\":\"ESTE ACCESORIO ES UNA CAPA QUE SE COLOCA ENCIMA DEL CUBREVESTIDO. EN EL CAMPO ALTO: INDIQUE EL ALTO DE LA CAPERUZA.\",\"ancho\":0,\"alto\":22}],\"cantidadesReporte\":[{\"cantidad\":3000,\"valor_bolsa\":1605,\"valor_iva\":0,\"subtotal\":4815000,\"total\":4815000}]}]}'";
    //NOT WORK
    String clientData = "'{\"nombre_cliente\":\"MARCA DE PRUEBA\",\"contacto\":\"Harry\",\"email\":\"harry@test.com\",\"telefono\":\"4553773773\",\"observaciones\":\"\",\"totalizar\":false,\"mostrar_impuesto\":true,\"credito\":false,\"creador\":\"jvalderrama\",\"creador_nombre\":\"JUAN CARLOS\",\"creador_apellido\":\"VALDERRAMA GONZALEZ\",\"cargo_asesor\":\"desarrollador\",\"email_asesor\":\"dyehuty@gmail.com\",\"telefono_asesor\":\"2373719 EXT 1147 - 5138731 - 8033205\",\"celular_asesor\":\"3149008989\",\"productos\":[{\"modelo\":\"BOLSA ACCESORIOS CIERRE ESPECIAL\",\"tela\":\"KAMBREL O POLITEX DE 70GR\",\"cantidad\":\"300,600,1000\",\"destino\":4,\"destino_label\":\"ANTIOQUIA - BARBOSA\",\"ancho\":23,\"alto\":44,\"fuelle\":0,\"manija\":0,\"estampado_cara_frontal\":\"1 TINTA MATE\",\"estampado_cara_posterior\":\"SIN ESTAMPADO\",\"estampado_fuelle_izquierdo\":\"SIN ESTAMPADO\",\"estampado_fuelle_derecho\":\"SIN ESTAMPADO\",\"estampado_fuelle_base\":\"SIN ESTAMPADO\",\"valor_bolsa\":\"1543,1202,1151\",\"valor_iva\":\"293,228,218\",\"iva\":19,\"accesorios_modelo\":[],\"accesorios_adicionales\":[{\"id\":\"37\",\"nombre\":\"BASE DE CARTON FORRADO\",\"descripcion\":\"ESTE ACCESORIO SE USA PARA COLOCARLE BASE DE CARTON FORRADA EN EL MISMO MATERIAL A LA BOLSA. NORMALMENTE SE USA PARA LA BOLSA ANCHETA,PERO SE LE PUEDE COLOCAR A CUALQUIER BOLSA.\",\"ancho\":2,\"alto\":0}],\"cantidadesReporte\":[{\"cantidad\":300,\"valor_bolsa\":1543,\"valor_iva\":87900,\"subtotal\":462900,\"total\":550800},{\"cantidad\":600,\"valor_bolsa\":1202,\"valor_iva\":136800,\"subtotal\":721200,\"total\":858000},{\"cantidad\":1000,\"valor_bolsa\":1151,\"valor_iva\":218000,\"subtotal\":1151000,\"total\":1369000}]},{\"modelo\":\"BOLSA ACCESORIOS CIERRE ESPECIAL\",\"tela\":\"YUTE LAMINADO COLOR CRUDO\",\"cantidad\":\"300,600,1000\",\"destino\":4,\"destino_label\":\"ANTIOQUIA - BARBOSA\",\"ancho\":23,\"alto\":44,\"fuelle\":0,\"manija\":0,\"estampado_cara_frontal\":\"1 TINTA MATE\",\"estampado_cara_posterior\":\"SIN ESTAMPADO\",\"estampado_fuelle_izquierdo\":\"SIN ESTAMPADO\",\"estampado_fuelle_derecho\":\"SIN ESTAMPADO\",\"estampado_fuelle_base\":\"SIN ESTAMPADO\",\"valor_bolsa\":\"6439,5016,4830\",\"valor_iva\":\"1223,953,917\",\"iva\":19,\"accesorios_modelo\":[],\"accesorios_adicionales\":[{\"id\":\"37\",\"nombre\":\"BASE DE CARTON FORRADO\",\"descripcion\":\"ESTE ACCESORIO SE USA PARA COLOCARLE BASE DE CARTON FORRADA EN EL MISMO MATERIAL A LA BOLSA. NORMALMENTE SE USA PARA LA BOLSA ANCHETA,PERO SE LE PUEDE COLOCAR A CUALQUIER BOLSA.\",\"ancho\":2,\"alto\":0}],\"cantidadesReporte\":[{\"cantidad\":300,\"valor_bolsa\":6439,\"valor_iva\":366900,\"subtotal\":1931700,\"total\":2298600},{\"cantidad\":600,\"valor_bolsa\":5016,\"valor_iva\":571800,\"subtotal\":3009600,\"total\":3581400},{\"cantidad\":1000,\"valor_bolsa\":4830,\"valor_iva\":917000,\"subtotal\":4830000,\"total\":5747000}]},{\"modelo\":\"BOLSA ACCESORIOS CIERRE ESPECIAL\",\"tela\":\"TELA DE SUBLIMAR EN KAMB. DE 70GR\",\"cantidad\":\"300,600,1000\",\"destino\":4,\"destino_label\":\"ANTIOQUIA - BARBOSA\",\"ancho\":23,\"alto\":44,\"fuelle\":0,\"manija\":0,\"estampado_cara_frontal\":\"1 TINTA MATE\",\"estampado_cara_posterior\":\"SIN ESTAMPADO\",\"estampado_fuelle_izquierdo\":\"SIN ESTAMPADO\",\"estampado_fuelle_derecho\":\"SIN ESTAMPADO\",\"estampado_fuelle_base\":\"SIN ESTAMPADO\",\"valor_bolsa\":\"1906,1485,1423\",\"valor_iva\":\"362,282,270\",\"iva\":19,\"accesorios_modelo\":[],\"accesorios_adicionales\":[{\"id\":\"37\",\"nombre\":\"BASE DE CARTON FORRADO\",\"descripcion\":\"ESTE ACCESORIO SE USA PARA COLOCARLE BASE DE CARTON FORRADA EN EL MISMO MATERIAL A LA BOLSA. NORMALMENTE SE USA PARA LA BOLSA ANCHETA,PERO SE LE PUEDE COLOCAR A CUALQUIER BOLSA.\",\"ancho\":2,\"alto\":0}],\"cantidadesReporte\":[{\"cantidad\":300,\"valor_bolsa\":1906,\"valor_iva\":108600,\"subtotal\":571800,\"total\":680400},{\"cantidad\":600,\"valor_bolsa\":1485,\"valor_iva\":169200,\"subtotal\":891000,\"total\":1060200},{\"cantidad\":1000,\"valor_bolsa\":1423,\"valor_iva\":270000,\"subtotal\":1423000,\"total\":1693000}]}]}'";

    new PDFGenerator().createPdf(DEST, clientData);     
}

public void createPdf(String dest, String data) throws IOException {

    data = data.replace("'","");
    JSONObject jsonPeticion = new JSONObject(data);
    JSONArray jsonProductos= jsonPeticion.getJSONArray("productos");
    boolean mostrarIva = jsonPeticion.getBoolean("mostrar_impuesto");
    NumberFormat formateador = NumberFormat.getInstance(new Locale("us", "US"));
    formateador.setMinimumFractionDigits(0);
    formateador.setMaximumFractionDigits(0);
    System.out.println("JSON ARRAY......" + jsonProductos);
    System.out.println("JSON ARRAY LENGTH......" + jsonProductos.length());

    PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
    try (Document document = new Document(pdf)) {

        document.setMargins(120, 36, 120, 36);

        document.add(new Paragraph("ESPECIFICACIONES TÉCNICAS DEL PRODUCTO")
                .setTextAlignment(TextAlignment.CENTER)
                .setBold());

        for (int i = 0; i < jsonProductos.length(); i++) {

        Text textoTinta = new Text("Tinta Utilizada");
        textoTinta.setUnderline(1.5f, -1);
        textoTinta.setTextAlignment(TextAlignment.LEFT);

        Text textoTintaDescripcion = new Text(": Las tintas que usamos son 100% Ecológicas y Base Agua, "
                + "nuestra visión no es solo comercial sino de responsabilidad "
                + "con el medio ambiente y social.");

        Text textoNota = new Text("NOTA: ").setBold();
        textoNota.setTextAlignment(TextAlignment.LEFT);

        Text textoNotaDescripcion = new Text("Señor cliente por favor tener presente, que en el momento "
                + "de la facturación, debemos facturar todo lo que salga, normalmente "
                + "puede salir un 5% de más o de menos.");

        document.add(new Paragraph(textoTinta).add(textoTintaDescripcion)
                .setTextAlignment(TextAlignment.JUSTIFIED));

        document.add(new Paragraph(textoNota).add(textoNotaDescripcion)
                .setTextAlignment(TextAlignment.JUSTIFIED));

        String IMG = "C:\\path\\images\\logoSmallBiobolsa.png";
        String FONT = "C:\\path\\COMIC.ttf";
        ImageData imageData = ImageDataFactory.create(IMG);
        Image pdfImg = new Image(imageData);
        pdfImg.setWidth(70);
        pdfImg.setHeight(77);

        Color verdeBioBolsa = new DeviceRgb(5, 94, 27);
        PdfFont comic = PdfFontFactory.createFont(FONT, true);
        System.out.println("MARGENES SUPERIOR..... " + document.getTopMargin());
        System.out.println("MARGENES INFERIOR..... " + document.getBottomMargin());
        System.out.println("MARGENES IZQUIERDO..... " + document.getLeftMargin());
        System.out.println("MARGENES DERECHO..... " + document.getRightMargin());

        Paragraph headerImg = new Paragraph("").add(pdfImg);

        Paragraph headerNombreEmpresa = new Paragraph("BIO BOLSA S.A.S")
                .setFont(comic)
                .setFontSize(20)
                .setBold()
                .setFontColor(verdeBioBolsa);

        Paragraph headerSlogan = new Paragraph("!!Una Empresa con Conciencia Ambiental!!")
                .setFont(comic)
                .setFontSize(14)
                .setFontColor(verdeBioBolsa);

        Paragraph headerRegimen = new Paragraph("Régimen Común")
                .setFont(comic)
                .setFontSize(12)
                .setBold()
                .setFontColor(verdeBioBolsa);

        Paragraph headerIdentificador = new Paragraph("NIT: 900.390.537-1")
                .setFont(comic)
                .setFontSize(12)
                .setFontColor(verdeBioBolsa);

        Paragraph footerTelefonosAsesor = new Paragraph("Tels: (57) (1) 7137516 EXT 1142 – 7138731 - 2033205 Cel: (57) 300 275 45 51")
                .setFontSize(10)
                .setFontColor(verdeBioBolsa);

        Paragraph footerWebEmail = new Paragraph("Web: www.biobolsa.com.co   E-mail: pchacon@biobolsa.com.co")
                .setFontSize(10)
                .setFontColor(verdeBioBolsa);

        Paragraph footerDireccion = new Paragraph("Fábrica CRA 57 NO 45 A – 52 SUR LA SEVILLANA")
                .setFontSize(10)
                .setFontColor(verdeBioBolsa);

        Paragraph footerCiudad = new Paragraph("Bogotá D.C, Colombia")
                .setFontSize(10)
                .setFontColor(verdeBioBolsa);

        for (int i = 1; i <= document.getPdfDocument().getNumberOfPages(); i++) {

            System.out.println("PAGINA DEL PDF" + i);
            try {
                Rectangle pageSize = document.getPdfDocument().getPage(i).getPageSize();
                //Rectangle pageSize = document.getPdfDocument().getPage(i).getMediaBox();
                System.out.println("RECTANGLE....." + pageSize);
            } catch (Exception e) {
                // TODO: handle exception
                System.out.println("EXCEPCION RECTANGULO..." + e);
            }
        }
      }
   }
}

【问题讨论】:

  • 如何将Rectangle pageSize = document.getPdfDocument().getPage(i).getPageSize() 拆分为单独的步骤,以便您查看哪个是null
  • 我做到了,这两行 PdfPage pageSize = document.getPdfDocument().getPage(i);Rectangle tamanoPagina = pageSize.getPageSize(); 错误在 tamanoPagina 变量中,但我不知道为什么。

标签: java itext7


【解决方案1】:

总之

问题是由于您的代码访问了 iText 已经从内存中刷新到目标文件的页面。您可以通过使用三参数Document 构造函数并将immediateFlush 参数设置为false 来指示iText 不要提前刷新页面,即通过替换

try (Document document = new Document(pdf)) {

通过

try (Document document = new Document(pdf, pdf.getDefaultPageSize(), false)) {

一些解释

iText 被设计为可在不需要相应大量内存的情况下生成巨大的 PDF(或同时生成多个 PDF)的环境中使用。它通过将 PDF 的完成部分写入其输出目标并将它们从内存中删除来降低其内存占用。特别是在创建多页文档时,通常只有当前页和上一页保留在内存中,而之前的页面被刷新并且剩余页面对象的内容设置为null

因此,当您最终遍历 PDF 的所有页面时,除了最近的页面之外,所有页面确实不再具有其 MediaBox 条目,因此您在尝试访问时会收到 NullPointerException页面大小。

对于像您这样不适合提前刷新的用例,iText 提供了上面使用的标志,以防止它提前刷新页面。

顺便说一句……

...如果您想知道为什么之前没有回答您的问题:您发布了一段巨大的代码,由于您没有为 data 参数提供 JSON 字符串,甚至无法执行该代码来重现该问题.因此,为了能够重现该问题,我必须将您的代码缩减为重现该问题的基本核心:

public void createPdf(String dest) throws IOException {

    PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
    try (Document document = new Document(pdf)) {

        document.setMargins(120, 36, 120, 36);

        document.add(new Paragraph("some content"));
        document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
        document.add(new Paragraph("some more content"));
        document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
        document.add(new Paragraph("still more content"));

        for (int i = 1; i <= document.getPdfDocument().getNumberOfPages(); i++) {

            System.out.println("PAGINA DEL PDF" + i);
            try {
                Rectangle pageSize = document.getPdfDocument().getPage(i).getPageSize();
                // Rectangle pageSize = document.getPdfDocument().getPage(i).getMediaBox();
                System.out.println("RECTANGLE....." + pageSize);
            } catch (Exception e) {
                // TODO: handle exception
                System.out.println("EXCEPCION RECTANGULO..." + e);
            }
        }
    }
}

如果您自己这样做,您的问题会更早得到回答。

【讨论】:

    【解决方案2】:

    如果你使用 immediateFlush=false,别忘了在操作文档后使用 document.Flush()

    Document document =  
        new Document(pdf, pdf.GetDefaultPageSize(), false);
    ...
    document.Flush();
    pdf.Close();
    

    【讨论】:

    • ... 或 close 文档,显式或(如在我的回答中)隐式使用 try-with-resourcesDocumentClosable 是有原因的...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-31
    • 1970-01-01
    相关资源
    最近更新 更多