SpringBoot实战(十五)集成iText

目录

    • 1.简介
    • 2.Maven依赖
    • 3.实现示例:第1章
      • 1)创建PDF文件,写入 Hello World
      • 2)创建PDF,定制字体并写入多行(Rick Astley 歌词)
      • 3)创建PDF,定制字体并写入文字和图片(快棕狐)
      • 4)创建PDF,定制字体并根据csv文件写入表格(美国城市信息)
    • 4.实现示例:第2章
      • 1)创建PDF,画坐标轴
      • 2)创建PDF,画网格线
      • 3)创建PDF,写星球大战
      • 4)创建PDF,写星球大战(滚动版)
    • 5.实现示例:第3章
      • 1)创建PDF,简单的列渲染示例(纽约时代周刊)
      • 2)创建PDF,简单的表渲染示例(英格兰足球超级联赛)
      • 3)创建PDF,简单的事件渲染示例(UFO文件)
    • 6.实现示例:第4章
      • 1)创建PDF,添加文本批注
      • 2)创建PDF,添加链接批注
      • 3)创建PDF,添加线批注
      • 4)创建PDF,添加文本标记批注
      • 5)创建PDF,添加简单组件的批注(职位申请表)
      • 6)创建PDF,添加并填充表单(职位申请表)
      • 7)指定PDF,简单填充表单(职位申请表)
    • 7.实现示例:第5章
      • 1)创建PDF,添加可回复型批注
      • 2)根据PDF,填写并修改表单
      • 3)根据PDF,填充内容(页眉、页脚线、页脚页码、水印)
      • 4)根据PDF,改变页面(大小、边框、旋转)
    • 8.实现示例:第6章
      • 1)根据PDF,缩放尺寸(金门大桥)
      • 2)根据PDF,一分为四(金门大桥)
      • 3)根据PDF,多页合并(金门大桥)
      • 4)根据PDF,进行拼接(第88届奥斯卡)
      • 5)根据PDF,抽取指定页数进行拼接(第88届奥斯卡)
      • 6)根据PDF,拼接并添加目录(第88届奥斯卡)
      • 7)根据PDF,合并表格
      • 8)根据PDF,批量填写并合并表格
      • 9)根据PDF,批量填写并合并表格(是否开启智能模式)
    • 9.实现示例:第7章
      • 1)创建PDF,PDF/UA标准(快棕狐)
      • 2)创建PDF,PDF/A-1a标准(快棕狐)
      • 3)创建PDF,PDF/A-1b标准(快棕狐)
      • 4)创建PDF,PDF/A-3a标准(美国信息)
      • 5)根据PDF,合并PDF/A类文档(快棕狐+美国信息)

在这里插入图片描述

1.简介

iText: 是一个用于创建和处理 PDF 文件的开源 Java 库。它提供了一种在 Java 程序中创建和操作 PDF 文档的简单方法,并可以生成包含文本、表格、图像、列表和其他元素的PDF文件。

官网地址: https://itextpdf.com/

GitHub: https://github.com/itext

官方示例: https://itextpdf.com/demos

官方文档: https://wiki.itextsupport.com/home/it7kb/installation-guidelines/installing-itext-7-for-java

官网页面如下:

在这里插入图片描述

官网示例页面如下:

在这里插入图片描述

2.Maven依赖

注意:iText 5 已经停止更新了,推荐使用 iText 7

<properties>
   <itext.version>7.2.5</itext.version>
</properties>
<dependencies>
   <!-- iText 7 -->
   <dependency>
       <groupId>com.itextpdf</groupId>
       <artifactId>itext7-core</artifactId>
       <version>${itext.version}</version>
       <type>pom</type>
   </dependency>
</dependencies>

3.实现示例:第1章

代码地址:https://gitee.com/acgkaka/SpringBootExamples/tree/master/springboot-itext

代码涉及资源地址: https://gitee.com/acgkaka/SpringBootExamples/tree/master/springboot-itext/src/main/resources

官方示例文档地址: https://kb.itextpdf.com/home/it7kb/examples/itext-7-jump-start-tutorial-chapter-1

官方示例代码地址: https://github.com/itext/i7js-jumpstart

1)创建PDF文件,写入 Hello World

在这里插入图片描述

/**
 * 创建PDF,并写入Hello World
 */
@GetMapping(value = "/helloWorld", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> helloWorld() {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(outputStream);
    PdfDocument pdfDocument = new PdfDocument(writer);
    Document document = new Document(pdfDocument);

    // 写入 Hello World
    document.add(new Paragraph("Hello World!"));
    document.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

2)创建PDF,定制字体并写入多行(Rick Astley 歌词)

在这里插入图片描述

/**
 * 创建PDF,定制字体并写入多行(Rick Astley 歌词)
 */
@GetMapping(value = "/createPdfWithLines", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> createPdfWithLines() throws IOException {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(outputStream);
    PdfDocument pdfDocument = new PdfDocument(writer);
    Document document = new Document(pdfDocument);

    // 定制字体,并写入多行
    PdfFont font = PdfFontFactory.createFont(StandardFonts.TIMES_ROMAN);
    document.add(new Paragraph("iText is:").setFont(font));
    // import com.itextpdf.layout.element.List
    List list = new List()
            .setSymbolIndent(12)
            .setListSymbol("\u2022")
            .setFont(font);
    list.add(new ListItem("Never gonna give you up"))
            .add(new ListItem("Never gonna let you down"))
            .add(new ListItem("Never gonna run around and desert you"))
            .add(new ListItem("Never gonna make you cry"))
            .add(new ListItem("Never gonna say goodbye"))
            .add(new ListItem("Never gonna tell a lie and hurt you"));
    document.add(list);
    document.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

3)创建PDF,定制字体并写入文字和图片(快棕狐)

在这里插入图片描述

/**
 * 创建PDF,定制字体并写入文字和图片(快棕狐)
 */
@GetMapping(value = "/createPdfWithImg", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> createPdfWithImg() throws IOException {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(outputStream);
    PdfDocument pdfDocument = new PdfDocument(writer);
    Document document = new Document(pdfDocument);

    // 插入图片
    final String foxImgPath = "src/main/resources/img/fox.bmp";
    final String dogImgPath = "src/main/resources/img/dog.bmp";
    Image fox = new Image(ImageDataFactory.create(foxImgPath));
    Image dog = new Image(ImageDataFactory.create(dogImgPath));
    Paragraph p = new Paragraph("The quick brown ")
            .add(fox)
            .add(" jumps over the lazy ")
            .add(dog);
    document.add(p);
    document.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

4)创建PDF,定制字体并根据csv文件写入表格(美国城市信息)

在这里插入图片描述

/**
 * 创建PDF,定制字体并根据csv文件写入表格(美国城市信息)
 */
@GetMapping(value = "/createPdfWithTable", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> createPdfWithTable() throws IOException {
    final String data = "src/main/resources/data/united_states.csv";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(outputStream);
    PdfDocument pdfDocument = new PdfDocument(writer);
    Document document = new Document(pdfDocument, PageSize.A4.rotate());
    document.setMargins(20, 20, 20, 20);

    // 根据csv文件写入表格
    PdfFont font = PdfFontFactory.createFont(StandardFonts.HELVETICA);
    PdfFont bold = PdfFontFactory.createFont(StandardFonts.HELVETICA_BOLD);
    Table table = new Table(UnitValue.createPercentArray(new float[]{4, 1, 3, 4, 3, 3, 3, 3, 1}))
            .useAllAvailableWidth();
    BufferedReader br = new BufferedReader(new FileReader(data));
    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.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

/**
 * 处理表格
 * @param table 表格
 * @param line  csv中一行内容
 * @param font  字体
 * @param isHeader  是否是表头
 */
private 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)));
        }
    }
}

4.实现示例:第2章

1)创建PDF,画坐标轴

在这里插入图片描述

/**
 * 创建PDF,画坐标轴
 */
