给图片或者PDF流数据加水印
当业务需要对图片/PDF文件预览或者下载文件加水印实现,当我们获取不到图片路径时(如图片放在阿里云服务器),故我们只能对文件流加水印!!!(文章末尾附完整代码)
fileId为get请求中携带的文件id,我们通过传递的文件id获取文件扩展名判断文件类型,选择调用不同的方法,setWatermark()是给pdf文件加水印,paintWatermarkImage()图片格式加水印
DefaultFile sysFile = fileManager.get(fileId);
String extensionName = sysFile.getExtensionName();
if(extensionName.equals("pdf")){
WaterMarkPdfUtil.setWatermark(response,byteArrayOutputStream);
}else{
ImageWatermarkUtil.paintWatermarkImage(response,byteArrayOutputStream,fileId);
}
setWatermark()给pdf文件加水印
该方法有两个参数,outputStream为pdf文件的文件流
setWatermark(HttpServletResponse response, OutputStream outputStream)
package com.hotent.util;
import com.alibaba.fastjson.JSONObject;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletResponse;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.text.SimpleDateFormat;
@Slf4j
public class WaterMarkPdfUtil {
//设置水印内容
private static final String MARK_TEXT = "公司LOGO\npinyinming\n";
private static final BaseColor bg = new BaseColor(0x70, 0x70, 0x70);
private static final int FONT_SIZE = 60;
private static final float ALPHA = 0.2F;
private static final String FONT_NAME = "宋体";
private static final int FONT_STYLE = Font.BOLD;
/**
*
* @param response pdf文件加水印后
* @param outputStream pdf原文件流
* @throws DocumentException
* @throws IOException
*/
public static void setWatermark(HttpServletResponse response, OutputStream outputStream, String fileId)
throws DocumentException, IOException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd:HH:mm");
String format = simpleDateFormat.format(System.currentTimeMillis());
//水印内容拼接当前时间
String MARK = MARK_TEXT+format;
// 使用"\n"将内容进行分割
String[] waterMarkContents = MARK.split("\n");
log.info("水印内容:{}", JSONObject.toJSONString(waterMarkContents));
InputStream in = new ByteArrayInputStream(((ByteArrayOutputStream)outputStream).toByteArray());
PdfReader reader = new PdfReader(in);
//
PdfStamper stamper = new PdfStamper(reader,
response.getOutputStream());
// new FileOutputStream("C:\\Users\\HP\\Desktop\\dd.pdf"));
// 获取总页数 +1, 下面从1开始遍历
int total = reader.getNumberOfPages() + 1;
BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
// 间隔
int interval = 20;
// 获取水印文字的最大高度和宽度
int textH = 0, textW = 0;
for (int j = 0; j < waterMarkContents.length; j++) {
JLabel label = new JLabel();
log.info("waterMarkContents[j]:{}", waterMarkContents[j]);
label.setText(waterMarkContents[j]);
FontMetrics metrics = label.getFontMetrics(label.getFont());
if (textH < metrics.getHeight()) {
textH = metrics.getHeight();
}
if (textW < metrics.stringWidth(label.getText())) {
textW = metrics.stringWidth(label.getText());
}
// 设置水印透明度
PdfGState gs = new PdfGState();
gs.setFillOpacity(ALPHA);
gs.setStrokeOpacity(ALPHA);
Rectangle pageSizeWithRotation = null;
PdfContentByte content = null;
for (int i = 1; i < total; i++) {
content = stamper.getOverContent(i);
content.saveState();
content.setGState(gs);
// 设置字体和字体大小
content.beginText();
content.setFontAndSize(base, FONT_SIZE);
// 设置颜色
content.setColorFill(bg);
// 获取每一页的高度、宽度
pageSizeWithRotation = reader.getPageSizeWithRotation(i);
float pageHeight = (float) pageSizeWithRotation.getHeight();
float pageWidth = (float) pageSizeWithRotation.getWidth();
int lineX =0;
for (int z = 0; z < waterMarkContents.length; z++) {
content.showTextAligned(Element.ALIGN_RIGHT, waterMarkContents[z], (float) (pageWidth*0.7 + textW*(z-1)),
(float) (pageHeight*0.7-textW/1.4-(textH + textH+90)*z),45);
}
content.endText();
}
// 关闭流
stamper.close();
reader.close();
}
}
}
paintWatermarkImage()方法,对图片格式加水印
paintWatermarkImage(HttpServletResponse response,OutputStream outputStream,String fileId)主要有两个参数,outputStream是我们图片的流数据,response是为了给添加水印后调用response.getOutputStream()返回加水印后的流数据
方法中水印的位置以及字体信息都有相应注释,可找到自行设置,本文设置水印为单个居中。(也可自行加for循环使水印铺满全屏)
package com.hotent.util;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import sun.plugin2.jvm.CircularByteBuffer;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.List;
public class ImageWatermarkUtil {
private static final double ROTATE_ANGLE_RADIANS = Math.toRadians(30);
private static final double SIN_ROTATE_ANGLE = Math.sin(ROTATE_ANGLE_RADIANS);
private static final double COS_ROTATE_ANGLE = Math.cos(ROTATE_ANGLE_RADIANS);
//定义水印文字样式
private static final Color FONT_COLOR = new Color(0x70, 0x70, 0x70);
//宋体 微软雅黑
private static final String FONT_NAME = "宋体";
private static final int FONT_STYLE = Font.BOLD;
private static final float ALPHA = 0.2F;
// public static void main(String[] args) throws IOException {
// ImageWatermarkUtil.paintWatermarkImage(inputPath, outPutPath);
// }
/**
*
* @param outputStream 图片原始
* @param response 图片加水印之后
*/
public static void paintWatermarkImage(HttpServletResponse response,OutputStream outputStream,String fileId) {
String text = "公司LOGO\npinyinming\n";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd:HH:mm");
String format = simpleDateFormat.format(System.currentTimeMillis());
String MARK = text+format;
Image image = null;
try {
InputStream in = new ByteArrayInputStream(((ByteArrayOutputStream)outputStream).toByteArray());
image = ImageIO.read(in);
} catch (IOException e) {
e.printStackTrace();
}
//计算原始图片宽度长度
int width = image.getWidth(null);
int height = image.getHeight(null);
// 三角函数算出来的最小宽高,不浪费内存
width = (int) (width * COS_ROTATE_ANGLE + height * SIN_ROTATE_ANGLE);
height = (int) (width * SIN_ROTATE_ANGLE + height * COS_ROTATE_ANGLE);
BufferedImage bufferedImage =null;
try {
//创建图片缓存对象
bufferedImage= new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//创建java绘图工具对象
Graphics2D g = bufferedImage.createGraphics();
//参数主要是,原图,坐标,宽高
g.drawImage(image, 0, 0, width, height, null);
// 考虑到大尺寸图片,水印在手机上显示比较小,字体大小根据图片宽度来设置
g.setFont(new Font(FONT_NAME, FONT_STYLE, (width / MARK.length())*4));
g.setColor(FONT_COLOR);
// 设置旋转角度,透明度
g.rotate(-ROTATE_ANGLE_RADIANS, bufferedImage.getWidth() / 2, bufferedImage.getHeight() / 2);
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, ALPHA));
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
List<String> watermarkTextLines = Arrays.asList(MARK.split("\n"));
int blockWidth = getTextBlockWidth(g, watermarkTextLines);
int blockHeight = getTextBlockHeight(g, watermarkTextLines);
int evenStartX = -(blockWidth + 480) / 2; // 偶数行的起始位置
evenStartX = 0;
int lineNum = 0; // 当前行号
// for (int y = 20; y < height; y += (blockHeight*3+ blockHeight)) {
// // 水印交错排列
// lineNum++;
// int startX = lineNum % 2 == 0 ? evenStartX : 0;
//
// for (int x = startX; x < width; x += (blockWidth*3+ blockWidth)) {
// drawString(g, blockWidth, x, y, watermarkTextLines);
// }
// }
drawString(g, blockWidth, (int) (width*0.4), (int) (height*0.4), watermarkTextLines);
g.dispose();
ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
private static int getTextBlockHeight(Graphics g, List<String> watermarkTextLines) {
return g.getFontMetrics().getHeight() * watermarkTextLines.size();
}
private static int getTextBlockWidth(Graphics g, List<String> watermarkTextLines) {
int blockWidth = 0; // 整个文本块的宽度
for (String line : watermarkTextLines) {
int lineWidth = g.getFontMetrics().stringWidth(line);
if (lineWidth > blockWidth) {
blockWidth = lineWidth;
}
}
return blockWidth;
}
// 绘制一个水印块,多行文本居中对齐
private static void drawString(Graphics g, int blockWidth, int x, int y, List<String> watermarkTextLines) {
int midX = x + blockWidth / 2; // 中线的x坐标
for (String line : watermarkTextLines) {
int lineWidth = g.getFontMetrics().stringWidth(line);
int lineX = midX - lineWidth / 2;
// 对齐
lineX = lineX - (int) Math.round(y * SIN_ROTATE_ANGLE / COS_ROTATE_ANGLE);
g.drawString(line, lineX, y);
y += g.getFontMetrics().getHeight()*2;
}
}
}
最后我们通过调用请求接口可得到结果
PDF文件加水印后对比
链接: https://blog.csdn.net/m0_63279291/article/details/124323317