当前位置: 代码网 > it编程>编程语言>Java > Java实现PDF批量处理之合并、拆分、加水印的技术方案与实践

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

2026年02月11日 Java 我要评论
一、技术选型java生态中处理pdf的库主要有以下几个:| 库名 | 特点 | 适用场景 ||------|------|----------|| apache pdfbox | 开源免费,功能全面

一、技术选型

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 注意事项

  • 内存管理:处理大文件时建议使用setuptempfileonly()将临时数据写入磁盘,避免oom
  • 文件顺序:合并顺序取决于addsource的调用顺序,前端可通过拖拽排序来控制
  • 书签处理:合并后原有书签可能丢失,如需保留需额外处理pddocumentoutline

四、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(如上千页),逐页操作可能较慢。可以考虑:

  • 使用splitter类的setsplitatpage()方法按固定页数批量拆分
  • 对于仅需提取少量页面的场景,直接操作页面树比使用splitter更高效

五、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文档的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com