Bootstrap

iText7使用总结

IText7使用总结

核心概念

  • PdfWriter
    • PdfWriter类负责将Pdf内容写入到输出流中,它是与物理文件或输出流关联的底层Pdf生成器;
    • 创建一个pdf之前需要先创建一个PdfWriter实例;
  • PdfDocument
    • PdfDocument是更高层次的抽象,它封装了一个PdfWriter实例和其它与文档有关的数据;
    • PdfDocument 还可以用来读取现有的 PDF 文件,进行修改后再保存;
  • Document
    • Document 类是 iText 7 中用于布局内容的主要类。它不是直接操作 PDF 的低层类,而是提供了一个更友好的 API 来添加文本、图像、表格等内容;
    • 将 PdfDocument 传递给 Document 构造器,然后使用 Document 来添加内容,如段落、列表、表格等;
    • Document 负责自动布局和分页,使得内容能够适配到 PDF 页面上;
  • Paragraph
    • Paragraph 类代表一个段落,它可以包含文本、图像、链接等元素;
    • 可以向 Paragraph 添加多个 Text 对象,或者嵌入其他类型的元素,如 Image 或 List;
    • Paragraph 是 Document 中最常用的元素之一,用于添加文本内容;

使用

引入依赖

       <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext7-core</artifactId>
            <version>7.0.4</version>
            <type>pom</type>
        </dependency>

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>kernel</artifactId>
            <version>7.0.4</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>io</artifactId>
            <version>7.0.4</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>layout</artifactId>
            <version>7.0.4</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>forms</artifactId>
            <version>7.0.4</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>pdfa</artifactId>
            <version>7.0.4</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>pdftest</artifactId>
            <version>7.0.4</version>
        </dependency>

创建pdf

保存在项目根目录下

    @Operation(summary = "简单Pdf创建")
    @GetMapping(value = "/createPdf")
    public String  createPdf() throws FileNotFoundException {
        PdfWriter writer = new PdfWriter("hello1.pdf");
        PdfDocument pdf = new PdfDocument(writer);
        Document document = new Document(pdf);
        document.add(new Paragraph("Hello World!"));
        document.close();
        return "success create pdf";
    }

效果
在这里插入图片描述

添加列表

    @Operation(summary = "Pdf中添加列表")
    @GetMapping("/generatePdf")
    public ResponseEntity<byte[]> generatePdf() throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PdfWriter pdfWriter = new PdfWriter(baos);
        PdfDocument pdfDocument = new PdfDocument(pdfWriter);
        Document document = new Document(pdfDocument);

        //字体
        PdfFont font = PdfFontFactory.createFont(FontConstants.TIMES_ROMAN);
        document.add(new Paragraph("Hello World!")).setFont(font);

        //列表
        List list = new List().setSymbolIndent(12).setListSymbol("\u2022").setFont(font);
        list.add(new ListItem("Item 1"))
                .add(new ListItem("Item 2"))
                .add(new ListItem("Item 3"))
                .add(new ListItem("Item 4"));

        document.add(list);

        document.close();

        byte[] bytes = baos.toByteArray();

        //浏览器会将文件保存为test.pdf,而不是打开
//        return ResponseEntity.ok().contentType(MediaType.APPLICATION_OCTET_STREAM)
//                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"test.pdf\"")
//                .body(bytes);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", "test.pdf");

        return ResponseEntity.ok()
                .headers(headers)
                .body(bytes);

        //浏览器会识别出这是pdf文件,并尝试在浏览器窗口中打开它,或者根据浏览器的设置进行下载
//        return ResponseEntity.ok().contentType(MediaType.APPLICATION_PDF)
//                .body(bytes);
    }

效果如下
在这里插入图片描述

