Contents

Java中将文本添加到图像

1. 概述

有时我们需要在一个图像 或一组图像中添加一些文本。使用图像编辑工具手动执行此操作很容易。但是,当我们想以相同的方式将相同的文本添加到大量图片时,以编程方式执行此操作将非常有用。

在这个快速教程中,我们将学习如何使用 Java向图像添加一些文本。

2. 向图像添加文本

要读取图像并添加一些文本,我们可以使用不同的类。在接下来的部分中,我们将看到几个选项。

2.1. ImagePlusImageProcessor

首先,让我们看看如何使用ImageJ 库 中提供的**ImagePlusImageProcessor **类。要使用这个库,我们需要在我们的项目中包含这个依赖项:

<dependency>
    <groupId>net.imagej</groupId>
    <artifactId>ij</artifactId>
    <version>1.51h</version>
</dependency>

要读取图像,我们将使用openImage静态方法。此方法的结果将使用ImagePlus对象存储在内存中:

ImagePlus image = IJ.openImage(path);

一旦我们将图像加载到内存中,让我们使用类ImageProcessor添加一些文本:

Font font = new Font("Arial", Font.BOLD, 18);
ImageProcessor ip = image.getProcessor();
ip.setColor(Color.GREEN);
ip.setFont(font);
ip.drawString(text, 0, 20);

使用这段代码,我们正在做的是在图像的左上角添加指定的绿色文本。请注意,我们使用drawString方法的第二个和第三个参数设置位置,它们分别表示从左侧和顶部的像素数。

2.2. BufferedImageGraphics

接下来,我们将看看**如何使用BufferedImageGraphics **类实现相同的结果。Java 的标准构建包括这些类,因此不需要额外的库。

与我们使用ImageJopenImage的方式相同,我们将使用ImageIO中可用的read方法:

BufferedImage image = ImageIO.read(new File(path));

一旦我们将图像加载到内存中,让我们使用类Graphics添加一些文本:

Font font = new Font("Arial", Font.BOLD, 18);
Graphics g = image.getGraphics();
g.setFont(font);
g.setColor(Color.GREEN);
g.drawString(text, 0, 20);

正如我们所看到的,这两种选择在使用方式上都非常相似。在这种情况下,方法drawString的第二个和第三个参数的指定方式与我们为ImageProcessor方法所做的相同。

2.3. 基于AttributedCharacterIterator绘制

Graphics中可用的方法drawString允许我们**使用AttributedCharacterIterator **打印文本。这意味着我们可以使用带有一些关联属性的文本,而不是使用普通的String。让我们看一个例子:

Font font = new Font("Arial", Font.BOLD, 18);
AttributedString attributedText = new AttributedString(text);
attributedText.addAttribute(TextAttribute.FONT, font);
attributedText.addAttribute(TextAttribute.FOREGROUND, Color.GREEN);
Graphics g = image.getGraphics();
g.drawString(attributedText.getIterator(), 0, 20);

这种打印文本的方式让我们有机会直接将格式与String关联起来,这比在我们想要更改格式时更改Graphics对象属性更干净。

3. 文本对齐

现在我们已经学会了如何在图像的左上角添加一个简单的文本,现在让我们看看如何在某些位置添加这个文本

3.1. 居中文本

我们要处理的第一种对齐方式是居中文本。要动态设置我们要写入文本的正确位置,我们需要弄清楚一些信息:

  • 图片尺寸
  • 字体大小

这些信息可以很容易地获得。在图像大小的情况下,可以通过BufferedImage对象的getWidthgetHeight方法访问此数据。另一方面,要获取与字体大小相关的数据,我们需要使用FontMetrics对象。

让我们看一个例子,我们计算文本的正确位置并绘制它:

Graphics g = image.getGraphics();
FontMetrics metrics = g.getFontMetrics(font);
int positionX = (image.getWidth() - metrics.stringWidth(text)) / 2;
int positionY = (image.getHeight() - metrics.getHeight()) / 2 + metrics.getAscent();
g.drawString(attributedText.getIterator(), positionX, positionY);

3.2. 右下角对齐的文本

我们将要看到的下一种对齐方式是右下角。在这种情况下,我们需要动态获取正确的位置:

int positionX = (image.getWidth() - metrics.stringWidth(text));
int positionY = (image.getHeight() - metrics.getHeight()) + metrics.getAscent();

3.3. 文本位于左上角

最后,让我们看看如何在左上角打印我们的文本

int positionX = 0;
int positionY = metrics.getAscent();

其余的对齐可以从我们看到的三个中推断出来。

4. 根据图像调整文本大小

当我们在图像中绘制文本时,我们可能会发现这个文本超出了图像的大小。为了解决这个问题,我们必须根据图像大小调整我们正在使用的字体大小。 首先,我们需要使用基本字体获取文本的预期宽度和高度。为了实现这一点,我们将使用FontMetricsGlyphVectorShape 类。

FontMetrics ruler = graphics.getFontMetrics(baseFont);
GlyphVector vector = baseFont.createGlyphVector(ruler.getFontRenderContext(), text);
    
Shape outline = vector.getOutline(0, 0);
    
double expectedWidth = outline.getBounds().getWidth();
double expectedHeight = outline.getBounds().getHeight();

下一步是检查是否需要调整字体大小。为此,让我们比较文本的预期大小和图像的大小:

boolean textFits = image.getWidth() >= expectedWidth && image.getHeight() >= expectedHeight;

最后,如果我们的文本不适合图像,我们必须减小字体大小。我们将为此使用方法derivedFont

double widthBasedFontSize = (baseFont.getSize2D()*image.getWidth())/expectedWidth;
double heightBasedFontSize = (baseFont.getSize2D()*image.getHeight())/expectedHeight;
double newFontSize = widthBasedFontSize < heightBasedFontSize ? widthBasedFontSize : heightBasedFontSize;
newFont = baseFont.deriveFont(baseFont.getStyle(), (float)newFontSize);

请注意,我们需要根据宽度和高度获取新的字体大小并应用它们中的最小值。