参考的博客:https://blog.csdn.net/m0_37798992/article/details/80856338
原文实现了根据文字自动换行的逻辑。参考后略加修改和优化,实现了左右留白,文字在最下面显示。
package util;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javassist.bytecode.stackmap.BasicBlock.Catch;
public final class MarkImageUtils {
private MarkImageUtils() {
}
/**
* 给图片添加单个文字水印、可设置水印文字旋转角度
* @param source 需要添加水印的图片路径(如:F:/images/6.jpg)
* @param outPut 添加水印后图片输出路径(如:F:/images/)
* @param imageName 图片名称(如:11111)
* @param imageType 图片类型(如:jpg)
* @param waterMarkWord 水印文字
* @param color 水印文字的颜色
* @param fontSize 水印字体的大小
* @param degree 水印文字旋转角度,为null表示不旋转
*/
public static String markImageBySingleText(String source,String output,String imageName,String imageType,String waterMarkWord, Color color, int fontSize, Integer degree) {
String result = "添加文字水印出错";
try {
//读取原图片信息
File file = new File(source);
if (!file.isFile()) {
return file + " 不是一个图片文件!";
}
Image img = ImageIO.read(file);
int width = img.getWidth(null);
int height = img.getHeight(null);
//初始化
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
g.drawImage(img, 0, 0, width, height, null);
//设置水印字体样式
Font font = new Font("宋体", Font.BOLD, fontSize);
//根据图片的背景设置水印颜色
g.setColor(color);
// 设置字体
g.setFont(font);
if (null != degree) {
//设置水印旋转
g.rotate(Math.toRadians(degree),(double) bi.getWidth() / 2, (double) bi.getHeight() / 2);
}
// 获取行数
int strContentWidth =getStringLength(g,waterMarkWord);
int row = getRows(strContentWidth, width, g);
// 基本字符长度
int basicCharLen = getCharLen('一', g);
int x = basicCharLen;
int y = height - row * getStringHeight(g);
// 自动换行
drawStringWithFontStyleLineFeed(g,waterMarkWord, x, y, width);
g.dispose();
//输出图片
File sf = new File(output, imageName+"."+imageType);
ImageIO.write(bi, imageType, sf); // 保存图片
result = "图片完成添加Word水印";
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String output = "F:/";
String source = "F:/1.jpg"; //源图片路径
String imageName = "mark_image"; //图片名称
String imageType = "jpg"; //图片类型jpg,jpeg,png,gif
String waterMarkWord = "[大雾黄色预警信号]市气象台2019年12月16日08时00分发布大雾黄色预警信号:预计16日08时至23时,本市大部分地区有雾,能见度小于1千米,部分地区小于500米,请注意防范。";
Integer degree = null; //水印旋转角度-45,null表示不旋转
String result = null;
// 给图片加单个文字水印
result = MarkImageUtils.markImageBySingleText(source, output, imageName, imageType, waterMarkWord, Color.red, 30, degree);
System.out.println(result);
}
/**
*@Description: 水印文字总宽度(包括中英文)
*@Since: 2019年12月16日上午10:59:10
*@param g 画笔
*@param waterMarkWord 字符串
*@return 字符串总宽度
*/
public static int getStringLength( Graphics g, String waterMarkWord) {
char[] strcha=waterMarkWord.toCharArray();
int strWidth = g.getFontMetrics().charsWidth(strcha, 0, waterMarkWord.length());
System.out.println("水印文字总宽度:"+strWidth);
return strWidth;
}
public static int getCharLen(char c, Graphics g) {
return g.getFontMetrics(g.getFont()).charWidth(c);
}
/**
*@Description: 计算字符行数
*@Since: 2019年12月16日上午11:36:32
*@param strContentWidth 水印文字所占宽度
*@param rowWidth 每一行字符串|图片宽度
*@return
*/
private static int getRows(int strContentWidth,int imgWidth, Graphics g){
int rows=0;
int basicCharLen = getCharLen('一', g);
imgWidth = imgWidth-2*basicCharLen;
if(strContentWidth%imgWidth>0){
rows=strContentWidth/imgWidth+1;
}else{
rows=strContentWidth/imgWidth;
}
System.out.println("行数:"+rows);
return rows;
}
/**
*@Description: 字符高度
*@Since: 2019年12月16日上午11:05:25
*@param g
*@return
*/
private static int getStringHeight(Graphics g) {
int height = g.getFontMetrics().getHeight();
System.out.println("字符高度:"+height);
return height;
}
private static void drawStringWithFontStyleLineFeed(Graphics g, String waterMarkWord, int locX, int locY, int width){
//获取水印文字总宽度
int strContentWidth =getStringLength(g,waterMarkWord);
//图片宽度
int imgWidth=width - 10;
System.out.println("每行文字|图片宽度:"+imgWidth);
//获取字符高度
int strHeight=getStringHeight(g);
//字符串总个数(中英文标点都算一个字符)
int strLength = waterMarkWord.length();
System.out.println("字符串总个数:"+strLength);
int tempX = locX;
int tempY = locY;
if(strContentWidth>imgWidth){
//文字叠加,自动换行叠加
int tempCharLen = 0;//单字符长度
int tempLineLen = 0;//单行字符总长度临时计算
int basicCharLen = getCharLen('一', g);
StringBuilder stringBuffer = new StringBuilder();
for (int i = 0; i < waterMarkWord.length(); i++) {
char tempChar = waterMarkWord.charAt(i);
tempCharLen = getCharLen(tempChar, g);
if (tempLineLen + 2*basicCharLen >= imgWidth) {
// 绘制前一行
g.drawString(stringBuffer.toString(), tempX, tempY);
//清空内容,重新追加
stringBuffer.delete(0, stringBuffer.length());
//文字长度已经满一行,Y的位置加1字符高度
tempY = tempY + strHeight;
tempLineLen = 0;
}
//追加字符
tempLineLen += tempCharLen;
stringBuffer.append(tempChar);
}
//最后叠加余下的文字
g.drawString(stringBuffer.toString(), tempX, tempY);
}else{
//直接绘制
g.drawString(waterMarkWord, tempX, tempY);
}
}
}
效果: