在 Java 中镜像图像
Mirroring an Image in Java
背景信息: 我制作了一个程序,使用 JFileChooser 上传图像并填充 JFrame 的 space。然后我通过按钮应用过滤器。目前我的 4 个滤镜中有 3 个在工作,或者除了我的镜像滤镜之外的所有滤镜。它随机地(或者我想不是那么随机,因为总有一个原因,我只是不知道我做了什么)工作了几次。
我的问题: 我尝试按照教程进行操作,但必须稍作更改,以便我可以通过具有 JFile 选择器的按钮将其保存到新文件。目前,当我保存它时,它不会镜像,但是我的其他过滤器会做同样的细微变化。我的镜像逻辑有什么问题?感谢您的帮助!
我的代码:
全局变量:
// Save Button
private final JButton saveButton = new JButton("Save Files");
private File selFile1;
private File output = new File("Output.png");
private File selFile2;
private String path1;
上传文件:
// Browse Files Button ActionListener
BrowseButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser getFile = new JFileChooser();
getFile.setCurrentDirectory(new File(System.getProperty("user.home")));
// Filter files
FileNameExtensionFilter filter1 = new FileNameExtensionFilter("*.Images", "jpg", "png");
getFile.addChoosableFileFilter(filter1);
int res = getFile.showSaveDialog(null);
if(res == JFileChooser.APPROVE_OPTION) {
selFile1 = getFile.getSelectedFile();
path1 = selFile1.getAbsolutePath();
label.setIcon(resize(path1));
System.out.println("1st selFile1 = " + selFile1);
try {
getImg = ImageIO.read(selFile1);
} catch (IOException ex) {
System.out.println(ex);
} // End try-catch
} // End if
} // End actionPerformer
}); // End ActionListener
}); // End ActionListener
保存文件:
// Save Files Button ActionListener
saveButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser getFile = new JFileChooser();
getFile.setCurrentDirectory(new File(System.getProperty("user.home")));
// Filter files
FileNameExtensionFilter filter1 = new FileNameExtensionFilter("*.Images", "jpg",
"png");
getFile.addChoosableFileFilter(filter1);
int res = getFile.showSaveDialog(null);
if(res == JFileChooser.APPROVE_OPTION) {
selFile2 = getFile.getSelectedFile();
path1 = selFile2.getAbsolutePath();
label.setIcon(resize(path1));
System.out.println("1st selFile1 = " + selFile2);
try {
ImageIO.write(getImg, "png", selFile2);
} catch (IOException ex) {
System.out.println(ex);
} // End try-catch
} // End if
} // End actionPerformer
}); // End ActionListener
有效的灰度方法:
grayScale.setMnemonic('G'); //Hot key
// ActionListener for grayscale button
grayScale.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
File f = selFile1;
// Read image
try{
getImg = ImageIO.read(f);
} catch(IOException ef){
System.out.println(ef);
} // End try-catch
// Get image width and height
int width = getImg.getWidth();
int height = getImg.getHeight();
// Convert to grayscale
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
int p = getImg.getRGB(x,y);
int a = (p>>24)&0xff;
int r = (p>>16)&0xff;
int g = (p>>8)&0xff;
int b = p&0xff;
// Calculate average
int avg = (r+g+b)/3;
// Replace RGB value with avg
p = (a<<24) | (avg<<16) | (avg<<8) | avg;
getImg.setRGB(x, y, p);
}
} // End for
JOptionPane.showMessageDialog(comboBoxPanel, "Gray Scale Filter has been applied. Save to view!");
// Write image
try {
f = output;
ImageIO.write(getImg, "png", f);
} catch(IOException ex){
System.out.println(ex);
} // End try-catch
} // End actionPerformed
}); //End ActionListener
镜像方法不行:
mirrored.setMnemonic('M'); // Hot Key
// ActionListener for mirror button
mirrored.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
File f = selFile1;
BufferedImage res = null;
try{
getImg = ImageIO.read(f);
res = ImageIO.read(f);
} catch(IOException ex){
System.out.println(ex);
} // End try-catch
// Get source image dimension
int width = getImg.getWidth();
int height = getImg.getHeight();
//BufferedImage for mirror image
res = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//create mirror image pixel by pixel
for(int y = 0; y < height; y++){
for(int lx = 0, rx = width - 1; lx < width; lx++, rx--){
// lx starts from the left side of the image
// rx starts from the right side of the image
// Get source pixel value
int p = getImg.getRGB(lx, y);
// Set mirror image pixel value - both left and right
res.setRGB(rx, y, p);
}
} // End for
JOptionPane.showMessageDialog(comboBoxPanel, "Mirrored Filter has been applied. Save to view!");
// Write image
try{
f = output;
ImageIO.write(res, "png", f);
} catch(IOException ex){
System.out.println(ex);
} // End try-catch
} // End actionPerformed
}); // End actionListener
GUI(供参考):
所以,推测,你开始做...
File f = selFile1;
BufferedImage res = null;
try {
getImg = ImageIO.read(f);
res = ImageIO.read(f);
} catch (IOException ex) {
System.out.println(ex);
} // End try-catch
最后你这样做...
// Write image
try {
f = output;
ImageIO.write(res, "png", f);
} catch (IOException ex) {
System.out.println(ex);
} // End try-catch
但是,getImg
仍然指向源(未修改)图像。如果您使用它向用户显示结果,那么您显示的是错误的图像。根据您的其他“过滤”操作,您正在直接修改 getImg
。
现在,话虽如此,您的代码充其量是有问题的。
让我解释一下...
File f = selFile1;
BufferedImage res = null;
try {
getImg = ImageIO.read(f);
res = ImageIO.read(f);
} catch (IOException ex) {
System.out.println(ex);
} // End try-catch
你怎么知道 selFile1
不是 null
或者它指向一个有效的 File
?你在这里没有做任何检查。另外,两次读取文件有什么意义,尤其是当你在它之后立即执行 res = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
时?
这又引出了一个问题,如果图片加载失败怎么办?您继续尝试使用 getImg
引用,它可能包含“脏”数据或更糟的是 null
.
相反,我可能会做一些更像...
if (selFile1 == null) {
// Show error message
// Use JOptionPane to show message to user
return;
}
try {
BufferedImage sourceImage = ImageIO.read(selFile1);
// Get source image dimension
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
//BufferedImage for mirror image
BufferedImage mirroredImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//create mirror image pixel by pixel
for (int y = 0; y < height; y++) {
for (int lx = 0, rx = width - 1; lx < width; lx++, rx--) {
// lx starts from the left side of the image
// rx starts from the right side of the image
// Get source pixel value
int p = sourceImage.getRGB(lx, y);
// Set mirror image pixel value - both left and right
mirroredImage.setRGB(rx, y, p);
}
} // End for
JOptionPane.showMessageDialog(comboBoxPanel, "Mirrored Filter has been applied. Save to view!");
// Write image
ImageIO.write(mirroredImage, "png", selFile1);
} catch (IOException ex) {
ex.printStackTrace();
// Use JOptionPane to show message to user
} // End try-catch
现在您也可以在内部 try-catch
中隔离写入,但重点是尝试进行一些先发制人的检查,以防止已知问题导致代码崩溃。
哦,你可能会发现...
BufferedImage mirrored = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = mirrored.createGraphics();
g2d.scale(-1, 1);
g2d.translate(-source.getWidth(), 0);
g2d.drawImage(source, 0, 0, null);
g2d.dispose();
还有更简单的镜像方式
您可以使用 Graphics2D
对象的 scale()
方法为您完成此操作:
import java.awt.*;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.swing.*;
import javax.imageio.*;
public class MirrorImage extends JPanel
{
public MirrorImage()
{
try
{
BufferedImage image = ImageIO.read( new File("dukewavered.gif") );
JLabel label = new JLabel( new ImageIcon( image ) );
add(label);
BufferedImage mirrorImage = createMirror( image );
JLabel mirror = new JLabel( new ImageIcon( mirrorImage ) );
add(mirror);
}
catch (Exception e) {e.printStackTrace();}
}
public BufferedImage createMirror(Image image)
{
BufferedImage bi = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
g2d.translate(bi.getWidth(), 0);
g2d.scale(-1, 1);
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
return bi;
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Mirror Image");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MirrorImage());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}
背景信息: 我制作了一个程序,使用 JFileChooser 上传图像并填充 JFrame 的 space。然后我通过按钮应用过滤器。目前我的 4 个滤镜中有 3 个在工作,或者除了我的镜像滤镜之外的所有滤镜。它随机地(或者我想不是那么随机,因为总有一个原因,我只是不知道我做了什么)工作了几次。
我的问题: 我尝试按照教程进行操作,但必须稍作更改,以便我可以通过具有 JFile 选择器的按钮将其保存到新文件。目前,当我保存它时,它不会镜像,但是我的其他过滤器会做同样的细微变化。我的镜像逻辑有什么问题?感谢您的帮助!
我的代码:
全局变量:
// Save Button
private final JButton saveButton = new JButton("Save Files");
private File selFile1;
private File output = new File("Output.png");
private File selFile2;
private String path1;
上传文件:
// Browse Files Button ActionListener
BrowseButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser getFile = new JFileChooser();
getFile.setCurrentDirectory(new File(System.getProperty("user.home")));
// Filter files
FileNameExtensionFilter filter1 = new FileNameExtensionFilter("*.Images", "jpg", "png");
getFile.addChoosableFileFilter(filter1);
int res = getFile.showSaveDialog(null);
if(res == JFileChooser.APPROVE_OPTION) {
selFile1 = getFile.getSelectedFile();
path1 = selFile1.getAbsolutePath();
label.setIcon(resize(path1));
System.out.println("1st selFile1 = " + selFile1);
try {
getImg = ImageIO.read(selFile1);
} catch (IOException ex) {
System.out.println(ex);
} // End try-catch
} // End if
} // End actionPerformer
}); // End ActionListener
}); // End ActionListener
保存文件:
// Save Files Button ActionListener
saveButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser getFile = new JFileChooser();
getFile.setCurrentDirectory(new File(System.getProperty("user.home")));
// Filter files
FileNameExtensionFilter filter1 = new FileNameExtensionFilter("*.Images", "jpg",
"png");
getFile.addChoosableFileFilter(filter1);
int res = getFile.showSaveDialog(null);
if(res == JFileChooser.APPROVE_OPTION) {
selFile2 = getFile.getSelectedFile();
path1 = selFile2.getAbsolutePath();
label.setIcon(resize(path1));
System.out.println("1st selFile1 = " + selFile2);
try {
ImageIO.write(getImg, "png", selFile2);
} catch (IOException ex) {
System.out.println(ex);
} // End try-catch
} // End if
} // End actionPerformer
}); // End ActionListener
有效的灰度方法:
grayScale.setMnemonic('G'); //Hot key
// ActionListener for grayscale button
grayScale.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
File f = selFile1;
// Read image
try{
getImg = ImageIO.read(f);
} catch(IOException ef){
System.out.println(ef);
} // End try-catch
// Get image width and height
int width = getImg.getWidth();
int height = getImg.getHeight();
// Convert to grayscale
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
int p = getImg.getRGB(x,y);
int a = (p>>24)&0xff;
int r = (p>>16)&0xff;
int g = (p>>8)&0xff;
int b = p&0xff;
// Calculate average
int avg = (r+g+b)/3;
// Replace RGB value with avg
p = (a<<24) | (avg<<16) | (avg<<8) | avg;
getImg.setRGB(x, y, p);
}
} // End for
JOptionPane.showMessageDialog(comboBoxPanel, "Gray Scale Filter has been applied. Save to view!");
// Write image
try {
f = output;
ImageIO.write(getImg, "png", f);
} catch(IOException ex){
System.out.println(ex);
} // End try-catch
} // End actionPerformed
}); //End ActionListener
镜像方法不行:
mirrored.setMnemonic('M'); // Hot Key
// ActionListener for mirror button
mirrored.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
File f = selFile1;
BufferedImage res = null;
try{
getImg = ImageIO.read(f);
res = ImageIO.read(f);
} catch(IOException ex){
System.out.println(ex);
} // End try-catch
// Get source image dimension
int width = getImg.getWidth();
int height = getImg.getHeight();
//BufferedImage for mirror image
res = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//create mirror image pixel by pixel
for(int y = 0; y < height; y++){
for(int lx = 0, rx = width - 1; lx < width; lx++, rx--){
// lx starts from the left side of the image
// rx starts from the right side of the image
// Get source pixel value
int p = getImg.getRGB(lx, y);
// Set mirror image pixel value - both left and right
res.setRGB(rx, y, p);
}
} // End for
JOptionPane.showMessageDialog(comboBoxPanel, "Mirrored Filter has been applied. Save to view!");
// Write image
try{
f = output;
ImageIO.write(res, "png", f);
} catch(IOException ex){
System.out.println(ex);
} // End try-catch
} // End actionPerformed
}); // End actionListener
GUI(供参考):
所以,推测,你开始做...
File f = selFile1;
BufferedImage res = null;
try {
getImg = ImageIO.read(f);
res = ImageIO.read(f);
} catch (IOException ex) {
System.out.println(ex);
} // End try-catch
最后你这样做...
// Write image
try {
f = output;
ImageIO.write(res, "png", f);
} catch (IOException ex) {
System.out.println(ex);
} // End try-catch
但是,getImg
仍然指向源(未修改)图像。如果您使用它向用户显示结果,那么您显示的是错误的图像。根据您的其他“过滤”操作,您正在直接修改 getImg
。
现在,话虽如此,您的代码充其量是有问题的。
让我解释一下...
File f = selFile1;
BufferedImage res = null;
try {
getImg = ImageIO.read(f);
res = ImageIO.read(f);
} catch (IOException ex) {
System.out.println(ex);
} // End try-catch
你怎么知道 selFile1
不是 null
或者它指向一个有效的 File
?你在这里没有做任何检查。另外,两次读取文件有什么意义,尤其是当你在它之后立即执行 res = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
时?
这又引出了一个问题,如果图片加载失败怎么办?您继续尝试使用 getImg
引用,它可能包含“脏”数据或更糟的是 null
.
相反,我可能会做一些更像...
if (selFile1 == null) {
// Show error message
// Use JOptionPane to show message to user
return;
}
try {
BufferedImage sourceImage = ImageIO.read(selFile1);
// Get source image dimension
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
//BufferedImage for mirror image
BufferedImage mirroredImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//create mirror image pixel by pixel
for (int y = 0; y < height; y++) {
for (int lx = 0, rx = width - 1; lx < width; lx++, rx--) {
// lx starts from the left side of the image
// rx starts from the right side of the image
// Get source pixel value
int p = sourceImage.getRGB(lx, y);
// Set mirror image pixel value - both left and right
mirroredImage.setRGB(rx, y, p);
}
} // End for
JOptionPane.showMessageDialog(comboBoxPanel, "Mirrored Filter has been applied. Save to view!");
// Write image
ImageIO.write(mirroredImage, "png", selFile1);
} catch (IOException ex) {
ex.printStackTrace();
// Use JOptionPane to show message to user
} // End try-catch
现在您也可以在内部 try-catch
中隔离写入,但重点是尝试进行一些先发制人的检查,以防止已知问题导致代码崩溃。
哦,你可能会发现...
BufferedImage mirrored = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = mirrored.createGraphics();
g2d.scale(-1, 1);
g2d.translate(-source.getWidth(), 0);
g2d.drawImage(source, 0, 0, null);
g2d.dispose();
还有更简单的镜像方式
您可以使用 Graphics2D
对象的 scale()
方法为您完成此操作:
import java.awt.*;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.swing.*;
import javax.imageio.*;
public class MirrorImage extends JPanel
{
public MirrorImage()
{
try
{
BufferedImage image = ImageIO.read( new File("dukewavered.gif") );
JLabel label = new JLabel( new ImageIcon( image ) );
add(label);
BufferedImage mirrorImage = createMirror( image );
JLabel mirror = new JLabel( new ImageIcon( mirrorImage ) );
add(mirror);
}
catch (Exception e) {e.printStackTrace();}
}
public BufferedImage createMirror(Image image)
{
BufferedImage bi = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
g2d.translate(bi.getWidth(), 0);
g2d.scale(-1, 1);
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
return bi;
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Mirror Image");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MirrorImage());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}