You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java绘制字符串:每次生成新Font还是使用预生成字体集合?

字体大小适配方案的资源消耗疑问

我实现了一个基于java.awt.Font的字符串绘制字体大小决策方法,字体大小由字符串长度和目标高度决定——通过do-while循环逐步减小字体大小,直到字符串高度适配目标值。

原实现方法

private void decideOnFontSize(String text) {
    int fontSize = 72;
    do {
        font = new Font("Arial", Font.PLAIN, fontSize);
        // 计算文本高度等逻辑...
        fontSize -= 2;
    } while (textHeight >= targetHeight);
}

这个方法属于公共API服务,可能被频繁调用,每次循环都实例化新Font对象看起来会浪费资源。因此我设计了另一种方案:通过工具类预定义并缓存字体集合。

优化方案:预定义字体缓存工具类

public class FontsUtil {

    private static Map<Integer, Font> fonts = new HashMap<>();

    public static final Integer MAX_FONT_SIZE = 72;
    public static final Integer MIN_FONT_SIZE = 10;

    static {
        String fontName = "Arial";
        for(int fontSize = MAX_FONT_SIZE; fontSize >= MIN_FONT_SIZE; fontSize -= 2) {
            fonts.put(fontSize, new Font(fontName, Font.PLAIN, fontSize));
        }
    }

    public static Font getFontBySize(Integer fontSize) {
        return fonts.get(fontSize);
    }
}

修改后的字体大小决策方法

private void decideOnFontSize(String text) {
    int fontSize = FontsUtil.MAX_FONT_SIZE;
    do {
        font = FontsUtil.getFontBySize(fontSize);
        // 计算文本高度等逻辑...
        fontSize -= 2;
    } while (textHeight >= targetHeight);
}

补充说明:实际业务逻辑

由于需要同时适配目标宽度和高度,实际会通过LineBreakMeasurer创建TextLayout对象,完整的do-while循环代码如下:

List<TextLayout> lines;
int fontSize = font.getSize();
int textHeight;
do {
    font = FontsUtil.getFontBySize(fontSize);
    g2d.setFont(font);

    lines = splitStringIntoPiecesToFitTargetWidth(text, targetWidth, g2d);
    textHeight = getTextHeight(lines);

    fontSize -= 2;
} while (textHeight >= targetHeight);

注:font为实例变量

字符串拆分方法splitStringIntoPiecesToFitTargetWidth实现如下:

private List<TextLayout> splitStringIntoPiecesToFitTargetWidth(String string,
int width, Graphics2D g2d) {
    List<TextLayout> lines = new ArrayList<>();

    AttributedString attributedString = new AttributedString(string);
    attributedString.addAttribute(TextAttribute.FONT, font);
    LineBreakMeasurer lineBreakMeasurer =
        new LineBreakMeasurer(attributedString.getIterator(), g2d.getFontRenderContext());

    while (lineBreakMeasurer.getPosition() < string.length()) {
        lines.add(lineBreakMeasurer.nextLayout(width));
    }

    return lines;
}

我认为第二种预缓存字体的方案理论上资源消耗更少,但不确定实际是否真的如此?

内容的提问来源于stack exchange,提问作者Alexander Novikov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 11:45:30