#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. Большое вам спасибо!