[itext7] Use itext7 to merge multiple PDF files and pictures into one PDF file, rotate and zoom the pictures

This article mainly introduces the use of itext7 to merge multiple PDF files and pictures into one PDF file, image rotation, and image scaling.

Table of contents

1. itext7 merge PDF

1.1. Introducing dependencies

1.2. Introduction to merging PDFs

1.3. Read PDF files using byte array method

1.4. Merge multiple PDF files

1.5. Merge images into PDF files

1.6. Rotate pictures

1.7. Complete case code

(1) PDFUtil tool class

(2) Test code

(3) Merger effect


1. itext7 merge PDF

1.1. Introducing dependencies

I am using itext-core version 7.1.16 here. I only need to introduce an itext-core dependency, because this dependency has already introduced the dependencies required by itext for us.

<!-- 引入 itext7-core 依赖 -->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext7-core</artifactId>
    <version>7.1.16</version>
    <type>pom</type>
</dependency>

1.2. Introduction to merging PDFs

The simplest way to merge is to read two PDF files and then merge them into a new PDF file. After saving it to the server, merge this new PDF file with the next PDF file to be merged. By analogy, you can finally get a complete PDF file. However, the disadvantage of this method is that after each merge, a new PDF file needs to be generated, and after the next merge, the PDF file must be read again. This is It will lead to the process of reading the file multiple times, and the efficiency is not very ideal.

In this article, I mainly read the PDF into the memory as a byte array, and then merge the byte data of the two PDFs in the memory. This can reduce the number of reading and generating PDF files, and the execution efficiency will also be improved. Even better, the method of merging two PDF byte arrays is as follows:

/**
 * 基于内存中的字节数组进行PDF文档的合并
 * @param firstPdf 第一个PDF文档
 * @param secondPdf 第二个PDF文档
 */
private static byte[] mergePdfBytes(byte[] firstPdf, byte[] secondPdf) throws IOException {
    if (firstPdf != null && secondPdf != null) {
        // 创建字节数组,基于内存进行合并
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PdfDocument destDoc = new PdfDocument(new PdfWriter(baos));
        // 合并的pdf文件对象
        PdfDocument firstDoc = new PdfDocument(new PdfReader(new ByteArrayInputStream(firstPdf)));
        PdfDocument secondDoc = new PdfDocument(new PdfReader(new ByteArrayInputStream(secondPdf)));
        // 合并对象
        PdfMerger merger = new PdfMerger(destDoc);
        merger.merge(firstDoc, 1, firstDoc.getNumberOfPages());
        merger.merge(secondDoc, 1, secondDoc.getNumberOfPages());
        // 关闭文档流
        merger.close();
        firstDoc.close();
        secondDoc.close();
        destDoc.close();
        return baos.toByteArray();
    }
    return null;
}

1.3. Read PDF files using byte array method

When merging PDF files, some PDF files may be on the network, and some may be on the local disk, so you need to make a judgment here. If they are PDF files on the network, you need to access the network first, and then save them to the PDF file. In the section array, if it is a local disk file, you need to read the local file.

/**
 * 将pdf文档转换成字节数组
 * @param pdf PDF文档路径
 * @return 返回对应PDF文档的字节数组
 */
private static byte[] getPdfBytes(String pdf) throws Exception {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    InputStream is;
    if (pdf.startsWith("http://") || pdf.startsWith("https://")) {
        is = new URL(pdf).openStream();
    } else {
        is = new FileInputStream(pdf);
    }
    byte[] data = new byte[2048];
    int len;
    while ((len = is.read(data)) != -1) {
        out.write(data, 0, len);
    }
    return out.toByteArray();
}

1.4. Merge multiple PDF files

When merging PDFs, just pass the path of the PDF files that need to be merged. Call the following method to complete the merge.

/**
 * 将给定List集合中的pdf文档,按照顺序依次合并,生成最终的目标PDF文档
 * @param pdfPathLists 待合并的PDF文档路径集合,可以是本地PDF文档,也可以是网络上的PDF文档
 * @param destPath 目标合并生成的PDF文档路径
 */
