mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
add FontUtil
This commit is contained in:
parent
7c803950ef
commit
73b2f75de2
@ -16,6 +16,7 @@
|
||||
* 【core 】 BeanValuePovider转换失败时,返回原数据,而非null
|
||||
* 【core 】 支持BeanUtil.toBean(object, Map.class)转换(issue#I1I4HC@Gitee)
|
||||
* 【core 】 MapUtil和CollUtil增加clear方法(issue#I1I4HC@Gitee)
|
||||
* 【core 】 增加FontUtil,可定义pressText是否从中间(issue#I1HSWU@Gitee)
|
||||
|
||||
### Bug修复
|
||||
* 【core 】 修复SimpleCache死锁问题(issue#I1HOKB@Gitee)
|
||||
|
123
hutool-core/src/main/java/cn/hutool/core/img/FontUtil.java
Normal file
123
hutool-core/src/main/java/cn/hutool/core/img/FontUtil.java
Normal file
@ -0,0 +1,123 @@
|
||||
package cn.hutool.core.img;
|
||||
|
||||
import cn.hutool.core.exceptions.UtilException;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import sun.font.FontDesignMetrics;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontFormatException;
|
||||
import java.awt.FontMetrics;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* AWT中字体相关工具类
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.3.6
|
||||
*/
|
||||
public class FontUtil {
|
||||
|
||||
/**
|
||||
* 创建默认字体
|
||||
*
|
||||
* @return 默认字体
|
||||
*/
|
||||
public static Font createFont() {
|
||||
return new Font(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建SansSerif字体
|
||||
*
|
||||
* @param size 字体大小
|
||||
* @return 字体
|
||||
*/
|
||||
public static Font createSansSerifFont(int size) {
|
||||
return createFont(Font.SANS_SERIF, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指定名称的字体
|
||||
*
|
||||
* @param name 字体名称
|
||||
* @param size 字体大小
|
||||
* @return 字体
|
||||
*/
|
||||
public static Font createFont(String name, int size) {
|
||||
return new Font(name, Font.PLAIN, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件创建字体<br>
|
||||
* 首先尝试创建{@link Font#TRUETYPE_FONT}字体,此类字体无效则创建{@link Font#TYPE1_FONT}
|
||||
*
|
||||
* @param fontFile 字体文件
|
||||
* @return {@link Font}
|
||||
*/
|
||||
public static Font createFont(File fontFile) {
|
||||
try {
|
||||
return Font.createFont(Font.TRUETYPE_FONT, fontFile);
|
||||
} catch (FontFormatException e) {
|
||||
// True Type字体无效时使用Type1字体
|
||||
try {
|
||||
return Font.createFont(Font.TYPE1_FONT, fontFile);
|
||||
} catch (Exception e1) {
|
||||
throw new UtilException(e);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件创建字体<br>
|
||||
* 首先尝试创建{@link Font#TRUETYPE_FONT}字体,此类字体无效则创建{@link Font#TYPE1_FONT}
|
||||
*
|
||||
* @param fontStream 字体流
|
||||
* @return {@link Font}
|
||||
*/
|
||||
public static Font createFont(InputStream fontStream) {
|
||||
try {
|
||||
return Font.createFont(Font.TRUETYPE_FONT, fontStream);
|
||||
} catch (FontFormatException e) {
|
||||
// True Type字体无效时使用Type1字体
|
||||
try {
|
||||
return Font.createFont(Font.TYPE1_FONT, fontStream);
|
||||
} catch (Exception e1) {
|
||||
throw new UtilException(e1);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得字体对应字符串的长宽信息
|
||||
*
|
||||
* @param font 字体
|
||||
* @param str 字符串
|
||||
* @return 长宽信息
|
||||
*/
|
||||
public static Dimension getDimension(Font font, String str) {
|
||||
final FontMetrics metrics = FontDesignMetrics.getMetrics(font);
|
||||
return getDimension(FontDesignMetrics.getMetrics(font), str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得字体对应字符串的长宽信息
|
||||
*
|
||||
* @param metrics {@link FontMetrics}
|
||||
* @param str 字符串
|
||||
* @return 长宽信息
|
||||
*/
|
||||
public static Dimension getDimension(FontMetrics metrics, String str) {
|
||||
final int width = metrics.stringWidth(str);
|
||||
final int height = metrics.getAscent() - metrics.getLeading() - metrics.getDescent();
|
||||
|
||||
return new Dimension(width, height);
|
||||
}
|
||||
|
||||
}
|
@ -1,16 +1,23 @@
|
||||
package cn.hutool.core.img;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* {@link Graphics}相关工具类
|
||||
*
|
||||
*
|
||||
* @author looly
|
||||
* @since 4.5.2
|
||||
*/
|
||||
@ -18,7 +25,7 @@ public class GraphicsUtil {
|
||||
|
||||
/**
|
||||
* 创建{@link Graphics2D}
|
||||
*
|
||||
*
|
||||
* @param image {@link BufferedImage}
|
||||
* @param color {@link Color}背景颜色以及当前画笔颜色,{@code null}表示不设置背景色
|
||||
* @return {@link Graphics2D}
|
||||
@ -26,8 +33,8 @@ public class GraphicsUtil {
|
||||
*/
|
||||
public static Graphics2D createGraphics(BufferedImage image, Color color) {
|
||||
final Graphics2D g = image.createGraphics();
|
||||
|
||||
if(null != color) {
|
||||
|
||||
if (null != color) {
|
||||
// 填充背景
|
||||
g.setColor(color);
|
||||
g.fillRect(0, 0, image.getWidth(), image.getHeight());
|
||||
@ -39,8 +46,8 @@ public class GraphicsUtil {
|
||||
/**
|
||||
* 获取文字居中高度的Y坐标(距离上边距距离)<br>
|
||||
* 此方法依赖FontMetrics,如果获取失败,默认为背景高度的1/3
|
||||
*
|
||||
* @param g {@link Graphics2D}画笔
|
||||
*
|
||||
* @param g {@link Graphics2D}画笔
|
||||
* @param backgroundHeight 背景高度
|
||||
* @return 最小高度,-1表示无法获取
|
||||
* @since 4.5.17
|
||||
@ -64,11 +71,11 @@ public class GraphicsUtil {
|
||||
|
||||
/**
|
||||
* 绘制字符串,使用随机颜色,默认抗锯齿
|
||||
*
|
||||
* @param g {@link Graphics}画笔
|
||||
* @param str 字符串
|
||||
* @param font 字体
|
||||
* @param width 字符串总宽度
|
||||
*
|
||||
* @param g {@link Graphics}画笔
|
||||
* @param str 字符串
|
||||
* @param font 字体
|
||||
* @param width 字符串总宽度
|
||||
* @param height 字符串背景高度
|
||||
* @return 画笔对象
|
||||
* @since 4.5.10
|
||||
@ -79,12 +86,12 @@ public class GraphicsUtil {
|
||||
|
||||
/**
|
||||
* 绘制字符串,默认抗锯齿
|
||||
*
|
||||
* @param g {@link Graphics}画笔
|
||||
* @param str 字符串
|
||||
* @param font 字体
|
||||
* @param color 字体颜色,{@code null} 表示使用随机颜色(每个字符单独随机)
|
||||
* @param width 字符串背景的宽度
|
||||
*
|
||||
* @param g {@link Graphics}画笔
|
||||
* @param str 字符串
|
||||
* @param font 字体
|
||||
* @param color 字体颜色,{@code null} 表示使用随机颜色(每个字符单独随机)
|
||||
* @param width 字符串背景的宽度
|
||||
* @param height 字符串背景的高度
|
||||
* @return 画笔对象
|
||||
* @since 4.5.10
|
||||
@ -98,7 +105,7 @@ public class GraphicsUtil {
|
||||
g.setFont(font);
|
||||
|
||||
// 文字高度(必须在设置字体后调用)
|
||||
int midY = GraphicsUtil.getCenterY(g, height);
|
||||
int midY = getCenterY(g, height);
|
||||
if (null != color) {
|
||||
g.setColor(color);
|
||||
}
|
||||
@ -115,4 +122,97 @@ public class GraphicsUtil {
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制字符串,默认抗锯齿。<br>
|
||||
* 此方法定义一个矩形区域和坐标,文字基于这个区域中间偏移x,y绘制。
|
||||
*
|
||||
* @param g {@link Graphics}画笔
|
||||
* @param str 字符串
|
||||
* @param font 字体,字体大小决定了在背景中绘制的大小
|
||||
* @param color 字体颜色,{@code null} 表示使用黑色
|
||||
* @param rectangle 字符串绘制坐标和大小,此对象定义了绘制字符串的区域大小和偏移位置
|
||||
* @return 画笔对象
|
||||
* @since 4.5.10
|
||||
*/
|
||||
public static Graphics drawString(Graphics g, String str, Font font, Color color, Rectangle rectangle) {
|
||||
// 背景长宽
|
||||
final int backgroundWidth = rectangle.width;
|
||||
final int backgroundHeight = rectangle.height;
|
||||
|
||||
//获取字符串本身的长宽
|
||||
Dimension dimension;
|
||||
try {
|
||||
dimension = FontUtil.getDimension(g.getFontMetrics(font), str);
|
||||
} catch (Exception e) {
|
||||
// 此处报告bug某些情况下会抛出IndexOutOfBoundsException,在此做容错处理
|
||||
dimension = new Dimension(backgroundWidth / 3, backgroundHeight / 3);
|
||||
}
|
||||
|
||||
rectangle.setSize(dimension.width, dimension.height);
|
||||
final Point point = ImgUtil.getPointBaseCentre(rectangle, backgroundWidth, backgroundHeight);
|
||||
|
||||
return drawString(g, str, font, color, point);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制字符串,默认抗锯齿
|
||||
*
|
||||
* @param g {@link Graphics}画笔
|
||||
* @param str 字符串
|
||||
* @param font 字体,字体大小决定了在背景中绘制的大小
|
||||
* @param color 字体颜色,{@code null} 表示使用黑色
|
||||
* @param point 绘制字符串的位置坐标
|
||||
* @return 画笔对象
|
||||
* @since 5.3.6
|
||||
*/
|
||||
public static Graphics drawString(Graphics g, String str, Font font, Color color, Point point) {
|
||||
// 抗锯齿
|
||||
if (g instanceof Graphics2D) {
|
||||
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
}
|
||||
|
||||
g.setFont(font);
|
||||
g.setColor(ObjectUtil.defaultIfNull(color, Color.BLACK));
|
||||
g.drawString(str, point.x, point.y);
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制图片
|
||||
*
|
||||
* @param g 画笔
|
||||
* @param img 要绘制的图片
|
||||
* @param point 绘制的位置,基于左上角
|
||||
* @return 画笔对象
|
||||
*/
|
||||
public static Graphics drawImg(Graphics g, Image img, Point point) {
|
||||
return drawImg(g, img,
|
||||
new Rectangle(point.x, point.y, img.getWidth(null), img.getHeight(null)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制图片
|
||||
*
|
||||
* @param g 画笔
|
||||
* @param img 要绘制的图片
|
||||
* @param rectangle 矩形对象,表示矩形区域的x,y,width,height,,基于左上角
|
||||
* @return 画笔对象
|
||||
*/
|
||||
public static Graphics drawImg(Graphics g, Image img, Rectangle rectangle) {
|
||||
g.drawImage(img, rectangle.x, rectangle.y, rectangle.width, rectangle.height, null); // 绘制切割后的图
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置画笔透明度
|
||||
*
|
||||
* @param g 画笔
|
||||
* @param alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
|
||||
* @return 画笔
|
||||
*/
|
||||
public static Graphics2D setAlpha(Graphics2D g, float alpha){
|
||||
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
|
||||
return g;
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,9 @@ import javax.imageio.stream.ImageOutputStream;
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Toolkit;
|
||||
@ -145,13 +145,13 @@ public class Img implements Serializable {
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param srcImage 来源图片
|
||||
* @param srcImage 来源图片
|
||||
* @param targetImageType 目标图片类型
|
||||
* @since 5.0.7
|
||||
*/
|
||||
public Img(BufferedImage srcImage, String targetImageType) {
|
||||
this.srcImage = srcImage;
|
||||
if(null == targetImageType){
|
||||
if (null == targetImageType) {
|
||||
targetImageType = ImgUtil.IMAGE_TYPE_JPG;
|
||||
}
|
||||
this.targetImageType = targetImageType;
|
||||
@ -312,7 +312,7 @@ public class Img implements Serializable {
|
||||
Graphics2D g = image.createGraphics();
|
||||
|
||||
// 设置背景
|
||||
if(null != fixedColor){
|
||||
if (null != fixedColor) {
|
||||
g.setBackground(fixedColor);
|
||||
g.clearRect(0, 0, width, height);
|
||||
}
|
||||
@ -450,20 +450,22 @@ public class Img implements Serializable {
|
||||
|
||||
if (null == font) {
|
||||
// 默认字体
|
||||
font = new Font("Courier", Font.PLAIN, (int) (targetImage.getHeight() * 0.75));
|
||||
font = FontUtil.createSansSerifFont((int) (targetImage.getHeight() * 0.75));
|
||||
}
|
||||
|
||||
// 抗锯齿
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g.setColor(color);
|
||||
g.setFont(font);
|
||||
// 透明度
|
||||
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
|
||||
// 在指定坐标绘制水印文字
|
||||
final FontMetrics metrics = g.getFontMetrics(font);
|
||||
final int textLength = metrics.stringWidth(pressText);
|
||||
final int textHeight = metrics.getAscent() - metrics.getLeading() - metrics.getDescent();
|
||||
g.drawString(pressText, Math.abs(targetImage.getWidth() - textLength) / 2 + x, Math.abs(targetImage.getHeight() + textHeight) / 2 + y);
|
||||
|
||||
// 绘制
|
||||
if (positionBaseCentre) {
|
||||
// 基于中心绘制
|
||||
GraphicsUtil.drawString(g, pressText, font, color,
|
||||
new Rectangle(x, y, targetImage.getWidth(), targetImage.getHeight()));
|
||||
} else {
|
||||
// 基于左上角绘制
|
||||
GraphicsUtil.drawString(g, pressText, font, color,
|
||||
new Point(x, y));
|
||||
}
|
||||
|
||||
g.dispose();
|
||||
this.targetImage = targetImage;
|
||||
|
||||
@ -497,7 +499,6 @@ public class Img implements Serializable {
|
||||
public Img pressImage(Image pressImg, Rectangle rectangle, float alpha) {
|
||||
final Image targetImg = getValidSrcImg();
|
||||
|
||||
fixRectangle(rectangle, targetImg.getWidth(null), targetImg.getHeight(null));
|
||||
this.targetImage = draw(ImgUtil.toBufferedImage(targetImg), pressImg, rectangle, alpha);
|
||||
return this;
|
||||
}
|
||||
@ -619,12 +620,21 @@ public class Img implements Serializable {
|
||||
* @param backgroundImg 背景图片
|
||||
* @param img 要绘制的图片
|
||||
* @param rectangle 矩形对象,表示矩形区域的x,y,width,height,x,y从背景图片中心计算
|
||||
* @param alpha 透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
|
||||
* @return 绘制后的背景
|
||||
*/
|
||||
private static BufferedImage draw(BufferedImage backgroundImg, Image img, Rectangle rectangle, float alpha) {
|
||||
private BufferedImage draw(BufferedImage backgroundImg, Image img, Rectangle rectangle, float alpha) {
|
||||
final Graphics2D g = backgroundImg.createGraphics();
|
||||
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
|
||||
g.drawImage(img, rectangle.x, rectangle.y, rectangle.width, rectangle.height, null); // 绘制切割后的图
|
||||
GraphicsUtil.setAlpha(g, alpha);
|
||||
|
||||
Point point;
|
||||
if (positionBaseCentre) {
|
||||
point = ImgUtil.getPointBaseCentre(rectangle, backgroundImg.getWidth(), backgroundImg.getHeight());
|
||||
} else {
|
||||
point = new Point(rectangle.x, rectangle.y);
|
||||
}
|
||||
GraphicsUtil.drawImg(g, img, point);
|
||||
|
||||
g.dispose();
|
||||
return backgroundImg;
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package cn.hutool.core.img;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.exceptions.UtilException;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
@ -25,10 +24,10 @@ import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontFormatException;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.geom.AffineTransform;
|
||||
@ -1377,18 +1376,7 @@ public class ImgUtil {
|
||||
* @since 3.0.9
|
||||
*/
|
||||
public static Font createFont(File fontFile) {
|
||||
try {
|
||||
return Font.createFont(Font.TRUETYPE_FONT, fontFile);
|
||||
} catch (FontFormatException e) {
|
||||
// True Type字体无效时使用Type1字体
|
||||
try {
|
||||
return Font.createFont(Font.TYPE1_FONT, fontFile);
|
||||
} catch (Exception e1) {
|
||||
throw new UtilException(e);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
return FontUtil.createFont(fontFile);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1400,18 +1388,7 @@ public class ImgUtil {
|
||||
* @since 3.0.9
|
||||
*/
|
||||
public static Font createFont(InputStream fontStream) {
|
||||
try {
|
||||
return Font.createFont(Font.TRUETYPE_FONT, fontStream);
|
||||
} catch (FontFormatException e) {
|
||||
// True Type字体无效时使用Type1字体
|
||||
try {
|
||||
return Font.createFont(Font.TYPE1_FONT, fontStream);
|
||||
} catch (Exception e1) {
|
||||
throw new UtilException(e1);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
return FontUtil.createFont(fontStream);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1917,4 +1894,20 @@ public class ImgUtil {
|
||||
}
|
||||
return new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得修正后的矩形坐标位置,变为以背景中心为基准坐标(即x,y == 0,0时,处于背景正中)
|
||||
*
|
||||
* @param rectangle 矩形
|
||||
* @param backgroundWidth 参考宽(背景宽)
|
||||
* @param backgroundHeight 参考高(背景高)
|
||||
* @return 修正后的{@link Point}
|
||||
* @since 5.3.6
|
||||
*/
|
||||
public static Point getPointBaseCentre(Rectangle rectangle, int backgroundWidth, int backgroundHeight) {
|
||||
return new Point(
|
||||
rectangle.x + (Math.abs(backgroundWidth - rectangle.width) / 2), //
|
||||
rectangle.y + (Math.abs(backgroundHeight - rectangle.height) / 2)//
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user