最近项目需要给用户上传的图片打上时间戳等信息的水印。由于我们图片是存在阿里云OSS上,首先想的是用OSS自带的方式添加省事,地址是https://help.aliyun.com/document_detail/44957.html
发现虽然简单,但是水印内容通过编码拼接在图片地址后面,每次访问都要加上,如果要保存下来还需要自己存第二遍有水印的图。可是我们并不需要没有水印的原图,于是决定通过代码添加,更自由。
代码如下:
/**
* 添加文字水印
* @param inputStream 原图片
* @param waterMarkContent 水印文字内容数组
* @param markContentColor 颜色
* @param font 字体
* @param format 图片格式
* @return
*/
public static byte[] addWaterMark(byte[] inputStream, String[] waterMarkContent,Color markContentColor,Font font,String format) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
// printSysFont();
try {
if(markContentColor==null)
markContentColor=new Color(189, 66, 71, 255); //水印图片色彩以及透明度 255是不透明
if(font==null)
font = new Font("宋体", Font.PLAIN, 15); //水印字体
ByteArrayInputStream in = new ByteArrayInputStream(inputStream); //将b作为输入流;
Image srcImg = ImageIO.read(in);
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);
g.setColor(markContentColor); //根据图片的背景设置水印颜色
g.setFont(font); //设置字体
//设置水印的坐标
for(int i = 0;i<waterMarkContent.length;i++){
if(StringUtils.isBlank(waterMarkContent[i]))
continue;
System.out.println("内容:"+waterMarkContent[i]);
int x = srcImgWidth - getWatermarkLength(waterMarkContent[i], g);
int y = font.getSize()*(i+1);
g.drawString(waterMarkContent[i], x>0?x:0, y); //画出水印
System.out.println("画出水印x:"+x+",y:"+y);
}
g.dispose();
// 输出图片
ImageIO.write(bufImg, format, out);
System.out.println("添加水印完成");
byte[] ret = out.toByteArray();
return ret;
} catch (Exception e) {
e.printStackTrace();
return inputStream;
// TODO: handle exception
}
}
public static byte[] addWaterMark(byte[] inputStream, String[] waterMarkContent,String format) {
return addWaterMark(inputStream, waterMarkContent, null, null,format);
}
/**
* 要打上文字的长度
* @param waterMarkContent
* @param g
* @return
*/
private static int getWatermarkLength(String waterMarkContent, Graphics2D g) {
return g.getFontMetrics(g.getFont()).charsWidth(waterMarkContent.toCharArray(), 0, waterMarkContent.length());
}
其中因为水印内容预计有三行,分别是公司名,时间戳以及另一个内容,所以传入的是字符数组,它会一行一行印上去,传入的是一个byte[],因为是在其它业务逻辑里面添加的功能,所以返回也是byte 其它格式转也很方便的。
使用:
String[] waterMarkContent = new String[3];
waterMarkContent[0] = "XXXXX";
waterMarkContent[1] = "XXXXX公司";
waterMarkContent[2] = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date());
imageFile = ImageUtil.addWaterMark(imageFile, waterMarkContent, "jpg");
之后在我自己电脑上测试了一下没什么问题
项目通过docker部署,打包后发现中文显示不出来!是框框!
因为不是乱码排除编码格式问题,比较明显是该环境下没有对应的字体。
搜了一下解决办法,比较好的解决方式是在dockerfile制作镜像的时候把你要用的字体文件放进去:
自己找个 simsun.ttf 放到工程目录
然后添加一行:COPY simsun.ttf /usr/share/fonts/simsun.ttf
FROM java:8
ENV TZ=Asia/Shanghai
RUN apt-get install tzdata
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 配置字体
COPY simsun.ttf /usr/share/fonts/simsun.ttf
VOLUME /tmp
ADD myApp.jar /app.jar
EXPOSE 0000
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
OK,问题解决。希望能帮助遇到同样问题的人,毕竟网上其他手动安装,加入字体下载命令 等方式不太好用
11月15日更新一下:水印的字体大小自适应。发现用户上传的图片大小不一,字体需要相应变化。
int srcImgWidth = srcImg.getWidth(null);//获取图片的宽 int srcImgHeight = srcImg.getHeight(null);//获取图片的高 if(font==null){ int fontSize = srcImgWidth/300*10+10; font = new Font("宋体", Font.PLAIN, fontSize);//水印字体 }