package cn.sealevel.util;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.UUID;
import javax.imageio.ImageIO;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFPictureShape;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xssf.usermodel.XSSFRelation;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.core.io.ClassPathResource;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.extgstate.PdfExtGState;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.VerticalAlignment;
import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.HeaderFooter;
import com.spire.doc.Section;
import com.spire.doc.TextWatermark;
import com.spire.doc.documents.ShapeLineStyle;
import com.spire.doc.documents.ShapeType;
import com.spire.doc.documents.WatermarkLayout;
import com.spire.doc.fields.ShapeObject;
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.graphics.PdfBrush;
import com.spire.pdf.graphics.PdfRGBColor;
import com.spire.pdf.graphics.PdfSolidBrush;
import com.spire.pdf.graphics.PdfStringFormat;
import com.spire.pdf.graphics.PdfTextAlignment;
import com.spire.pdf.graphics.PdfTilingBrush;
import com.spire.pdf.graphics.PdfTrueTypeFont;
import lombok.extern.slf4j.Slf4j;
/**
* @author yiTeng
* @version 1.0 2023/10/20
*/
@Slf4j
public class FileWaterMarkUtils {
private static final String PDF = "pdf";
private static final String DOC = ".doc.docx";
private static final String XLS = ".xls.xlsx";
private static final String PPT = ".ppt.pptx";
private static final String IMG = ".jpg.JPG.png.PNG.jpeg.JPEG.bmp.BMP";
private static final String FONT_PATH = "/font/simsun.ttf";
private static final Float FONT_SIZE = 30f;
public static Font loadFont() {
try {
InputStream fileStream = Font.class.getClass().getResourceAsStream(FONT_PATH);
Font myFont = Font.createFont(Font.TRUETYPE_FONT, fileStream);
return myFont.deriveFont(FONT_SIZE);
} catch (FontFormatException | IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 生成水印文件
*
* @param filePath 原文件绝对路径
* @param watermark 水印内容
* @param
*/
public static ByteArrayOutputStream generateFile(String filePath, String watermark) {
log.info("添加水印文件:{}", filePath);
log.info("水印内容:{}", watermark);
ByteArrayOutputStream out = null;
// 获取文件后缀
String suffix = filePath.substring((filePath.lastIndexOf(".") + 1));
if (PDF.equals(suffix)) {
// out = generatePDF(filePath, watermark);
// 多行多条水印
out = generatePDF2(filePath, watermark);
log.info("生成水印pdf成功!");
}
if (DOC.contains(suffix)) {
out = generateDOC(filePath, watermark);
log.info("生成水印word成功!");
}
if (XLS.contains(suffix)) {
out = generateExcel(filePath, watermark);
log.info("生成水印excel成功!");
}
if (PPT.contains(suffix)) {
out = generatePPT(filePath, watermark);
log.info("生成水印ppt成功!");
}
if (IMG.contains(suffix)) {
out = generateImage(filePath, watermark);
log.info("生成水印image成功!");
}
return out;
}
private static ByteArrayOutputStream generateImage(String filePath, String watermark) {
ByteArrayOutputStream out = null;
try {
log.info("生成水印后的图片地址:{}");
out = setImageWatermark(filePath, Color.GRAY, watermark);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return out;
}
private static ByteArrayOutputStream generatePPT(String filePath, String watermark) {
ByteArrayOutputStream out = null;
try {
File file = new File(filePath);
XMLSlideShow slideShow = new XMLSlideShow(new FileInputStream(file));
ByteArrayOutputStream os = getWaterImage(watermark);
PictureData pictureData = slideShow.addPicture(os.toByteArray(), PictureData.PictureType.PNG);
for (XSLFSlide slide : slideShow.getSlides()) {
XSLFPictureShape pictureShape = slide.createPicture(pictureData);
pictureShape.setAnchor(pictureShape.getAnchor());
}
log.info("水印PPT生成成功:{}");
out = new ByteArrayOutputStream();
slideShow.write(out);
slideShow.close();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return out;
}
/**
* PDF多行多条水印
*/
static ByteArrayOutputStream generatePDF2(String filePath, String watermark) {
ByteArrayOutputStream out = null;
try {
File file = new File(filePath);
// 创建PdfDocument类的对象
com.spire.pdf.PdfDocument pdf = new com.spire.pdf.PdfDocument();
// 加载测试文档
pdf.loadFromFile(file.toString());
// 添加一个空白页,目的为了删除jar包添加的水印,后面再移除这一页
pdf.getPages().add();
// 获取测试文档中的第一页
// 遍历文档中的页
for (int i = 0; i < pdf.getPages().getCount(); i++) {
PdfPageBase page = pdf.getPages().get(i);
// 添加文本水印
addPDFWatermark(page, watermark);
}
// 移除第一个页
pdf.getPages().remove(pdf.getPages().get(pdf.getPages().getCount() - 1));
out = new ByteArrayOutputStream();
// 保存文档
pdf.saveToStream(out);
pdf.close();
out.close();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return out;
}
private static ByteArrayOutputStream generateExcel(String filePath, String watermark) {
ByteArrayOutputStream fos = null;
try {
File file = new File(filePath);
// 读取excel文件
XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream(file));
ByteArrayOutputStream os = getWaterImage(watermark);
int pictureIdx = workbook.addPicture(os.toByteArray(), Workbook.PICTURE_TYPE_PNG);
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {// 获取每个Sheet表
XSSFSheet sheet = workbook.getSheetAt(i);
String rID = sheet.addRelation(null, XSSFRelation.IMAGES, workbook.getAllPictures().get(pictureIdx))
.getRelationship().getId();
sheet.getCTWorksheet().addNewPicture().setId(rID);
}
log.info("水印excel生成成功:{}");
fos = new ByteArrayOutputStream();
workbook.write(fos);
workbook.close();
fos.close();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return fos;
}
private static ByteArrayOutputStream generateDOC(String fileName, String watermark) {
ByteArrayOutputStream fos = null;
try {
File file = new File(fileName);
Document document = new Document();
document.loadFromFile(file.toString());
// 添加水印
InsertManyTextWatermark(document, watermark);
log.info("水印doc生成成功");
fos = new ByteArrayOutputStream();
String suffix = fileName.substring(fileName.lastIndexOf('.'));
//不写入原文件 写入新文件 后
//document.saveToFile(fileName, suffix.equals("doc") ? FileFormat.Doc : FileFormat.Docx);
document.saveToStream(fos, suffix.equals("doc") ? FileFormat.Doc : FileFormat.Docx);
// 写出文件
document.close();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
return fos;
}
private static ByteArrayOutputStream generatePDF(String filePath, String watermark) {
ByteArrayOutputStream out = null;
try {
File file = new File(filePath);
FileInputStream fis = new FileInputStream(file);
out = new ByteArrayOutputStream();
PdfReader readerInfo = new PdfReader(fis);
PdfDocument docInfo = new PdfDocument(readerInfo, new PdfWriter(out));
//中文字体
File tempFile = File.createTempFile(UUID.randomUUID().toString().replaceAll("-", ""), ".otf");
InputStream input = new ClassPathResource(FONT_PATH).getInputStream();
Files.copy(input, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
String fontPath = tempFile.getAbsolutePath();
//加水印
addWater(docInfo, fontPath, watermark);
//关闭文档
docInfo.close();
readerInfo.close();
out.close();
fis.close();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return out;
}
/**
* 图片添加水印
*
* @param srcImgPath 需要添加水印的图片的路径
* @param markContentColor 水印文字的颜色
* @param waterMarkContent 水印的文字
*/
private static ByteArrayOutputStream setImageWatermark(String srcImgPath, Color markContentColor, String waterMarkContent) {
ByteArrayOutputStream outImgStream = null;
String suffix = srcImgPath.substring(srcImgPath.lastIndexOf('.') + 1);
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 = loadFont();
//根据图片的背景设置水印颜色
g.setColor(markContentColor);
//设置旋转角度
g.rotate(Math.toRadians(-45), (double) bufImg.getWidth() / 2, (double) bufImg.getHeight() / 2);
//设置水印透明度
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1.0F));
g.setFont(font);
int x = (srcImgWidth - getWatermarkLength(waterMarkContent, g)) / 2;
int y = srcImgHeight / 2;
g.drawString(waterMarkContent, x, y);
g.dispose();
// 输出图片
outImgStream = new ByteArrayOutputStream();
ImageIO.write(bufImg, suffix, outImgStream);
outImgStream.flush();
outImgStream.close();
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
if (outImgStream != null) {
try {
outImgStream.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
}
return outImgStream;
}
/**
* 获取水印文字总长度
*
* @param waterMarkContent 水印的文字
* @param g
* @return 水印文字总长度
*/
private static int getWatermarkLength(String waterMarkContent, Graphics2D g) {
return g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0, waterMarkContent.length());
}
/**
* 获取水印文字图片流
*
* @param text
* @return
*/
private static ByteArrayOutputStream getWaterImage(String text) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
// 导出到字节流B
BufferedImage image = createWaterMarkImageBig(text);
ImageIO.write(image, "png", os);
} catch (IOException e) {
log.info(e.getMessage(), e);
}
return os;
}
/**
* 根据文字生成水印图片(大号 平铺)
*
* @param text
* @return
*/
private 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, 36);
Font font = loadFont();
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;
}
/**
* PDF
*
* @param docInfo
*/
private static void addWater(PdfDocument docInfo, String path, String watermark) {
docInfo.addEventHandler(PdfDocumentEvent.END_PAGE, new IEventHandler() {
@Override
public void handleEvent(Event event) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdfDoc = docEvent.getDocument();
PdfPage page = docEvent.getPage();
PdfFont font = null;
try {
font = PdfFontFactory.createFont(path, PdfEncodings.IDENTITY_H, false);
} catch (IOException e) {
log.error(e.getMessage(), e);
}
PdfCanvas canvas = new PdfCanvas(page);
PdfExtGState gs1 = new PdfExtGState();
gs1.setFillOpacity(0.10f); // 水印透明度
canvas.setExtGState(gs1);
new Canvas(canvas, pdfDoc, page.getPageSize()).setFontSize(60)
.setFont(font).showTextAligned(new Paragraph(watermark), 298, 421,
pdfDoc.getPageNumber(page), TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);
}
});
}
static void addPDFWatermark(PdfPageBase page, String watermark) {
Dimension2D dimension2D = new Dimension();
//水印数量
dimension2D.setSize(page.getCanvas().getClientSize().getWidth() / 5, page.getCanvas().getClientSize().getHeight() / 5);
PdfTilingBrush brush = new PdfTilingBrush(dimension2D);
//透明度
brush.getGraphics().setTransparency(0.4F);
brush.getGraphics().save();
//浮动
brush.getGraphics().translateTransform((float) brush.getSize().getWidth() / 5, (float) brush.getSize().getHeight() / 5);
//倾斜度(负:上倾斜,正:下倾斜)
brush.getGraphics().rotateTransform(-45);
//设置字体颜色
PdfBrush brush_color = new PdfSolidBrush(new PdfRGBColor(Color.GRAY));
//水印内容和水印坐标
//Font font = new Font("宋体", Font.PLAIN, 15);
Font font =loadFont();
brush.getGraphics().drawString(watermark, new PdfTrueTypeFont(font), brush_color, 25, 30, new PdfStringFormat(PdfTextAlignment.Center));
brush.getGraphics().restore();
brush.getGraphics().setTransparency(1);
Rectangle2D loRect = new Rectangle2D.Float();
loRect.setFrame(new Point2D.Float(0, 0), page.getCanvas().getClientSize());
page.getCanvas().drawRectangle(brush, loRect);
}
/**
* 自定义方法插入文本水印并格式水印效果
* word
*/
private static void InsertTextWatermark(Section section, String watermark) {
TextWatermark txtWatermark = new TextWatermark();
txtWatermark.setText(watermark);
txtWatermark.setFontSize(40);
txtWatermark.setColor(Color.LIGHT_GRAY);
txtWatermark.setLayout(WatermarkLayout.Diagonal);
section.getDocument().setWatermark(txtWatermark);
}
/**
* word 通过页眉生成多条文字水印
*
* @param document
* @param watermark
*/
private static void InsertManyTextWatermark(Document document, String watermark) {
ShapeObject shape = new ShapeObject(document, ShapeType.Text_Plain_Text);
shape.setWidth(50);
shape.setHeight(15);
//设置艺术字文本内容、位置及样式
shape.setVerticalPosition(10);
shape.setHorizontalPosition(5);
shape.setRotation(330);
shape.getWordArt().setText(watermark);
shape.setFillColor(Color.GRAY);
shape.setLineStyle(ShapeLineStyle.Single);
shape.setStrokeColor(new Color(192, 192, 192, 255));
shape.setStrokeWeight(1);
Section section = document.getSections().get(0);
//获取section的页眉
HeaderFooter header = section.getHeadersFooters().getHeader();
com.spire.doc.documents.Paragraph paragraph;
for (int i = 0; i < 3; i++) {
//添加段落到页眉
paragraph = header.addParagraph();
for (int j = 0; j < 3; j++) {
//复制艺术字并设置多行多列位置
shape = (ShapeObject) shape.deepClone();
shape.setVerticalPosition(150 + 180 * i);
shape.setHorizontalPosition(40 + 150 * j);
paragraph.getChildObjects().add(shape);
}
}
}
public static void main(String[] args) throws IOException {
// word ok
// System.out.println( ResourceReader.class.getClassLoader().getResource("font/SOURCEHANSANSCN-LIGHT.OTF"));
// String exclePath = "D:\\mask\\DMS1.docx";
//excel ok
//String exclePath = "D:\\mask\\dms.xlsx";
//png ok
String exclePath = "E:\\down\\file\\b535f9fe-45cb-4382-b710-e4e38b8cda58.jpg";
//pdf not ok
// String exclePath = "D:\\mask\\dms.pdf";
String exclePathWater = exclePath.substring(0, exclePath.lastIndexOf("\\") + 1) + "WaterText"
+ exclePath.substring((exclePath.lastIndexOf(".")));
ByteArrayOutputStream out = generateFile(exclePath, "测试 hzm");
File waterFile = new File(exclePathWater);
if (!waterFile.exists()) {
waterFile.createNewFile();
}
FileOutputStream fis = null;
try {
fis = new FileOutputStream(waterFile);
byte[] buffer = out.toByteArray();
fis.write(buffer);
} catch (Exception e) {
e.printStackTrace();
} finally {
out.close();
if (fis != null) {
fis.close();
}
}
}
}
需要的jar
Maven 地址
复制代码
<repositories>
<repository>
<id>com.e-iceblue</id>
<url>https://repo.e-iceblue.cn/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.doc.free</artifactId>
<version>5.2.0</version>
</dependency>
</dependencies>