package com.caimei.modules.archive.utils; import com.itextpdf.text.*; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.*; import com.thinkgem.jeesite.common.config.Global; import groovy.util.logging.Slf4j; import org.apache.poi.POIXMLDocument; import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.sl.usermodel.PictureData; import org.apache.poi.sl.usermodel.PictureData.PictureType; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xslf.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFRelation; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xwpf.model.XWPFHeaderFooterPolicy; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFHeader; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import schemasMicrosoftComVml.CTShape; import javax.imageio.ImageIO; import javax.swing.*; import java.awt.Color; import java.awt.Font; import java.awt.*; import java.awt.Image; import java.awt.font.FontRenderContext; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.*; import java.lang.reflect.Field; /** * Description * * @author : Charles * @date : 2021/9/18 */ public class WaterMarkUtils { private final static String outPath = Global.getConfig("archive.tempPath"); /** * 日志对象 */ private static Logger log = LoggerFactory.getLogger(WaterMarkUtils.class); // 水印透明度 private static float alpha = 0.5f; // 水印之间的间隔 private static final int XMOVE = 200; // 水印之间的间隔 private static final int YMOVE = 200; public static void main(String[] args) { /*addPictureWaterMark("D:\\WorkSpace\\file\\img.jpg", "D:\\WorkSpace\\file\\temp\\img1.jpg", "我是水印"); setPictureWatermark("D:\\WorkSpace\\file\\img.jpg", "D:\\WorkSpace\\file\\temp\\img2.jpg", Color.GRAY, "我是水印"); // setWordWaterMark("D:\\WorkSpace\\file\\test.doc", "D:\\WorkSpace\\file\\temp\\test.doc", "我是水印", "doc"); setWordWaterMark("D:\\WorkSpace\\file\\test.docx", "D:\\WorkSpace\\file\\temp\\test.docx", "我是水印", "docx"); setPdfWatermark("D:\\WorkSpace\\file\\test.pdf", "D:\\WorkSpace\\file\\temp\\test.pdf", "我是水印"); // setExcelWaterMark("D:\\WorkSpace\\file\\test.xls", "D:\\WorkSpace\\file\\temp\\test.xls", "我是水印"); // setPPTWaterMark("D:\\WorkSpace\\file\\test.ppt", "D:\\WorkSpace\\file\\temp\\test.ppt", "我是水印"); setPPTWaterMark("D:\\WorkSpace\\file\\test.pptx", "D:\\WorkSpace\\file\\temp\\test.pptx", "我是水印"); */} /** * @param srcImgPath 源图片路径 * @param tarImgPath 保存的图片路径 * @param waterMarkContent 水印内容 */ public static void addPictureWaterMark(String srcImgPath, String tarImgPath, String waterMarkContent) { FileOutputStream outImgStream = null; try { // 读取原图片信息 File srcImgFile = new File(srcImgPath);// 得到文件 Image srcImg = ImageIO.read(srcImgFile);// 文件转化为图片 int srcImgWidth = srcImg.getWidth(null);// 获取图片的宽 int srcImgHeight = srcImg.getHeight(null);// 获取图片的高 // 加水印 BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB); Graphics2D g = bufImg.createGraphics(); // 设置对线段的锯齿状边缘处理 g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.drawImage(srcImg, 0, 0, srcImgWidth, srcImgHeight, null); // 设置水印旋转 g.rotate(Math.toRadians(-40), (double) bufImg.getWidth() / 2, (double) bufImg.getHeight() / 2); g.setColor(new Color(107, 109, 106)); // 根据图片的背景设置水印颜色 Font font = new Font("宋体", Font.PLAIN, 20); g.setFont(font); // 设置字体 // 设置水印文字透明度 // g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,alpha)); //根据不同的像素判断多个水印还是单个水印300*300 if (srcImgWidth > 300 && srcImgHeight > 300) { //多个水印 // 设置水印的坐标 int x = -srcImgWidth / 2; int y = -srcImgHeight / 2; int markWidth = font.getSize() * getTextLength(waterMarkContent);// 字体长度 int markHeight = font.getSize();// 字体高度 // 循环添加水印 while (x < srcImgWidth * 1.5) { y = -srcImgHeight / 2; while (y < srcImgHeight * 1.5) { g.drawString(waterMarkContent, x, y); y += markHeight + YMOVE; } x += markWidth + XMOVE; } } else { //单个水印 int x = (srcImgWidth - getWatermarkLength(waterMarkContent, g)) / 2; int y = srcImgHeight / 2; g.drawString(waterMarkContent, x, y); } g.dispose(); // 输出图片 outImgStream = new FileOutputStream(tarImgPath); String formatName = srcImgPath.substring(srcImgPath.lastIndexOf(".") + 1, srcImgPath.length()); ImageIO.write(bufImg, formatName, outImgStream); outImgStream.flush(); } catch (Exception e) { log.error("addPictureWatermark fail", e); // throw new MyException(ResultCode.FAILURE, "addPictureWatermark fail"); } finally { if (outImgStream != null) { try { outImgStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 图片添加水印 * * @param srcImgPath 需要添加水印的图片的路径 * @param outImgPath 添加水印后图片输出路径 * @param markContentColor 水印文字的颜色 * @param waterMarkContent 水印的文字 */ public static void setPictureWatermark(String srcImgPath, String outImgPath, Color markContentColor, String waterMarkContent) { FileOutputStream outImgStream = null; try { // 读取原图片信息 File srcImgFile = new File(srcImgPath); Image srcImg = ImageIO.read(srcImgFile); int srcImgWidth = srcImg.getWidth(null); int srcImgHeight = srcImg.getHeight(null); // 加水印 BufferedImage bufImg = new BufferedImage(srcImgWidth, srcImgHeight, BufferedImage.TYPE_INT_RGB); Graphics2D g = bufImg.createGraphics(); g.drawImage(srcImg, 0, 0, srcImgWidth, srcImgHeight, null); Font font = new Font("宋体", Font.BOLD, srcImgHeight / 6); //根据图片的背景设置水印颜色 g.setColor(markContentColor); //设置旋转角度 g.rotate(Math.toRadians(-45), (double) bufImg.getWidth() / 2, (double) bufImg.getHeight() / 2); //设置水印透明度 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.2F)); g.setFont(font); int x = (srcImgWidth - getWatermarkLength(waterMarkContent, g)) / 2; int y = srcImgHeight / 2; g.drawString(waterMarkContent, x, y); g.dispose(); // 输出图片 outImgStream = new FileOutputStream(outImgPath); ImageIO.write(bufImg, "jpg", outImgStream); outImgStream.flush(); outImgStream.close(); } catch (Exception e) { log.error("setPictureWatermark fail", e); // throw new MyException(ResultCode.FAILURE, "setPictureWatermark fail"); } finally { if (outImgStream != null) { try { outImgStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * word文字水印 * * @param markStr */ public static void setWordWaterMark(File inputFile, String markStr,String filePath, String fileType) { if ("docx".equals(fileType)) { //2003doc 用HWPFDocument ; 2007doc 用 XWPFDocument XWPFDocument doc = null; try { // OPCPackage pack = POIXMLDocument.openPackage(inputPath); // doc = new XWPFDocument(pack); doc = new XWPFDocument(new FileInputStream(inputFile)); // doc = new XWPFDocument(new FileInputStream(inputFile)); } catch (FileNotFoundException e) { log.error("setWordWaterMark fail: 源文件不存在", e); // throw new MyException(ResultCode.FAILURE, "setWordWaterMark fail: 源文件不存在"); } catch (IOException e) { log.error("setWordWaterMark fail: 读取源文件IO异常", e); // throw new MyException(ResultCode.FAILURE, "setWordWaterMark fail: 读取源文件IO异常"); } catch (Exception e) { log.error("setWordWaterMark fail: 不支持的文档格式", e); // throw new MyException(ResultCode.FAILURE, "setWordWaterMark fail: 不支持的文档格式"); } XWPFParagraph paragraph = doc.createParagraph(); XWPFHeaderFooterPolicy headerFooterPolicy = doc.getHeaderFooterPolicy(); if (headerFooterPolicy == null) { headerFooterPolicy = doc.createHeaderFooterPolicy(); } // create default Watermark - fill color black and not rotated headerFooterPolicy.createWatermark(markStr); // get the default header // Note: createWatermark also sets FIRST and EVEN headers // but this code does not updating those other headers XWPFHeader header = headerFooterPolicy.getHeader(XWPFHeaderFooterPolicy.DEFAULT); paragraph = header.getParagraphArray(0); // // get com.microsoft.schemas.vml.CTShape where fill color and rotation is set // paragraph.getCTP().newCursor(); // System.out.println(paragraph.getCTP().getRArray(0)); // System.out.println(paragraph.getCTP().getRArray(0).getPictArray(0)); org.apache.xmlbeans.XmlObject[] xmlobjects = paragraph.getCTP().getRArray(0).getPictArray(0).selectChildren( new javax.xml.namespace.QName("urn:schemas-microsoft-com:vml", "shape")); if (xmlobjects.length > 0) { com.microsoft.schemas.vml.CTShape ctshape = (com.microsoft.schemas.vml.CTShape) xmlobjects[0]; ctshape.setFillcolor("#D3D3D3"); ctshape.setStyle(ctshape.getStyle() + ";rotation:315" + ";height:60pt;width:360pt"); } File file = new File(outPath + filePath); if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { log.error("setWordWaterMark fail: 创建输出文件IO异常", e); // throw new MyException(ResultCode.FAILURE, "setWordWaterMark fail: 创建输出文件失败"); } } try { doc.write(new FileOutputStream(outPath + filePath)); } catch (FileNotFoundException e) { log.error("setWordWaterMark fail: 输出文件不存在", e); // throw new MyException(ResultCode.FAILURE, "setWordWaterMark fail: 创建输出文件失败"); } catch (IOException e) { log.error("setWordWaterMark fail: ", e); // throw new MyException(ResultCode.FAILURE, "setWordWaterMark fail"); } finally { if (doc != null) { try { doc.close(); } catch (IOException e) { e.printStackTrace(); } } } } } /** * pdf设置文字水印 * * @param inputPath * @param outPath * @param markStr */ public static void setPdfWatermark(String inputPath, String outPath, String markStr) { File file = new File(outPath); if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { log.error("setPdfWatermark fail: 创建输出文件IO异常", e); // throw new MyException(ResultCode.FAILURE, "setPdfWatermark fail: 创建输出文件IO异常"); } } BufferedOutputStream bufferOut = null; try { bufferOut = new BufferedOutputStream(new FileOutputStream(file)); } catch (FileNotFoundException e) { log.error("setPdfWatermark fail: 源文件不存在", e); // throw new MyException(ResultCode.FAILURE, "setPdfWatermark fail: 源文件不存在"); } PdfStamper stamper = null; int total = 0; PdfContentByte content; Rectangle pageSizeWithRotation = null; BaseFont base = null; PdfReader reader = null; try { reader = new PdfReader(inputPath); //解决PdfReader not opened with owner password Field f = PdfReader.class.getDeclaredField("ownerPasswordUsed"); f.setAccessible(true); f.set(reader, Boolean.TRUE); stamper = new PdfStamper(reader, bufferOut); total = reader.getNumberOfPages() + 1; base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED); } catch (IOException e) { log.error("setPdfWatermark fail:", e); // throw new MyException(ResultCode.FAILURE, "setPdfWatermark fail"); } catch (DocumentException e) { log.error("setPdfWatermark fail:", e); // throw new MyException(ResultCode.FAILURE, "setPdfWatermark fail"); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } // 获取水印文字的高度和宽度 int textH = 0, textW = 0; JLabel label = new JLabel(); label.setText(markStr); FontMetrics metrics = label.getFontMetrics(label.getFont()); textH = metrics.getHeight(); textW = metrics.stringWidth(label.getText()); PdfGState gs = new PdfGState(); for (int i = 1; i < total; i++) { //在内容上方加水印 content = stamper.getOverContent(i); gs.setFillOpacity(0.5f); content.saveState(); content.setGState(gs); content.beginText(); // content.setRGBColorFill(0, 0, 0); content.setFontAndSize(base, 20); // 获取每一页的高度、宽度 pageSizeWithRotation = reader.getPageSizeWithRotation(i); float pageHeight = pageSizeWithRotation.getHeight(); float pageWidth = pageSizeWithRotation.getWidth(); // 根据纸张大小多次添加, 水印文字成30度角倾斜 for (int height = -5 + textH; height < pageHeight; height = height + YMOVE) { for (int width = -5 + textW; width < pageWidth + textW; width = width + XMOVE) { content.showTextAligned(Element.ALIGN_LEFT, markStr, width - textW, height - textH, 30); } } content.endText(); } try { stamper.close(); bufferOut.flush(); bufferOut.close(); reader.close(); } catch (IOException e) { log.error("setPdfWatermark fail:", e); // throw new MyException(ResultCode.FAILURE, "setPdfWatermark fail"); } catch (DocumentException e) { log.error("setPdfWatermark fail:", e); // throw new MyException(ResultCode.FAILURE, "setPdfWatermark fail"); } } /** * excel设置水印 * * @param inputPath * @param outPath * @param markStr */ public static void setExcelWaterMark(String inputPath, String outPath, String markStr) { //读取excel文件 XSSFWorkbook workbook = null; try { workbook = new XSSFWorkbook(new FileInputStream(inputPath)); } catch (FileNotFoundException e) { log.error("setExcelWaterMark fail: 源文件不存在", e); // throw new MyException(ResultCode.FAILURE, "setExcelWaterMark fail: 源文件不存在"); } catch (IOException e) { log.error("setExcelWaterMark fail: 读取源文件IO异常", e); //throw new MyException(ResultCode.FAILURE, "setExcelWaterMark fail: 读取源文件IO异常"); } OutputStream fos = null; ByteArrayOutputStream os = null; try { //获取水印 os = getImage(markStr); int pictureIdx = workbook.addPicture(os.toByteArray(), Workbook.PICTURE_TYPE_PNG); for (int i = 0; i < workbook.getNumberOfSheets(); i++) {//获取每个Sheet表 XSSFSheet sheet1 = workbook.getSheetAt(i); String rID = sheet1.addRelation(null, XSSFRelation.IMAGES, workbook.getAllPictures().get(pictureIdx)).getRelationship().getId(); //set background picture to sheet sheet1.getCTWorksheet().addNewPicture().setId(rID); } // Excel文件生成后存储的位置。 File file = new File(outPath); fos = new FileOutputStream(file); workbook.write(fos); } catch (Exception e) { log.error("setExcelWaterMark fail: 创建输出文件IO异常", e); // throw new MyException(ResultCode.FAILURE, "setExcelWaterMark fail: 创建输出文件IO异常"); } finally { if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if (workbook != null) { try { workbook.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * PPT设置水印 * * @param path * @param targetpath * @param markStr * @throws IOException */ public static void setPPTWaterMark(String path, String targetpath, String markStr) { XMLSlideShow slideShow = null; try { slideShow = new XMLSlideShow(new FileInputStream(path)); } catch (IOException e) { log.error("setPPTWaterMark fail:", e); // throw new MyException(ResultCode.FAILURE, "setPPTWaterMark fail:获取PPT文件失败"); } ByteArrayOutputStream os = null; FileOutputStream out = null; try { //获取水印 os = getImage(markStr); PictureData pictureData1 = slideShow.addPicture(os.toByteArray(), PictureType.PNG); for (XSLFSlide slide : slideShow.getSlides()) { XSLFPictureShape pictureShape = slide.createPicture(pictureData1); // pictureShape.setAnchor(new java.awt.Rectangle(250, 0, 500, 500)); pictureShape.setAnchor(pictureShape.getAnchor()); } out = new FileOutputStream(targetpath); slideShow.write(out); } catch (IOException e) { log.error("setPPTWaterMark fail:" + e); // throw new MyException(ResultCode.FAILURE, "setPPTWaterMark fail:生成ppt文件失败"); } finally { if (slideShow != null) { try { slideShow.close(); } catch (IOException e) { e.printStackTrace(); } } if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 获取水印文字总长度 * * @param waterMarkContent 水印的文字 * @param g * @return 水印文字总长度 */ public static int getWatermarkLength(String waterMarkContent, Graphics2D g) { return g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0, waterMarkContent.length()); } /** * 获取文本长度。汉字为1:1,英文和数字为2:1 */ private static int getTextLength(String text) { int length = text.length(); for (int i = 0; i < text.length(); i++) { String s = String.valueOf(text.charAt(i)); if (s.getBytes().length > 1) { length++; } } length = length % 2 == 0 ? length / 2 : length / 2 + 1; return length; } /** * 获取水印文字图片流 * * @param text * @return */ private static ByteArrayOutputStream getImage(String text) { ByteArrayOutputStream os = new ByteArrayOutputStream(); try { // 导出到字节流B BufferedImage image = createWaterMarkImageBig(text); ImageIO.write(image, "png", os); } catch (IOException e) { log.error("getImage fail: 创建水印图片IO异常", e); // throw new MyException(ResultCode.FAILURE, "getImage fail: 创建水印图片IO异常"); } return os; } /** * 根据文字生成水印图片(大号 平铺) * * @param text * @return */ public static BufferedImage createWaterMarkImageBig(String text) { Integer width = 1000; Integer height = 800; BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 获取bufferedImage对象 Font font = new Font("宋体", Font.PLAIN, 70); Graphics2D g2d = image.createGraphics(); image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT); g2d.dispose(); g2d = image.createGraphics(); //设置字体颜色和透明度 g2d.setColor(new Color(0, 0, 0, 60)); //设置字体 g2d.setStroke(new BasicStroke(1)); //设置字体类型 加粗 大小 g2d.setFont(font); //设置倾斜度 g2d.rotate(Math.toRadians(-30), (double) image.getWidth() / 2, (double) image.getHeight() / 2); FontRenderContext context = g2d.getFontRenderContext(); Rectangle2D bounds = font.getStringBounds(text, context); double x = (width - bounds.getWidth()) / 2; double y = (height - bounds.getHeight()) / 2; double ascent = -bounds.getY(); double baseY = y + ascent; //写入水印文字原定高度过小,所以累计写水印,增加高度 g2d.drawString(text, (int) x, (int) baseY); //设置透明度 g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); //释放对象 g2d.dispose(); return image; } public static void addWaterMark(File inputFile, String markStr, String filePath, String fileType) { if (fileType.contains("doc")) { setWordWaterMark(inputFile, markStr, filePath, fileType); } } }