目录
回顾上期美颜相机博客,我们已经实现了将图片地址输入文本框中后将所在地址图片绘画出来的功能。然而有人可能会觉得一个个字符将图片地址打入文本框中太累了,每次打开图片都要去获取图片地址不方便,而且按钮与绘图区域位置设定不方便。
有没有什么方法能将打开图片的方式变得简单,就像我们下载时可以自由选择下载的位置那样,可以自由选择电脑上存在的图片打开;并且按钮的布局更加灵活,通过这篇博客我们完善美颜相机的功能。
1.创建主窗体
public void showUI(){
JFrame jf=new JFrame();
jf.setTitle("美颜相机");
jf.setSize(1000,800);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setLocationRelativeTo(null);
//设置窗口布局为边界布局
jf.setLayout(new BorderLayout());
jf.setVisible(true);
}
2.面板JPanel 类.
JPanel是Java图形用户界面工具包Swing中的面板容器类,包含在javax.swing包中,是一种轻量级容器,可以加入到JFrame窗体中。JPanel默认的布局管理器是FlowLayout,其自身可以嵌套组合,在不同子容器中可包含其他组件,如JButton、JTextArea、JTextField等,功能是对窗体上的这些控件进行组合。
容器:可以存放其他组件
*窗体JFrame自己可以独立显示在屏幕上
*面板JPanel要加载到JFrame等高级容器上
2.1.createPanel()
创建createPanel()方法实现创建面板对象并将面板对象添加到窗体中
public JPanel createPanel(JFrame jf,Color color,int size,String border) {
JPanel jp=new JPanel();
jp.setBackground(color);
jf.add(jp,border);
jp.setPreferredSize(new Dimension(size,size));
return jp;
}
面板背景色为color,方位为border,常用的有SOUTH,NORTH,EAST,WEST
在窗体中下方添加面板
JPanel jp_s=createPanel(jf,Color.LIGHT_GRAY,100,BorderLayout.SOUTH);
多个面板
2.2.initBtnPanel()
面板创建好了,可要知道面板是一个容器,里面不放东西发挥不了它的作用
接下来我们创建initBtnPanel()方法将按钮添加到面板上
public void initBtnPanel(JPanel jp){
String[] strs={"打开","撤回", "原图", "马赛克", "灰度", "二值化", "圆点马赛克", "反片", "轮廓化", "油画", "暖色调","冷色调"};
for(int i=0;i<strs.length;i++){
JButton btn =new JButton(strs[i]);
btn.setBackground(Color.white);
btn.addActionListener(lis);
jp.add(btn);
}
}
initBtnPanel(jp_s);
lis为我们创建的监听器,用jp.add()将按钮添加到面板上
2.3.创建中央面板以绘制图像
2.3.1.创建ImagePanel类
ImagePanel继承JPanel类
public class ImagePanel extends JPanel{
ArrayList<BufferedImage> bfImgList;
public void paint(Graphics g){
super.paint(g);
if(bfImgList.size()==0){
return;
}
int index=bfImgList.size()-1;
BufferedImage bfImg=bfImgList.get(index);
g.drawImage(bfImg,100,80,null);
}
}
BufferedImage是Java中的一个类,它继承自Image类。它是用于处理和操作图像的常用工具之
一。BufferedImage提供了一些方法来创建、修改和访问图像数据。BufferedImage将一幅图片加载
到内存中以便我们更好地对图像进行处理。
bufImgList中存储每幅加载的图片
paint()方法用来在面板上实时画最新一幅图,若bfImgList为空,则不执行
2.3.2.initImgPanel()
public ImagePanel initImgPanel(JFrame jf,Color color){
ImagePanel imagePanel=new ImagePanel();
imagePanel.setBackground(color);
jf.add(imagePanel);
imagePanel.bfImgList=lis.bfImgList;//传递监听器中图像列表到ImagePanel中
lis.imagePanel=imagePanel;
return imagePanel;
}
3.ImageFilter类
public class ImageFilter {
//原图
public BufferedImage drawImage_01(int[][] imgArr) {
//创建新的bufferedImage对象,用于绘制图像
BufferedImage bfimg = new BufferedImage(imgArr.length, imgArr[0].length, BufferedImage.TYPE_INT_ARGB);
//获取绘图上下文
Graphics bg = bfimg.getGraphics();
for (int i = 0; i < imgArr.length; i++) {
for (int j = 0; j < imgArr[0].length; j++) {
int rgb = imgArr[i][j];
Color color = new Color(rgb);
bg.setColor(color);
bg.fillRect(i, j, 1, 1);
}
}
//返回绘制好的缓存图像
return bfimg;
}
//马赛克
public BufferedImage drawImage_02(int[][] imgArr) {
BufferedImage bfimg = new BufferedImage(imgArr.length, imgArr[0].length, BufferedImage.TYPE_INT_ARGB);
Graphics bg = bfimg.getGraphics();
for (int i = 0; i < imgArr.length; i += 3) {
for (int j = 0; j < imgArr[0].length; j += 3) {
int rgb = imgArr[i][j];
Color color = new Color(rgb);
bg.setColor(color);
bg.fillRect(i, j, 3, 3);
}
}
return bfimg;
}
//获取图片地址
public int[][] getImagePixel(String imagePaths){
File file=new File(imagePaths);
BufferedImage buffImg=null;
try {
buffImg = ImageIO.read(file);
} catch (IOException e) {
throw new RuntimeException(e);
}
int width=buffImg.getWidth();
int height=buffImg.getHeight();
int [][]imgArr=new int[width][height];
for(int i=0;i<width;i++){
for(int j=0;j<height;j++){
imgArr[i][j]=buffImg.getRGB(i,j);
}
}
return imgArr;
}
}
在此仅列举两种图像处理方法和获取图片地址的方法,有兴趣的可以参考上一篇博客
4.监听器ImageProListener
基本布局有了,接下来要将窗体对象中的按钮与具体的方法相关联,通过监听器来实现
public class ImageProListener implements ActionListener {
Graphics g;
int[][] imagePixel;
int index;
BufferedImage bfImg;//当前绘制的图像
ArrayList<BufferedImage> bfImgList=new ArrayList<>();//存储图像的列表
ImagePanel imagePanel;//图片显示面板
ImageFilter imgFl=new ImageFilter();//创建图片处理器对象
@Override
public void actionPerformed(ActionEvent e) {
String btnText=e.getActionCommand();//获取按钮文本
System.out.println(btnText);
if(btnText.equals("打开")){
JFileChooser chooser=new JFileChooser();
FileNameExtensionFilter filter=new FileNameExtensionFilter("JPG & PNG Images", "jpg", "png", "jpeg");
chooser.setFileFilter(filter);
int returnVal=chooser.showOpenDialog(null);
if(returnVal==JFileChooser.APPROVE_OPTION){
System.out.println("You chose to open this file"+chooser.getSelectedFile().getName());
String path=chooser.getSelectedFile().getPath();
imagePixel=imgFl.getImagePixel(path);
bfImg=imgFl.drawImage_01(imagePixel);
bfImgList.add(bfImg);
}
}
if(imagePixel==null){
JOptionPane.showMessageDialog(null,"请先选择一张图片");
}
if(btnText.equals("原图")){
bfImg=imgFl.drawImage_01(imagePixel);
bfImgList.add(bfImg);//将画好的图片缓存到图像列表中,方便撤回操作
} else if (btnText.equals("马赛克")) {
bfImg=imgFl.drawImage_02(imagePixel);
bfImgList.add(bfImg);
} else if (btnText.equals("灰度")) {
bfImg=imgFl.drawImage_03(imagePixel);
bfImgList.add(bfImg);
} else if (btnText.equals("二值化")) {
bfImg=imgFl.drawImage_04(imagePixel);
bfImgList.add(bfImg);
} else if (btnText.equals("圆点马赛克")) {
bfImg=imgFl.drawImage_05(imagePixel);
bfImgList.add(bfImg);
} else if (btnText.equals("反片")) {
bfImg=imgFl.drawImage_06(imagePixel);
bfImgList.add(bfImg);
} else if (btnText.equals("轮廓化")) {
bfImg=imgFl.drawImage_07(imagePixel);
bfImgList.add(bfImg);
} else if (btnText.equals("油画")) {
bfImg=imgFl.drawImage_08(imagePixel);
bfImgList.add(bfImg);
} else if (btnText.equals("暖色调")) {
bfImg=imgFl.drawImage_09(imagePixel);
bfImgList.add(bfImg);
} else if (btnText.equals("冷色调")) {
bfImg=imgFl.drawImage_10(imagePixel);
bfImgList.add(bfImg);
}else if(btnText.equals("撤回")){
//如果图像列表中有图像记录,则将上一张图片记录画出
if(bfImgList.size()>0){
index=bfImgList.size()-1;//获取当前图片存储的位置
bfImgList.remove(index);//将当前图片移除
}else{
JOptionPane.showMessageDialog(null,"无缓存记录,无法撤回");
}
}
imagePanel.repaint();//重绘
}
}
JFileChooser是Java中一个用于打开文件对话框的类,可以方便地选择文件
FileNameExtensionFilter是Java中一个用于过滤文件后缀的类,可以设置文件后缀过滤器。
FileNameExtensionFilter filter=new FileNameExtensionFilter("JPG & PNG Images", "jpg", "png", "jpeg");
该代码表示过滤后缀为jpg或png或jpeg的文件,同时描述文件类型为JPG & PNG Images。
5.实现效果
屏幕录制 2023-10-25 192425