我无法将图像(混合中间)保存到文件?



我试过查看Oracle关于写入/保存图像的建议,但我所做的都不起作用。我有一个开始按钮,可以开始从一个图像到另一个图像的混合。然后是一个停止按钮,在中途(或任何你想要的地方)停止混合,然后我有一个saveImage按钮,希望它在当前状态下捕捉图像并将其保存到文件中。但是怎么做呢?这是Frame.java 的代码

import java.awt.AlphaComposite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.Timer;
class Frame extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
private Image MeSmaller1;
private Image MeSmaller2;
protected Timer timer;
private float alpha;
JPanel pnlButton = new JPanel();
static JButton btnStartBlend = new JButton("Start Blend");
static JButton btnStopBlend = new JButton("Stop Blend");
static JButton saveImage = new JButton("Save Image To File");
public Frame() {
loadImages();
initTimer();
pnlButton.add(btnStartBlend);
this.add(pnlButton);
pnlButton.add(btnStopBlend);
this.add(pnlButton);
pnlButton.add(saveImage);
this.add(pnlButton);
addListeners();
}
// start button actionlistener
public void addListeners() {
btnStartBlend.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
initTimer();
timer.start();
System.out.println("Timer started");
}
});
// stop button actionlistener
btnStopBlend.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// initTimer();
timer.stop();
System.out.println("Timer stopped");
}
});
// Save button actionlistener
saveImage.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Save image clicked");
}
});
}
private void loadImages() {
MeSmaller1 = new ImageIcon("MeSmaller1.jpg").getImage();
MeSmaller2 = new ImageIcon("MeSmaller2.jpg").getImage();
}
public void initTimer() {
timer = new Timer(1000, this);
timer.start();
timer.stop();
alpha = 1f;
}
private void doDrawing(Graphics g) {
Graphics2D g2Dim = (Graphics2D) g;
// below sets the size of picture
BufferedImage buffImage = new BufferedImage(400, 600,
BufferedImage.TYPE_INT_ARGB);

Graphics2D gBuffI = buffImage.createGraphics();
AlphaComposite aComp = AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha);
// decides where images are drawn in JFrame
gBuffI.drawImage(MeSmaller1, 28, 55, null);
gBuffI.setComposite(aComp);
gBuffI.drawImage(MeSmaller2, 30, 48, null);
g2Dim.drawImage(buffImage, 10, 10, null);
}
public static void saveToFile(BufferedImage img) {

}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
@Override
public void actionPerformed(ActionEvent e) {
alpha -= 0.1;
if (alpha <= 0) {
alpha = 0;
timer.stop();
System.out.println("Morph Finished please restart.");
}
repaint();
}

}

这里有人能帮忙吗?就是不起作用。还有另一个类PictureMorph.java

import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class PictureMorph extends JFrame {
private static final long serialVersionUID = 1L;
public PictureMorph() {
initUI();
}
private void initUI() {
JFrame frame = new JFrame ("Image Morph");
setTitle("Facial Image Manipulation");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new Frame());
// below set Frame Size around image
setSize(380, 470);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
PictureMorph picMorph = new PictureMorph();
picMorph.setVisible(true);
}
});
}
}

还有3个类(我认为现在实际上可能是多余的?),名为BtnStartBlendListener、BtnStopBlendListener和SaveImageListener,它们根本不包含太多代码。有人能帮忙吗?

要使用JFileChooser并最终获得用户友好的文件选择器,可以执行以下操作:

private static Frame workFrame;
public static Frame getWorkFrame() {
return workFrame;
}
public static void setWorkFrame(Frame frame) {
workFrame = frame;
}

然后按以下方式修改保存方法(签名更改,我还对使用Scanner的代码进行了注释,并用JFileChooser替换它)

public static void save(BufferedImage img, Frame frame) {
//  Scanner scan = new Scanner(System.in);
//  System.out.println("Enter the file name: ");
//  String fileFullPath = scan.next();
String fileFullPath = getFileToSaveTo(frame);
file = new File(fileFullPath);
saveToFile(img, file);
}

添加以下方法:

public static String getFileToSaveTo(Frame frame) {
JFileChooser fc=new JFileChooser();
int returnVal=fc.showOpenDialog(frame);
if (returnVal == JFileChooser.APPROVE_OPTION) {
return fc.getSelectedFile().getAbsolutePath();
}
else {
return null;
}
}

在您的主方法中,有一个类似Frame.setWorkFrame(fr);的调用,其中fr定义为Frame fr = new Frame();

这应该使它与JFileChooser一起工作。例如,下面是我如何调用主方法中的程序

public static void main(String[] args) {
JFrame theFrame = new JFrame("Testing catess...");
theFrame.setSize(400, 400);
Frame fr = new Frame();
theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theFrame.add(fr, BorderLayout.CENTER);
theFrame.setVisible(true);
Frame.setWorkFrame(fr);
}

它在我的测试中运行良好。测试并让我知道它是否有效

由于您将saveToFile方法留空,我认为这是您遇到的主要问题。

对于saveToFile方法,您可以使用javax.imageio.imageio。我建议您将File对象参数传递给您的方法,以便它知道在哪里保存图像。

