基于pdfbox实现的pdf添加文字水印工具|焦点速看
发稿时间:2023-04-11 11:27:12 来源: 博客园
【资料图】
简述
最近有个需求需要给pdf加文字水印,于是开始搜索大法,但是发现网络上的代码基本都是将字体文件直接放在jar包里面。个人强迫症发作(手动狗头),想要像poi一样直接加载系统字体,于是研究了一下午pdfbox的源代码,发现FontFileFinder类可以实现这个功能。废话不多说,直接上代码。
引入依赖
org.apache.pdfbox pdfbox org.projectlombok lombok provided jakarta.servlet jakarta.servlet-api
新增水印配置类
@Data@NoArgsConstructorpublic class PdfWatermarkProperties { public PdfWatermarkProperties(String content) { this.content = content; } /** * 文字水印内容 */ private String content = ""; /** * ttf类型字体文件. 为null则使用默认字体 */ private File fontFile; private float fontSize = 13; /** * cmyk颜色.参数值范围为 0-255 */ private int[] color = {0, 0, 0, 210}; /** * 透明度 */ private float transparency = 0.3f; /** * 倾斜度. 默认30° */ private double rotate = 0.3; /** * 初始添加水印的点位 */ private int x = -10; private int y = 10; /** * 内容区域的宽高.即单个水印范围的大小 */ private int width = 200; private int height = 200;}
工具类
import org.apache.fontbox.ttf.TTFParser;import org.apache.fontbox.ttf.TrueTypeCollection;import org.apache.fontbox.ttf.TrueTypeFont;import org.apache.fontbox.util.autodetect.FontFileFinder;import org.apache.pdfbox.pdmodel.PDDocument;import org.apache.pdfbox.pdmodel.PDPage;import org.apache.pdfbox.pdmodel.PDPageContentStream;import org.apache.pdfbox.pdmodel.font.PDFont;import org.apache.pdfbox.pdmodel.font.PDType0Font;import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;import org.apache.pdfbox.util.Matrix;import javax.servlet.http.HttpServletResponse;import java.io.*;import java.net.URI;import java.net.URLEncoder;public class PdfUtil { private static final String DEFAULT_TTF_FILENAME = "simsun.ttf"; private static final String DEFAULT_TTC_FILENAME = "simsun.ttc"; private static final String DEFAULT_FONT_NAME = "SimSun"; private static final TrueTypeFont DEFAULT_FONT; static { DEFAULT_FONT = loadSystemFont(); } /** * 加载系统字体,提供默认字体 * * @return */ private synchronized static TrueTypeFont loadSystemFont() { //load 操作系统的默认字体. 宋体 FontFileFinder fontFileFinder = new FontFileFinder(); for (URI uri : fontFileFinder.find()) { try { final String filePath = uri.getPath(); if (filePath.endsWith(DEFAULT_TTF_FILENAME)) { return new TTFParser(false).parse(filePath); } else if (filePath.endsWith(DEFAULT_TTC_FILENAME)) { TrueTypeCollection trueTypeCollection = new TrueTypeCollection(new FileInputStream(filePath)); final TrueTypeFont font = trueTypeCollection.getFontByName(DEFAULT_FONT_NAME); //复制完之后关闭ttc trueTypeCollection.close(); return font; } } catch (Exception e) { throw new RuntimeException("加载操作系统字体失败", e); } } return null; } /** * 添加文本水印 * * 使用内嵌字体模式,pdf文件大小会增加1MB左右 * * @param sourceFile 需要加水印的文件 * @param descFile 目标存储路径 * @param props 水印配置 * @throws IOException */ public static void addTextWatermark(File sourceFile, String descFile, PdfWatermarkProperties props) throws IOException { // 加载PDF文件 PDDocument document = PDDocument.load(sourceFile); addTextToDocument(document, props); document.save(descFile); document.close(); } /** * 添加文本水印 * * @param inputStream 需要加水印的文件流 * @param outputStream 加水印之后的流。执行完之后会关闭outputStream, 建议使用{@link BufferedOutputStream} * @param props 水印配置 * @throws IOException */ public static void addTextWatermark(InputStream inputStream, OutputStream outputStream, PdfWatermarkProperties props) throws IOException { // 加载PDF文件 PDDocument document = PDDocument.load(inputStream); addTextToDocument(document, props); document.save(outputStream); } /** * 处理PDDocument,添加文本水印 * * @param document * @param props * @throws IOException */ public static void addTextToDocument(PDDocument document, PdfWatermarkProperties props) throws IOException { document.setAllSecurityToBeRemoved(true); // 遍历PDF文件,在每一页加上水印 for (PDPage page : document.getPages()) { PDPageContentStream stream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true); // 加载水印字体 if (DEFAULT_FONT == null) { throw new RuntimeException(String.format("未提供默认字体.请安装字体文件%s或%s", DEFAULT_TTF_FILENAME, DEFAULT_TTC_FILENAME)); } PDFont font; if (props.getFontFile() != null) { font = PDType0Font.load(document, props.getFontFile()); } else { //当TrueTypeFont为字体集合时, embedSubSet 需要设置为true, 嵌入其子集 font = PDType0Font.load(document, DEFAULT_FONT, true); } PDExtendedGraphicsState r = new PDExtendedGraphicsState(); // 设置透明度 r.setNonStrokingAlphaConstant(props.getTransparency()); r.setAlphaSourceFlag(true); stream.setGraphicsStateParameters(r); // 设置水印字体颜色 final int[] color = props.getColor(); stream.setNonStrokingColor(color[0], color[1], color[2], color[3]); stream.beginText(); stream.setFont(font, props.getFontSize()); // 获取PDF页面大小 float pageHeight = page.getMediaBox().getHeight(); float pageWidth = page.getMediaBox().getWidth(); // 根据纸张大小添加水印,30度倾斜 for (int h = props.getY(); h < pageHeight; h = h + props.getHeight()) { for (int w = props.getX(); w < pageWidth; w = w + props.getWidth()) { stream.setTextMatrix(Matrix.getRotateInstance(props.getRotate(), w, h)); stream.showText(props.getContent()); } } // 结束渲染,关闭流 stream.endText(); stream.restoreGraphicsState(); stream.close(); } } /** * 设置pdf文件输出的响应头 * * @param response web response * @param fileName 文件名(不含扩展名) */ public static void setPdfResponseHeader(HttpServletResponse response, String fileName) throws UnsupportedEncodingException { response.setContentType("application/pdf"); response.setCharacterEncoding("utf-8"); response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".pdf"); }}
测试
@GetMapping("/t")public void getFile(HttpServletResponse response) throws IOException { PdfUtil.setPdfResponseHeader(response, "watermark"); final ServletOutputStream out = response.getOutputStream(); PdfUtil.addTextWatermark(new FileInputStream("D:/测试文件.pdf"), out, new PdfWatermarkProperties("测试pdf水印"));}
- 基于pdfbox实现的pdf添加文字水印工具|焦点速看
- 黎明觉醒作战特训答案分享_世界速递
- 张江已集聚近百家细胞与基因企业 张江基因岛即将投用
- 广东将打造万亿世界级食品制造贸易高地
- 广西最大海气登陆管道项目正式投用-全球速递
- 焦点热议:天津57个重点项目已获政策性金融支持 授信金额超过1353亿元
- 北向资金净买入超20亿元-世界新消息
- 世界观点:2023国考国家文物局考试录用公务员面试递补公告(二)
- 2023浙江金融职业学院招聘14人公告(2023年第二批)
- 2023浙江商业职业技术学院招聘7人公告(2023年第二批) 全球微动态
- 1158万人!今年高校毕业生数量再创历史新高!找工作更难了..._全球快看点
- 天天热文:宝马集团将携史上最强电动化阵容亮相上海
- 比姆总还狂。1.2亿球星本性暴露,皇马引援紧急刹车,4将迎来春天-全球快播报
- 泰山奇葩赛程内幕曝光:是文旅自己要求的,众明星空降,中超让路
- 天天即时:?新赛季中超实行“升二降二”
- 全球速递!旅游餐饮板块强势拉升,曲江文旅等涨停,五一出游订单量暴增
- 统计局:3月CPI同比上涨0.7% 环比下降0.3%_全球快播
- 半导体板块震荡走强 恒烁股份20%涨停
- 环球观察:不合格率10.2% 市场监管总局抽查400家企业农业生产资料产品
- 鼎龙股份2022年营收净利双增长 重点聚焦半导体创新材料领域
- 环球微速讯:马丁·沃尔夫:银行业危机,不只是央行的锅
- 怀孕可以吃芒果吗_孕妇吃芒果要注意什么-焦点播报
- 电子商务专业前景(电子商务前景好吗)|环球快报
- 梅妻鹤子打一动物(梅妻鹤子是指什么生肖?)|全球快看
- mk是什么牌子(mk是什么牌子?)
- 两市ETF两融余额减少2.01亿元
- 沪市主板公司去年披露56单重大资产重组 产业整合占比约六成|天天新消息
- 百亿级投资!400亿赛道巨头大手笔|世界资讯
- 养老金2022年四季度新进4只科创板股 增持3股 播资讯
- 环球聚焦:3月份工业生产者出厂价格同比下降2.5% 环比持平
延伸阅读
创业