最近由于业务上的需求,需要动态的在图片模板上加上用户的姓名和日期等信息。
在一番搜索后找到了如下方法,记录一下。
/**
* 为图片增加水印
*
* @param srcImgFile 源图片
* @param imageFile 保存的图片
* @param contentList 水印参数
* @throws IOException
*/
public File addWaterMark(File srcImgFile, File imageFile, List<WaterContentParam> contentList,
Color markContentColor) throws IOException {
// 文件转化为图片
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);
// 根据图片的背景设置水印颜色
g.setColor(markContentColor);
// 循环增加水印
for (WaterContentParam param : contentList) {
String content = param.getContentText();
// 设置字体
g.setFont(param.getFont());
// 设置水印的坐标
int contentWidth = g.getFontMetrics(g.getFont()).charsWidth(content.toCharArray(), 0, content.length());
int x = param.getStartX() + (param.getSpaceWidth() - contentWidth) / 2;
// 画出水印
g.drawString(content, x, param.getStartY());
}
g.dispose();
// 输出图片
ImageIO.write(bufImg, "png", imageFile);
return imageFile;
}
参数类
/**
* 图片增加水印的相关参数
*
*/
public class WaterContentParam {
/**
* 水印内容文本
*/
private String contentText;
/**
* 水印位置X坐标
*/
private Integer startX;
/**
* 水印位置Y坐标
*/
private Integer startY;
/**
* 水印字体参数
*/
private Font font;
/**
*文本所在空间宽度 方便计算居中
*/
private Integer spaceWidth;
public WaterContentParam(String contentText, Integer startX, Integer startY, Font font, Integer spaceWidth) {
this.contentText = contentText;
this.startX = startX;
this.startY = startY;
this.font = font;
this.spaceWidth = spaceWidth;
}
public String getContentText() {
return contentText;
}
public void setContentText(String contentText) {
this.contentText = contentText;
}
public Integer getStartX() {
return startX;
}
public void setStartX(Integer startX) {
this.startX = startX;
}
public Integer getStartY() {
return startY;
}
public void setStartY(Integer startY) {
this.startY = startY;
}
public Font getFont() {
return font;
}
public void setFont(Font font) {
this.font = font;
}
public Integer getSpaceWidth() {
return spaceWidth;
}
public void setSpaceWidth(Integer spaceWidth) {
this.spaceWidth = spaceWidth;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
}
总结:
1.g.getFontMetrics(g.getFont()).charsWidth(str.toCharArray(),0, str.length());
这个方法用来获取水印文本的整体宽度,可以用来动态计算水印的X坐标。比如我在业务实现中通过这个计算来使用户名字能够居中显示在图片横线上。
2.在服务器测试环境上出现了无法读取文件的错误。经过老大的提醒,原因出在工程是打了jar包发到环境上的,无法通过地址去读取文件。解决方法是转换为流读取。
// 环境上的文件因为打为jar包的原因 需要用流去获取
InputStream is = this.getClass().getClassLoader().getResourceAsStream(pngPath);
// 读取原图片信息
File imgFile = new File(pngPath);
// 流信息复制到file中
FileUtils.copyInputStreamToFile(is, imgFile);
3.在测试环境上还出现了图片中中文乱码,显示几个方框的问题。经过排查是因为测试环境没有中文字体。需要增加字体到测试环境上就可以解决问题了,这里注意增加字体后需要重启服务
才会生效,这点很容易被忽视导致加了字体还是乱码却找不到原因。
Font[] allfonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
for (int j = 0; j < allfonts.length; j++) {
System.out.println(j + "-" + allfonts[j].getFontName());
}
上面是输出环境中字体信息的方法,可以用来检测。