Home > Net >  Graphics2D overlaying image text problem: text is wrong
Graphics2D overlaying image text problem: text is wrong

Time:10-23

I'm using the Graphics2D class to overlay two images (i want one to act as background and another smaller one to appear on top) and after that i want to add a simple line of text. This code works great, but im calling it from a for loop, and after the first image is generated the text of the rest starts to come off weird. I'm printing numbers, and its like the program is inserting the new text over the text in the last image and so on.

This is the function I call from the for loop to create the image:

private static void createCompositeImage(BufferedImage image, BufferedImage overlay, String filename, String codigo) throws IOException {
        Graphics2D g = image.createGraphics();
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
        g.drawImage(overlay, (image.getWidth() - overlay.getWidth()),
                (image.getHeight() - overlay.getHeight())-200, null);

        g.setFont(g.getFont().deriveFont(40f));
        g.drawString("Entrada número: "   codigo, 30, image.getHeight()-300);
        g.dispose();

        ImageIO.write(image, "jpeg", new File(filename   ".jpeg"));

    }

And this is what happens on any image that's not the first: enter image description here

Anyone knows what i'm doing wrong?

CodePudding user response:

Painting graphics is a lot like painting on a real world canvas, you are simply painting over the top of what is already there. If you want to "replace" a portion of the image, you need to paint over the top of it first.

In this case...

You could...

Fill a rectangle with a default color over the area that the text will be painted to.

This is problematic as you need to either know the "maximum" possible area covered or the size of the content that was painted previously.

Alternatively...

You could...

Start with a blank slate on each cycle. That is, start with a copy of the "master" image on each cycle and simply repaint the state into.

For example...

Background

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    JFrame frame = new JFrame();
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    public class TestPane extends JPanel {

        private BufferedImage master;
        private BufferedImage background;
        private Timer timer;

        private DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("hh:mm:ss a");

        public TestPane() throws IOException {
            master = ImageIO.read(getClass().getResource("/images/background.jpg"));
            background = new BufferedImage(master.getWidth(), master.getHeight(), BufferedImage.TYPE_INT_ARGB);
            renderBackground();
        }

        protected void renderBackground() {
            if (master == null) {
                return;
            }
            Graphics2D g2d = background.createGraphics();
            g2d.drawImage(master, 0, 0, this);

            g2d.setFont(getFont());
            FontMetrics fm = g2d.getFontMetrics();

            String time = LocalTime.now().format(timeFormatter);

            int x = (background.getWidth() - fm.stringWidth(time)) / 2;
            int y = ((background.getHeight() - fm.getHeight()) / 2)   fm.getAscent();

            g2d.drawString(time, x, y);

            g2d.dispose();

            repaint();
        }

        @Override
        public Dimension getPreferredSize() {
            if (master == null) {
                return new Dimension(200, 200);
            }

            return new Dimension(master.getWidth(), master.getHeight());
        }

        @Override
        public void addNotify() {
            super.addNotify();
            if (timer != null) {
                timer.stop();
            }
            timer = new Timer(500, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    renderBackground();
                }
            });
            timer.start();
        }

        @Override
        public void removeNotify() {
            super.removeNotify();
            if (timer != null) {
                timer.stop();
            }
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (background == null) {
                return;
            }
            Graphics2D g2d = (Graphics2D) g.create();
            int x = (getWidth() - background.getWidth()) / 2;
            int y = (getHeight() - background.getHeight()) / 2;
            g2d.drawImage(background, x, y, this);
            g2d.dispose();
        }

    }

}
  • Related