基于POI对Word/PPT/PDF/Excel增加文件水印

前言

在Web项目中,对于MS Ofice类型的文档有时会存在加密或权限限制的需求,除了对文档增加限制修改密码外,一般需要增加水印以达到溯源的效果。
本文基于POI完成了对常见MS Offce文档(Word/PPT/PDF/Excel)的水印添加操作。

技术要点

添加文档水印的基本步骤是先根据需求生成对应的图像,再通过对应MS Office文档对象提供的方法将图片插入。
不同的文档提供的接口不同,有的自带写水印的方法,有的需要引用第三方组件,有的需要使用awt生成图像写入。

给Word文档添加水印

XWPFHeaderFooterPolicy 官方文档

public static void addWordWaterMark(String inputPath, String outPath, String markStr) {// 读取原始文件File inputFile = new File(inputPath);XWPFDocument doc = null;try {doc = new XWPFDocument(new FileInputStream(inputFile));} catch (FileNotFoundException var24) {throw new RuntimeException("源文件不存在");} catch (IOException var25) {throw new RuntimeException("读取源文件IO异常");} catch (Exception var26) {throw new RuntimeException("不支持的文档格式");}// 使用自带工具类完成水印填充XWPFHeaderFooterPolicy headerFooterPolicy = doc.getHeaderFooterPolicy();headerFooterPolicy.createWatermark(markStr);// 设置文档只读doc.enforceReadonlyProtection();// 生成输出文件File file = new File(outPath);if (!file.exists()) {try {file.createNewFile();} catch (IOException var23) {throw new RuntimeException("创建输出文件失败");}}// 打开输出流,将doc写入输出文件OutputStream os = null;try {os = new FileOutputStream(outPath);doc.write(os);} catch (FileNotFoundException var21) {throw new RuntimeException("创建输出文件失败");} catch (Exception var22) {throw new RuntimeException("添加文档水印失败");} finally {if (os != null) {try {os.close();} catch (IOException var20) {var20.printStackTrace();}}}}

给PPT文档添加水印

使用了国产PPT组件:Spire-Presentation-JAVA,但是从官网下载的组件会有免费版限制,请自行决定要不要使用。

Spire-Presentation-JAVA 官网
官方教程-添加文字水印


public static void addPptWaterMark(String inputPath, String outPath, String markStr) {//加载PPT源文档Presentation ppt = new Presentation();// 设置PPT密码ppt.encrypt("Ka_ze");try {ppt.loadFromFile(inputPath);ISlide slide = null;//获取指定幻灯片for (int o = 0; o < ppt.getSlides().getCount(); o++) {slide = ppt.getSlides().get(o);//设置文本水印文本宽和高int width= 110;int height= 80;//起始坐标float x = 10;float y = 40;for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){//绘制文本,设置文本格式并将其添加到第一张幻灯片// 定义一个长方形区域Rectangle2D.Double rect = new Rectangle2D.Double(x,y,width, height);// 添加一个shape到定义区域IAutoShape shape = slide.getShapes().appendShape(ShapeType.RECTANGLE, rect);// 设置shape样式shape.getFill().setFillType(FillFormatType.NONE);shape.getShapeStyle().getLineColor().setColor(Color.white);shape.setRotation(-45);shape.getLocking().setSelectionProtection(true);shape.getLine().setFillType(FillFormatType.NONE);// 添加文本到shapeshape.getTextFrame().setText(markStr);shape.setShapeArrange(ShapeAlignmentEnum.ShapeArrange.SendToBack);// 设置文本水印样式PortionEx textRange = shape.getTextFrame().getTextRange();textRange.getFill().setFillType(FillFormatType.SOLID);textRange.getFill().getSolidColor().setColor(new Color(Integer.parseInt("#C5CBCF".substring(1), 16)));textRange.setFontHeight(20);// 设置下一个水印的横坐标x += (100 + ppt.getSlideSize().getSize().getWidth()/6);}x = 30;// 设置下一个水印的纵坐标y += (100 + ppt.getSlideSize().getSize().getHeight()/7) ;}}//保存文档ppt.saveToFile(outPath, FileFormat.PPTX_2013);ppt.dispose();} catch (Exception e) {e.printStackTrace();}}

给PDF文档添加水印

使用了开源组件iText,可以用于创建和操作 PDF 文档。

maven仓库
官方文档-itext-v7.0.0
官方Github


<dependency><groupId>com.itextpdfgroupId><artifactId>itext-asianartifactId><version>5.2.0version>dependency><dependency><groupId>com.itextpdfgroupId><artifactId>itextpdfartifactId><version>5.4.3version>dependency>

public static void addPDFWaterMark(String input, String output, String waterMarkName) {BufferedOutputStream bos = null;try {// 读取文件,生成readercom.itextpdf.text.pdf.PdfReader reader = new com.itextpdf.text.pdf.PdfReader(input);// 生成输出文件,开启输出流bos = new BufferedOutputStream(new FileOutputStream(new File(output)));// 读取输出流,生成stamper(印章)com.itextpdf.text.pdf.PdfStamper stamper = new com.itextpdf.text.pdf.PdfStamper(reader, bos);// 设置stamper加密stamper.setEncryption(null, "Ka_ze".getBytes(StandardCharsets.UTF_8), PdfWriter.ALLOW_PRINTING, PdfWriter.STANDARD_ENCRYPTION_128);// 获取总页数 +1, 下面从1开始遍历int total = reader.getNumberOfPages() + 1;// 使用classpath下面的字体库com.itextpdf.text.pdf.BaseFont base = null;try {base = com.itextpdf.text.pdf.BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", com.itextpdf.text.pdf.BaseFont.EMBEDDED);} catch (Exception e) {// 日志处理e.printStackTrace();}// 间隔int interval = -15;// 获取水印文字的高度和宽度int textH = 0, textW = 0;JLabel label = new JLabel();label.setText(waterMarkName);FontMetrics metrics = label.getFontMetrics(label.getFont());textH = metrics.getHeight();textW = metrics.stringWidth(label.getText());      // 设置水印透明度com.itextpdf.text.pdf.PdfGState gs = new com.itextpdf.text.pdf.PdfGState();gs.setFillOpacity(0.2f);gs.setStrokeOpacity(0.7f);com.itextpdf.text.Rectangle pageSizeWithRotation = null;PdfContentByte content = null;for (int i = 1; i < total; i++) {// 在内容上方加水印content = stamper.getOverContent(i);// 在内容下方加水印// content = stamper.getUnderContent(i);content.saveState();content.setGState(gs);// 设置字体和字体大小content.beginText();content.setFontAndSize(base, 20);// 获取每一页的高度、宽度pageSizeWithRotation = reader.getPageSizeWithRotation(i);float pageHeight = pageSizeWithRotation.getHeight();float pageWidth = pageSizeWithRotation.getWidth();// 根据纸张大小多次添加, 水印文字成30度角倾斜for (int height = interval + textH; height < pageHeight; height = height + textH * 6) {for (int width = interval + textW; width < pageWidth + textW; width = width + textW * 2) {content.showTextAligned(Element.ALIGN_LEFT, waterMarkName, width - textW, height - textH, 30);}}content.endText();}// 关流stamper.close();reader.close();} catch (DocumentException | IOException e) {e.printStackTrace();}}

给Excel文档添加水印

使用awt包的Graphics2D设置图像属性。


private static void addExcelWaterMark(String inputSrc, String outputSrc, String waterMarkName) {// 读取水印文字String[] textArray = waterMark.split("\n");// 设置字体Font font = new Font("microsoft-yahei", Font.PLAIN, 20);// 单元水印图片宽高int width = 500;int height = 200;// 缓冲区图片对象BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 基于特定宽高,创建图形对象Graphics2D g = image.createGraphics();// 基于图形对象生成半透明图片image = g.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);// 释放画笔g.dispose();// 基于半透明图片,创建图形对象g = image.createGraphics();// 设置图形颜色g.setColor(new Color(Integer.parseInt("#C5CBCF".substring(1), 16)));// 设置图形字体g.setFont(font);// 设置图形倾斜度g.shear(0.1, -0.26);// 设置字体平滑g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// 画出字符串int y = 150;for (int i = 0; i < textArray.length; i++) {g.drawString(textArray[i], 0, y);y = y + font.getSize();}// 释放画笔g.dispose();ByteArrayOutputStream os = new ByteArrayOutputStream();try {// 将内存中的图片写入至输出流ImageIO.write(image, "png", os);// 读取原文档XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream(inputSrc));// 将图片输出流写入Excelint pictureIdx = workbook.addPicture(os.toByteArray(), Workbook.PICTURE_TYPE_PNG);// 获取工作簿中的图片对象POIXMLDocumentPart poixmlDocumentPart = workbook.getAllPictures().get(pictureIdx);for (int i = 0; i < workbook.getNumberOfSheets(); i++) {//获取每个Sheet表XSSFSheet sheet = workbook.getSheetAt(i);PackagePartName ppn = poixmlDocumentPart.getPackagePart().getPartName();String relType = XSSFRelation.IMAGES.getRelation();// 为当前Sheet添加图片关系PackageRelationship pr = sheet.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);// 将图片关系添加到Sheet底层结构中sheet.getCTWorksheet().addNewPicture().setId(pr.getId());}try {workbook.write(new FileOutputStream(outputSrc));} finally {os.close();}} catch (Exception e) {e.printStackTrace();}}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部