PNG 文件保存为全黑图像
PNG file saves as a completely black image
所以,我正在尝试做一个绘画程序,我添加了一些功能,但现在我希望能够保存图片。我打开程序,画一幅画,保存它,一切正常!除了图像现在完全是黑色的事实。提前致谢!
(如果我的代码哪里有问题请告诉我,因为我仍然是一个学习中的 Java 程序员,这对我将来有很大的帮助)
类:
主要class:
import javax.swing.JFrame;
public class Test{
public static void main(String args[]){
Ploofer ploof = new Ploofer();
ploof.setSize(1000, 950);
PumpkinPie f = new PumpkinPie(ploof);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(1000,1000);
f.setResizable(false);
f.setVisible(true);
f.setLayout(null);
f.add(ploof);
}
}
"Ploofer" class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import javax.swing.JPanel;
public class Ploofer extends JPanel{
private static boolean calledOnce = false;
private BufferedImage img = new BufferedImage(1000, 950, BufferedImage.TYPE_INT_RGB);
static private Color backgroundColor = null;
private PumpkinPie pObj;
@Override
public void paintComponent(Graphics g){
if(calledOnce == false){
pObj = new PumpkinPie(this);
calledOnce = true;
}
super.paintComponent(g);
private Graphics2D g2d = img.createGraphics();
if(pObj.colour != null){
g2d.setColor(pObj.colour);
}
else{
g2d.setColor(Color.BLACK);
}
if(pObj.setToBackgroundColor == true){
pObj.colour = backgroundColor;
pObj.setToBackgroundColor = false;
}
if(pObj.changeBackgroundColor == true){
backgroundColor = pObj.colour;
this.setBackground(backgroundColor);
g2d.setBackground(backgroundColor);
pObj.changeBackgroundColor = false;
update(g2d);
update(g);
}
if(pObj.wipe == true){
g2d.clearRect(0, 0, img.getWidth(), img.getHeight());
g.dispose();
g2d.setBackground(Color.WHITE);
g.drawImage(img, 0, 0, null);
pObj.wipe = false;
repaint();
}
if(pObj.draw == true){
g2d.fillRect(pObj.x, pObj.y, 8, 8);
pObj.draw = false;
}
if(img != null){
g.drawImage(img, 0, 0, null);
}
}
public BufferedImage getImage(){
return img;
}
}
"PumpkinPie" class:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.Border;
public class PumpkinPie extends JFrame{
public int x;
public int y;
static public boolean draw = false;
static public boolean changeBackgroundColor = false;
static public boolean setToBackgroundColor = false;
static public boolean wipe = false;
static public Color colour = Color.WHITE;
Box box;
private JMenuBar menuBar;
private JMenu file, edit;
private JMenuItem save, saveas, exit, open, clear, changeBackground;
private JPanel colourButton;
private JButton saveButton;
private Icon eraser;
private JLabel eraserLabel;
private JFileChooser fc;
Ploofer ploof = new Ploofer();
public PumpkinPie(JPanel panel){
super("SPLAT! SPLAT!");
file = new JMenu("File");
edit = new JMenu("Edit");
box = Box.createHorizontalBox();
menuBar = new JMenuBar();
open = new JMenuItem("Open file");
save = new JMenuItem("Save");
saveas = new JMenuItem("Save as...");
exit = new JMenuItem("Exit");
clear = new JMenuItem("Clear");
changeBackground = new JMenuItem("Change background color");
colourButton = new JPanel();
eraserLabel = new JLabel();
eraser = new ImageIcon(getClass().getResource("/Resources/Eraser.png"));
fc = new JFileChooser();
fc.setCurrentDirectory(new File("C:\Users\" + System.getProperty("user.name") + "\Pictures"));
fc.setDialogTitle("Choose a location...");
saveButton = new JButton("Save");
panel.setSize(1000, 950);
panel.setLocation(0, 50);
colourButton.setSize(50, 50);
colourButton.setBorder(BorderFactory.createLineBorder(Color.BLACK));
eraserLabel.setIcon(eraser);
eraserLabel.setSize(50, 50);
eraserLabel.setLocation(50, 0);
this.setJMenuBar(menuBar);
setLayout(new BorderLayout());
menuBar.add(file);
menuBar.add(edit);
file.add(open);
file.add(save);
file.add(saveas);
file.add(exit);
edit.add(clear);
edit.add(changeBackground);
setLayout(null);
add(colourButton);
add(eraserLabel);
MouseMoveHandlerer mouseMoveHandler = new MouseMoveHandlerer();
MouseHandlerer mouseHandler = new MouseHandlerer();
ButtonHandlerer buttonHandler = new ButtonHandlerer();
panel.addMouseMotionListener(mouseMoveHandler);
eraserLabel.addMouseListener(mouseHandler);
clear.addActionListener(buttonHandler);
colourButton.addMouseListener(mouseHandler);
changeBackground.addActionListener(buttonHandler);
save.addActionListener(buttonHandler);
saveas.addActionListener(buttonHandler);
}
private class MouseMoveHandlerer extends MouseMotionAdapter{
public void mouseDragged(MouseEvent event){
x = event.getX();
y = event.getY();
draw = true;
repaint();
}
}
private class MouseHandlerer extends MouseAdapter{
public void mouseClicked(MouseEvent event){
if(event.getSource() == colourButton){
colour = JColorChooser.showDialog(null, "Choose a colour", colour);
colourButton.setBackground(colour);
}
else if(event.getSource() == eraserLabel){
setToBackgroundColor = true;
repaint();
colourButton.setBackground(colour);
}
}
}
private class ButtonHandlerer implements ActionListener{
@Override
public void actionPerformed(ActionEvent event) {
if(event.getSource() == save){
}
else if(event.getSource() == saveas){
if(fc.showSaveDialog(saveButton) == JFileChooser.APPROVE_OPTION){
try{
ImageIO.write(ploof.getImage(), "PNG", new File(fc.getSelectedFile().getPath() + ".png"));
}catch(Exception e){
e.printStackTrace();
}
}
}
else if (event.getSource() == clear){
wipe = true;
repaint();
}
else{
changeBackgroundColor = true;
repaint();
}
}
}
}
对于您遇到的问题可能有一些更好的解决方案,也许对 here 中的某些代码进行一些调整会有帮助?我从来没有在我个人使用过的任何东西中使用 Graphics2D,但我认为这是你最好的选择。
不能真正理解你的绘画逻辑,但有几点意见:
不要直接调用 update(...)。 Swing 将在适当的时候调用该方法。一个绘画方法应该只关注绘画逻辑
不要使用 paintComponent() 方法创建 BufferedImage。使用 BufferedImage 的要点是将图像绘制到 BufferedImage 上一次,然后只需在 paintComponent() 方法中绘制 BufferedImage。
如果你打算每次都重新创建 BufferedImage,那么你还不如直接在面板的 Graphics 上绘制。因为你似乎有一堆可以改变的变量,我猜你应该直接在面板上绘画而不用担心 BufferedImage。
Except for the fact that the image is now completely black
您可以根据需要创建 BufferedImage,而不是尝试在 paintCompnent() 方法中创建图像。查看 ScreenImage class。它将允许您创建任何 Swing 组件的图像。
使用此 class 代码 create/save 图像将类似于;
BufferedImage bi = ScreenImage.createImage(yourPanel);
ScreenImage.writeImage(bi, "panel-image.png");
您可能还想查看 Custom Painting Approaches 以了解在 BufferedImage 上绘画和在 paintComponent() 方法中绘画之间的区别。
所以,我解决了!如果有人在同一件事上需要帮助,我会在这里发布解决方案!这有点作弊,但它确实有效!
基本上我做了一个新的 class 叫做 "ScreenCapture"
private class ScreenCapture{
Dimension d = new Dimension(980, 896);
public void takePicture(Point i, File file){
BufferedImage image;
try {
image = new Robot().createScreenCapture(new Rectangle(i, d));
ImageIO.write(image, "PNG", file);
} catch (Exception e) {
e.printStackTrace();
}
}
}
每当我想调用它时,我都会这样做:
try{
ScreenCapture screenCap = new ScreenCapture();
screenCap.takePicture(getScreenPlace(), new File(fc.getSelectedFile().getPath() + ".png"));
}catch(Exception e){
e.printStackTrace();
}
getScreenPlace() 函数只获取和更改 JFrame 的屏幕位置
private Point getScreenPlace(){
this.setLocation(0, 0);
Point location = getLocation();
location.setLocation(location.getX()+3, location.getY()+100);
return location;
}
我需要移动相框,因为如果有其他东西挡住了,它就会出现在图片上。感谢@camickr 帮助我
(另外,我之所以不测量屏幕尺寸,是因为我的程序设置屏幕尺寸的方式无法更改)
所以,我正在尝试做一个绘画程序,我添加了一些功能,但现在我希望能够保存图片。我打开程序,画一幅画,保存它,一切正常!除了图像现在完全是黑色的事实。提前致谢!
(如果我的代码哪里有问题请告诉我,因为我仍然是一个学习中的 Java 程序员,这对我将来有很大的帮助)
类:
主要class:
import javax.swing.JFrame;
public class Test{
public static void main(String args[]){
Ploofer ploof = new Ploofer();
ploof.setSize(1000, 950);
PumpkinPie f = new PumpkinPie(ploof);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(1000,1000);
f.setResizable(false);
f.setVisible(true);
f.setLayout(null);
f.add(ploof);
}
}
"Ploofer" class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import javax.swing.JPanel;
public class Ploofer extends JPanel{
private static boolean calledOnce = false;
private BufferedImage img = new BufferedImage(1000, 950, BufferedImage.TYPE_INT_RGB);
static private Color backgroundColor = null;
private PumpkinPie pObj;
@Override
public void paintComponent(Graphics g){
if(calledOnce == false){
pObj = new PumpkinPie(this);
calledOnce = true;
}
super.paintComponent(g);
private Graphics2D g2d = img.createGraphics();
if(pObj.colour != null){
g2d.setColor(pObj.colour);
}
else{
g2d.setColor(Color.BLACK);
}
if(pObj.setToBackgroundColor == true){
pObj.colour = backgroundColor;
pObj.setToBackgroundColor = false;
}
if(pObj.changeBackgroundColor == true){
backgroundColor = pObj.colour;
this.setBackground(backgroundColor);
g2d.setBackground(backgroundColor);
pObj.changeBackgroundColor = false;
update(g2d);
update(g);
}
if(pObj.wipe == true){
g2d.clearRect(0, 0, img.getWidth(), img.getHeight());
g.dispose();
g2d.setBackground(Color.WHITE);
g.drawImage(img, 0, 0, null);
pObj.wipe = false;
repaint();
}
if(pObj.draw == true){
g2d.fillRect(pObj.x, pObj.y, 8, 8);
pObj.draw = false;
}
if(img != null){
g.drawImage(img, 0, 0, null);
}
}
public BufferedImage getImage(){
return img;
}
}
"PumpkinPie" class:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.Border;
public class PumpkinPie extends JFrame{
public int x;
public int y;
static public boolean draw = false;
static public boolean changeBackgroundColor = false;
static public boolean setToBackgroundColor = false;
static public boolean wipe = false;
static public Color colour = Color.WHITE;
Box box;
private JMenuBar menuBar;
private JMenu file, edit;
private JMenuItem save, saveas, exit, open, clear, changeBackground;
private JPanel colourButton;
private JButton saveButton;
private Icon eraser;
private JLabel eraserLabel;
private JFileChooser fc;
Ploofer ploof = new Ploofer();
public PumpkinPie(JPanel panel){
super("SPLAT! SPLAT!");
file = new JMenu("File");
edit = new JMenu("Edit");
box = Box.createHorizontalBox();
menuBar = new JMenuBar();
open = new JMenuItem("Open file");
save = new JMenuItem("Save");
saveas = new JMenuItem("Save as...");
exit = new JMenuItem("Exit");
clear = new JMenuItem("Clear");
changeBackground = new JMenuItem("Change background color");
colourButton = new JPanel();
eraserLabel = new JLabel();
eraser = new ImageIcon(getClass().getResource("/Resources/Eraser.png"));
fc = new JFileChooser();
fc.setCurrentDirectory(new File("C:\Users\" + System.getProperty("user.name") + "\Pictures"));
fc.setDialogTitle("Choose a location...");
saveButton = new JButton("Save");
panel.setSize(1000, 950);
panel.setLocation(0, 50);
colourButton.setSize(50, 50);
colourButton.setBorder(BorderFactory.createLineBorder(Color.BLACK));
eraserLabel.setIcon(eraser);
eraserLabel.setSize(50, 50);
eraserLabel.setLocation(50, 0);
this.setJMenuBar(menuBar);
setLayout(new BorderLayout());
menuBar.add(file);
menuBar.add(edit);
file.add(open);
file.add(save);
file.add(saveas);
file.add(exit);
edit.add(clear);
edit.add(changeBackground);
setLayout(null);
add(colourButton);
add(eraserLabel);
MouseMoveHandlerer mouseMoveHandler = new MouseMoveHandlerer();
MouseHandlerer mouseHandler = new MouseHandlerer();
ButtonHandlerer buttonHandler = new ButtonHandlerer();
panel.addMouseMotionListener(mouseMoveHandler);
eraserLabel.addMouseListener(mouseHandler);
clear.addActionListener(buttonHandler);
colourButton.addMouseListener(mouseHandler);
changeBackground.addActionListener(buttonHandler);
save.addActionListener(buttonHandler);
saveas.addActionListener(buttonHandler);
}
private class MouseMoveHandlerer extends MouseMotionAdapter{
public void mouseDragged(MouseEvent event){
x = event.getX();
y = event.getY();
draw = true;
repaint();
}
}
private class MouseHandlerer extends MouseAdapter{
public void mouseClicked(MouseEvent event){
if(event.getSource() == colourButton){
colour = JColorChooser.showDialog(null, "Choose a colour", colour);
colourButton.setBackground(colour);
}
else if(event.getSource() == eraserLabel){
setToBackgroundColor = true;
repaint();
colourButton.setBackground(colour);
}
}
}
private class ButtonHandlerer implements ActionListener{
@Override
public void actionPerformed(ActionEvent event) {
if(event.getSource() == save){
}
else if(event.getSource() == saveas){
if(fc.showSaveDialog(saveButton) == JFileChooser.APPROVE_OPTION){
try{
ImageIO.write(ploof.getImage(), "PNG", new File(fc.getSelectedFile().getPath() + ".png"));
}catch(Exception e){
e.printStackTrace();
}
}
}
else if (event.getSource() == clear){
wipe = true;
repaint();
}
else{
changeBackgroundColor = true;
repaint();
}
}
}
}
对于您遇到的问题可能有一些更好的解决方案,也许对 here 中的某些代码进行一些调整会有帮助?我从来没有在我个人使用过的任何东西中使用 Graphics2D,但我认为这是你最好的选择。
不能真正理解你的绘画逻辑,但有几点意见:
不要直接调用 update(...)。 Swing 将在适当的时候调用该方法。一个绘画方法应该只关注绘画逻辑
不要使用 paintComponent() 方法创建 BufferedImage。使用 BufferedImage 的要点是将图像绘制到 BufferedImage 上一次,然后只需在 paintComponent() 方法中绘制 BufferedImage。
如果你打算每次都重新创建 BufferedImage,那么你还不如直接在面板的 Graphics 上绘制。因为你似乎有一堆可以改变的变量,我猜你应该直接在面板上绘画而不用担心 BufferedImage。
Except for the fact that the image is now completely black
您可以根据需要创建 BufferedImage,而不是尝试在 paintCompnent() 方法中创建图像。查看 ScreenImage class。它将允许您创建任何 Swing 组件的图像。
使用此 class 代码 create/save 图像将类似于;
BufferedImage bi = ScreenImage.createImage(yourPanel);
ScreenImage.writeImage(bi, "panel-image.png");
您可能还想查看 Custom Painting Approaches 以了解在 BufferedImage 上绘画和在 paintComponent() 方法中绘画之间的区别。
所以,我解决了!如果有人在同一件事上需要帮助,我会在这里发布解决方案!这有点作弊,但它确实有效!
基本上我做了一个新的 class 叫做 "ScreenCapture"
private class ScreenCapture{
Dimension d = new Dimension(980, 896);
public void takePicture(Point i, File file){
BufferedImage image;
try {
image = new Robot().createScreenCapture(new Rectangle(i, d));
ImageIO.write(image, "PNG", file);
} catch (Exception e) {
e.printStackTrace();
}
}
}
每当我想调用它时,我都会这样做:
try{
ScreenCapture screenCap = new ScreenCapture();
screenCap.takePicture(getScreenPlace(), new File(fc.getSelectedFile().getPath() + ".png"));
}catch(Exception e){
e.printStackTrace();
}
getScreenPlace() 函数只获取和更改 JFrame 的屏幕位置
private Point getScreenPlace(){
this.setLocation(0, 0);
Point location = getLocation();
location.setLocation(location.getX()+3, location.getY()+100);
return location;
}
我需要移动相框,因为如果有其他东西挡住了,它就会出现在图片上。感谢@camickr 帮助我
(另外,我之所以不测量屏幕尺寸,是因为我的程序设置屏幕尺寸的方式无法更改)