Graphics2D проблема с наложением изображения текста: текст неверен

#java #user-interface #graphics #graphics2d

Вопрос:

Я использую класс Graphics2D для наложения двух изображений (я хочу, чтобы одно из них выступало в качестве фона, а другое, меньшее, появлялось сверху), а затем я хочу добавить простую строку текста. Этот код отлично работает, но я вызываю его из цикла for, и после создания первого изображения текст остальных начинает казаться странным. Я печатаю цифры, и похоже, что программа вставляет новый текст поверх текста на последнем изображении и так далее.

Это функция, которую я вызываю из цикла for для создания изображения:

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

    }

 

И это то, что происходит на любом изображении, которое не является первым:
введите описание изображения здесь

Кто — нибудь знает, что я делаю не так?

Комментарии:

1. Таким образом, каждый раз, когда вы рисуете изображение, вы просто закрашиваете пиксели, которые уже были там, вам нужно «очистить» область, которую вы хотите нарисовать в первую очередь

2. Хорошо, я подумал, что мне нужно очистить буфер или что-то подобное. Как я могу это сделать?

3. Самым простым способом было бы не использовать изображение повторно. Имейте базовое изображение, на которое каждый раз наносится содержимое, поэтому вы всегда начинаете с «нового» состояния. В противном случае вам нужно будет заполнить прямоугольник вокруг «возможной» области, в которой был/может быть текст

4. Это Полезно! В настоящее время я открываю базовое изображение только один раз за пределами цикла for и каждый раз вызываю этот экземпляр изнутри. Я попробую открыть его внутри цикла, хотя это худший стиль и займет немного больше времени

5. Загрузите основное изображение. Создайте второе изображение того же размера, что и основное. Затем, в цикле, нарисуйте мастер в копии и используйте его вместо этого для остальных операций рисования

Ответ №1:

Рисование графики очень похоже на рисование на холсте реального мира, вы просто рисуете поверх того, что уже есть. Если вы хотите «заменить» часть изображения, сначала вам нужно закрасить его сверху.

В этом случае…

Ты мог бы…

Заполните прямоугольник цветом по умолчанию в области, на которую будет нанесен текст.

Это проблематично, так как вам нужно либо знать «максимально» возможную площадь покрытия, либо размер содержимого, которое было нарисовано ранее.

Альтернативно…

Ты мог бы…

Начните с чистого листа в каждом цикле. То есть начните с копии «главного» изображения в каждом цикле и просто перекрасьте состояние в.

Например…

Фон

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

    }

}
 

Комментарии:

1. Большое вам спасибо!