pdfbox 《PDF加水印、PDF转图片、PDF附加图片》
引入依赖
<dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.24</version> </dependency>
配置文件
PdfWatermarkProperties.java
package com.teamcenter.utils; import java.io.File; public class PdfWatermarkProperties { /** * 文字水印内容 */ private String content = ""; /** * ttf类型字体文件. 为null则使用默认字体 */ private File fontFile; private float fontSize = 16; /** * cmyk颜色.参数值范围为 0-255 */ private int[] color = {0, 0, 0, 210}; /** * 透明度 */ private float transparency = 0.3f; /** * 倾斜度. 默认30° */ // private double rotate = 0.3; private double rotate = 0; /** * 初始添加水印的点位 */ private int x = 10; private int y = 10; /** * 内容区域的宽高.即单个水印范围的大小 */ private int width = 200; private int height = 200; public PdfWatermarkProperties() { } public PdfWatermarkProperties(String content) { this.content = content; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public File getFontFile() { return fontFile; } public void setFontFile(File fontFile) { this.fontFile = fontFile; } public float getFontSize() { return fontSize; } public void setFontSize(float fontSize) { this.fontSize = fontSize; } public int[] getColor() { return color; } public void setColor(int[] color) { this.color = color; } public float getTransparency() { return transparency; } public void setTransparency(float transparency) { this.transparency = transparency; } public double getRotate() { return rotate; } public void setRotate(double rotate) { this.rotate = rotate; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } }
工具类
PdfUtil.java
package com.teamcenter.utils; 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.image.PDImageXObject; import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState; import org.apache.pdfbox.rendering.PDFRenderer; import org.apache.pdfbox.text.PDFTextStripper; import org.apache.pdfbox.util.Matrix; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.*; import java.net.URI; import java.nio.file.Files; import java.nio.file.Paths; /** * PDFUtil */ 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; private static final String PNG_WITH_DOT=".png"; private static final String PNG="png"; private static final String UNDER_LINE="_"; 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.saveIncremental(new FileOutputStream(new File(descFile))); 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 file * @return content string for pdf */ public static String readPdf(File file){ try(PDDocument pdfDoc = PDDocument.load(file)){ //新建文件玻璃器 PDFTextStripper stripper = new PDFTextStripper(); //获取总页数 int numberOfPages = pdfDoc.getNumberOfPages(); //默认为false true=>按看到的顺序读取 false=>按顺序写入 读取 stripper.setSortByPosition(false); //从第几页读取,默认为第一页 stripper.setStartPage(1); stripper.setEndPage(numberOfPages); return stripper.getText(pdfDoc); }catch (Exception e){ e.printStackTrace(); } return null; } /** * 图片转换 * @param file */ public static void toImage(File file){ try(PDDocument pdfDoc = PDDocument.load(file)){ PDFRenderer renderer = new PDFRenderer(pdfDoc); // 获取总页数量 int numberOfPages = pdfDoc.getNumberOfPages(); // 获取文件名称(没有后缀) String baseName = PdfUtil.getFileName(file); //再文件所在目录下创建同名目录 File imageFolder = PdfUtil.createImageFolder(file, baseName); //文件名称公共前缀 String imgPrefix = baseName+UNDER_LINE; //每页生成独立的png文件 for (int i = 1; i <= numberOfPages; i++) { String imageName = imgPrefix+i+PNG_WITH_DOT; File destFile = new File(imageFolder,imageName); BufferedImage bufferedImage = renderer.renderImageWithDPI(i-1, 96); ImageIO.write(bufferedImage,PNG,destFile); } }catch (Exception e){ e.printStackTrace(); } } /** * 创建保存文件的目录 * *在在文件同级目录下新建文件名同名文件* * exp: D://pdf/test01.pdf =》创建目录 D://pdf/test01 * @param file 要保存的文件(pdf文件) * @param baseName 文件名称D://pdf/test01.pdf =》 test01 * @return 创建的文件夹 * @throws Exception */ private static File createImageFolder(File file,String baseName) throws Exception{ File imageFolderFile = new File(file.getParent(),baseName); mkdir(imageFolderFile.getPath()); return imageFolderFile; } /** * 根据输入的路径创建文件夹 * @param destDirName * @return */ public static boolean mkdir(String destDirName){ File dir = new File(destDirName); if(dir.exists()){ System.out.println("目录已经存在 : "+destDirName); return false; } if(!destDirName.endsWith(File.separator)){ destDirName+=File.separator; } //创建目录 if(dir.mkdirs()){ System.out.println("创建目录"+destDirName+"成功!"); return true; }else { System.out.println("创建目录"+destDirName+"失败!"); return false; } } public static String getFileName(File file){ String fileName = file.getName(); return fileName.substring(0,fileName.indexOf(".")); } /** * 附加 * @param pdfFile * @param imageFile * @param pathToStore * @throws Exception */ public static void addImagePdf(File pdfFile,File imageFile,String pathToStore) throws Exception{ try (PDDocument pdDocument = PDDocument.load(pdfFile)){ //图片对象 PDImageXObject image = PDImageXObject.createFromFileByContent(imageFile,pdDocument); float imageWidth =(float) (image.getWidth()*0.25); float imageHeight =(float) (image.getHeight()*0.25); //遍历原文档 for (PDPage page : pdDocument.getPages()) { float pageWidth = page.getMediaBox().getWidth(); float pageHeight = page.getMediaBox().getHeight(); //添加图片 //创建水引流内容 PDPageContentStream pdPageContentStream = new PDPageContentStream(pdDocument, page, PDPageContentStream.AppendMode.APPEND, true, true); //设置图片位置 float imageX = pageWidth -imageWidth -10; float imageY = pageHeight -imageHeight -10; // 在指定位置绘制图像 pdPageContentStream.drawImage(image,imageX,imageY,imageWidth,imageHeight); pdPageContentStream.close();; } File outputFile = new File(pathToStore); //文件存在则删除文件 Files.deleteIfExists(Paths.get(outputFile.toURI())); pdDocument.save(outputFile); }catch (Exception e){ e.printStackTrace(); } } }
测试代码
@Test public void testWaterMark() throws IOException { PdfWatermarkProperties props = new PdfWatermarkProperties("一个笨蛋"); PdfUtil.addTextWatermark(new File("D://pdf/test.pdf"),"D://pdf//out_text.pdf",props); } @Test public void testReadPdf() throws Exception { String s = PdfUtil.readPdf(new File("D://pdf//out_text.pdf")); PdfUtil.mkdir("D://pdf/test"); File file = new File("D://pdf//out_text.pdf"); PdfUtil.toImage(file); PdfUtil.addImagePdf(new File("D://pdf/test.pdf"),new File("D://pdf/test.png"),"D://pdf/test_image.pdf"); }
本文来自博客园,作者:一个小笨蛋,转载请注明原文链接:https://www.cnblogs.com/paylove/p/18285858
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通