@GetMapping(value = "/createPdfWithAxes", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> createPdfWithLines() {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(outputStream);
    PdfDocument pdf = new PdfDocument(writer);

    PageSize ps = PageSize.A4.rotate();
    PdfPage page = pdf.addNewPage(ps);

    PdfCanvas canvas = new PdfCanvas(page);
    // 把坐标系的原点放到页面中间
    canvas.concatMatrix(1, 0, 0, 1, ps.getWidth() / 2, ps.getHeight() / 2);
    drawAxes(canvas, ps);
    pdf.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

/**
 * 画坐标轴
 * @param canvas    画布
 * @param ps        页面大小
 */
private void drawAxes(PdfCanvas canvas, PageSize ps) {
    // 画X轴
    canvas.moveTo(-(ps.getWidth() / 2 - 15), 0)
            .lineTo(ps.getWidth() / 2 - 15, 0)
            .stroke();

    // 画X轴箭头
    canvas.setLineJoinStyle(PdfCanvasConstants.LineJoinStyle.ROUND)
            .moveTo(ps.getWidth() / 2 - 25, -10)
            .lineTo(ps.getWidth() / 2 - 15, 0)
            .lineTo(ps.getWidth() / 2 - 25, 10).stroke()
            .setLineJoinStyle(PdfCanvasConstants.LineJoinStyle.MITER);

    // 画y轴
    canvas.moveTo(0, -(ps.getHeight() / 2 - 15))
            .lineTo(0, ps.getHeight() / 2 - 15)
            .stroke();

    // 画Y轴箭头
    canvas.saveState()
            .setLineJoinStyle(PdfCanvasConstants.LineJoinStyle.ROUND)
            .moveTo(-10, ps.getHeight() / 2 - 25)
            .lineTo(0, ps.getHeight() / 2 - 15)
            .lineTo(10, ps.getHeight() / 2 - 25).stroke()
            .restoreState();

    // 画X衬线
    for (int i = -((int) ps.getWidth() / 2 - 61); i < ((int) ps.getWidth() / 2 - 60); i += 40) {
        canvas.moveTo(i, 5).lineTo(i, -5);
    }
    // 画Y衬线
    for (int j = -((int) ps.getHeight() / 2 - 57); j < ((int) ps.getHeight() / 2 - 56); j += 40) {
        canvas.moveTo(5, j).lineTo(-5, j);
    }
    canvas.stroke();
}

2)创建PDF,画网格线

在这里插入图片描述

/**
 * 创建PDF,画网格线
 */
@GetMapping(value = "/createPdfWithGridlines", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> createPdfWithGridlines(String dest) throws IOException {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(outputStream);
    PdfDocument pdf = new PdfDocument(writer);

    PageSize ps = PageSize.A4.rotate();
    PdfPage page = pdf.addNewPage(ps);

    PdfCanvas canvas = new PdfCanvas(page);
    // 把坐标系的原点放到页面中间
    canvas.concatMatrix(1, 0, 0, 1, ps.getWidth() / 2, ps.getHeight() / 2);

    Color grayColor = new DeviceCmyk(0.f, 0.f, 0.f, 0.875f);
    Color greenColor = new DeviceCmyk(1.f, 0.f, 1.f, 0.176f);
    Color blueColor = new DeviceCmyk(1.f, 0.156f, 0.f, 0.118f);

    canvas.setLineWidth(0.5f).setStrokeColor(blueColor);

    // 画水平网格线
    for (int i = -((int) ps.getHeight() / 2 - 57); i < ((int) ps.getHeight() / 2 - 56); i += 40) {
        canvas.moveTo(-(ps.getWidth() / 2 - 15), i)
                .lineTo(ps.getWidth() / 2 - 15, i);
    }
    // 画垂直网格线
    for (int j = -((int) ps.getWidth() / 2 - 61); j < ((int) ps.getWidth() / 2 - 60); j += 40) {
        canvas.moveTo(j, -(ps.getHeight() / 2 - 15))
                .lineTo(j, ps.getHeight() / 2 - 15);
    }
    canvas.stroke();

    // 画轴
    canvas.setLineWidth(3).setStrokeColor(grayColor);
    drawAxes(canvas, ps);

    // 画虚线
    canvas.setLineWidth(2).setStrokeColor(greenColor)
            .setLineDash(10, 10, 8)
            .moveTo(-(ps.getWidth() / 2 - 15), -(ps.getHeight() / 2 - 15))
            .lineTo(ps.getWidth() / 2 - 15, ps.getHeight() / 2 - 15).stroke();
    pdf.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

3)创建PDF,写星球大战

在这里插入图片描述

/**
 * 创建PDF,并写星球大战
 */
@GetMapping(value = "/createPdfWithStarWars", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> createPdfWithStarWars() throws IOException {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(outputStream);
    PdfDocument pdf = new PdfDocument(writer);

    //Add new page
    PageSize ps = PageSize.A4;
    PdfPage page = pdf.addNewPage(ps);

    PdfCanvas canvas = new PdfCanvas(page);

    List<String> text = new ArrayList<>();
    text.add("         Episode V         ");
    text.add("  THE EMPIRE STRIKES BACK  ");
    text.add("It is a dark time for the");
    text.add("Rebellion. Although the Death");
    text.add("Star has been destroyed,");
    text.add("Imperial troops have driven the");
    text.add("Rebel forces from their hidden");
    text.add("base and pursued them across");
    text.add("the galaxy.");
    text.add("Evading the dreaded Imperial");
    text.add("Starfleet, a group of freedom");
    text.add("fighters led by Luke Skywalker");
    text.add("has established a new secret");
    text.add("base on the remote ice world");
    text.add("of Hoth...");

    //Replace the origin of the coordinate system to the top left corner
    canvas.concatMatrix(1, 0, 0, 1, 0, ps.getHeight());
    canvas.beginText()
            .setFontAndSize(PdfFontFactory.createFont(StandardFonts.COURIER_BOLD), 14)
            .setLeading(14 * 1.2f)
            .moveText(70, -40);
    for (String s : text) {
        //Add text and move to the next line
        canvas.newlineShowText(s);
    }
    canvas.endText();
    pdf.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

4)创建PDF,写星球大战(滚动版)

在这里插入图片描述

/**
 * 创建PDF,并滚动写星球大战
 */
@GetMapping(value = "/createPdfWithStarWarsCrawl", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> createPdfWithStarWarsCrawl() throws IOException {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(outputStream);
    PdfDocument pdf = new PdfDocument(writer);

    //Add new page
    PageSize ps = PageSize.A4;
    PdfPage page = pdf.addNewPage(ps);

    List<String> text = new ArrayList();
    text.add("            Episode V      ");
    text.add("    THE EMPIRE STRIKES BACK  ");
    text.add("It is a dark time for the");
    text.add("Rebellion. Although the Death");
    text.add("Star has been destroyed,");
    text.add("Imperial troops have driven the");
    text.add("Rebel forces from their hidden");
    text.add("base and pursued them across");
    text.add("the galaxy.");
    text.add("Evading the dreaded Imperial");
    text.add("Starfleet, a group of freedom");
    text.add("fighters led by Luke Skywalker");
    text.add("has established a new secret");
    text.add("base on the remote ice world");
    text.add("of Hoth...");

    int maxStringWidth = 0;
    for (String fragment : text) {
        if (fragment.length() > maxStringWidth) {
            maxStringWidth = fragment.length();
        }
    }

    PdfCanvas canvas = new PdfCanvas(page);

    //Set black background
    canvas.rectangle(0, 0, ps.getWidth(), ps.getHeight())
            .setColor(ColorConstants.BLACK, true)
            .fill();

    //Replace the origin of the coordinate system to the top left corner
    canvas.concatMatrix(1, 0, 0, 1, 0, ps.getHeight());
    Color yellowColor = new DeviceCmyk(0.f, 0.0537f, 0.769f, 0.051f);
    float lineHeight = 5;
    float yOffset = -40;
    canvas.beginText()
            .setFontAndSize(PdfFontFactory.createFont(StandardFonts.COURIER_BOLD), 1)
            .setColor(yellowColor, true);
    for (int j = 0; j < text.size(); j++) {
        String line = text.get(j);
        float xOffset = ps.getWidth() / 2 - 45 - 8 * j;
        float fontSizeCoeff = 6 + j;
        float lineSpacing = (lineHeight + j) * j / 1.5f;
        int stringWidth = line.length();
        for (int i = 0; i < stringWidth; i++) {
            float angle = (maxStringWidth / 2 - i) / 2f;
            float charXOffset = (4 + (float) j / 2) * i;
            canvas.setTextMatrix(fontSizeCoeff, 0,
                            angle, fontSizeCoeff / 1.5f,
                            xOffset + charXOffset, yOffset - lineSpacing)
                    .showText(String.valueOf(line.charAt(i)));
        }
    }
    canvas.endText();

    //Close document
    pdf.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

5.实现示例:第3章

注意:部分高级 PDF 功能需要使用 Adobe 才可以看到。

Adobe 官方下载地址: https://www.adobe.com/acrobat/pdf-reader.html

1)创建PDF,简单的列渲染示例(纽约时代周刊)

在这里插入图片描述

private static final String APPLE_IMG = "src/main/resources/img/ny_times_apple.jpg";
private static final String APPLE_TXT = "src/main/resources/data/ny_times_apple.txt";
private static final String FACEBOOK_IMG = "src/main/resources/img/ny_times_fb.jpg";
private static final String FACEBOOK_TXT = "src/main/resources/data/ny_times_fb.txt";
private static final String INST_IMG = "src/main/resources/img/ny_times_inst.jpg";
private static final String INST_TXT = "src/main/resources/data/ny_times_inst.txt";

static PdfFont timesNewRoman = null;
static PdfFont timesNewRomanBold = null;

/**
 * 创建PDF,简单的列渲染示例(纽约时代周刊)
 */
@GetMapping(value = "/newYorkTimes", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> newYorkTimes() throws IOException {
    timesNewRoman = PdfFontFactory.createFont(StandardFonts.TIMES_ROMAN);
    timesNewRomanBold = PdfFontFactory.createFont(StandardFonts.TIMES_BOLD);

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(outputStream);

    //Initialize PDF document
    PdfDocument pdf = new PdfDocument(writer);
    PageSize ps = PageSize.A5;

    // Initialize document
    Document document = new Document(pdf, ps);

    //Set column parameters
    float offSet = 36;
    float columnWidth = (ps.getWidth() - offSet * 2 + 10) / 3;
    float columnHeight = ps.getHeight() - offSet * 2;

    //Define column areas
    Rectangle[] columns = {new Rectangle(offSet - 5, offSet, columnWidth, columnHeight),
            new Rectangle(offSet + columnWidth, offSet, columnWidth, columnHeight),
            new Rectangle(offSet + columnWidth * 2 + 5, offSet, columnWidth, columnHeight)};
    document.setRenderer(new ColumnDocumentRenderer(document, columns));

    Image apple = new Image(ImageDataFactory.create(APPLE_IMG)).setWidth(columnWidth);
    String articleApple = new String(Files.readAllBytes(Paths.get(APPLE_TXT)), StandardCharsets.UTF_8);
    addArticle(document, "Apple Encryption Engineers, if Ordered to Unlock iPhone, Might Resist", "By JOHN MARKOFF MARCH 18, 2016", apple, articleApple);
    Image facebook = new Image(ImageDataFactory.create(FACEBOOK_IMG)).setWidth(columnWidth);
    String articleFB = new String(Files.readAllBytes(Paths.get(FACEBOOK_TXT)), StandardCharsets.UTF_8);
    addArticle(document, "With \"Smog Jog\" Through Beijing, Zuckerberg Stirs Debate on Air Pollution", "By PAUL MOZUR MARCH 18, 2016", facebook, articleFB);
    Image inst = new Image(ImageDataFactory.create(INST_IMG)).setWidth(columnWidth);
    String articleInstagram = new String(Files.readAllBytes(Paths.get(INST_TXT)), StandardCharsets.UTF_8);
    addArticle(document, "Instagram May Change Your Feed, Personalizing It With an Algorithm","By MIKE ISAAC MARCH 15, 2016", inst, articleInstagram);

    document.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

/**
 * 添加文章
 * @param doc       文档
 * @param title     标题
 * @param author    作者
 * @param img       图片
 * @param text      文本
 * @throws IOException IO异常
 */
private static void addArticle(Document doc, String title, String author, Image img, String text) throws IOException {
    Paragraph p1 = new Paragraph(title)
            .setFont(timesNewRomanBold)
            .setFontSize(14);
    doc.add(p1);
    doc.add(img);
    Paragraph p2 = new Paragraph()
            .setFont(timesNewRoman)
            .setFontSize(7)
            .setFontColor(ColorConstants.GRAY)
            .add(author);
    doc.add(p2);
    Paragraph p3 = new Paragraph()
            .setFont(timesNewRoman)
            .setFontSize(10)
            .add(text);
    doc.add(p3);
}

2)创建PDF,简单的表渲染示例(英格兰足球超级联赛)

在这里插入图片描述

Color greenColor = new DeviceCmyk(0.78f, 0, 0.81f, 0.21f);
Color yellowColor = new DeviceCmyk(0, 0, 0.76f, 0.01f);
Color redColor = new DeviceCmyk(0, 0.76f, 0.86f, 0.01f);
Color blueColor = new DeviceCmyk(0.28f, 0.11f, 0, 0);

/**
 * 创建PDF,简单的表渲染示例(英格兰足球超级联赛)
 */
@GetMapping(value = "/premierLeague", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> premierLeague() throws IOException {
    final String data = "src/main/resources/data/premier_league.csv";
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(outputStream);

    //Initialize PDF document
    PdfDocument pdf = new PdfDocument(writer);
    PageSize ps = new PageSize(842, 680);

    // Initialize document
    Document document = new Document(pdf, ps);

    PdfFont font = PdfFontFactory.createFont(StandardFonts.HELVETICA);
    PdfFont bold = PdfFontFactory.createFont(StandardFonts.HELVETICA_BOLD);
    Table table = new Table(UnitValue.createPercentArray(new float[]{1.5f, 7, 2, 2, 2, 2, 3, 4, 4, 2}));
    table
            .setTextAlignment(TextAlignment.CENTER)
            .setHorizontalAlignment(HorizontalAlignment.CENTER);

    BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(data), StandardCharsets.UTF_8));
    String line = br.readLine();
    processTable1(table, line, bold, true);
    while ((line = br.readLine()) != null) {
        processTable1(table, line, font, false);
    }
    br.close();

    document.add(table);

    //Close document
    document.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

/**
 * 处理表格
 * @param table     表格
 * @param line      行
 * @param font      字体
 * @param isHeader  是否是表头
 */
private void processTable1(Table table, String line, PdfFont font, boolean isHeader) {
    StringTokenizer tokenizer = new StringTokenizer(line, ";");
    int columnNumber = 0;
    while (tokenizer.hasMoreTokens()) {
        if (isHeader) {
            Cell cell = new Cell().add(new Paragraph(tokenizer.nextToken()));
            cell.setNextRenderer(new RoundedCornersCellRenderer(cell));
            cell.setPadding(5).setBorder(null);
            table.addHeaderCell(cell);
        } else {
            columnNumber++;
            Cell cell = new Cell().add(new Paragraph(tokenizer.nextToken()));
            cell.setFont(font).setBorder(new SolidBorder(ColorConstants.BLACK, 0.5f));
            switch (columnNumber) {
                case 4:
                    cell.setBackgroundColor(greenColor);
                    break;
                case 5:
                    cell.setBackgroundColor(yellowColor);
                    break;
                case 6:
                    cell.setBackgroundColor(redColor);
                    break;
                default:
                    cell.setBackgroundColor(blueColor);
                    break;
            }
            table.addCell(cell);
        }
    }
}


/**
 * 自定义渲染器
 */
private class RoundedCornersCellRenderer extends CellRenderer {
    public RoundedCornersCellRenderer(Cell modelElement) {
        super(modelElement);
    }

    @Override
    public void drawBorder(DrawContext drawContext) {
        Rectangle rectangle = getOccupiedAreaBBox();
        float llx = rectangle.getX() + 1;
        float lly = rectangle.getY() + 1;
        float urx = rectangle.getX() + getOccupiedAreaBBox().getWidth() - 1;
        float ury = rectangle.getY() + getOccupiedAreaBBox().getHeight() - 1;
        PdfCanvas canvas = drawContext.getCanvas();
        float r = 4;
        float b = 0.4477f;
        canvas.moveTo(llx, lly).lineTo(urx, lly).lineTo(urx, ury - r)
                .curveTo(urx, ury - r * b, urx - r * b, ury, urx - r, ury)
                .lineTo(llx + r, ury)
                .curveTo(llx + r * b, ury, llx, ury - r * b, llx, ury - r)
                .lineTo(llx, lly).stroke();
        super.drawBorder(drawContext);
    }
}

3)创建PDF,简单的事件渲染示例(UFO文件)

在这里插入图片描述

static PdfFont helvetica = null;
static PdfFont helveticaBold = null;

/**
 * 创建PDF,简单的事件渲染示例(UFO文件)
 */
@GetMapping(value = "/ufo", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> ufo() throws IOException {
    final String data = "src/main/resources/data/ufo.csv";
    helvetica = PdfFontFactory.createFont(StandardFonts.HELVETICA);
    helveticaBold = PdfFontFactory.createFont(StandardFonts.HELVETICA_BOLD);

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(outputStream);

    //Initialize PDF document
    PdfDocument pdf = new PdfDocument(writer);
    pdf.addEventHandler(PdfDocumentEvent.END_PAGE, new MyEventHandler());

    // Initialize document
    Document document = new Document(pdf);
    Paragraph p = new Paragraph("List of reported UFO sightings in 20th century")
            .setTextAlignment(TextAlignment.CENTER).setFont(helveticaBold).setFontSize(14);
    document.add(p);
    Table table = new Table(UnitValue.createPercentArray(new float[]{3, 5, 7, 4}));
    BufferedReader br = new BufferedReader(new FileReader(data));
    String line = br.readLine();
    processTable2(table, line, helveticaBold, true);
    while ((line = br.readLine()) != null) {
        processTable2(table, line, helvetica, false);
    }
    br.close();
    document.add(table);
    document.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

/**
 * 处理表格
 * @param table     表格
 * @param line      行
 * @param font      字体
 * @param isHeader  是否是表头
 */
private void processTable2(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)).setFontSize(9).setBorder(new SolidBorder(ColorConstants.BLACK, 0.5f)));
        } else {
            table.addCell(new Cell().add(new Paragraph(tokenizer.nextToken()).setFont(font)).setFontSize(9).setBorder(new SolidBorder(ColorConstants.BLACK, 0.5f)));
        }
    }
}


/**
 * 自定义事件处理器
 */
private class MyEventHandler implements IEventHandler {

    public void handleEvent(Event event) {
        PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
        PdfDocument pdfDoc = docEvent.getDocument();
        PdfPage page = docEvent.getPage();
        int pageNumber = pdfDoc.getPageNumber(page);
        Rectangle pageSize = page.getPageSize();
        PdfCanvas pdfCanvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdfDoc);

        //Set background
        Color limeColor = new DeviceCmyk(0.208f, 0, 0.584f, 0);
        Color blueColor = new DeviceCmyk(0.445f, 0.0546f, 0, 0.0667f);
        pdfCanvas.saveState()
                .setFillColor(pageNumber % 2 == 1 ? limeColor : blueColor)
                .rectangle(pageSize.getLeft(), pageSize.getBottom(), pageSize.getWidth(), pageSize.getHeight())
                .fill().restoreState();

        //Add header and footer
        pdfCanvas.beginText()
                .setFontAndSize(helvetica, 9)
                .moveText(pageSize.getWidth() / 2 - 60, pageSize.getTop() - 20)
                .showText("THE TRUTH IS OUT THERE")
                .moveText(60, -pageSize.getTop() + 30)
                .showText(String.valueOf(pageNumber))
                .endText();

        //Add watermark
        Canvas canvas = new Canvas(pdfCanvas, page.getPageSize());
        canvas.setFontColor(ColorConstants.WHITE);
        canvas.setProperty(Property.FONT_SIZE, UnitValue.createPointValue(60));
        canvas.setProperty(Property.FONT, helveticaBold);
        canvas.showTextAligned(new Paragraph("CONFIDENTIAL"), 298, 421, pdfDoc.getPageNumber(page),
                TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);

        pdfCanvas.release();
    }
}