添加图片


    @Operation(summary = "带图片的pdf")
    @GetMapping("/generate-pdf2")
    public ResponseEntity<byte[]> generatePdf2() throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        PdfWriter pdfWriter = new PdfWriter(baos);
        PdfDocument pdfDocument = new PdfDocument(pdfWriter);
        Document document = new Document(pdfDocument);

        //图片
        Image img1 = new Image(ImageDataFactory.create("C:\\Users\\DELL\\Desktop\\BeanFactory.png"));
        Image img2 = new Image(ImageDataFactory.create("C:\\Users\\DELL\\Desktop\\BeanFactory.png"));
        Paragraph paragraph = new Paragraph("This is img2:").add(img1).add("This is img2: ").add(img2);

        document.add(paragraph);

        document.close();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", "test.pdf");

        byte[] bytes = baos.toByteArray();
        return ResponseEntity.ok().headers(headers).body(bytes);
    }

添加表格

    @Operation(summary = "带表格的pdf")
    @GetMapping("/generate-table")
    public ResponseEntity<byte[]> generateTablePdf() throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        PdfWriter pdfWriter = new PdfWriter(baos);
        PdfDocument pdfDocument = new PdfDocument(pdfWriter);
        //第二个参数用来定义页面的大小:默认是A4,这里也是A4只不过旋转了页面
        Document document = new Document(pdfDocument, PageSize.A4.rotate());
        //默认的情况下,iText使用36个用户单位作为页边距(半英寸)。我们把所有的页边距都改为20个用户单位
        document.setMargins(20, 20, 20, 20);

        PdfFont font = PdfFontFactory.createFont(FontConstants.HELVETICA);
        PdfFont bold = PdfFontFactory.createFont(FontConstants.HELVETICA_BOLD);

        //定义了一个列的相对宽度。第1列是第2列的4倍宽。第3列是第2列的3倍宽等
        Table table = new Table(new float[]{4, 1, 3, 4, 3, 3, 3, 3, 1});
			

        BufferedReader br = new BufferedReader(new FileReader(new File("C:\\Users\\DELL\\Desktop\\united_states.csv")));
        String line = br.readLine();
        //创建表格的标题行
        process(table, line, bold, true);
        
        while ((line = br.readLine()) != null) {
            process(table, line, font, false);
        }
        br.close();
        document.add(table);
        document.close();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", "test.pdf");

        byte[] bytes = baos.toByteArray();
        return ResponseEntity.ok().headers(headers).body(bytes);
    }

    public void process(Table table, String line, PdfFont font, boolean isHeader) {
        StringTokenizer tokenizer = new StringTokenizer(line, ";");
        while (tokenizer.hasMoreTokens()) {
            if (isHeader) {
                //添加标题单元格
                table.addHeaderCell(
                        new Cell().add(
                                new Paragraph(tokenizer.nextToken()).setFont(font)));
            } else {
                table.addCell(
                        new Cell().add(
                                new Paragraph(tokenizer.nextToken()).setFont(font)));
            }
        }
    }

效果如下

在这里插入图片描述

pdf中创建表单