public static boolean mergeMultiplePdfs(List<String> pdfPathLists, String destPath) {
    try {
        int size = pdfPathLists.size();
        byte[] pdfData = getPdfBytes(pdfPathLists.get(0));
        for (int i = 1; i < size; i++) {
            pdfData = mergePdfBytes(pdfData, getPdfBytes(pdfPathLists.get(i)));
        }
        if (pdfData != null) {
            FileOutputStream fis = new FileOutputStream(destPath);
            fis.write(pdfData);
            fis.close();
        }
        return true;
    } catch (Exception e) {
        logger.error("合并PDF异常:", e);
    }
    return false;
}

1.5. Merge images into PDF files

How to merge pictures into PDF files? ? ? Here I added the picture directly to the blank page of the PDF file. One picture occupies one page. Of course, you can also set it to be displayed on the same page. After the page height is exceeded, the picture will automatically be displayed on the next page.

/**
 * 将给定集合中的图片合并到一个pdf文档里面
 * @param imagePathList 图片路径集合
 * @param destPath 合并之后的PDF文档
 */
public static boolean mergeImagesToPdf(List<String> imagePathList, String destPath) {
    try {
        PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destPath));
        Document document = new Document(pdfDocument);
        if (imagePathList != null && imagePathList.size() > 0) {
            int size = imagePathList.size();
            for (int i = 0; i < size; i++) {
                String imgPath = imagePathList.get(i);
                ImageData imageData;
                if (imgPath.startsWith("http://") || imgPath.startsWith("https://")) {
                    imageData = ImageDataFactory.create(new URL(imgPath));
                } else {
                    imageData = ImageDataFactory.create(imgPath);
                }
                Image image = new Image(imageData);
                /*
                    设置旋转的弧度值,默认是逆时针旋转的。
                    弧度、角度换算公式:
                    1° = PI / 180°
                    1 rad = 180° / PI
                */
                image.setRotationAngle(- Math.PI / 2); // 顺时针旋转90°
                // 设置图片自动缩放,即:图片宽高自适应
                image.setAutoScale(true);
                document.add(image);
                if (i != size - 1) {
                    // 最后一页不需要新增空白页
                    document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
                }
            }
        }
        pdfDocument.close();
        return true;
    } catch (Exception e) {
        logger.error("合并图片到PDF异常:", e);
    }
    return false;
}

1.6. Rotate pictures

Under certain requirements, you may want to place certain pictures vertically and some pictures horizontally. At this time, you can call the [setRotationAngle()] method of the [Image] picture object in itext7 to rotate it. , it should be noted that: the setRotationAngle method sets the rotation arc, not the rotation angle, and it rotates counterclockwise. There is a conversion formula between radians and degrees as follows:

1.7. Complete case code

(1) PDFUtil tool class

package com.gitcode.itext.util;

import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.utils.PdfMerger;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.AreaBreak;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.property.AreaBreakType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.URL;
import java.util.List;

/**
 * @version 1.0.0
 * @Date: 2023/10/04 10:07
 * @Author ZhuYouBin
 * @Description: PDF工具类【基于 itext7 组件实现】
 */
public class PDFUtil {
    private static final Logger logger = LoggerFactory.getLogger(PDFUtil.class);

    /**
     * 将给定List集合中的pdf文档,按照顺序依次合并,生成最终的目标PDF文档
     * @param pdfPathLists 待合并的PDF文档路径集合,可以是本地PDF文档,也可以是网络上的PDF文档
     * @param destPath 目标合并生成的PDF文档路径
     */
    public static boolean mergeMultiplePdfs(List<String> pdfPathLists, String destPath) {
        try {
            int size = pdfPathLists.size();
            byte[] pdfData = getPdfBytes(pdfPathLists.get(0));
            for (int i = 1; i < size; i++) {
                pdfData = mergePdfBytes(pdfData, getPdfBytes(pdfPathLists.get(i)));
            }
            if (pdfData != null) {
                FileOutputStream fis = new FileOutputStream(destPath);
                fis.write(pdfData);
                fis.close();
            }
            return true;
        } catch (Exception e) {
            logger.error("合并PDF异常:", e);
        }
        return false;
    }

