Search code examples
javabufferedimagegraphics2d

Using Graphics2D to overlay text on a BufferedImage and return a BufferedImage


I have checked similarly named questions, but they don't answer this use case.

Basically, I was to overlay some text (text) at a given coordinate (x,y) I have the below function in a package;

protected BufferedImage Process2(BufferedImage image){
    Graphics2D gO = image.createGraphics();
    gO.setColor(Color.red);
    gO.setFont(new Font( "SansSerif", Font.BOLD, 12 ));
    gO.drawString(this.text, this.x, this.y);
    System.err.println(this.text+this.x+this.y);
    return image;
}

I feel like im missing something patently obvious; every reference to Graphics2D I can find is dealing with either games or writing directly to a file but I just want a BufferedImage returned. with the overlay 'rendered'

In the current code, the image appears out the end unchanged.

Thanks!


Solution

  • The method drawString() uses x and y for the leftmost character's baseline. Numbers typically have no descenders; if the same is true of text, a string drawn at position (0,0) will be rendered entirely outside the image. See this example.

    Addendum: You may be having trouble with an incompatible color model in your image. One simple expedient is to render the image and then modify it in situ.

    Hello

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Font;
    import java.awt.FontMetrics;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.net.URL;
    import javax.imageio.ImageIO;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    /**
     * @see https://stackoverflow.com/questions/2658663
     */
    public class TextOverlay extends JPanel {
    
        private BufferedImage image;
    
        public TextOverlay() {
            try {
                image = ImageIO.read(new URL(
                    "http://cdn.sstatic.net/stackexchange/img/logos/so/so-logo.png"));
            } catch (IOException e) {
                e.printStackTrace();
            }
            image = process(image);
        }
    
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(image.getWidth(), image.getHeight());
        }
    
        private BufferedImage process(BufferedImage old) {
            int w = old.getWidth() / 3;
            int h = old.getHeight() / 3;
            BufferedImage img = new BufferedImage(
                w, h, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = img.createGraphics();
            g2d.drawImage(old, 0, 0, w, h, this);
            g2d.setPaint(Color.red);
            g2d.setFont(new Font("Serif", Font.BOLD, 20));
            String s = "Hello, world!";
            FontMetrics fm = g2d.getFontMetrics();
            int x = img.getWidth() - fm.stringWidth(s) - 5;
            int y = fm.getHeight();
            g2d.drawString(s, x, y);
            g2d.dispose();
            return img;
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(image, 0, 0, null);
        }
    
        private static void create() {
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.add(new TextOverlay());
            f.pack();
            f.setVisible(true);
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    create();
                }
            });
        }
    }