Springboot 整合 itext 实现PDF文件合并,识别图片则转成PDF拼接

目录


前言

本文实现 Springboot 整合 itext 实现PDF文件合并,图片转PDF拼接。


一、引用依赖

xml 复制代码
<dependency>
     <groupId>com.itextpdf</groupId>
     <artifactId>itext7-core</artifactId>
     <version>8.0.5</version>
     <type>pom</type>
</dependency>

二、使用步骤

1.Controller

代码如下(示例):

java 复制代码
import com.ruoyi.tools.service.IPdfHandlerService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.util.List;

@RestController
@RequiredArgsConstructor
@RequestMapping("/pdf")
public class PdfHandlerController {

private final IPdfHandlerService pdfHandlerService;

@PostMapping(value = "/generateFromFiles", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public void uploadFiles(@RequestPart("files") List<MultipartFile> files, HttpServletResponse response) throws Exception {
    byte[] pdfBytes = pdfHandlerService.generatePdfFromFiles(files);
    response.setContentType("application/pdf");
    response.setContentLength(pdfBytes.length);
    //把字节数组写入输出流中
    response.getOutputStream().write(pdfBytes);
}

2.Service接口

java 复制代码
import org.springframework.web.multipart.MultipartFile;
import java.util.List;

public interface IPdfHandlerService {

    byte[] generatePdfFromFiles(List<MultipartFile> files);
}

3.实现类

java 复制代码
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.ruoyi.tools.service.IPdfHandlerService;
import lombok.SneakyThrows;
import org.apache.commons.io.FilenameUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.List;

@Service
public class PdfHandlerServiceImpl implements IPdfHandlerService {

    @SneakyThrows
    public byte[] generatePdfFromFiles(List<MultipartFile> files) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PdfWriter writer = new PdfWriter(baos);
        PdfDocument pdfDoc = new PdfDocument(writer);
        Document document = new Document(pdfDoc);

        for (MultipartFile file : files) {
            if (isPdf(file)) {
                PdfDocument sourcePdf = new PdfDocument(new PdfReader(file.getInputStream()));
                int n = sourcePdf.getNumberOfPages();
                for (int i = 1; i <= n; i++) {
                    PdfPage page = sourcePdf.getPage(i);
                    PdfFormXObject pageCopy = page.copyAsFormXObject(pdfDoc);
                    Rectangle pageSize = page.getPageSize();

                    PdfPage newPage = pdfDoc.addNewPage();
                    newPage.setMediaBox(pageSize);
                    new PdfCanvas(newPage).addXObjectAt(pageCopy, 0, 0);
                    newPage.setRotation(page.getRotation());
                }
                sourcePdf.close();
                continue;
            }

            if (isImage(file)) {
                // 创建一个新的 A4 页面
                PdfPage newPage = pdfDoc.addNewPage(PageSize.A4);
                Image img = new Image(ImageDataFactory.create(file.getBytes()));
                // 设置图片大小以适应 A4 页面
                img.scaleToFit(PageSize.A4.getWidth(), PageSize.A4.getHeight());
                // 获取当前页面编号
                int pageNumber = pdfDoc.getNumberOfPages();
                // 设置图片位置为页面中心
                img.setFixedPosition(pageNumber,
                    (PageSize.A4.getWidth() - img.getImageScaledWidth()) / 2,
                    (PageSize.A4.getHeight() - img.getImageScaledHeight()) / 2);
                // 添加图片到文档
                document.add(img);
                continue;
            }

            //可以删掉此提示
            document.add(new Paragraph(file.getOriginalFilename() + "仅支持PDF和图片的拼接"));

        }

        document.close();
        return baos.toByteArray();
    }

    @SneakyThrows
    private boolean isPdf(MultipartFile file) {
        String contentType = file.getContentType();
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());

        if (contentType != null && contentType.equals("application/pdf")) {
            return true;
        }

        if ("pdf".equalsIgnoreCase(extension)) {
            byte[] fileHeader = new byte[4];
            try (ByteArrayInputStream bis = new ByteArrayInputStream(file.getBytes())) {
                int bytesRead = bis.read(fileHeader);
                if (bytesRead != fileHeader.length) {
                    return false;
                }
            }
            return new String(fileHeader).startsWith("%PDF");
        }

        return false;
    }

    @SneakyThrows
    private boolean isImage(MultipartFile file) {
        String contentType = file.getContentType();
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());

        if (contentType != null && contentType.startsWith("image")) {
            return true;
        }

        if (extension != null) {
            switch (extension.toLowerCase()) {
                case "jpg":
                case "jpeg":
                case "png":
                case "gif":
                case "bmp":
                    return true;
                default:
                    return false;
            }
        }

        return false;
    }

}

三、请求接口及结果

http://localhost:8080/pdf/generateFromFiles

相关推荐
qq_17448285751 小时前
springboot基于微信小程序的旧衣回收系统的设计与实现
spring boot·后端·微信小程序
锅包肉的九珍1 小时前
Scala的Array数组
开发语言·后端·scala
心仪悦悦1 小时前
Scala的Array(2)
开发语言·后端·scala
2401_882727572 小时前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架
心仪悦悦2 小时前
Scala中的集合复习(1)
开发语言·后端·scala
代码小鑫3 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计
真心喜欢你吖3 小时前
SpringBoot与MongoDB深度整合及应用案例
java·spring boot·后端·mongodb·spring
激流丶3 小时前
【Kafka 实战】Kafka 如何保证消息的顺序性?
java·后端·kafka
周全全3 小时前
Spring Boot + Vue 基于 RSA 的用户身份认证加密机制实现
java·vue.js·spring boot·安全·php
uzong4 小时前
一个 IDEA 老鸟的 DEBUG 私货之多线程调试
java·后端