需求:
创建一个能修改润色图片的程序,拥有打开,保存等基本功能,并且实现马赛克,灰度,画笔等对图片进行修改的功能。
1.设计界面
程序创建了一个包含图像显示、操作按钮和图像文件列表的图形用户界面(GUI),用户可以通过点击按钮对图像进行打开、保存、应用滤镜、绘制图形等操作,还能从文件列表中选择图像进行加载显示。
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
public class ImageProUI {
ImageListener imgl = new ImageListener();
ImageUtils imgUtils = new ImageUtils();
ImagePanel imgPanel = new ImagePanel();
public void showUI() {
// 创建窗体
JFrame jf = new JFrame();
jf.setTitle("美颜相机");
jf.setSize(1000, 800);
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel btnPanel = new JPanel();
JPanel listPanel = new JPanel();
// 设置面板的属性
btnPanel.setBackground(Color.DARK_GRAY);
listPanel.setBackground(Color.LIGHT_GRAY);
imgPanel.setBackground(Color.BLACK);
// 设置宽高
Dimension dim = new Dimension(200, 100);
btnPanel.setPreferredSize(dim);
listPanel.setPreferredSize(dim);
// 初始化按钮面板
initBtnPanel(btnPanel);
initListPanel(listPanel);
// 添加到窗体上
jf.add(btnPanel, BorderLayout.SOUTH);
jf.add(listPanel, BorderLayout.WEST);
jf.add(imgPanel, BorderLayout.CENTER);
jf.setVisible(true);
imgPanel.addMouseListener(imgl);
imgPanel.addMouseMotionListener(imgl);
// 三个对象之间交替传递
imgPanel.addImageUtils(imgUtils);
imgl.addImagePanel(imgPanel);
imgl.addImageUtils(imgUtils);
}
public void initBtnPanel(JPanel btnPanel) {
String[] btnTexts = {"打开", "保存", "原图", "马赛克", "灰度"};
for (int i = 0; i < btnTexts.length; i++) {
JButton btn = new JButton(btnTexts[i]);
btn.setBackground(Color.WHITE);
btnPanel.add(btn);
btn.addActionListener(imgl);
}
String[] btnTexts2 = {"画笔", "直线", "矩形", "填充", "截图", "马赛克画笔", "灰 度画笔"};
for (int i = 0; i < btnTexts2.length; i++) {
JButton btn = new JButton(btnTexts2[i]);
btn.setBackground(Color.WHITE);
btnPanel.add(btn);
btn.addActionListener(imgl);
}
}
public void initListPanel(JPanel listPanel) {
//获取文件地址
String rootPath = "C:\\Users\\sheng\\Desktop\\新建文件夹 (2)";
listPanel.setLayout(new BorderLayout());
JTextField tf = new JTextField(rootPath);
listPanel.add(tf, BorderLayout.NORTH);
JPanel imgBtnPanel = new JPanel();
imgBtnPanel.setLayout(new GridLayout(0, 1));
File rootFile = new File(rootPath);
File[] files = rootFile.listFiles();
for (int i = 0; i < files.length; i++) {
// files[i].getName()
File imgFile = files[i];
JButton btn = new JButton(imgFile.getName());
BufferedImage btnImage = imgUtils.getBtnImage(imgFile);
btn.setIcon(new ImageIcon(btnImage));
btn.setBackground(Color.WHITE);
btn.setPreferredSize(new Dimension(200, 100));
imgBtnPanel.add(btn);
btn.addActionListener(e -> { String fileName = e.getActionCommand();
tf.setText(rootPath + "\\" + fileName);
imgUtils.loadImage(tf.getText());
imgPanel.repaint();
});
}
JScrollPane jsp = new JScrollPane();
jsp.setViewportView(imgBtnPanel);
listPanel.add(jsp, BorderLayout.CENTER);
}
public static void main(String[] args) {
ImageProUI ipu = new ImageProUI();
ipu.showUI();
}
}
ImageListener imgl
:用于处理各种用户交互事件,如按钮点击、鼠标操作等。ImageUtils imgUtils
:图像处理器,负责图像的加载、保存、滤镜处理等操作。ImagePanel imgPanel
:用于显示和绘制图像的面板,支持鼠标交互。-
showUI()
方法 - 创建主窗口:创建一个
JFrame
对象,设置窗口标题、大小、位置和关闭操作。 - 创建面板:创建三个面板,分别为按钮面板
btnPanel
、图像文件列表面板listPanel
和图像显示面板imgPanel
,并设置它们的背景颜色和大小。 - 初始化面板:调用
initBtnPanel
和initListPanel
方法初始化按钮面板和图像文件列表面板。 - 添加面板到窗口:将三个面板添加到主窗口的不同位置(底部、左侧和中间)。
- 显示窗口:设置窗口可见。
- 添加监听器:为图像显示面板添加鼠标监听器和鼠标移动监听器,并在三个对象之间建立关联。
2.监听器设置
实现了 ActionListener
、MouseMotionListener
和 MouseListener
接口,用于处理图像操作界面中的各种事件,包括按钮点击事件和鼠标操作事件。
package Camera;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class ImageListener implements ActionListener, MouseMotionListener,
MouseListener{
ImagePanel imagePanel;
ImageUtils imgUtils;
String drawType = "画笔";
public void addImageUtils(ImageUtils imgUtils) {
this.imgUtils = imgUtils;
}
public void addImagePanel(ImagePanel imagePanel) {
this.imagePanel = imagePanel;
}
@Override
public void actionPerformed(ActionEvent e) {
String ac = e.getActionCommand();
System.out.println("ac:" + ac);
if (ac.equals("打开")) {
JFileChooser jfc = new JFileChooser("C:\\Users\\");
// 文件名过滤器
FileNameExtensionFilter filter = new FileNameExtensionFilter
("JPG & PNG", "jpg", "png");
jfc.setFileFilter(filter);
int state = jfc.showOpenDialog(null);
if (state == JFileChooser.APPROVE_OPTION) {
String path = jfc.getSelectedFile().getAbsolutePath();
// 图像处理对象 调用加载图片的方法 转为像素二维数组
imgUtils.loadImage(path);
}
} else if (ac.equals("保存")) {
JFileChooser jfc = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter
("JPG & PNG", "jpg", "png");
jfc.setFileFilter(filter);
int state = jfc.showSaveDialog(null);
if (state == JFileChooser.APPROVE_OPTION) {
File file = jfc.getSelectedFile();
BufferedImage lastImage = imgUtils.getLastImage();
try {
ImageIO.write(lastImage, "PNG", file);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
System.out.println("保存完成");
}
} else if (ac.equals("原图")) {
imgUtils.drawImage();
} else if (ac.equals("灰度")) {
imgUtils.drawGray();
} else if (ac.equals("马赛克")) {
} else {
drawType = ac;
}
// 刷新面板
imagePanel.repaint();
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
oldX = 0;
oldY = 0;
} @Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
int oldX, oldY;
@Override
public void mouseDragged(MouseEvent e) {
// 获取拖动时的坐标
int x = e.getX();
int y = e.getY();
// 要在图片绘制 ,将面板的坐标与图片的坐标进行转换
int pw = imagePanel.getWidth();
int ph = imagePanel.getHeight();
BufferedImage lastImage = imgUtils.getLastImage();
int iw = lastImage.getWidth();
int ih = lastImage.getHeight();
int dx = (pw - iw) / 2;
int dy = (ph - ih) / 2;
Graphics imgGra = lastImage.getGraphics();
imgGra.setColor(Color.RED);
x = x - dx;
y = y - dy;
if (oldX <= 0 || oldY <= 0) {
oldX = x;
oldY = y;
}
if (x > iw || y > ih) {
return;
}
if (drawType.equals("画笔")) {
imgGra.drawLine(x, y, oldX, oldY);
} else if (drawType.equals("马赛克画笔")) {
// 画笔马赛克 从图片上取出对应位置的像素 将像素放大 绘制出来
int rgb = imgUtils.getLastImage().getRGB(x, y);
Color color = new Color(rgb);
imgGra.setColor(color);
imgGra.fillRect(x, y, 20, 20);
} else if (drawType.equals("灰度画笔")) {
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 20; j++) {
int rgb = imgUtils.getLastImage().getRGB(x + i, y + j); Color color = new Color(rgb);
int gray = (color.getRed() + color.getGreen() + color.getBlue()) /
3;
Color gColor = new Color(gray, gray, gray);
imgGra.setColor(gColor);
imgGra.fillRect(x + i, y + j, 1, 1);
}
}
}
oldX = x;
oldY = y;
imagePanel.repaint();
System.out.println("拖动绘制直线 ");
}
@Override
public void mouseMoved(MouseEvent e) {
}
}
ImageListener
类:用于处理图像界面的交互事件,包括按钮点击和鼠标操作。- 成员变量:
imagePanel
:ImagePanel
类型的对象,用于显示和绘制图像,并且在事件处理后可以调用其repaint
方法刷新面板。imgUtils
:ImageUtils
类型的对象,负责执行加载图片、滤镜处理等操作。drawType
:String
类型,用于记录当前的绘制类型,默认值为"画笔"
。oldX
和oldY
:int
类型,用于记录鼠标拖动时的上一个位置。
- actionPerformed(ActionEvent e)
- 功能:处理按钮点击事件,根据按钮的命令执行相应的操作。
- 具体操作:
- 打开图片:当点击 “打开” 按钮时,弹出文件选择器,用户可以选择 JPG 或 PNG 格式的图片,选择后调用
imgUtils.loadImage(path)
方法加载图片。 - 保存图片:当点击 “保存” 按钮时,弹出文件保存对话框,用户可以选择保存的文件路径和文件名,选择后将
imgUtils
中最后一张图片保存为 PNG 格式的文件。 - 显示原图:当点击 “原图” 按钮时,调用
imgUtils.drawImage()
方法显示原始图片。 - 灰度处理:当点击 “灰度” 按钮时,调用
imgUtils.drawGray()
方法对图片进行灰度处理。 - 其他操作:对于其他按钮,将按钮的命令赋值给
drawType
,用于后续的鼠标绘制操作。 - 刷新面板:无论执行哪种操作,最后都会调用
imagePanel.repaint()
方法刷新图像显示面板。
- 打开图片:当点击 “打开” 按钮时,弹出文件选择器,用户可以选择 JPG 或 PNG 格式的图片,选择后调用
-
mouseDragged(MouseEvent e)
- 功能:处理鼠标拖动事件,根据
drawType
的值进行不同的绘制操作。 - 具体操作:
- 坐标转换:将鼠标在面板上的坐标转换为图片上的坐标。
- 画笔绘制:当
drawType
为"画笔"
时,在图片上绘制一条从上次位置到当前位置的红色直线。 - 马赛克画笔绘制:当
drawType
为"马赛克画笔"
时,从图片上取出当前位置的像素颜色,将该颜色填充到一个 20x20 的矩形区域。 - 灰度画笔绘制:当
drawType
为"灰度画笔"
时,从图片上取出当前位置周围 20x20 区域的像素颜色,将每个像素转换为灰度颜色后填充到对应的位置。 - 更新位置:将当前位置更新为
oldX
和oldY
,并调用imagePanel.repaint()
方法刷新面板。
3.在面板上显示并且绘制图片
package Camera;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
public class ImagePanel extends JPanel {
ImageUtils imgUtils;
public void addImageUtils(ImageUtils imgUtils) {
this.imgUtils = imgUtils;
}
@Override
public void paint(Graphics g) {
super.paint(g);
paintImage(g);
System.out.println("绘制最后一张照片");
}
public void paintImage(Graphics g) {
BufferedImage lastImage = imgUtils.getLastImage();
if (lastImage == null) {
return;
}
int w = lastImage.getWidth();
int h = lastImage.getHeight();
int x = this.getWidth() / 2 - w / 2;
int y = (this.getHeight() - h) / 2;
g.drawImage(lastImage, x, y, null);
}
}
4.用于处理图像的各种操作,如加载图像、获取图像缩略图、将图像转换为灰度图、绘制图像等
package Camera;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
public class ImageUtils {
private int[][] imgArr;
private int w;
private int h;
private ArrayList<BufferedImage> imgList = new ArrayList<>();
public BufferedImage getBtnImage(File file) {
try {
BufferedImage image = ImageIO.read(file);
BufferedImage minImg = new BufferedImage(190, 100, 2);
Graphics minG = minImg.getGraphics();
minG.drawImage(image, 0, 0, 190, 100, null);
return minImg;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void addImage(BufferedImage image) {
imgList.add(image);
}
public BufferedImage getLastImage() {
if (imgList.isEmpty()) {
return null;
}
return imgList.get(imgList.size() - 1);
}
public BufferedImage getFirstImage() {
if (imgList.isEmpty()) {
return null;
}
return imgList.get(0);
}
// 加载图片
public void loadImage(String path) {
File file = new File(path);
try {
BufferedImage image = ImageIO.read(file);
addImage(image);
w = image.getWidth();
h = image.getHeight();
//存储图片的像素值
imgArr = new int[w][h];
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
imgArr[i][j] = image.getRGB(i, j);
}
}
System.out.println("加载图片完成");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public BufferedImage drawImage() {
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics imgGra = image.getGraphics();
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
int pixNum = imgArr[i][j];
Color color = new Color(pixNum);
imgGra.setColor(color);
imgGra.fillRect(i, j, 1, 1);
}
}
addImage(image);
return image;
}
public BufferedImage drawGray() {
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics imgGra = image.getGraphics();
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
int pixNum = imgArr[i][j];
Color color = new Color(pixNum);
int red = color.getRed();
int green = color.getGreen(); int blue = color.getBlue();
int gray = (red + green + blue) / 3;
Color grayColor = new Color(gray, gray, gray);
imgGra.setColor(grayColor);
imgGra.fillRect(i, j, 1, 1);
}
}
addImage(image);
return image;
}
}
loadImage(String path)
- 功能:根据给定的文件路径加载图像,将图像的像素值存储到
imgArr
中,并将图像对象添加到imgList
中。 - 具体操作:
1. 创建一个File
对象file
,表示指定路径的文件。
2. 使用ImageIO.read(file)
方法读取文件的图像。
3. 将读取的图像添加到imgList
中。
4. 获取图像的宽度w
和高度h
。
5. 创建一个二维数组imgArr
,用于存储图像的像素值。
6. 遍历图像的每个像素,将其 RGB 值存储到imgArr
中。
7. 打印提示信息 “加载图片完成”。
drawImage()
- 功能:根据
imgArr
中存储的像素值,创建一个新的BufferedImage
对象,并将像素值绘制到图像上,然后将该图像添加到imgList
中并返回。 - 具体操作:
1. 创建一个新的BufferedImage
对象image
,大小为w
xh。
2. 获取image
的Graphics
对象imgGra
。
3. 遍历imgArr
中的每个像素,根据像素值创建Color
对象,并使用imgGra.setColor
和imgGra.fillRect
方法将像素绘制到图像上。
4. 将绘制好的图像添加到imgList
中。
5. 返回绘制好的图像image
。
drawGray()
- 功能:将
imgArr
中存储的像素值转换为灰度值,创建一个新的BufferedImage
对象,并将灰度像素值绘制到图像上,然后将该图像添加到imgList
中并返回。 - 具体操作:
1. 创建一个新的BufferedImage
对象image
,大小为w
xh
,类型为BufferedImage.TYPE_INT_ARGB
。
2. 获取image
的Graphics
对象imgGra
。
3. 遍历imgArr
中的每个像素,根据像素的 RGB 值计算灰度值,创建Color
对象,并使用imgGra.setColor
和imgGra.fillRect
方法将灰度像素绘制到图像上。
4. 将绘制好的灰度图像添加到imgList
中。
5. 返回绘制好的灰度图像image
。
实现效果如下