Java | 将文字生成在空白图片居中位置(根据图片大小,自动调节文字大小)
话不多说,直接上代码。(大家可以自己根据需要设置图片大小,不过图片过小时,字体会变模糊,尽量设置图片大一点,600~1000左右比较合适)
代码:
import lombok.extern.slf4j.Slf4j;
import sun.font.FontDesignMetrics;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 慌途L
* 描述:将文字居中对齐生成在空白图片中间
*/
@Slf4j
public class ImagesUtils {
/**
* 图片宽度
*/
private static final int WIDTH = 800;
/**
* 图片高度
*/
private static final int HEIGHT = 800;
/**
* 字符间距缩放比
*/
private static final double SCALE_WORD_SPACE = 1.0;
/**
* 文字开头和结尾在图片中距离左、右的总和(单边距离最少30)
*/
private static final int MIN_DISTANCE = 60;
/**
* 文字大小
*/
public static int size = 120;
/**
* 默认字体格式
*/
private static final Font font = new Font("宋体", Font.PLAIN, size);
/**
* 生成图片并转成字节流,方便上传到OSS服务器
*
* @param content 文字
* @return 返回字节流
*/
public static InputStream generateImagesToInputStream(String content) {
BufferedImage image = drawString(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB, content, Color.BLACK, SCALE_WORD_SPACE);
ByteArrayOutputStream os = new ByteArrayOutputStream();
InputStream input = null;
try {
ImageIO.write(image, "jpg", os);
input = new ByteArrayInputStream(os.toByteArray());
return input;
} catch (IOException e) {
e.printStackTrace();
log.error("根据文字生成图片转换成字节流异常", e);
throw new RuntimeException("根据文字生成图片转换成字节流异常...");
}
}
/**
* 根据文字生成图片
*
* @param content 文字
* @param filePath 生成图片后存的路径和名字(如:D:\\test.jpg)
* @return 返回图片路径
*/
public static String generateImages(String content, String filePath) {
OutputStream out = null;
try {
BufferedImage bufferedImage = drawString(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB, content, Color.BLACK, SCALE_WORD_SPACE);
out = new BufferedOutputStream(new FileOutputStream(filePath));
ImageIO.write(bufferedImage, "jpg", out);
return filePath;
} catch (Exception e) {
e.printStackTrace();
log.error("根据文字生成图片转换成字节流异常", e);
throw new RuntimeException("根据文字生成图片转换成字节流异常...");
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
log.error("关流失败");
}
}
}
/**
* 绘制图片
*
* @param width 画布宽
* @param height 画布高
* @param imageType 画布类型
* @param content 绘制的文本
* @param color 字体颜色
* @param scaleWordSpace 字符间距缩放比
* @return
*/
public static BufferedImage drawString(int width, int height, int imageType, String content, Color color, double scaleWordSpace) {
BufferedImage image = new BufferedImage(width, height, imageType);
Graphics2D graphics = image.createGraphics();
// 填充白色背景图
graphics.fillRect(0, 0, width, height);
graphics.setColor(Color.WHITE);
// 设置字体
Font font = new Font("宋体", Font.PLAIN, size);
graphics.setFont(font);
//根据字体格式,获取字符串占用宽度
int stringWidth = graphics.getFontMetrics().stringWidth(content);
//通过比较字符串体每次设定完尺寸后的宽度是否超过图片宽度限定尺寸,从而减小字体尺寸
while (stringWidth > (width + MIN_DISTANCE)) {
size -= 1;
graphics.setFont(new Font("宋体", Font.PLAIN, size));
stringWidth = graphics.getFontMetrics().stringWidth(content);
}
// 计算文字在图片中的x轴坐标
int x = (width - stringWidth) / 2;
while (x < (MIN_DISTANCE / 2)) {
size -= 1;
graphics.setFont(new Font("宋体", Font.PLAIN, size));
stringWidth = graphics.getFontMetrics().stringWidth(content);
x = (width - stringWidth) / 2;
}
// 平分文字前和文字后距离图片边距X轴的距离
x = x / 2;
// 设置字体颜色
graphics.setColor(color);
// 抗锯齿 添加文字 (KEY_TEXT_ANTIALIASING 确定对文本着色时是否抗锯齿。可能的值有 VALUE_TEXT_ANTIALIASING_ON, _OFF 或 _DEFAULT)
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// 用于计算字体的宽高
FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
// 计算文字在宽高的位置进行固定
Rectangle2D bounds = metrics.getStringBounds(content, graphics);
int boundsHeight = (int) bounds.getHeight();
// 文字在图片中的y轴坐标
int y = Math.round((height + boundsHeight - font.getSize() * 1.0f / 2) / 2 - 2);
// 将文字在图片中指定的xy轴坐标画出
drawString(content, x, y, scaleWordSpace, graphics);
graphics.dispose();
image.flush();
return image;
}
/**
* 根据X-Y轴的坐标绘制字体在图片中的位置
*
* @param content 绘制的文本
* @param x 起始位置
* @param y 起始位置
* @param scaleWordSpace 字符间距缩放比
* @param graphics
*/
private static void drawString(String content, int x, int y, double scaleWordSpace, Graphics graphics) {
String tempStr = "";
int tempx = x;
int tempy = y;
double workSpace = scaleWordSpace;
double orgStringWith = 0.0;
while (content.length() > 0) {
tempStr = content.substring(0, 1);
content = content.substring(1);
orgStringWith = graphics.getFontMetrics().stringWidth(tempStr);
graphics.drawString(tempStr, tempx, tempy);
// 如果不是中文则需要增加字符或数字之间的间距
workSpace = !isContainChinese(tempStr) ? 1.3 : workSpace;
if (tempStr.getBytes().length == 1) {
tempx = (int) Math.round(tempx + orgStringWith * workSpace * 0.8);
} else {
tempx = (int) Math.round(tempx + orgStringWith * workSpace);
}
}
}
/**
* 判断字符串中是否包含中文
*
* @param str 待校验字符串
* @return 是:true 否:false
* @warn 不能校验是否为中文标点符号
*/
private static boolean isContainChinese(String str) {
Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
Matcher m = p.matcher(str);
return m.find();
}
public static void main(String[] args) {
String filePath = ImagesUtils.generateImages("12345652316411sdfffdf", "F:\\test.jpg");
System.out.println(filePath);
}
}