123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577 |
- 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);
- }
- }
- }
|