表单中的字段是由注解表示的,当创建一个字段时,这个小部件注解是隐式创建的。

    @Operation(summary = "pdf中创建表单")
    @GetMapping(value ="/edit-pdf2")
    public void editPdf2() throws IOException {
        //PdfReader是一个允许iText访问PDF文件并读取存储在PDF文件中的不同PDF对象的类
        PdfWriter pdfWriter = new PdfWriter("hello.pdf");
        PdfDocument pdfDocument = new PdfDocument(pdfWriter);
        Document document = new Document(pdfDocument);

        //表单
        PdfAcroForm acroForm = PdfAcroForm.getAcroForm(pdfDocument, true);

        //加载中文字体
        String font = this.getClass().getClassLoader().getResource("msyh.ttc").getPath();
        PdfFont f2 = PdfFontFactory.createFont(font + ",0", PdfEncodings.IDENTITY_H, true);

        //添加表单中的字段
        PdfTextFormField textFormField = PdfTextFormField.createText(pdfDocument, new Rectangle(99, 753, 425, 30),
                "name", "张三");
        textFormField.setVisibility(PdfFormField.VISIBLE).setFont(f2);
        acroForm.addField(textFormField);

        //单选按钮
        PdfButtonFormField group = PdfFormField.createRadioGroup(
                pdfDocument, "language", "");
        PdfFormField.createRadioButton(pdfDocument,
                new Rectangle(130, 728, 15, 15), group, "English");
        PdfFormField.createRadioButton(pdfDocument,
                new Rectangle(200, 728, 15, 15), group, "French");
        PdfFormField.createRadioButton(pdfDocument,
                new Rectangle(260, 728, 15, 15), group, "German");
        PdfFormField.createRadioButton(pdfDocument,
                new Rectangle(330, 728, 15, 15), group, "Russian");
        PdfFormField.createRadioButton(pdfDocument,
                new Rectangle(400, 728, 15, 15), group, "Spanish");
        acroForm.addField(group);
        
        //复选框
        for (int i = 0; i < 3; i++) {
            PdfButtonFormField checkField = PdfFormField.createCheckBox(
                    pdfDocument, new Rectangle(119 + i * 69, 701, 15, 15),
                    "experience".concat(String.valueOf(i+1)), "Off",
                    PdfFormField.TYPE_CHECK);
            acroForm.addField(checkField);
        }
        
        //下拉列表
        String[] options = {"Any", "6.30 am - 2.30 pm", "1.30 pm - 9.30 pm"};
        PdfChoiceFormField choiceField = PdfFormField.createComboBox(
                pdfDocument, new Rectangle(163, 676, 115, 25),
                "shift", "Any", options);
        acroForm.addField(choiceField);

        //多行文本框
        PdfTextFormField infoField = PdfTextFormField.createMultilineText(
                pdfDocument, new Rectangle(158, 625, 366, 40), "info", "");
        infoField.setFont(f2);
        acroForm.addField(infoField);

        //重置按钮
        PdfButtonFormField button = PdfFormField.createPushButton(pdfDocument,
                new Rectangle(479, 594, 45, 15), "reset", "RESET");
        button.setAction(PdfAction.createResetForm(
                new String[] {"name", "language", "experience1", "experience2",
                        "experience3", "shift", "info"}, 0));
        acroForm.addField(button);

        Map<String, PdfFormField> fields = acroForm.getFormFields();
        fields.get("name").setValue("James Bond  张三");
        fields.get("language").setValue("English");
        fields.get("experience1").setValue("Off");
        fields.get("experience2").setValue("Yes");
        fields.get("experience3").setValue("Yes");
        fields.get("shift").setValue("Any");
        fields.get("info").setValue("I was 38 years old when I became an MI6 agent.");

        document.close();
    }

需要下载中文字体msyh.ttc放到项目的resource目录下,否则无法显示中文。

往pdf模版中填充数据

使用前面创建的表单作为pdf,往其中填充数据。

    @Operation(summary = "操纵现有的pdf")
    @GetMapping(value ="/edit-pdf3")
    public void editPdf3() throws IOException {
        PdfWriter writer = new PdfWriter("hello2.pdf");
        PdfDocument pdfDocument = new PdfDocument(new PdfReader("hello.pdf"), writer);

        //向pdf中添加注解
        PdfAnnotation ann = new PdfTextAnnotation(new Rectangle(400, 795, 0, 0))
                .setTitle(new PdfString("iText"))
                .setContents("Please, fill out the form.")
                .setOpen(true);
        pdfDocument.getFirstPage().addAnnotation(ann);

        //加载中文字体
        String font = this.getClass().getClassLoader().getResource("msyh.ttc").getPath();
        PdfFont f2 = PdfFontFactory.createFont(font + ",0", PdfEncodings.IDENTITY_H, true);

        //修改pdf中表单的的字段的值
        PdfAcroForm acroForm = PdfAcroForm.getAcroForm(pdfDocument, true);
        Map<String, PdfFormField> fields = acroForm.getFormFields();
        fields.get("name").setValue("James 李四").setVisibility(PdfFormField.VISIBLE).setFont(f2);
        fields.get("language").setValue("English");
        fields.get("experience1").setValue("Off");
        fields.get("experience2").setValue("Yes");
        fields.get("experience3").setValue("Yes");
        fields.get("shift").setValue("Any");
        fields.get("info").setValue("job job job");

        //将可编辑的表单变为不可编辑的
        acroForm.flattenFields();

        pdfDocument.close();

        return;
    }

效果如下
在这里插入图片描述

参考

  1. iText7 中文文档帮助手册教程
  2. 官方教程
;