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

Time:10-13

I am trying to add some text to an image in Java with the following code:

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);
}

But I have a problem: I would need to be able to scale the font size or send words to a new line so that the whole string fits in a rectangular region at the center of the image with a maximum size of x,y. How can i do it?

CodePudding user response:

I used an image I found on the web. Basically, you try with a large font size and reduce the font size until your text fits on the image.

Here's the image after I added the text.

Car with text

I started with a font size of 96 and worked my way down to 46, which fit in the image.

Here's the complete runnable code.

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);
    }

}

CodePudding user response:

To wrap the text, create TextLayout objects from a LineBreakMeasurer, and use TextLayout.draw instead of drawing with Graphics.drawString.

First, you need to create an AttributedCharacterIterator. You can do that by creating an AttributedString from your text:

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

Now you can create a LineBreakMeasurer:

Graphics2D g2 = (Graphics2D) g;

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

You then obtain the lines as TextLayouts, one at a time, from the LineBreakMeasurer:

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

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

Once you have them, you can figure out the total height:

float textHeight = 0;

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

Finally, you can draw the lines:

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();
}
  • Related