6.实现示例:第4章

1)创建PDF,添加文本批注

在这里插入图片描述

在这里插入图片描述

/**
 * 创建PDF,添加文本批注
 */
@GetMapping(value = "/textAnnotation", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> textAnnotation() {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(outputStream);

    //Initialize PDF document
    PdfDocument pdf = new PdfDocument(writer);

    //Initialize document
    Document document = new Document(pdf);
    document.add(new Paragraph("The example of text annotation."));

    //Create text annotation
    PdfAnnotation ann = new PdfTextAnnotation(new Rectangle(20, 800, 0, 0))
            .setOpen(true)
            .setColor(ColorConstants.GREEN)
            .setTitle(new PdfString("iText"))
            .setContents("With iText, you can truly take your documentation needs to the next level.");
    pdf.getFirstPage().addAnnotation(ann);
    document.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

2)创建PDF,添加链接批注

在这里插入图片描述

/**
 * 创建PDF,添加链接批注
 */
@GetMapping(value = "/linkAnnotation", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> linkAnnotation() {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(outputStream);

    //Initialize PDF document
    PdfDocument pdf = new PdfDocument(writer);

    //Initialize document
    Document document = new Document(pdf);

    //Create link annotation
    PdfLinkAnnotation annotation = new PdfLinkAnnotation(new Rectangle(0, 0))
            .setAction(PdfAction.createURI("http://itextpdf.com/"));
    Link link = new Link("here", annotation);
    Paragraph p = new Paragraph("The example of link annotation. Click ")
            .add(link.setUnderline())
            .add(" to learn more...");
    document.add(p);

    //Close document
    document.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

3)创建PDF,添加线批注

(注意:这里不要用谷歌浏览器了,是看不到的)

在这里插入图片描述

/**
 * 创建PDF,添加线批注
 */
@GetMapping(value = "/lineAnnotation", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> lineAnnotation() {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    PdfWriter writer = new PdfWriter(outputStream);

    //Initialize PDF document
    PdfDocument pdf = new PdfDocument(writer);
    PdfPage page = pdf.addNewPage();

    PdfArray lineEndings = new PdfArray();
    lineEndings.add(new PdfName("Diamond"));
    lineEndings.add(new PdfName("Diamond"));

    //Create line annotation with inside caption
    PdfAnnotation annotation = new PdfLineAnnotation(
            new Rectangle(0, 0),
            new float[]{20, 790, page.getPageSize().getWidth() - 20, 790})
            .setLineEndingStyles((lineEndings))
            .setContentsAsCaption(true)
            .setTitle(new PdfString("iText"))
            .setContents("The example of line annotation")
            .setColor(ColorConstants.BLUE);
    page.addAnnotation(annotation);

    //Close document
    pdf.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

4)创建PDF,添加文本标记批注

在这里插入图片描述

/**
 * 创建PDF,添加文本标记批注
 */
@GetMapping(value = "/textMarkupAnnotation", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> textMarkupAnnotation() {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //Initialize PDF document
    PdfDocument pdf = new PdfDocument(new PdfWriter(outputStream));

    //Initialize document
    Document document = new Document(pdf);

    Paragraph p = new Paragraph("The example of text markup annotation.");
    document.showTextAligned(p, 20, 795, 1, TextAlignment.LEFT,
            VerticalAlignment.MIDDLE, 0);

    //Create text markup annotation
    PdfAnnotation ann = PdfTextMarkupAnnotation.createHighLight(new Rectangle(105, 790, 64, 10),
                    new float[]{169, 790, 105, 790, 169, 800, 105, 800})
            .setColor(ColorConstants.YELLOW)
            .setTitle(new PdfString("Hello!"))
            .setContents(new PdfString("I'm a popup."))
            .setTitle(new PdfString("iText"))
            .setRectangle(new PdfArray(new float[]{100, 600, 200, 100}));
    pdf.getFirstPage().addAnnotation(ann);

    //Close document
    document.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

5)创建PDF,添加简单组件的批注(职位申请表)

在这里插入图片描述

/**
 * Add acroform to the document
 * @param doc   document
 * @return      PdfAcroForm
 */
private PdfAcroForm addAcroForm(Document doc) {

    Paragraph title = new Paragraph("Application for employment")
            .setTextAlignment(TextAlignment.CENTER)
            .setFontSize(16);
    doc.add(title);
    doc.add(new Paragraph("Full name:").setFontSize(12));
    doc.add(new Paragraph("Native language:      English         French       German        Russian        Spanish").setFontSize(12));
    doc.add(new Paragraph("Experience in:       cooking        driving           software development").setFontSize(12));
    doc.add(new Paragraph("Preferred working shift:").setFontSize(12));
    doc.add(new Paragraph("Additional information:").setFontSize(12));

    //Add acroform
    PdfAcroForm form = PdfAcroForm.getAcroForm(doc.getPdfDocument(), true);

    //Create text field
    PdfTextFormField nameField = PdfTextFormField.createText(doc.getPdfDocument(),
            new Rectangle(99, 753, 425, 15), "name", "");
    form.addField(nameField);

    //Create radio buttons
    PdfButtonFormField group = PdfFormField.createRadioGroup(doc.getPdfDocument(), "language", "");
    PdfFormField.createRadioButton(doc.getPdfDocument(), new Rectangle(130, 728, 15, 15), group, "English");
    PdfFormField.createRadioButton(doc.getPdfDocument(), new Rectangle(200, 728, 15, 15), group, "French");
    PdfFormField.createRadioButton(doc.getPdfDocument(), new Rectangle(260, 728, 15, 15), group, "German");
    PdfFormField.createRadioButton(doc.getPdfDocument(), new Rectangle(330, 728, 15, 15), group, "Russian");
    PdfFormField.createRadioButton(doc.getPdfDocument(), new Rectangle(400, 728, 15, 15), group, "Spanish");
    form.addField(group);

    //Create checkboxes
    for (int i = 0; i < 3; i++) {
        PdfButtonFormField checkField = PdfFormField.createCheckBox(doc.getPdfDocument(), new Rectangle(119 + i * 69, 701, 15, 15),
                "experience".concat(String.valueOf(i+1)), "Off", PdfFormField.TYPE_CHECK);
        form.addField(checkField);
    }

    //Create combobox
    String[] options = {"Any", "6.30 am - 2.30 pm", "1.30 pm - 9.30 pm"};
    PdfChoiceFormField choiceField = PdfFormField.createComboBox(doc.getPdfDocument(), new Rectangle(163, 676, 115, 15),
            "shift", "Any", options);
    form.addField(choiceField);

    //Create multiline text field
    PdfTextFormField infoField = PdfTextFormField.createMultilineText(doc.getPdfDocument(),
            new Rectangle(158, 625, 366, 40), "info", "");
    form.addField(infoField);

    //Create push button field
    PdfButtonFormField button = PdfFormField.createPushButton(doc.getPdfDocument(),
            new Rectangle(479, 594, 45, 15), "reset", "RESET");
    button.setAction(PdfAction.createResetForm(new String[] {"name", "language", "experience1", "experience2", "experience3", "shift", "info"}, 0));
    form.addField(button);

    return form;

}

6)创建PDF,添加并填充表单(职位申请表)

在这里插入图片描述

/**
 * 创建PDF,添加并填充表单(职位申请表)
 */
@GetMapping(value = "/createAndFill", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> createAndFill() {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //Initialize PDF document
    PdfDocument pdf = new PdfDocument(new PdfWriter(outputStream));

    // Initialize document
    Document doc = new Document(pdf);

    PdfAcroForm form = addAcroForm(doc);
    Map<String, PdfFormField> fields = form.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.");

    doc.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

7)指定PDF,简单填充表单(职位申请表)

在这里插入图片描述

/**
 * 指定PDF,简单填写表单(职位申请表)
 */
@GetMapping(value = "/flattenForm", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> flattenForm() throws IOException {
    final String src = "src/main/resources/pdf/job_application.pdf";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //Initialize PDF document
    PdfDocument pdf = new PdfDocument(new PdfReader(src), new PdfWriter(outputStream));

    PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);
    Map<String, PdfFormField> fields = form.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.");
    form.flattenFields();

    pdf.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

7.实现示例:第5章

1)创建PDF,添加可回复型批注

在这里插入图片描述

/**
 * 创建PDF,添加可回复型批注
 */
@GetMapping(value = "/addAnnotationAndContent", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> addAnnotationAndContent() throws IOException {
    final String src = "src/main/resources/pdf/job_application.pdf";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //Initialize PDF document
    PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(outputStream));

    //Add text annotation
    PdfAnnotation ann = new PdfTextAnnotation(new Rectangle(400, 795, 0, 0))
            .setOpen(true)
            .setTitle(new PdfString("iText"))
            .setContents("Please, fill out the form.");
    pdfDoc.getFirstPage().addAnnotation(ann);

    PdfCanvas canvas = new PdfCanvas(pdfDoc.getFirstPage());
    canvas.beginText().setFontAndSize(PdfFontFactory.createFont(StandardFonts.HELVETICA), 12)
            .moveText(265, 597)
            .showText("I agree to the terms and conditions.")
            .endText();

    //Add form field
    PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
    PdfButtonFormField checkField = PdfFormField.createCheckBox(pdfDoc, new Rectangle(245, 594, 15, 15),
            "agreement", "Off", PdfFormField.TYPE_CHECK);
    checkField.setRequired(true);
    form.addField(checkField);

    //Update reset button
    form.getField("reset").setAction(PdfAction.createResetForm(new String[]{"name", "language",
            "experience1", "experience2", "experience3", "shift", "info", "agreement"}, 0));

    pdfDoc.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

2)根据PDF,填写并修改表单

在这里插入图片描述

/**
 * 根据PDF,填写并修改表单
 */
@GetMapping(value = "/fillAndModifyForm", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> fillAndModifyForm() throws IOException {
    final String src = "src/main/resources/pdf/job_application.pdf";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //Initialize PDF document
    PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(outputStream));


    PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
    Map<String, PdfFormField> fields = form.getFormFields();

    fields.get("name").setValue("James Bond").setBackgroundColor(ColorConstants.ORANGE);
    fields.get("language").setValue("English");

    fields.get("experience1").setValue("Yes");
    fields.get("experience2").setValue("Yes");
    fields.get("experience3").setValue("Yes");

    List<PdfString> options = new ArrayList<PdfString>();
    options.add(new PdfString("Any"));
    options.add(new PdfString("8.30 am - 12.30 pm"));
    options.add(new PdfString("12.30 pm - 4.30 pm"));
    options.add(new PdfString("4.30 pm - 8.30 pm"));
    options.add(new PdfString("8.30 pm - 12.30 am"));
    options.add(new PdfString("12.30 am - 4.30 am"));
    options.add(new PdfString("4.30 am - 8.30 am"));
    PdfArray arr = new PdfArray(options);
    fields.get("shift").setOptions(arr);
    fields.get("shift").setValue("Any");

    PdfFont courier = PdfFontFactory.createFont(StandardFonts.COURIER);
    fields.get("info").setValue("I was 38 years old when I became an MI6 agent.", courier, 7f);

    pdfDoc.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

3)根据PDF,填充内容(页眉、页脚线、页脚页码、水印)

在这里插入图片描述

在这里插入图片描述

/**
 * 根据PDF,填充内容(页眉、页脚线、页脚页码、水印)
 */
@GetMapping(value = "/addContent", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> addContent() throws IOException {
    final String src = "src/main/resources/pdf/ufo.pdf";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //Initialize PDF document
    PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(outputStream));

    Document document = new Document(pdfDoc);
    Rectangle pageSize;
    PdfCanvas canvas;
    int n = pdfDoc.getNumberOfPages();
    for (int i = 1; i <= n; i++) {
        PdfPage page = pdfDoc.getPage(i);
        pageSize = page.getPageSize();
        canvas = new PdfCanvas(page);
        // 画页眉文字
        canvas.beginText().setFontAndSize(PdfFontFactory.createFont(StandardFonts.HELVETICA), 7)
                .moveText(pageSize.getWidth() / 2 - 24, pageSize.getHeight() - 10)
                .showText("I want to believe")
                .endText();
        // 画页脚线
        canvas.setStrokeColor(ColorConstants.BLACK)
                .setLineWidth(.2f)
                .moveTo(pageSize.getWidth() / 2 - 30, 20)
                .lineTo(pageSize.getWidth() / 2 + 30, 20).stroke();
        // 画页码
        canvas.beginText().setFontAndSize(PdfFontFactory.createFont(StandardFonts.HELVETICA), 7)
                .moveText(pageSize.getWidth() / 2 - 7, 10)
                .showText(String.valueOf(i))
                .showText(" of ")
                .showText(String.valueOf(n))
                .endText();
        // 画水印
        Paragraph p = new Paragraph("CONFIDENTIAL").setFontSize(60);
        canvas.saveState();
        PdfExtGState gs1 = new PdfExtGState().setFillOpacity(0.2f);
        canvas.setExtGState(gs1);
        document.showTextAligned(p,
                pageSize.getWidth() / 2, pageSize.getHeight() / 2,
                pdfDoc.getPageNumber(page),
                TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);
        canvas.restoreState();
    }

    pdfDoc.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

4)根据PDF,改变页面(大小、边框、旋转)

在这里插入图片描述

在这里插入图片描述

/**
 * 根据PDF,改变页面(大小、边框、旋转)
 */
@GetMapping(value = "/changePage", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> changePage() throws IOException {
    final String src = "src/main/resources/pdf/ufo.pdf";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //Initialize PDF document
    PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), new PdfWriter(outputStream));


    float margin = 72;
    for (int i = 1; i <= pdfDoc.getNumberOfPages(); i++) {
        PdfPage page = pdfDoc.getPage(i);
        // change page size
        Rectangle mediaBox = page.getMediaBox();
        Rectangle newMediaBox = new Rectangle(mediaBox.getLeft() - margin, mediaBox.getBottom() - margin,
                mediaBox.getWidth() + margin * 2, mediaBox.getHeight() + margin * 2);
        page.setMediaBox(newMediaBox);
        // add border
        PdfCanvas over = new PdfCanvas(page);
        over.setStrokeColor(ColorConstants.GRAY);
        over.rectangle(mediaBox.getLeft(), mediaBox.getBottom(), mediaBox.getWidth(), mediaBox.getHeight());
        over.stroke();
        // change rotation of the even pages
        if (i % 2 == 0) {
            page.setRotation(180);
        }
    }

    pdfDoc.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

8.实现示例:第6章

1)根据PDF,缩放尺寸(金门大桥)

在这里插入图片描述

/**
 * 根据PDF,缩放尺寸(金门大桥)
 */
@GetMapping(value = "/theGoldenGateBridgeScaleShrink", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> createPdfWithLines() throws IOException {
    final String src = "src/main/resources/pdf/the_golden_gate_bridge.pdf";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //Initialize PDF document
    PdfDocument pdf = new PdfDocument(new PdfWriter(outputStream));
    PdfDocument origPdf = new PdfDocument(new PdfReader(src));

    //Original page size
    PdfPage origPage = origPdf.getPage(1);
    Rectangle orig = origPage.getPageSizeWithRotation();

    //Add A4 page
    PdfPage page = pdf.addNewPage(PageSize.A4.rotate());
    //Shrink original page content using transformation matrix
    PdfCanvas canvas = new PdfCanvas(page);
    AffineTransform transformationMatrix = AffineTransform.getScaleInstance(page.getPageSize().getWidth() / orig.getWidth(), page.getPageSize().getHeight() / orig.getHeight());
    canvas.concatMatrix(transformationMatrix);
    PdfFormXObject pageCopy = origPage.copyAsFormXObject(pdf);
    canvas.addXObjectAt(pageCopy, 0, 0);

    //Add page with original size
    pdf.addPage(origPage.copyTo(pdf));

    //Add A2 page
    page = pdf.addNewPage(PageSize.A2.rotate());
    //Scale original page content using transformation matrix
    canvas = new PdfCanvas(page);
    transformationMatrix = AffineTransform.getScaleInstance(page.getPageSize().getWidth() / orig.getWidth(), page.getPageSize().getHeight() / orig.getHeight());
    canvas.concatMatrix(transformationMatrix);
    canvas.addXObjectAt(pageCopy, 0, 0);

    pdf.close();
    origPdf.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

2)根据PDF,一分为四(金门大桥)

在这里插入图片描述

/**
 * 根据PDF,一分为四(金门大桥)
 */
@GetMapping(value = "/theGoldenGateBridgeTiles", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> theGoldenGateBridgeTiles() throws IOException {
    final String src = "src/main/resources/pdf/the_golden_gate_bridge.pdf";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //Initialize PDF document
    PdfDocument pdf = new PdfDocument(new PdfWriter(outputStream));
    PdfDocument sourcePdf = new PdfDocument(new PdfReader(src));

    //Original page
    PdfPage origPage = sourcePdf.getPage(1);
    PdfFormXObject pageCopy = origPage.copyAsFormXObject(pdf);

    //Original page size
    Rectangle orig = origPage.getPageSize();
    //Tile size
    Rectangle tileSize = PageSize.A4.rotate();
    // Transformation matrix
    AffineTransform transformationMatrix = AffineTransform.getScaleInstance(tileSize.getWidth() / orig.getWidth() * 2f, tileSize.getHeight() / orig.getHeight() * 2f);


    //The first tile
    PdfPage page = pdf.addNewPage(PageSize.A4.rotate());
    PdfCanvas canvas = new PdfCanvas(page);
    canvas.concatMatrix(transformationMatrix);
    canvas.addXObjectAt(pageCopy, 0, -orig.getHeight() / 2f);

    //The second tile
    page = pdf.addNewPage(PageSize.A4.rotate());
    canvas = new PdfCanvas(page);
    canvas.concatMatrix(transformationMatrix);
    canvas.addXObjectAt(pageCopy, -orig.getWidth() / 2f, -orig.getHeight() / 2f);

    //The third tile
    page = pdf.addNewPage(PageSize.A4.rotate());
    canvas = new PdfCanvas(page);
    canvas.concatMatrix(transformationMatrix);
    canvas.addXObjectAt(pageCopy, 0, 0);

    //The fourth tile
    page = pdf.addNewPage(PageSize.A4.rotate());
    canvas = new PdfCanvas(page);
    canvas.concatMatrix(transformationMatrix);
    canvas.addXObjectAt(pageCopy, -orig.getWidth() / 2f, 0);

    pdf.close();
    sourcePdf.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

3)根据PDF,多页合并(金门大桥)

在这里插入图片描述

/**
 * 根据PDF,多页合并(金门大桥)
 */
@GetMapping(value = "/theGoldenGateBridgeNUp", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> theGoldenGateBridgeNUp() throws IOException {
    final String src = "src/main/resources/pdf/the_golden_gate_bridge.pdf";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //Initialize PDF document
    PdfDocument pdf = new PdfDocument(new PdfWriter(outputStream));
    PdfDocument sourcePdf = new PdfDocument(new PdfReader(src));

    //Original page
    PdfPage origPage = sourcePdf.getPage(1);

    //Original page size
    Rectangle orig = origPage.getPageSize();
    PdfFormXObject pageCopy = origPage.copyAsFormXObject(pdf);

    //N-up page
    PageSize nUpPageSize = PageSize.A4.rotate();
    PdfPage page = pdf.addNewPage(nUpPageSize);
    PdfCanvas canvas = new PdfCanvas(page);

    //Scale page
    AffineTransform transformationMatrix = AffineTransform.getScaleInstance(nUpPageSize.getWidth() / orig.getWidth() / 2f, nUpPageSize.getHeight() / orig.getHeight() / 2f);
    canvas.concatMatrix(transformationMatrix);

    //Add pages to N-up page
    canvas.addXObjectAt(pageCopy, 0, orig.getHeight());
    canvas.addXObjectAt(pageCopy, orig.getWidth(), orig.getHeight());
    canvas.addXObjectAt(pageCopy, 0, 0);
    canvas.addXObjectAt(pageCopy, orig.getWidth(), 0);

    pdf.close();
    sourcePdf.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

4)根据PDF,进行拼接(第88届奥斯卡)

在这里插入图片描述

/**
 * 根据PDF,进行拼接(第88届奥斯卡)
 */
@GetMapping(value = "/the88thOscarCombine", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> the88thOscarCombine() throws IOException {
    final String src1 = "src/main/resources/pdf/88th_reminder_list.pdf";
    final String src2 = "src/main/resources/pdf/88th_noms_announcement.pdf";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //Initialize PDF document with output intent
    PdfDocument pdf = new PdfDocument(new PdfWriter(outputStream));
    PdfMerger merger = new PdfMerger(pdf);

    //Add pages from the first document
    PdfDocument firstSourcePdf = new PdfDocument(new PdfReader(src1));
    merger.merge(firstSourcePdf, 1, firstSourcePdf.getNumberOfPages());

    //Add pages from the second pdf document
    PdfDocument secondSourcePdf = new PdfDocument(new PdfReader(src2));
    merger.merge(secondSourcePdf, 1, secondSourcePdf.getNumberOfPages());

    firstSourcePdf.close();
    secondSourcePdf.close();
    pdf.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

5)根据PDF,抽取指定页数进行拼接(第88届奥斯卡)

在这里插入图片描述

在这里插入图片描述

/**
 * 根据PDF,抽取指定页数进行拼接(第88届奥斯卡)
 */
@GetMapping(value = "/the88thOscarCombineXofY", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> the88thOscarCombineXofY() throws IOException {
    final String src1 = "src/main/resources/pdf/88th_reminder_list.pdf";
    final String src2 = "src/main/resources/pdf/88th_noms_announcement.pdf";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //Initialize PDF document with output intent
    PdfDocument pdf = new PdfDocument(new PdfWriter(outputStream));

    PdfMerger merger = new PdfMerger(pdf);

    //Add pages from the first document
    PdfDocument firstSourcePdf = new PdfDocument(new PdfReader(src1));
    merger.merge(firstSourcePdf, Arrays.asList(1, 5, 7, 1));

    //Add pages from the second pdf document
    PdfDocument secondSourcePdf = new PdfDocument(new PdfReader(src2));
    merger.merge(secondSourcePdf, Arrays.asList(1, 15));

    firstSourcePdf.close();
    secondSourcePdf.close();
    pdf.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

6)根据PDF,拼接并添加目录(第88届奥斯卡)

在这里插入图片描述

/**
 * 存储目录清单
 */
private static final Map<String, Integer> TheRevenantNominations = new TreeMap<String, Integer>();
static {
    TheRevenantNominations.put("Performance by an actor in a leading role", 4);
    TheRevenantNominations.put("Performance by an actor in a supporting role", 4);
    TheRevenantNominations.put("Achievement in cinematography", 4);
    TheRevenantNominations.put("Achievement in costume design", 5);
    TheRevenantNominations.put("Achievement in directing", 5);
    TheRevenantNominations.put("Achievement in film editing", 6);
    TheRevenantNominations.put("Achievement in makeup and hairstyling", 7);
    TheRevenantNominations.put("Best motion picture of the year", 8);
    TheRevenantNominations.put("Achievement in production design", 8);
    TheRevenantNominations.put("Achievement in sound editing", 9);
    TheRevenantNominations.put("Achievement in sound mixing", 9);
    TheRevenantNominations.put("Achievement in visual effects", 10);
}

/**
 * 根据PDF,拼接并添加目录(第88届奥斯卡)
 */
@GetMapping(value = "/the88thOscarCombineAddTOC", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> the88thOscarCombineAddTOC() throws IOException {
    final String src1 = "src/main/resources/pdf/88th_noms_announcement.pdf";
    final String src2 = "src/main/resources/pdf/oscars_movies_checklist_2016.pdf";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outputStream));
    Document document = new Document(pdfDoc);
    document.add(new Paragraph(new Text("The Revenant nominations list"))
            .setTextAlignment(TextAlignment.CENTER));

    PdfDocument firstSourcePdf = new PdfDocument(new PdfReader(src1));
    for (Map.Entry<String, Integer> entry : TheRevenantNominations.entrySet()) {
        //Copy page
        PdfPage page  = firstSourcePdf.getPage(entry.getValue()).copyTo(pdfDoc);
        pdfDoc.addPage(page);

        //Overwrite page number
        Text text = new Text(String.format("Page %d", pdfDoc.getNumberOfPages() - 1));
        text.setBackgroundColor(ColorConstants.WHITE);
        document.add(new Paragraph(text).setFixedPosition(
                pdfDoc.getNumberOfPages(), 549, 742, 100));

        //Add destination
        String destinationKey = "p" + (pdfDoc.getNumberOfPages() - 1);
        PdfArray destinationArray = new PdfArray();
        destinationArray.add(page.getPdfObject());
        destinationArray.add(PdfName.XYZ);
        destinationArray.add(new PdfNumber(0));
        destinationArray.add(new PdfNumber(page.getMediaBox().getHeight()));
        destinationArray.add(new PdfNumber(1));
        pdfDoc.addNamedDestination(destinationKey, destinationArray);

        //Add TOC line with bookmark
        Paragraph p = new Paragraph();
        p.addTabStops(new TabStop(540, TabAlignment.RIGHT, new DottedLine()));
        p.add(entry.getKey());
        p.add(new Tab());
        p.add(String.valueOf(pdfDoc.getNumberOfPages() - 1));
        p.setProperty(Property.ACTION, PdfAction.createGoTo(destinationKey));
        document.add(p);
    }
    firstSourcePdf.close();

    //Add the last page
    PdfDocument secondSourcePdf = new PdfDocument(new PdfReader(src2));
    PdfPage page  = secondSourcePdf.getPage(1).copyTo(pdfDoc);
    pdfDoc.addPage(page);

    //Add destination
    PdfArray destinationArray = new PdfArray();
    destinationArray.add(page.getPdfObject());
    destinationArray.add(PdfName.XYZ);
    destinationArray.add(new PdfNumber(0));
    destinationArray.add(new PdfNumber(page.getMediaBox().getHeight()));
    destinationArray.add(new PdfNumber(1));
    pdfDoc.addNamedDestination("checklist", destinationArray);

    //Add TOC line with bookmark
    Paragraph p = new Paragraph();
    p.addTabStops(new TabStop(540, TabAlignment.RIGHT, new DottedLine()));
    p.add("Oscars\u00ae 2016 Movie Checklist");
    p.add(new Tab());
    p.add(String.valueOf(pdfDoc.getNumberOfPages() - 1));
    p.setProperty(Property.ACTION, PdfAction.createGoTo("checklist"));
    document.add(p);
    secondSourcePdf.close();

    // close the document
    document.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

7)根据PDF,合并表格

在这里插入图片描述

/**
 * 根据PDF,合并表格
 */
@GetMapping(value = "/combineForms", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> combineForms() throws IOException {
    final String src1 = "src/main/resources/pdf/subscribe.pdf";
    final String src2 = "src/main/resources/pdf/state.pdf";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    PdfDocument destPdfDocument = new PdfDocument(new PdfWriter(outputStream));
    PdfDocument[] sources = new PdfDocument[] {
            new PdfDocument(new PdfReader(src1)),
            new PdfDocument(new PdfReader(src2))
    };
    PdfPageFormCopier formCopier = new PdfPageFormCopier();
    for (PdfDocument sourcePdfDocument : sources) {
        sourcePdfDocument.copyPagesTo(
                1, sourcePdfDocument.getNumberOfPages(),
                destPdfDocument, formCopier);
        sourcePdfDocument.close();
    }
    destPdfDocument.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

8)根据PDF,批量填写并合并表格

在这里插入图片描述

/**
 * 根据PDF,批量填写并合并表格
 */
@GetMapping(value = "/fillOutAndMergeForms", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> fillOutAndMergeForms() throws IOException {
    final String src = "src/main/resources/pdf/state.pdf";
    final String data = "src/main/resources/data/united_states.csv";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outputStream));
    PdfPageFormCopier formCopier = new PdfPageFormCopier();

    BufferedReader bufferedReader = new BufferedReader(new FileReader(data));
    String line;
    boolean headerLine = true;
    int i = 1;
    while ((line = bufferedReader.readLine()) != null) {
        if (headerLine) {
            headerLine = false;
            continue;
        }

        com.itextpdf.io.source.ByteArrayOutputStream baos = new com.itextpdf.io.source.ByteArrayOutputStream();
        PdfDocument sourcePdfDocument = new PdfDocument(new PdfReader(src), new PdfWriter(baos));

        //Rename fields
        i++;
        PdfAcroForm form = PdfAcroForm.getAcroForm(sourcePdfDocument, true);
        form.renameField("name", "name_" + i);
        form.renameField("abbr", "abbr_" + i);
        form.renameField("capital", "capital_" + i);
        form.renameField("city", "city_" + i);
        form.renameField("population", "population_" + i);
        form.renameField("surface", "surface_" + i);
        form.renameField("timezone1", "timezone1_" + i);
        form.renameField("timezone2", "timezone2_" + i);
        form.renameField("dst", "dst_" + i);

        //Fill out fields
        StringTokenizer tokenizer = new StringTokenizer(line, ";");
        Map<String, PdfFormField> fields = form.getFormFields();
        fields.get("name_" + i).setValue(tokenizer.nextToken());
        fields.get("abbr_" + i).setValue(tokenizer.nextToken());
        fields.get("capital_" + i).setValue(tokenizer.nextToken());
        fields.get("city_" + i).setValue(tokenizer.nextToken());
        fields.get("population_" + i).setValue(tokenizer.nextToken());
        fields.get("surface_" + i).setValue(tokenizer.nextToken());
        fields.get("timezone1_" + i).setValue(tokenizer.nextToken());
        fields.get("timezone2_" + i).setValue(tokenizer.nextToken());
        fields.get("dst_" + i).setValue(tokenizer.nextToken());

        sourcePdfDocument.close();
        sourcePdfDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(baos.toByteArray())));

        //Copy pages
        sourcePdfDocument.copyPagesTo(1, sourcePdfDocument.getNumberOfPages(), pdfDocument, formCopier);
        sourcePdfDocument.close();
    }

    bufferedReader.close();
    pdfDocument.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

9)根据PDF,批量填写并合并表格(是否开启智能模式)

  • 在智能模式下,当遇到资源(如字体、图像等)时,对这些资源的引用将保存在缓存中,以便可以重复使用。这需要更多内存,但会减小生成的 PDF 文档的文件大小。
  • 参见:https://api.itextpdf.com/iText7/java/7.1.14/com/itextpdf/kernel/pdf/PdfWriter.html#setSmartMode-boolean-

在这里插入图片描述

在这里插入图片描述

/**
 * 根据PDF,批量填写并合并表格(是否开启智能模式)
 */
@GetMapping(value = "/fillOutFlattenAndMergeForms", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> fillOutFlattenAndMergeForms(boolean isSmartMode) throws IOException {
    final String src = "src/main/resources/pdf/state.pdf";
    final String data = "src/main/resources/data/united_states.csv";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    PdfDocument destPdfDocument;
    if (isSmartMode) {
        // 在智能模式下,当遇到资源(如字体、图像等)时,对这些资源的引用将保存在缓存中,以便可以重复使用。这需要更多内存,但会减小生成的 PDF 文档的文件大小。
        // 参见:https://api.itextpdf.com/iText7/java/7.1.14/com/itextpdf/kernel/pdf/PdfWriter.html#setSmartMode-boolean-
        destPdfDocument = new PdfDocument(new PdfWriter(outputStream).setSmartMode(true));
    } else {
        destPdfDocument = new PdfDocument(new PdfWriter(outputStream));
    }

    BufferedReader bufferedReader = new BufferedReader(new FileReader(data));
    String line;
    boolean headerLine = true;
    while ((line = bufferedReader.readLine()) != null) {
        if (headerLine) {
            headerLine = false;
            continue;
        }
        com.itextpdf.io.source.ByteArrayOutputStream baos = new com.itextpdf.io.source.ByteArrayOutputStream();
        PdfDocument sourcePdfDocument = new PdfDocument(new PdfReader(src), new PdfWriter(baos));

        //Read fields
        PdfAcroForm form = PdfAcroForm.getAcroForm(sourcePdfDocument, true);
        StringTokenizer tokenizer = new StringTokenizer(line, ";");
        Map<String, PdfFormField> fields = form.getFormFields();

        //Fill out fields
        fields.get("name").setValue(tokenizer.nextToken());
        fields.get("abbr").setValue(tokenizer.nextToken());
        fields.get("capital").setValue(tokenizer.nextToken());
        fields.get("city").setValue(tokenizer.nextToken());
        fields.get("population").setValue(tokenizer.nextToken());
        fields.get("surface").setValue(tokenizer.nextToken());
        fields.get("timezone1").setValue(tokenizer.nextToken());
        fields.get("timezone2").setValue(tokenizer.nextToken());
        fields.get("dst").setValue(tokenizer.nextToken());

        //Flatten fields
        form.flattenFields();

        sourcePdfDocument.close();
        sourcePdfDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(baos.toByteArray())));

        //Copy pages
        sourcePdfDocument.copyPagesTo(1, sourcePdfDocument.getNumberOfPages(), destPdfDocument, null);

        sourcePdfDocument.close();
    }

    bufferedReader.close();

    destPdfDocument.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

9.实现示例:第7章

1)创建PDF,PDF/UA标准(快棕狐)

PDF/UA: 代表 “PDF Universal Accessibility”,是一种 PDF 文档的标准格式。PDF/UA 标准要求文档具有元数据、书签、标题、语言表示、图像说明、超链接等功能,以及通过 PDF/UA 验证工具进行验证,以确保其符合标准。这使得 PDF/UA 成为在企业、政府机构和组织内部以及对外发布重要文档时的首选格式。

在这里插入图片描述

/**
 * 创建PDF,PDF/UA标准(快棕狐)
 */
@GetMapping(value = "/quickBrownFoxPDFUA", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> quickBrownFoxPDFUA() throws IOException {
    final String dog = "src/main/resources/img/dog.bmp";
    final String fox = "src/main/resources/img/fox.bmp";
    final String myFont = "src/main/resources/font/FreeSans.ttf";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    PdfDocument pdf = new PdfDocument(new PdfWriter(outputStream, new WriterProperties().addUAXmpMetadata()));
    Document document = new Document(pdf);

    //Setting some required parameters
    pdf.setTagged();
    pdf.getCatalog().setLang(new PdfString("en-US"));
    pdf.getCatalog().setViewerPreferences(
            new PdfViewerPreferences().setDisplayDocTitle(true));
    PdfDocumentInfo info = pdf.getDocumentInfo();
    info.setTitle("iText7 PDF/UA example");

    //Fonts need to be embedded
    PdfFont font = PdfFontFactory.createFont(myFont, PdfEncodings.WINANSI, PdfFontFactory.EmbeddingStrategy.FORCE_EMBEDDED);
    Paragraph p = new Paragraph();
    p.setFont(font);
    p.add(new Text("The quick brown "));
    Image foxImage = new Image(ImageDataFactory.create(fox));
    //PDF/UA: Set alt text
    foxImage.getAccessibilityProperties().setAlternateDescription("Fox");
    p.add(foxImage);
    p.add(" jumps over the lazy ");
    Image dogImage = new Image(ImageDataFactory.create(dog));
    //PDF/UA: Set alt text
    dogImage.getAccessibilityProperties().setAlternateDescription("Dog");
    p.add(dogImage);

    document.add(p);
    document.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

2)创建PDF,PDF/A-1a标准(快棕狐)

PDF/A: 是为了长期保存和存档而设计的一种PDF文件格式。其中,PDF/A-1a、PDF/A-1b和PDF/A-3a是PDF/A格式的三种子格式。

PDF/A-1a: 要求PDF文档必须包含所有必要的元数据,且必须是无障碍的(即所有文本必须是可选择和可复制的),并且不允许使用高级功能,如JavaScript和交互式表单等。PDF/A-1a通常用于长期保存和存档需要,例如政府文档、法律文件、金融报告等。

在这里插入图片描述

/**
 * 创建PDF,PDF/A-1a标准(快棕狐)
 */
@GetMapping(value = "/quickBrownFoxPDFA_1a", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> quickBrownFoxPDFA_1a() throws IOException {
    final String dog = "src/main/resources/img/dog.bmp";
    final String fox = "src/main/resources/img/fox.bmp";
    final String myFont = "src/main/resources/font/FreeSans.ttf";
    final String intent = "src/main/resources/color/sRGB_CS_profile.icm";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //Initialize PDFA document with output intent
    PdfADocument pdf = new PdfADocument(new PdfWriter(outputStream),
            PdfAConformanceLevel.PDF_A_1A,
            new PdfOutputIntent("Custom", "", "http://www.color.org",
                    "sRGB IEC61966-2.1", new FileInputStream(intent)));
    Document document = new Document(pdf);

    //Setting some required parameters
    pdf.setTagged();

    //Fonts need to be embedded
    PdfFont font = PdfFontFactory.createFont(myFont, PdfEncodings.WINANSI, PdfFontFactory.EmbeddingStrategy.FORCE_EMBEDDED);
    Paragraph p = new Paragraph();
    p.setFont(font);
    p.add(new Text("The quick brown "));
    Image foxImage = new Image(ImageDataFactory.create(fox));
    //Set alt text
    foxImage.getAccessibilityProperties().setAlternateDescription("Fox");
    p.add(foxImage);
    p.add(" jumps over the lazy ");
    Image dogImage = new Image(ImageDataFactory.create(dog));
    //Set alt text
    dogImage.getAccessibilityProperties().setAlternateDescription("Dog");
    p.add(dogImage);

    document.add(p);
    document.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

3)创建PDF,PDF/A-1b标准(快棕狐)

PDF/A-1b: PDF文档需要包含必要的元数据,但不需要无障碍性,且不允许使用JavaScript和其他高级功能。PDF/A-1b通常用于长期保存和存档需要,例如企业文件、技术文档等。

在这里插入图片描述

/**
 * 创建PDF,PDF/A-1b标准(快棕狐)
 */
@GetMapping(value = "/quickBrownFoxPDFA_1b", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> quickBrownFoxPDFA_1b() throws IOException {
    final String dog = "src/main/resources/img/dog.bmp";
    final String fox = "src/main/resources/img/fox.bmp";
    final String myFont = "src/main/resources/font/FreeSans.ttf";
    final String intent = "src/main/resources/color/sRGB_CS_profile.icm";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //Initialize PDFA document with output intent
    PdfADocument pdf = new PdfADocument(new PdfWriter(outputStream),
            PdfAConformanceLevel.PDF_A_1B,
            new PdfOutputIntent("Custom", "", "http://www.color.org",
                    "sRGB IEC61966-2.1", new FileInputStream(intent)));
    Document document = new Document(pdf);

    //Fonts need to be embedded
    PdfFont font = PdfFontFactory.createFont(myFont, PdfEncodings.WINANSI, PdfFontFactory.EmbeddingStrategy.FORCE_EMBEDDED);
    Paragraph p = new Paragraph();
    p.setFont(font);
    p.add(new Text("The quick brown "));
    Image foxImage = new Image(ImageDataFactory.create(fox));
    p.add(foxImage);
    p.add(" jumps over the lazy ");
    Image dogImage = new Image(ImageDataFactory.create(dog));
    p.add(dogImage);

    document.add(p);
    document.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

4)创建PDF,PDF/A-3a标准(美国信息)

PDF/A-3a: 允许将其他文件类型(如XML、CSV、JPEG等)嵌入到PDF文档中,同时保持PDF/A的规范和限制。PDF/A-3a通常用于长期保存和存档需要,例如电子发票、电子合同、电子档案等。

在这里插入图片描述

总之,PDF/A-1aPDF/A-1bPDF/A-3a 都是为了长期保存和存档而设计的 PDF 文件格式,它们各自具有特定的规范和限制,以确保文件的可靠性和一致性,同时也方便文档的长期保存和存档。

/**
 * 创建PDF,PDF/A-3a标准(快棕狐)
 */
@GetMapping(value = "/quickBrownFoxPDFA_3a", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> quickBrownFoxPDFA_3a() throws IOException {
    final String data = "src/main/resources/data/united_states.csv";
    final String myFont = "src/main/resources/font/FreeSans.ttf";
    final String boldFont = "src/main/resources/font/FreeSansBold.ttf";
    final String intent = "src/main/resources/color/sRGB_CS_profile.icm";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    PdfADocument pdf = new PdfADocument(new PdfWriter(outputStream),
            PdfAConformanceLevel.PDF_A_3A,
            new PdfOutputIntent("Custom", "", "http://www.color.org",
                    "sRGB IEC61966-2.1", new FileInputStream(intent)));
    Document document = new Document(pdf, PageSize.A4.rotate());
    document.setMargins(20, 20, 20, 20);

    //Setting some required parameters
    pdf.setTagged();
    pdf.getCatalog().setLang(new PdfString("en-US"));
    pdf.getCatalog().setViewerPreferences(
            new PdfViewerPreferences().setDisplayDocTitle(true));
    PdfDocumentInfo info = pdf.getDocumentInfo();
    info.setTitle("iText7 PDF/A-3 example");

    //Add attachment
    PdfDictionary parameters = new PdfDictionary();
    parameters.put(PdfName.ModDate, new PdfDate().getPdfObject());
    PdfFileSpec fileSpec = PdfFileSpec.createEmbeddedFileSpec(
            pdf, Files.readAllBytes(Paths.get(data)), "united_states.csv",
            "united_states.csv", new PdfName("text/csv"), parameters,
            PdfName.Data);
    fileSpec.put(new PdfName("AFRelationship"), new PdfName("Data"));
    pdf.addFileAttachment("united_states.csv", fileSpec);
    PdfArray array = new PdfArray();
    array.add(fileSpec.getPdfObject().getIndirectReference());
    pdf.getCatalog().put(new PdfName("AF"), array);

    //Embed fonts
    PdfFont font = PdfFontFactory.createFont(myFont, PdfFontFactory.EmbeddingStrategy.FORCE_EMBEDDED);
    PdfFont bold = PdfFontFactory.createFont(boldFont, PdfFontFactory.EmbeddingStrategy.FORCE_EMBEDDED);

    // Create content
    Table table = new Table(UnitValue.createPercentArray(new float[]{4, 1, 3, 4, 3, 3, 3, 3, 1}))
            .useAllAvailableWidth();

    BufferedReader br = new BufferedReader(new FileReader(data));
    String line = br.readLine();
    process(table, line, bold, true);
    while ((line = br.readLine()) != null) {
        process(table, line, font, false);
    }
    br.close();
    document.add(table);

    //Close document
    document.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

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().setHorizontalAlignment(HorizontalAlignment.CENTER).add(new Paragraph(tokenizer.nextToken()).setHorizontalAlignment(HorizontalAlignment.CENTER).setFont(font)));
        } else {
            table.addCell(new Cell().setHorizontalAlignment(HorizontalAlignment.CENTER).add(new Paragraph(tokenizer.nextToken()).setHorizontalAlignment(HorizontalAlignment.CENTER).setFont(font)));
        }
    }
}

5)根据PDF,合并PDF/A类文档(快棕狐+美国信息)

在这里插入图片描述

/**
 * 根据PDF,合并PDF/A类文档
 */
@GetMapping(value = "/mergePDFADocuments", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> mergePDFADocuments() throws IOException {
    final String intent = "src/main/resources/color/sRGB_CS_profile.icm";
    final String src1 = "src/main/resources/pdf/quick_brown_fox_PDFA-1a.pdf";
    final String src2 = "src/main/resources/pdf/united_states_PDFA-1a.pdf";

    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //Initialize PDFA document with output intent
    PdfADocument pdf = new PdfADocument(new PdfWriter(outputStream),
            PdfAConformanceLevel.PDF_A_1A,
            new PdfOutputIntent("Custom", "", "http://www.color.org",
                    "sRGB IEC61966-2.1", new FileInputStream(intent)));

    //Setting some required parameters
    pdf.setTagged();
    pdf.getCatalog().setLang(new PdfString("en-US"));
    pdf.getCatalog().setViewerPreferences(
            new PdfViewerPreferences().setDisplayDocTitle(true));
    PdfDocumentInfo info = pdf.getDocumentInfo();
    info.setTitle("iText7 PDF/A-1a example");

    //Create PdfMerger instance
    PdfMerger merger = new PdfMerger(pdf);
    //Add pages from the first document
    PdfDocument firstSourcePdf = new PdfDocument(new PdfReader(src1));
    merger.merge(firstSourcePdf, 1, firstSourcePdf.getNumberOfPages());
    //Add pages from the second pdf document
    PdfDocument secondSourcePdf = new PdfDocument(new PdfReader(src2));
    merger.merge(secondSourcePdf, 1, secondSourcePdf.getNumberOfPages());

    //Close the documents
    firstSourcePdf.close();
    secondSourcePdf.close();
    pdf.close();

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Disposition", "inline; filename=hello.pdf");
    return ResponseEntity.ok()
            .headers(headers)
            .contentType(MediaType.APPLICATION_PDF)
            .body(outputStream.toByteArray());
}

整理完毕,完结撒花~ 🌻

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/7676.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【云原生etcd】etcd的快速入门

在云计算时代&#xff0c;如何让服务快速透明地接入到计算集群中&#xff0c;如何让共享配置信息快速被集群中的所有机器发现&#xff0c;更为重要的是&#xff0c;如何构建这样一套高可用、安全、易于部署以及响 应快速的服务集群&#xff0c;已经成为了迫切需要解决的问题。目…

兆芯最新X86 CPU曝光:性能与英特尔/AMD相比,没落后10年

众所周知&#xff0c;在PC领域&#xff0c;X86完全是处于垄断地全的&#xff0c;至少占了90%以上的份额。其它的像MIPS、ARM、RISC-V等等&#xff0c;都不是X86的对手。 这与X86是复杂指令集有关&#xff0c;更与X86绑定了windows操作系统&#xff0c;有坚固的intel联盟有关&am…

多模态模型学习1——CLIP对比学习 语言-图像预训练模型

多模态模型学习1——CLIP对比学习 语言-图像预训练模型学习前言什么是CLIP模型代码下载CLIP实现思路一、网络结构介绍1、Image Encodera、PatchPosition Embeddingb、Transformer EncoderI、Self-attention结构解析II、Self-attention的矩阵运算III、MultiHead多头注意力机制IV…

美国Embarcadero公司2023年2月27日正式发布RAD Studio Delphi 11.3

Embarcadero很高兴地宣布发布RAD Studio 11 Alexandria Release 3&#xff0c;也称为RAD Studio 11.3&#xff0c;以及Delphi 11.3和CBuilder 11.3。此版本侧重于质量和改进&#xff0c;以RAD Studio 11 Alexandria三个先前版本中的强大新功能为基础。 RAD Studio 11.3包括对多…

BUUCTF-[GWCTF 2019]babyvm

题目下载&#xff1a;下载 这种简单vm逆向搞了快半辈子了&#xff0c;看别人wp也看的迷迷糊糊的&#xff0c;今天突然就看明白了&#xff0c;可能是受一个python虚拟机题的影响&#xff0c;第一次见vm&#xff0c;简单记录一下~ 参考&#xff1a;系统学习vm虚拟机逆向_43v3rY…

标准分布的累计分布函数的差分去模拟离散的高斯分布

标准分布的累计分布函数的差分去模拟离散的高斯分布如何理解图像生成中“标准分布的累积分布函数的差分去模拟离散的高斯分布”&#xff1f;discretized_gaussian_log_likelihoodcodeapprox_standard_normal_cdftanh激活函数标准正态分布的累积密度函数如何理解图像生成中“标准…

提高代码质量!详解在Gradle项目中使用PMD的正确姿势

当今的软件开发需要使用许多不同的工具和技术来确保代码质量和稳定性。PMD是一个流行的静态代码分析工具&#xff0c;可以帮助开发者在编译代码之前发现潜在的问题。在本文中&#xff0c;我们将讨论如何在Gradle中使用PMD&#xff0c;并介绍一些最佳实践。 什么是PMD&#xff…

国内智慧城市标准是怎样的?

我国智慧城市标准化工作的历史可以回溯至2013 年&#xff0c;相关工作也得到了国家标准委、中央网信办、发展改革委、工业和信息化部等部门的高度关注和支持&#xff0c;在标准化协调机制、国家标准研制实施等方面取得了积极进展。 北京智汇云舟科技有限公司成立于2012年&#…

【vSphere | Python】vSphere Automation SDK for Python Ⅲ—— vCenter Datacenter APIs

目录5. vCenter Datacenter APIs操作5.1 Create Datacenter5.2 List Datacenter5.3 Get Datacenter5.4 Delete Datacenter参考资料5. vCenter Datacenter APIs 数据中心服务&#xff08;Datacenter service&#xff09;提供管理 vCenter Server 中数据中心的操作。 操作 Cre…

新加坡电商系统上线指南

如果您正在考虑在新加坡开展电子商务业务并准备上线您的电商网站&#xff0c;以下是一些指南和建议&#xff0c;可以帮助您成功地启动和运营您的电商业务&#xff1a; 确认您的业务模式和目标市场。在上线之前&#xff0c;您需要确定您的业务模式&#xff0c;例如是B2B&#xf…

Python 进阶指南(编程轻松进阶):六、编写 Python 风格的代码

原文&#xff1a;http://inventwithpython.com/beyond/chapter6.html 强大对于编程语言来说是一个没有意义的形容词。每种编程语言都称自己长处。官方 Python 教程开头就说 Python 是一种简单易学、功能强大的编程语言。但是没有一种语言可以做另一种语言不能做的算法&#xff…

Robosense激光雷达Linux配置

文章目录1.1 速腾rs16连接&#xff1a;1.2 网络配置1&#xff09;官方说明2&#xff09;设置网络3&#xff09;检查是否连接成功2.1 激光雷达ROS包下载/编译1)下载ROS包2&#xff09;安装libpcap依赖3&#xff09;修改编译模式4&#xff09;config文件配置5&#xff09;编译并运…

AI-TestOps —— 软件测试工程师的一把利剑

写在前面软件测试的前世今生测试工具开始盛行AI-TestOps 云平台● AI-TestOps 功能模块● AI-TestOps 自动化测试流程写在前面 最近偶然间看到一句话&#xff1a;“软件测试是整个 IT 行业中最差的岗位”。这顿时激起了我对软件测试领域的兴趣&#xff0c;虽然之前未涉及过软件…

《Flutter进阶》flutter升级空安全遇到的一些问题及解决思路

空安全出来挺久了&#xff0c;由于业务需求较紧&#xff0c;一直没时间去升级空安全&#xff0c;最近花了几天去升级&#xff0c;发现其实升级也挺简单的&#xff0c;不要恐惧&#xff0c;没有想象中的多BUG。 flutter版本从1.22.4升到3.0.5&#xff1b; compileSdkVersion从1…

日撸 Java 三百行day11-13

文章目录说明day11-day12 顺序表1.面向过程面向对象区别2.代码2.1 面向过程2.2 面向对象day13 链表1.成员内部类2.链表的插入删除3.代码说明 闵老师的文章链接&#xff1a; 日撸 Java 三百行&#xff08;总述&#xff09;_minfanphd的博客-CSDN博客 自己也把手敲的代码放在了…

【51单片机】:LED任务及汇编解释任务

学习目标&#xff1a; 1、用汇编或者c语言实现D1 D3 D5 D7 为一组 &#xff1b;D2 D4 D6 D8 为一组 &#xff0c;两组实现 1&#xff09;一组亮约一秒 另一组灭一秒&#xff0c;这样的互闪现象五次后 25分 2&#xff09;所有灯灭约一秒后&#xff0c; …

关于ChatGPT的一些随笔

大家好&#xff0c;我是老三&#xff0c;最近几个月关于ChatGPT的信息可以说是铺天盖地。 “王炸&#xff0c;ChatGPT……” “xxx震撼发布……” “真的要失业了&#xff0c;xxx来袭……” “普通如何利用ChatGPT……” …… 不过老三前一阵比较忙&#xff0c;对ChatGPT…

ElasticSearch简介

第一章 ElasticSearch简介 1.1 什么是ElasticSearch Elaticsearch&#xff0c;简称为es&#xff0c; es是一个开源的高扩展的分布式全文检索引擎&#xff0c;它可以近乎实时的存储、检索数据&#xff1b;本身扩展性很好&#xff0c;可以扩展到上百台服务器&#xff0c;处理PB…

【数据结构与算法】树与二叉树

目录一.树1.树的定义2.结点的分类与关系3.树的相关概念4.树的表示方法二.二叉树1.二叉树的定义2.特殊二叉树3.二叉树的性质4.二叉树的顺序结构5.二叉树的链式结构(1)链式结构的创建(2)结点的创建(3)二叉树的手动构建(4)前中后序遍历(5)二叉树结点个数(6)二叉树的高度(7)第k层的…

Docker目录迁移

介绍 在docker的使用中随着下载镜像越来越多&#xff0c;构建镜像、运行容器越来越多, 数据目录必然会逐渐增大&#xff1b;当所有docker镜像、容器对磁盘的使用达到上限时&#xff0c;就需要对数据目录进行迁移。 如何避免&#xff1a; 1.在安装前对/var/lib/docker&#x…