通过借鉴其他csdn前辈的代码,优化后的整理,希望这些代码能更好的帮助其他人,欢迎读者提出建议继续优化(借鉴的地方比较多,时间也过的比较久了,忘了借鉴的网址了)
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.*;
import com.microsoft.schemas.office.office.CTLock;
import com.microsoft.schemas.vml.*;
import com.pccw.ihr.base.provider.util.IhrUserUtil;
import com.pccw.march.core.base.utils.login.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.wp.usermodel.HeaderFooterType;
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.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFHeader;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.stereotype.Component;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Date;
import java.util.stream.Stream;
@Slf4j
@Component
public class WaterMarkUtil {
public static void addWatermarkAndCopy(ByteArrayOutputStream byteArrayOutputStream, OutputStream os, String fileType) throws IOException {
if (byteArrayOutputStream != null) {
ByteArrayInputStream is = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
InputStream watermarkedStream = WaterMarkUtil.waterMarkfis(is, fileType);
if (watermarkedStream != null) {
try {
IOUtils.copy(watermarkedStream, os);
} finally {
IOUtils.closeQuietly(watermarkedStream);
}
}
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(byteArrayOutputStream);
}
}
public static InputStream waterMark(String file, String fileName) throws FileNotFoundException {
try (FileInputStream fis = new FileInputStream(file)) {
String fileType = FilenameUtils.getExtension(fileName);
return waterMarkfis(fis, fileType);
} catch (IOException e) {
log.error("文件添加水印失败" + e);
}
return null;
}
public static InputStream waterMarkfis(InputStream fis, String fileType) throws FileNotFoundException {
try {
String word = "";
LoginUser loginUser = IhrUserUtil.getCurrentLoginUser();
if (loginUser != null) {
word = loginUser.getLoginAccount() + " " + loginUser.getAccountName();
} else {
word = DateFormatUtils.format(new Date(), "yyyy-MM-dd");
}
ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 二进制OutputStream
if ("doc".equalsIgnoreCase(fileType) || "docx".equalsIgnoreCase(fileType)) {
XWPFDocument doc = new XWPFDocument(fis);
waterMarkDocXDocument(doc, word);
doc.write(baos); // 文档写入流
} else if ("xls".equalsIgnoreCase(fileType) || "xlsx".equalsIgnoreCase(fileType)) {
XSSFWorkbook workbook = new XSSFWorkbook(fis); // 加载现有的工作簿
addWorkbookWaterMark(workbook, word); // 水印信息
workbook.write(baos);
} else if ("pdf".equalsIgnoreCase(fileType)) {
pdfWatermark(fis, baos, word, 2);
}
return new ByteArrayInputStream(baos.toByteArray());
} catch (IOException | DocumentException e) {
log.error("文件添加水印失败" + e);
}
return null;
}
/************************************************************ PDF水印设置 ************************************************************/
/**
* 给pdf添加文字水印
*
* @param os 添加水印后的pdf文件路径,如/Users/mimhope/Documents/abc_new.pdf
* @param fis 添加水印前的pdf文件路径, 如/Users/mimhope/Documents/abc_old.pdf
* @param word 水印文字
* @param model 水印样式 1:平行居中 2:左右两边
* @return
* @throws DocumentException
* @throws IOException
*/
public static void pdfWatermark(InputStream fis, OutputStream os, String word, int model)
throws DocumentException, IOException {
PdfReader reader = new PdfReader(fis, "PDF".getBytes());
PdfStamper stamper = new PdfStamper(reader, os);
try {
// 设置权限,防止修改和注释
stamper.setEncryption(null, "super123456".getBytes(), PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_MODIFY_CONTENTS, PdfWriter.STANDARD_ENCRYPTION_128);
PdfContentByte content;
// 创建字体,第一个参数是字体路径,itext有一些默认的字体比如说:
BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
PdfGState gs = new PdfGState();
// 获取PDF页数
int total = reader.getNumberOfPages();
// 遍历每一页
for (int i = 0; i < total; i++) {
float width = reader.getPageSize(i + 1).getWidth(); // 页宽度
float height = reader.getPageSize(i + 1).getHeight(); // 页高度
content = stamper.getOverContent(i + 1);// 内容
content.beginText();//开始写入文本
gs.setFillOpacity(0.3f);//水印透明度
content.setGState(gs);
content.setColorFill(BaseColor.LIGHT_GRAY);
content.setTextMatrix(70, 200);//设置字体的输出位置
content.setColorFill(BaseColor.LIGHT_GRAY);
if (model == 1) { //平行居中的3条水印
content.setFontAndSize(base, 20); //字体大小
//showTextAligned 方法的参数分别是(文字对齐方式,位置内容,输出水印X轴位置,Y轴位置,旋转角度)
content.showTextAligned(Element.ALIGN_CENTER, word, width / 2, 650, 30);
content.showTextAligned(Element.ALIGN_CENTER, word, width / 2, 400, 30);
content.showTextAligned(Element.ALIGN_CENTER, word, width / 2, 150, 30);
} else { // 左右两边个从上到下4条水印
float rotation = 30;// 水印旋转度数
content.setFontAndSize(base, 20);
content.showTextAligned(Element.ALIGN_LEFT, word, 20, height - 50, rotation);
content.showTextAligned(Element.ALIGN_LEFT, word, 20, height / 4 * 3 - 50, rotation);
content.showTextAligned(Element.ALIGN_LEFT, word, 20, height / 2 - 50, rotation);
content.showTextAligned(Element.ALIGN_LEFT, word, 20, height / 4 - 50, rotation);
content.setFontAndSize(base, 22);
content.showTextAligned(Element.ALIGN_RIGHT, word, width - 20, height - 50, rotation);
content.showTextAligned(Element.ALIGN_RIGHT, word, width - 20, height / 4 * 3 - 50, rotation);
content.showTextAligned(Element.ALIGN_RIGHT, word, width - 20, height / 2 - 50, rotation);
content.showTextAligned(Element.ALIGN_RIGHT, word, width - 20, height / 4 - 50, rotation);
}
content.endText();//结束写入文本
stamper.flush();
}
} finally {
fis.close();
stamper.close();
reader.close();
}
}
/************************************************************ Excel水印设置 ************************************************************/
/**
* 设置excel水印
*/
static class FontImage {
final static String[] TEXT = new String[]{"XXXX水印"};
final static Integer fontSize = 24;
/**
* <p>Title: 设置水印相关信息 </p>
* <p>Description: 水印信息 </p>
*/
static class Watermark {
private Boolean enable;
private String[] text;
private String dateFormat;
private String color;
public Watermark() {
}
public Watermark(Boolean enable, String[] text, String dateFormat, String color) {
this.enable = enable;
this.text = text;
this.dateFormat = dateFormat;
this.color = color;
}
public Boolean getEnable() {
return enable;
}
public void setEnable(Boolean enable) {
this.enable = enable;
}
public String[] getText() {
return text;
}
public void setText(String[] text) {
this.text = text;
}
public String getDateFormat() {
return dateFormat;
}
public void setDateFormat(String dateFormat) {
this.dateFormat = dateFormat;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
/**
* <p>Title: 生成水印图片信息 </p>
* <p>Description: 生成水印图片信息 </p>
*/
public static BufferedImage createWatermarkImage(Watermark watermark) {
if (watermark == null) {
watermark = new Watermark();
watermark.setEnable(true);
watermark.setText(TEXT);
watermark.setColor("#C5CBCF");
watermark.setDateFormat("yyyy-MM-dd HH:mm");
} else {
if (StringUtils.isEmpty(watermark.getDateFormat())) {
watermark.setDateFormat("yyyy-MM-dd HH:mm");
} else if (watermark.getDateFormat().length() == 16) {
watermark.setDateFormat("yyyy-MM-dd HH:mm");
} else if (watermark.getDateFormat().length() == 10) {
watermark.setDateFormat("yyyy-MM-dd");
}
if (watermark.getText().length == 0) {
watermark.setText(TEXT);
}
if (StringUtils.isEmpty(watermark.getColor())) {
watermark.setColor("#C5CBCF");
}
}
Font font = new Font("微软雅黑", Font.PLAIN, fontSize);
Integer width = 500;
Integer height = 100 * watermark.getText().length;
// 设置最大的宽度
for (int j = 0; j < watermark.getText().length; j++) {
int textWidth = fontSize * watermark.getText()[j].length();
if (textWidth > width) {
width = textWidth;
}
}
height = (width / 2);
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(watermark.getColor().substring(1), 16)));
// 设置画笔字体
g.setFont(font);
// 设定倾斜度
g.shear(0, -0.3);
// 消除文字锯齿
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
//设置字体平滑
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int y = (height / 2) + font.getSize() * 2;
int x = 0;
for (int j = 0; j < watermark.getText().length; j++) {
String[] textArray = watermark.getText()[j].split("\n");
y += 1 * (j + 1);
// 计算文字长度,计算居中的x点坐标
FontMetrics fm = g.getFontMetrics(font);
int textWidth = fm.stringWidth(watermark.getText()[j]);
x = (width - textWidth) / 2;
for (int i = 0; i < textArray.length; i++) {
// 画出字符串
g.drawString(textArray[i], x, y);
y = y + font.getSize();
}
}
g.dispose();// 释放画笔
return image;
}
}
/**
* <p>Title: 添加水印 </p>
* <p>Description: 添加水印 </p>
*
* @param workbook 工作薄
* @param waterMark 水印信息
*/
public static void addWorkbookWaterMark(Workbook workbook, String waterMark) {
if (workbook != null) {
XSSFWorkbook xssfWorkbook = (XSSFWorkbook) workbook;
for (int i = 0; i < xssfWorkbook.getNumberOfSheets(); i++) {
addWaterMark(xssfWorkbook, xssfWorkbook.getSheetAt(i), waterMark);
}
}
}
/**
* <p>Title: 添加水印 </p>
* <p>Description: 添加水印信息 </p>
*
* @param wb 工作薄
* @param sheet 工作表
* @param waterMark 水印信息
*/
public static void addWaterMark(XSSFWorkbook wb, XSSFSheet sheet, String waterMark) {
//是否添加水印
if (StringUtils.isNotBlank(waterMark)) {
FontImage.Watermark watermark = new FontImage.Watermark();
watermark.setText(new String[]{waterMark});
watermark.setEnable(true);
BufferedImage image = FontImage.createWatermarkImage(watermark);
// 导出到字节流B
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
ImageIO.write(image, "png", os);
} catch (IOException e) {
log.error("add watermark error: {}", e.getMessage());
}
int pictureIdx = wb.addPicture(os.toByteArray(), Workbook.PICTURE_TYPE_PNG);
POIXMLDocumentPart poixmlDocumentPart = wb.getAllPictures().get(pictureIdx);
PackagePartName ppn = poixmlDocumentPart.getPackagePart().getPartName();
String relType = XSSFRelation.IMAGES.getRelation();
//add relation from sheet to the picture data
PackageRelationship pr = sheet.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);
//set background picture to sheet
sheet.getCTWorksheet().addNewPicture().setId(pr.getId());
}
}
/************************************************************ word水印设置 ************************************************************/
// word字体
private static final String fontName = "宋体";
// 字体大小
private static final String fontSize = "0.2pt";
// 字体颜色
private static final String fontColor = "#d0d0d0";
// 一个字平均长度,单位pt,用于:计算文本占用的长度(文本总个数*单字长度)
private static final Integer widthPerWord = 10;
// 与顶部的间距
private static Integer styleTop = 0;
// 文本旋转角度
private static final String styleRotation = "20";
/**
* 给文档添加水印
* 此方法可以单独使用
*
* @param doc
* @param customText
*/
public static void waterMarkDocXDocument(XWPFDocument doc, String customText) {
// 把整页都打上水印
for (int lineIndex = -5; lineIndex < 10; lineIndex++) {
styleTop = 300 * lineIndex;
waterMarkDocXDocument_0(doc, customText);
}
}
/**
* 为文档添加水印
*
* @param doc 需要被处理的docx文档对象
* @param customText 需要添加的水印文字
*/
public static void waterMarkDocXDocument_0(XWPFDocument doc, String customText) {
// 水印文字之间使用8个空格分隔
customText = customText + repeatString(" ", 8);
// 一行水印重复水印文字次数
customText = repeatString(customText, 10);
// 如果之前已经创建过 DEFAULT 的Header,将会复用
XWPFHeader header = doc.createHeader(HeaderFooterType.DEFAULT);
int size = header.getParagraphs().size();
if (size == 0) {
header.createParagraph();
}
CTP ctp = header.getParagraphArray(0).getCTP();
byte[] rsidr = doc.getDocument().getBody().getPArray(0).getRsidR();
byte[] rsidrdefault = doc.getDocument().getBody().getPArray(0).getRsidRDefault();
ctp.setRsidP(rsidr);
ctp.setRsidRDefault(rsidrdefault);
CTPPr ppr = ctp.addNewPPr();
ppr.addNewPStyle().setVal("Header");
// 开始加水印
CTR ctr = ctp.addNewR();
CTRPr ctrpr = ctr.addNewRPr();
ctrpr.addNewNoProof();
CTGroup group = CTGroup.Factory.newInstance();
CTShapetype shapetype = group.addNewShapetype();
CTTextPath shapeTypeTextPath = shapetype.addNewTextpath();
shapeTypeTextPath.setOn(STTrueFalse.T);
shapeTypeTextPath.setFitshape(STTrueFalse.T);
CTLock lock = shapetype.addNewLock();
lock.setExt(STExt.VIEW);
CTShape shape = group.addNewShape();
shape.setId("PowerPlusWaterMarkObject");
shape.setSpid("_x0000_s102");
shape.setType("#_x0000_t136");
// 设置形状样式(旋转,位置,相对路径等参数)
shape.setStyle(getShapeStyle(customText));
shape.setFillcolor(fontColor);
// 字体设置为实心
shape.setStroked(STTrueFalse.FALSE);
// 绘制文本的路径
CTTextPath shapeTextPath = shape.addNewTextpath();
// 设置文本字体与大小
shapeTextPath.setStyle("font-family:" + fontName + ";font-size:" + fontSize);
shapeTextPath.setString(customText);
CTPicture pict = ctr.addNewPict();
pict.set(group);
}
/**
* 构建Shape的样式参数
*
* @param customText
* @return
*/
private static String getShapeStyle(String customText) {
StringBuilder sb = new StringBuilder();
// 文本path绘制的定位方式
sb.append("position: ").append("absolute");
// 计算文本占用的长度(文本总个数*单字长度)
sb.append(";width: ").append(customText.length() * widthPerWord).append("pt");
// 字体高度
sb.append(";height: ").append("20pt");
sb.append(";z-index: ").append("-251654144");
sb.append(";mso-wrap-edited: ").append("f");
// 设置水印的间隔,这是一个大坑,不能用top,必须要margin-top。
sb.append(";margin-top: ").append(styleTop);
sb.append(";mso-position-horizontal-relative: ").append("page");
sb.append(";mso-position-vertical-relative: ").append("page");
sb.append(";mso-position-vertical: ").append("left");
sb.append(";mso-position-horizontal: ").append("center");
sb.append(";rotation: ").append(styleRotation);
return sb.toString();
}
/**
* 将指定的字符串重复repeats次.
*/
private static String repeatString(String pattern, int repeats) {
StringBuilder buffer = new StringBuilder(pattern.length() * repeats);
Stream.generate(() -> pattern).limit(repeats).forEach(buffer::append);
return new String(buffer);
}
}
调用示例
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); wb.write(byteArrayOutputStream); byteArrayOutputStream.flush(); WaterMarkUtil.addWatermarkAndCopy(byteArrayOutputStream, os, "xlsx");
return WaterMarkUtil.waterMark(file.toString(), doc.getDocumentName());
InputStream watermarkedStream = WaterMarkUtil.waterMarkfis(is, fileType);