向图像添加文本并使其适合 Java 中的矩形区域

Adding text to an image and make it fit into a rectangular region in Java

我正在尝试使用以下代码向 Java 中的图像添加一些文本:

public static void main(String[] args) throws IOException {
    BufferedImage image = ImageIO.read(new File("img.png"));
    Graphics g = image.getGraphics();
    Rectangle rectangle = new Rectangle(image.getWidth(), image.getHeight());
    g.setFont(g.getFont().deriveFont(30f));
    drawCenteredString(g, "TexvzgdsfadvcfkgsdASKJDFHJGgkdgfsakagjASGHDJStTexvzgdsfadvcfkgsdASKJDFHJGgkdgfsakagjASGHDJSt", rectangle, g.getFont());
    g.dispose();
    ImageIO.write(image, "png", new File("out.png"));
}

public static void drawCenteredString(Graphics g, String text, Rectangle rect, Font font) {
    FontMetrics metrics = g.getFontMetrics(font);
    int x = rect.x + (rect.width - metrics.stringWidth(text)) / 2;
    int y = rect.y + ((rect.height - metrics.getHeight()) / 2) + metrics.getAscent();
    g.setFont(font);
    g.drawString(text, x, y);
}

但我有一个问题:我需要能够缩放字体大小或将文字发送到新行,以便整个字符串适合图像中心的最大尺寸为x,y。 我该怎么做?

我使用了在网上找到的图片。基本上,您尝试使用较大的字体大小并减小字体大小,直到您的文本适合图像。

这是我添加文字后的图片。

我从 96 的字体大小开始,然后逐渐减小到 46,适合图像。

这是完整的可运行代码。

import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;

public class AddTextToImage {

    public static void main(String[] args) throws IOException {
        URL url = new URL("https://clipartmag.com/images/car-cartoon-png-18.png");
        BufferedImage image = ImageIO.read(url);
        Graphics g = image.getGraphics();
        Rectangle rectangle = new Rectangle(image.getWidth(), image.getHeight());
        String text = "TexvzgdsfadvcfkgsdASKJDFHJGgkdgfsakagjASGHDJSt"
                + "TexvzgdsfadvcfkgsdASKJDFHJGgkdgfsakagjASGHDJSt";
        int fontSize = 98;
        FontMetrics metrics;
        do {
            fontSize -= 2;
            g.setFont(g.getFont().deriveFont((float) fontSize));
            metrics = g.getFontMetrics(g.getFont());
        } while (metrics.stringWidth(text) > rectangle.width);
        
        System.out.println("Font Size: " + fontSize);
        drawCenteredString(g, text, rectangle, g.getFont());
        g.dispose();
        ImageIO.write(image, "png", new File("output.png"));
    }

    public static void drawCenteredString(Graphics g, String text, Rectangle rect, Font font) {
        FontMetrics metrics = g.getFontMetrics(font);
        int x = rect.x + (rect.width - metrics.stringWidth(text)) / 2;
        int y = rect.y + ((rect.height - metrics.getHeight()) / 2) + metrics.getAscent();
        g.setFont(font);
        g.drawString(text, x, y);
    }

}

要换行文字,create TextLayout objects from a LineBreakMeasurer, and use TextLayout.draw 而不是用 Graphics.drawString 绘图。

首先,您需要创建一个 AttributedCharacterIterator。您可以通过从您的文本中创建一个 AttributedString 来做到这一点:

AttributedString attrStr = new AttributedString(text);
AttributedCharacterIterator iter = attrStr.getIterator();

现在您可以创建一个 LineBreakMeasurer:

Graphics2D g2 = (Graphics2D) g;

LineBreakMeasurer measurer = new LineBreakMeasurer(iter,
    g2.getFontRenderContext());

然后您从 LineBreakMeasurer 中获取作为 TextLayouts 的行,一次一条:

List<TextLayout> lines = new ArrayList<>();

while (measurer.getPosition() < text.length()) {
    lines.add(measurer.nextLayout(rect.width));
}

一旦你有了它们,你就可以计算出总高度:

float textHeight = 0;

for (TextLayout line : lines) {
    textHeight += line.getAscent() + line.getDescent() + line.getLeading();
}

终于可以画线了:

float y = (rect.height - textHeight) / 2;

for (TextLayout line : lines) {
    Rectangle2D bounds = line.getBounds();
    float x = (rect.width - (float) bounds.getWidth()) / 2;

    line.draw(g2, x, y + line.getAscent());

    y += line.getAscent() + line.getDescent() + line.getLeading();
}