    /**
     * 将给定集合中的图片合并到一个pdf文档里面
     * @param imagePathList 图片路径集合
     * @param destPath 合并之后的PDF文档
     */
    public static boolean mergeImagesToPdf(List<String> imagePathList, String destPath) {
        try {
            PdfDocument pdfDocument = new PdfDocument(new PdfWriter(destPath));
            Document document = new Document(pdfDocument);
            if (imagePathList != null && imagePathList.size() > 0) {
                int size = imagePathList.size();
                for (int i = 0; i < size; i++) {
                    String imgPath = imagePathList.get(i);
                    ImageData imageData;
                    if (imgPath.startsWith("http://") || imgPath.startsWith("https://")) {
                        imageData = ImageDataFactory.create(new URL(imgPath));
                    } else {
                        imageData = ImageDataFactory.create(imgPath);
                    }
                    Image image = new Image(imageData);
                    /*
                        设置旋转的弧度值,默认是逆时针旋转的。
                        弧度、角度换算公式:
                        1° = PI / 180°
                        1 rad = 180° / PI
                    */
                    image.setRotationAngle(- Math.PI / 2); // 顺时针旋转90°
                    // 设置图片自动缩放,即:图片宽高自适应
                    image.setAutoScale(true);
                    document.add(image);
                    if (i != size - 1) {
                        // 最后一页不需要新增空白页
                        document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
                    }
                }
            }
            pdfDocument.close();
            return true;
        } catch (Exception e) {
            logger.error("合并图片到PDF异常:", e);
        }
        return false;
    }

    /**
     * 基于内存中的字节数组进行PDF文档的合并
     * @param firstPdf 第一个PDF文档
     * @param secondPdf 第二个PDF文档
     */
    private static byte[] mergePdfBytes(byte[] firstPdf, byte[] secondPdf) throws IOException {
        if (firstPdf != null && secondPdf != null) {
            // 创建字节数组,基于内存进行合并
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            PdfDocument destDoc = new PdfDocument(new PdfWriter(baos));
            // 合并的pdf文件对象
            PdfDocument firstDoc = new PdfDocument(new PdfReader(new ByteArrayInputStream(firstPdf)));
            PdfDocument secondDoc = new PdfDocument(new PdfReader(new ByteArrayInputStream(secondPdf)));
            // 合并对象
            PdfMerger merger = new PdfMerger(destDoc);
            merger.merge(firstDoc, 1, firstDoc.getNumberOfPages());
            merger.merge(secondDoc, 1, secondDoc.getNumberOfPages());
            // 关闭文档流
            merger.close();
            firstDoc.close();
            secondDoc.close();
            destDoc.close();
            return baos.toByteArray();
        }
        return null;
    }

    /**
     * 将pdf文档转换成字节数组
     * @param pdf PDF文档路径
     * @return 返回对应PDF文档的字节数组
     */
    private static byte[] getPdfBytes(String pdf) throws Exception {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        InputStream is;
        if (pdf.startsWith("http://") || pdf.startsWith("https://")) {
            is = new URL(pdf).openStream();
        } else {
            is = new FileInputStream(pdf);
        }
        byte[] data = new byte[2048];
        int len;
        while ((len = is.read(data)) != -1) {
            out.write(data, 0, len);
        }
        return out.toByteArray();
    }
}

(2) Test code

package com.gitcode.itext;

import com.gitcode.itext.util.PDFUtil;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;

/**
 * @version 1.0.0
 * @Date: 2023/10/4 11:12
 * @Author ZhuYouBin
 * @Description:
 */
public class ImageDemo {
    public static void main(String[] args) throws FileNotFoundException {
        // 图片合并之后生成的PDF路径
        String imagePath = "F:\\pdf-demo\\imagePath.pdf";
        List<String> imageList = new ArrayList<>();
        imageList.add("F:\\pdf-demo\\01.jpg");
        imageList.add("F:\\pdf-demo\\02.jpg");
        // 先合并图片
        PDFUtil.mergeImagesToPdf(imageList, imagePath);

        // 在合并PDF
        String destPath = "F:\\pdf-demo\\merge.pdf";
        List<String> pdfPath = new ArrayList<>();
        pdfPath.add("F:\\pdf-demo\\demo01.pdf");
        pdfPath.add("F:\\pdf-demo\\demo02.pdf");
        pdfPath.add(imagePath);
        PDFUtil.mergeMultiplePdfs(pdfPath, destPath);
    }
}

(3) Merger effect

At this point, the introduction to itext7 merging PDF files is complete.

In summary, this article is over. It mainly introduces the use of itext7 to merge multiple PDF files and pictures into one PDF file, image rotation, and image scaling.

Guess you like

Origin blog.csdn.net/qq_39826207/article/details/133549488