java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java批量处理PDF文档

Java实现PDF批量处理之合并、拆分、加水印的技术方案与实践

作者:用户3891775626958

在日常开发中,PDF文档处理是一个高频需求,无论是合同管理系统需要合并多份PDF,还是报表系统需要按页拆分,亦或是给机密文档添加水印,都需要一套可靠的PDF处理方案,本文将分享基于Java技术栈实现PDF批量处理的核心思路与代码实践,需要的朋友可以参考下

一、技术选型

Java生态中处理PDF的库主要有以下几个:

| 库名 | 特点 | 适用场景 |

|------|------|----------|

| Apache PDFBox | 开源免费,功能全面 | 合并、拆分、水印、文本提取 |

| iText | 功能强大,商用需授权 | 复杂PDF生成、表单处理 |

| OpenPDF | iText的开源分支 | 轻量级PDF生成 |

综合考虑开源协议和功能覆盖度,Apache PDFBox 是大多数项目的首选。

二、Maven依赖配置

<dependency>

<groupId>org.apache.pdfbox</groupId>

<artifactId>pdfbox</artifactId>

<version>2.0.27</version>

</dependency>

三、PDF合并实现

3.1 核心思路

PDF合并的本质是将多个PDF文档的页面按顺序追加到一个新文档中。PDFBox提供了PDFMergerUtility工具类来简化这个过程。

3.2 代码实现

import org.apache.pdfbox.multipdf.PDFMergerUtility;

import java.io.*;

import java.util.List;

  


public class PdfMergeService {

  


/**

* 合并多个PDF文件

* @param inputStreams PDF文件输入流列表

* @param outputPath 输出文件路径

*/

public void mergePdf(List<InputStream> inputStreams, String outputPath)

throws IOException {

PDFMergerUtility merger = new PDFMergerUtility();

merger.setDestinationFileName(outputPath);

  


for (InputStream is : inputStreams) {

merger.addSource(is);

}

  


// 执行合并,MemoryUsageSetting可控制内存使用

merger.mergeDocuments(

org.apache.pdfbox.io.MemoryUsageSetting.setupMainMemoryOnly()

);

}

}

3.3 注意事项

四、PDF拆分实现

4.1 按页码范围拆分

import org.apache.pdfbox.multipdf.Splitter;

import org.apache.pdfbox.pdmodel.PDDocument;

  


public class PdfSplitService {

  


/**

* 按页码范围拆分PDF

* @param inputStream 源PDF输入流

* @param startPage 起始页(从1开始)

* @param endPage 结束页

*/

public byte[] splitByPageRange(InputStream inputStream,

int startPage, int endPage) throws IOException {

  


try (PDDocument document = PDDocument.load(inputStream);

PDDocument newDoc = new PDDocument()) {

  


int totalPages = document.getNumberOfPages();

// 参数校验

startPage = Math.max(1, startPage);

endPage = Math.min(totalPages, endPage);

  


for (int i = startPage - 1; i < endPage; i++) {

newDoc.addPage(document.getPage(i));

}

  


ByteArrayOutputStream baos = new ByteArrayOutputStream();

newDoc.save(baos);

return baos.toByteArray();

}

}

}

4.2 性能优化建议

对于页数很多的PDF(如上千页),逐页操作可能较慢。可以考虑:

五、PDF加水印实现

5.1 文字水印核心代码

import org.apache.pdfbox.pdmodel.*;

import org.apache.pdfbox.pdmodel.font.PDType1Font;

import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;

import org.apache.pdfbox.util.Matrix;

  


public class PdfWatermarkService {

  


public byte[] addTextWatermark(InputStream input, String text,

float opacity, float rotation, float fontSize) throws IOException {

  


try (PDDocument document = PDDocument.load(input)) {

// 遍历每一页添加水印

for (PDPage page : document.getPages()) {

PDPageContentStream cs = new PDPageContentStream(

document, page,

PDPageContentStream.AppendMode.APPEND, true, true

);

  


// 设置透明度

PDExtendedGraphicsState gs = new PDExtendedGraphicsState();

gs.setNonStrokingAlphaConstant(opacity);

cs.setGraphicsStateParameters(gs);

  


// 设置字体和颜色

cs.setFont(PDType1Font.HELVETICA_BOLD, fontSize);

cs.setNonStrokingColor(200, 200, 200); // 浅灰色

  


// 计算页面中心位置

float pageWidth = page.getMediaBox().getWidth();

float pageHeight = page.getMediaBox().getHeight();

float cx = pageWidth / 2;

float cy = pageHeight / 2;

  


// 旋转变换

cs.beginText();

Matrix matrix = Matrix.getRotateInstance(

Math.toRadians(rotation), cx, cy

);

cs.setTextMatrix(matrix);

cs.showText(text);

cs.endText();

cs.close();

}

  


ByteArrayOutputStream baos = new ByteArrayOutputStream();

document.save(baos);

return baos.toByteArray();

}

}

}

5.2 中文水印的坑

PDFBox默认的PDType1Font不支持中文字符,直接使用会导致乱码或报错。解决方案:

// 加载系统中文字体

PDType0Font chineseFont = PDType0Font.load(document,

new FileInputStream("/usr/share/fonts/wqy-microhei/wqy-microhei.ttc"), 0);

cs.setFont(chineseFont, fontSize);

服务器部署时需确保安装了中文字体

# CentOS/RHEL

sudo yum install -y wqy-microhei-fonts

# Ubuntu/Debian

sudo apt-get install -y fonts-wqy-microhei

六、封装为REST API

在Spring Boot项目中,可以将上述功能封装为统一的REST接口:

@RestController

@RequestMapping("/api/document/pdf")

public class PdfController {

  


@PostMapping("/merge")

public ResponseEntity<?> merge(

@RequestParam("files") MultipartFile[] files) {

// 调用合并服务

}

  


@PostMapping("/split")

public ResponseEntity<?> split(

@RequestParam("file") MultipartFile file,

@RequestParam("startPage") int startPage,

@RequestParam("endPage") int endPage) {

// 调用拆分服务

}

  


@PostMapping("/watermark")

public ResponseEntity<?> watermark(

@RequestParam("file") MultipartFile file,

@RequestParam("text") String text,

@RequestParam(defaultValue = "0.5") float opacity) {

// 调用水印服务

}

}

七、实际效果

如果你不想自己搭建服务,也可以直接使用现成的在线工具来处理PDF。比如 轻语API开放平台 提供了免费的 PDF在线处理工具,支持合并、拆分、加水印、转Word、转图片等功能,底层就是基于上述技术方案实现的。

对于需要批量处理的场景,也可以通过API接口集成到自己的系统中,省去重复造轮子的成本。

八、总结

| 功能 | 核心类/方法 | 难点 |

|------|------------|------|

| PDF合并 | PDFMergerUtility | 大文件内存管理 |

| PDF拆分 | PDDocument.getPage() | 页码边界校验 |

| PDF水印 | PDPageContentStream | 中文字体支持 |

PDF处理看似简单,但在生产环境中需要关注内存控制、字体兼容、并发处理等问题。希望本文的实践经验能帮助你少踩一些坑。

以上就是Java实现PDF批量处理之合并、拆分、加水印的技术方案与实践的详细内容,更多关于Java批量处理PDF文档的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文