最新要闻
- 【全球新要闻】老爸老妈浪漫史第五季(老爸老妈的浪漫史第五季结局是什么?)
- 爷青回!《灌篮高手》中国首映礼官宣:4月15日见
- 世界信息:快科技App 5.2.1新版发布:新增沉浸式阅读、排行榜一键分享长图
- 环球通讯!特斯拉下代电机不用稀土 国内专家:屁股决定脑袋 马斯克是迫不得已
- 今日聚焦!"全聚德连亏三年"登热搜:今年净亏损2.78亿元
- 时讯:iPhone 15 Pro相机凸起3.78毫米:约2枚1元硬币厚度
- 通讯!GGII:2022年中国锂电池回收处理废旧锂电池量41万吨,同比增37%
- 每日看点!电动牙刷别乱买 买错代价太大了
- 全球即时:小鹏P7迎整车OTA:6项新增功能 360全景影像正式上线
- 世界热消息:挑战不可能!阿维塔11在“8D山城”重庆开启城区NCA智驾导航辅助体验
- 汽车促销潮蔓延 车险会降价吗?业内人士:没有直接影响
- 环球时讯:成都双流现飞机“横穿马路” 网友:真“飞”机动车道
- 钦州白癜风专科医院哪个好-白癜风患者如何缓解压力
- 全国18省份都有扬沙浮尘天气!沙尘暴趁夜入京:口罩挡不住行人吃土
- 今日要闻!乘联会:汽车价格没崩盘 降价潮不存在
- 天天简讯:别回家充电!电动车爆炸致死楼上邻居 全国又有多起发生:实测起火后可怕
广告
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
环球聚焦:基于pdfbox实现的pdf添加文字水印工具
(相关资料图)
简述
最近有个需求需要给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水印"));}
关键词:
关于算法开源乱七八糟事
【报资讯】RDIF.vNext全新低代码快速开发框架平台发布
环球聚焦:基于pdfbox实现的pdf添加文字水印工具
【全球新要闻】老爸老妈浪漫史第五季(老爸老妈的浪漫史第五季结局是什么?)
爷青回!《灌篮高手》中国首映礼官宣:4月15日见
世界信息:快科技App 5.2.1新版发布:新增沉浸式阅读、排行榜一键分享长图
环球通讯!特斯拉下代电机不用稀土 国内专家:屁股决定脑袋 马斯克是迫不得已
今日聚焦!"全聚德连亏三年"登热搜:今年净亏损2.78亿元
时讯:iPhone 15 Pro相机凸起3.78毫米:约2枚1元硬币厚度
通讯!GGII:2022年中国锂电池回收处理废旧锂电池量41万吨,同比增37%
环球速讯:如何用Golang处理每分钟100万个请求
天天热点评!全网最详细中英文ChatGPT-GPT-4示例文档-步骤指示智能生成从0到1快速入门——官网推荐的48种最佳应用场景(附python/node.js
【高端访谈】“与时俱进”|绿债担保品管理驱动绿色金融体系建设升级——专访中央结算公司担保品业务负责人
每日看点!电动牙刷别乱买 买错代价太大了
全球即时:小鹏P7迎整车OTA:6项新增功能 360全景影像正式上线
世界热消息:挑战不可能!阿维塔11在“8D山城”重庆开启城区NCA智驾导航辅助体验
汽车促销潮蔓延 车险会降价吗?业内人士:没有直接影响
环球时讯:成都双流现飞机“横穿马路” 网友:真“飞”机动车道
钦州白癜风专科医院哪个好-白癜风患者如何缓解压力
通过Nginx定义Header头信息
全国18省份都有扬沙浮尘天气!沙尘暴趁夜入京:口罩挡不住行人吃土
今日要闻!乘联会:汽车价格没崩盘 降价潮不存在
天天简讯:别回家充电!电动车爆炸致死楼上邻居 全国又有多起发生:实测起火后可怕
热推荐:中科大研发镧系新型固态电解质 全固态锂金属电池新突破
每日消息!聚焦京津冀协同发展|培育农业品牌 让河北新鲜蔬菜装进北京“菜篮子”
【读财报】两年持有期基金回撤透视:广发、上投摩根基金等产品亏损幅度居前
四大证券报精华摘要:4月11日
机械鼠标看了心动?智商税别再交了!
特斯拉将取消强制单踏板模式 选择权终于交还用户
环球实时:江苏封杀“老头乐” 国内多省或效仿:倒逼大爷买新能源车、考驾照现实吗
每日热门:《GTA6》想超越“三男一狗”很难 三主角影响力太强
每日速看!学系统集成项目管理工程师(中项)系列04a_项目管理一般知识(上)
快看:大家可以来介绍家里杨过的过程,供大家参考吗?
环球热消息:国产战机大片《长空之王》新预告公布:看完热血
天天热推荐:重学c#系列—— 简单编写一个guid [娱乐篇]
环球热议:乘联会:新能源车绿牌2年内或消失 但不是因为它难看
全球热议:男子网购耐克鞋挂李宁吊牌?平台回应:员工绑错了
精选!工匠精神又崩了 日本知名寿司店常年用过期食材:肉眼看不出变色就能用
环球热点!迪士尼《小美人鱼》新剧照出炉:人鱼对比高颜值反派公主 你选谁?
特斯拉在韩推出Model S/X 比国内便宜 约64.85万元起
名记:法国足球可能给梅西颁发超级金球奖 历史仅1人获此荣誉
【世界快播报】台州多地发布事业单位招聘公告
每日快报!小程序开发,uni-app,XBuilder 学习资源
天天新动态:前端工程化实战:React 模块化开发、性能优化和组件化实践
每日时讯!ADMM——交替方向乘子法
全球速递!中小型项目请求限流设计
天天新消息丨电动车价格有得降!“白色石油”碳酸锂价格雪崩:有公司濒临破产
世界快资讯丨局地阵风10级!北京发布大风沙尘暴双黄色预警:空气质量严重污染
全球消息!解释一下布隆过滤器原理
世界通讯!mit 6.824 lab1分析
每日热点:AQS源码学习
环球播报:日本拉面店禁止边吃边看手机!店长给出的理由看醉了:有损厨师尊严
4个月了!AMD RX 7900 XTX旗舰卡终于降价:一度杀到6399元 降幅20%
世界快播:Nimo全球盛典圆满举行 提速布局全球化业务
最新:screenfetch报错 /usr/bin/screenfetch: 行 1851: -: 语法错误:需要操作数(错误记号是 "-") 的一种解决方法
天天精选!直线光栅化-Bresenham算法
当前观点:客车司机开车途中嗦粉吓坏乘客 双手离开方向盘:官方回应
HTC发布Wildfire入门级4G手机:国产展锐处理器、3G内存
焦点速看:中国人自己的智能车身控制系统!比亚迪云辇实现0-1突破:填补国内技术空白
全球时讯:比亚迪云辇发布 王传福:传统豪华看车标、新能源豪华看技术
全球车身控制技术最高水平:比亚迪U9搭云辇X“跳舞”登台
伊宝馨2022年净利3220.96万同比增长161.43% 销售规模增加
天天视讯!百度松果菁英班--oj赛(第一次)
观点:未势能源首发“木星”车载液氢储氢系统:一罐氢气续航超1000km
最新消息:你掉的不是头发 而是“钻石”!
世界速读:长辈送礼绝不踩坑!平仄普洱茶大促:高档礼盒装到手99元
就等小米13 Ultra发布了!米粉晒工资:称“资金已到位”
比亚迪云辇技术来了:四套系统 汽车会自己“看路”
焦点速读:Android开发_记事本(2)数据库
领失业金的年轻人,重新思考工作的意义
看点:北上高铁出现大规模晚点 官方回应:故障抢修完毕 有序恢复通行
环球快讯:马斯克离开OpenAI内幕:大权独揽想法被拒 10亿美元打水漂
形同灾难电影!四子王旗沙尘暴红警:天空变橙红色
全球时讯:好吃无负担:诺梵55%~100%黑巧巧克力9.9元大促
全球今头条!Windmill 搭建个人任务中心
环球微头条丨市建局协办活动 重塑龙城特色风情
环球快播:水平接近ChatGPT!昆仑万维国产大语言模型“天工”3.5来了
世界热门:《铁甲小宝》高清重制引热议 网友:这次好好看看小姐姐
苦等703天后 《生化危机8村庄》Denuvo加密移除:正版玩家终于不卡了
售价20多万续航仅160公里 日系车工业垃圾果然凉凉:今年只卖出15辆
环球新资讯:1TB手机干到2599元 手机降价原因找到了:闪存市场暴跌
欧菲光:公司已预约4月28日披露2022年度报告
天天最资讯丨借力函数计算 FC,HEROZ 打造专业级 AI 日本将棋服务
Excelize 发布 2.7.1 版本,Go 语言 Excel 文档基础库
环球今头条!WebAssembly 助力云原生:APISIX 如何借助 Wasm 插件实现扩展功能?
世界速看:记录-html-docs-js避坑指南
阿里正式加入ChatGPT战局,“通义千问”上线后表现如何?
全球消息!债市日报:4月10日
焦点关注:重磅!亚洲最大推力液体火箭发动机试车台调试完成
视焦点讯!堆料最足超大杯!小米13 Ultra确认可变光圈+全焦段四摄
全优大七座SUV!全新一代揽月正式上市 18.99万元起售
环球最新:2人观影全程用手机录制电影内容 目击者:中途还换了一个手机
米哈游《崩坏星穹铁道》姬子角色PV:成熟妩媚的大姐姐
今日快讯:“算力中国行”大型调研采访活动启动,将深入各地了解算力应用发展情况
天天日报丨刷题疑惑3
今日观点!TCP三次握手和四次挥手
【环球报资讯】收评:人工智能板块跳水 10只注册制主板新股大涨
播报:ChatGPT消除无聊的工作 诺奖得主:人类上四休三就靠AI
对标特斯拉Model Y 小鹏G6再放送 博主:兴奋起来吧、有电动尾翼
《名侦探柯南:黑铁的鱼影》新宣传图 成人版灰原哀太劲爆