public static void saveToFile(BufferedImage img, File file) {
String filename = file.getName();
String suffix = filename.substring(filename.lastIndexOf('.') + 1);
suffix = suffix.toLowerCase();
if (suffix.equals("jpg") || suffix.equals("png")) {
try { ImageIO.write(img, suffix, file); }
catch (IOException e) { e.printStackTrace(); }
}
else {
System.out.println("Error: filename must end in .jpg or .png");
}
}

希望这能帮助

[EDIT]

File构造函数允许您使用表示文件路径的字符串来实例化File对象。

例如:假设我想把它保存在C:\Tests\image1.jpg中,我会做这个

File myFile = new File("C:\Tests\image1.jpg") 

,其中Tests表示现有文件夹,image1.jpg当然是将保存图像的新文件的名称。

因此,假设img是一个变量,包含对BufferedImage对象的引用,您将使用调用上面的方法

Frame.saveToFile(img, myFile);

其中myFile是上面的File对象。

您还可以添加一个静态方法,例如下面的方法,让用户指定文件的路径。我使用Scanner来快速获取它,但为了更友好的对话框,请使用JFileChooser(示例如下)

public static void save(BufferedImage img) {
Scanner scan = new Scanner(System.in);
System.out.println("Enter the file name: ");
String fileFullPath = scan.next();
File file = new File(fileFullPath);
saveToFile(img, file);
}

您遇到的问题主要与您声明了一些变量的final有关,特别是BufferedImage和File对象(它们为null,由于您使它们成为final,因此它们的值无法更改)

我纠正了这些问题。这是整个代码,除了imports语句,它们与源代码链接中的语句相同。

单击保存按钮后,在控制台中输入要保存的文件的完整路径:例如C:\test1.jpg。

class Frame extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
static BufferedImage bufferedImage = null;  // Don't need to make this     final
static File file = null;  // Don't need to make this final
private Image MeSmaller1;
private Image MeSmaller2;
protected Timer timer;
private float alpha;
JPanel pnlButton = new JPanel();
static JButton btnStartBlend = new JButton("Start Blend");
static JButton btnStopBlend = new JButton("Stop Blend");
static JButton saveImage = new JButton("Save Image To File");
public Frame() {
loadImages();
initTimer();
pnlButton.add(btnStartBlend);
this.add(pnlButton);
pnlButton.add(btnStopBlend);
this.add(pnlButton);
pnlButton.add(saveImage);
this.add(pnlButton);
addListeners();
}
// start button action listener
public void addListeners() {
btnStartBlend.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
initTimer();
timer.start();
System.out.println("Timer started");
}
});
// stop button actionlistener
btnStopBlend.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// initTimer();
timer.stop();
System.out.println("Timer stopped");
}
});
// Save button actionlistener
saveImage.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent saveImage) {
save(bufferedImage);
System.out.println("Save image clicked");
}
});
}
private void loadImages() {
// I did my local test using
//MeSmaller1 = new    ImageIcon("C:\Tests\Alain_Lompo.jpg").getImage();
//MeSmaller2 = new    ImageIcon("C:\Tests\Alain_Lompo.jpg").getImage();
MeSmaller1 = new ImageIcon("MeSmaller1.jpg").getImage();
MeSmaller2 = new ImageIcon("MeSmaller2.jpg").getImage();
}
public void initTimer() {
timer = new Timer(1000, this);
timer.start();
timer.stop();
alpha = 1f;
}
private void doDrawing(Graphics g) {
Graphics2D g2Dim = (Graphics2D) g;
// below sets the size of picture
bufferedImage = new BufferedImage(400, 600,
BufferedImage.TYPE_INT_ARGB);
Graphics2D gBuffI = bufferedImage.createGraphics();
AlphaComposite aComp = AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, alpha);
// decides where images are drawn in JFrame
gBuffI.drawImage(MeSmaller1, 28, 55, null);
gBuffI.setComposite(aComp);
gBuffI.drawImage(MeSmaller2, 30, 48, null);
g2Dim.drawImage(bufferedImage, 10, 10, null);
}

public static void save(BufferedImage img) {
Scanner scan = new Scanner(System.in);
System.out.println("Enter the file name: ");
String fileFullPath = scan.next();
file = new File(fileFullPath);
saveToFile(img, file);
}
public static void saveToFile(BufferedImage img, File file) {
String filename = file.getName();
String suffix = filename.substring(filename.lastIndexOf('.') + 1);
suffix = suffix.toLowerCase();
if (suffix.equals("jpg") || suffix.equals("png")) {
try { ImageIO.write(img, suffix, file); }
catch (IOException e) { e.printStackTrace(); }
}
else {
System.out.println("Error: filename must end in .jpg or .png");
}
}

@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
public void actionPerformed(ActionEvent e) {
alpha -= 0.1;
if (alpha <= 0) {
alpha = 0;
timer.stop();
System.out.println("Morph Finished please restart.");
}
repaint();
}
public static void main(String[] args) {
JFrame theFrame = new JFrame("Testing catess...");
theFrame.setSize(400, 400);
Frame fr = new Frame();
theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
theFrame.add(fr, BorderLayout.CENTER);
theFrame.setVisible(true);
}
}

最新更新