參考的博客: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);
}
}
}
效果: