Java- Write Text onto Image, then Write to Output File

12,408

Solution 1

You don't really need swing at all if you just want to generate image files.

You can do something like this:

import java.awt.image.BufferedImage;
import java.awt.Graphics2D;
import java.io.File;
import javax.imageio.ImageIO;
import java.io.IOException;

BufferedImage img = ImageIO.read(new File("dog.jpg")); // try/catch IOException
int width = img.getWidth();
int height = img.getHeight();

BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bufferedImage.createGraphics();

// draw graphics
g2d.drawImage(img, 0, 0, null);
g2d.drawString(text, x, y);

g2d.dispose();

try {

// Save as PNG
File file = new File("newimage.png");
ImageIO.write(bufferedImage, "png", file);

// Save as JPEG
file = new File("newimage.jpg");
ImageIO.write(bufferedImage, "jpg", file);

} catch (IOException e) { }

For more info, see:

http://www.exampledepot.com/egs/javax.imageio/Graphic2File.html

The text alignment and centering can be done using the FontMetrics class.

Solution 2

You should use a drawString().

To properly center a text you need to calculate the width for a given font:

Font font = getFont();
FontMetrics metrics = getFontMetrics( font );
int width = metrics.stringWidth( theString );

And remember to add -Djava.awt.headless=true if you want to call in on server (without GUI).

Solution 3

Use a JLabel to display the image and text:

JLabel picture = new JLabel( new ImageIcon(...) );
picture.setText("<html><center>Text<br>over<br>Image<center></html>");
picture.setHorizontalTextPosition(JLabel.CENTER);
picture.setVerticalTextPosition(JLabel.CENTER);

Then you can use the Screen Image class to create an image of any component.

Edit:

Missed your update that you don't want the text centered on the image. For your new requirement you can add other components to the label to do the formatting for you. The code below shows the original suggestion as will as some examples of using components:

import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;

public class LabelImageText extends JPanel
{
    public LabelImageText()
    {
        JLabel label1 = new JLabel( new ColorIcon(Color.ORANGE, 100, 100) );
        label1.setText( "Easy Way" );
        label1.setHorizontalTextPosition(JLabel.CENTER);
        label1.setVerticalTextPosition(JLabel.CENTER);
        add( label1 );

        //

        JLabel label2 = new JLabel( new ColorIcon(Color.YELLOW, 200, 150) );
        label2.setLayout( new BoxLayout(label2, BoxLayout.Y_AXIS) );
        add( label2 );

        JLabel text = new JLabel( "More Control" );
        text.setAlignmentX(JLabel.CENTER_ALIGNMENT);
        label2.add( Box.createVerticalGlue() );
        label2.add( text );
        label2.add( Box.createVerticalStrut(10) );

        //

        JLabel label3 = new JLabel( new ColorIcon(Color.GREEN, 200, 150) );
        add( label3 );

        JLabel text3 = new JLabel();
        text3.setText("<html><center>Text<br>over<br>Image<center></html>");
        text3.setLocation(20, 20);
        text3.setSize(text3.getPreferredSize());
        label3.add( text3 );

        //

        JLabel label4 = new JLabel( new ColorIcon(Color.CYAN, 200, 150) );
        add( label4 );

        JTextPane textPane = new JTextPane();
        textPane.setText("Add some text that will wrap at your preferred width");
        textPane.setEditable( false );
        textPane.setOpaque(false);
        SimpleAttributeSet center = new SimpleAttributeSet();
        StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
        StyledDocument doc = textPane.getStyledDocument();
        doc.setParagraphAttributes(0, doc.getLength(), center, false);
        textPane.setBounds(20, 20, 75, 100);
        label4.add( textPane );
    }

    public static class ColorIcon implements Icon
    {
        private Color color;
        private int width;
        private int height;

        public ColorIcon(Color color, int width, int height)
        {
            this.color = color;
            this.width = width;
            this.height = height;
        }

        public int getIconWidth()
        {
            return width;
        }

        public int getIconHeight()
        {
            return height;
        }

        public void paintIcon(Component c, Graphics g, int x, int y)
        {
            g.setColor(color);
            g.fillRect(x, y, width, height);
        }
    }

    private static void createAndShowUI()
    {
        JFrame frame = new JFrame("LabelImageText");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( new LabelImageText() );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}
Share:
12,408
TNC
Author by

TNC

Updated on June 11, 2022

Comments

  • TNC
    TNC almost 2 years

    I have an image on top of which I would like to write text that has multiple lines, is center-aligned, and dynamic (variable width). I've tried using the drawString method from Graphics, but I could not get the centering and dynamic positioning to work. I'm currently poking around in the swing library with JLabels and such, but I'm having difficulty with finding a relatively simple approach to this. I would also like to have the final image written to a file, but it seems that mixing ImageIO with JPanels is not working very well.. I'm getting just a black box at the moment.. If anyone could provide even a simple outline of how to approach this, I would greatly appreciate that.

    Thank you!


    Sorry, I should have been more specific.. I would like the text itself to be center-aligned (as in the middle of each row should line up), rather than having the text be placed in the center of the image. The text will be placed in some other location on the image, not in the middle. Again, I apologize for the unclear descriptions. Thanks!

  • TNC
    TNC over 12 years
    Thanks for your quick response, but the image file writing works (I had it pretty much identical to above); it's writing text on top of the image that I'm not sure how to do. I will take a look at the FontMetrics class to see what I use from there.
  • roartechs
    roartechs over 12 years
    Use the FontMetrics example from Michal to get the width of your String. Then calculate the center of your image (divide image width by 2). Then divide the string width by 2 and use that as the offset from the center of the image. That should center your text.
  • roartechs
    roartechs over 12 years
    But to get to that point, you can create a graphics context the same size as your image, draw your image onto the graphics context using drawImage(), then draw the text onto the graphics context using drawString().