我们以美颜相机举例,分析一个程序都需要什么。
1、UI界面:大部分需要交互的程序都需要UI界面来实现交流互动。
2、监听器:人们在UI中的操作需要监听器来捕捉和执行相应的命令。
3、工具类:将执行命令的方法单独封装成工具类,供监听器调用。
1. UI界面
实现UI界面,需要一个窗体,并在其中添加各种各样的功能区域、按钮。
美颜相机中需要显示和绘制图像的区域、各种特效工具按钮的区域。(可以再细分)
并且要给鼠标加上监听器以知道人们操作了什么。
我们用美颜相机项目的代码详细说明。
public class UI{// 监听器对象 整个程序只创建一个// 这种只有一个对象的模式称为 单例模式 是Java设计中最简单的设计模式,值得去了解一下ImageListener imgl = new ImageListener ();public void initUI(){// 创建一个窗体,并且使用 边界布局 ,组件可以被放在 东 西 南 北 中 5个区域中。JFrame jf = new JFrame ("美颜相机");jf.setSize (1000, 750);jf.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);// 添加面板JPanel imgshowPanel = new JPanel ();//图像显示面板JPanel btnPanel = new JPanel ();//工具面板imgshowPanel.setBackground (Color.GRAY);btnPanel.setBackground (new Color (200, 200, 200));// 尺寸Dimension dim = new Dimension (300, 0);btnPanel.setPreferredSize (dim);// 添加按钮,需要添加的功能按钮很多,于是封装addButton方法再调用this.addButton (btnPanel);// 图像显示面板添加到中心区域,工具面板添加到 东 区域jf.add (btnPanel, BorderLayout.EAST);jf.add (imgshowPanel, BorderLayout.CENTER);jf.setVisible (true);//获取Graphics 从 ImageJPanel上Graphics graphics1 = imgshowPanel.getGraphics ();// 赋值转递 传递的都是对象的引用地址imgl.gr=graphics1;}// 单独写方法 添加按钮public void addButton(JPanel btnjp){String[] btnstr = {"原图", "清空", "马赛克","黑白", "灰度", "油画", "波点","旋转","插值放大", "柔化", "锐化"};Dimension dim = new Dimension (120,35);for(int i = 0; i < btnstr.length; i++){JButton btn = new JButton (btnstr[i]);btn.setBackground (Color.WHITE);btn.setPreferredSize (dim);// 按钮添加监听器btn.addActionListener (imgl);// 添加到面板btnjp.add (btn);}}public static void main(String[] args){UI ui = new UI ();UI.initUI ();}
}
2. 监听器
人们在UI中的操作需要监听器来捕捉和执行相应的命令。
我们用美颜相机项目的代码详细说明。
public class ImageListener extends MouseAdapter implements ActionListener {// 监听器类继承MouseAdapter类,重写了所有的监听器中的抽象方法Graphics gr;// gr变量 赋值转递 传递的都是对象的引用地址int g;// 基本数据类型的变量 存储的值// 初始化一个图片操作对象Utils utils = new Utils ();BufferedImage buffimg = null;int[][] imgarr = {};{// 代码块 初始化(创建对象时自动调用) 图片的转化buffimg = Utils.getImage ("C:\\Users\\win\\Desktop\\****.jpeg");imgarr = Utils.getImageArray (buffimg);}// 动作监听器的方法public void actionPerformed(ActionEvent e){String action = e.getActionCommand ();if(action.equals ("原图")){imageUtils.normal (buffimg, gr);} else if(action.equals ("马赛克")){imageUtils.mosaic (imgarr, gr);} else if(action.equals ("灰度")){imageUtils.graylevel (imgarr, gr);} else if(action.equals ("黑白")){imageUtils.black_white (imgarr, gr);} else if(action.equals ("波点")){imageUtils.point (imgarr, gr);}else if(action.equals ("清空")){imageUtils.clean (imgarr, gr);}else if(action.equals ("旋转")){imageUtils.rotate(buffimg, gr);}else if(action.equals ("插值放大")){imageUtils.bigpro(imgarr, gr);}}
}
3. 工具类
public class Utils {public BufferedImage getImage(String path){// 根据指定文件路径 创建文件对象// 文件是存在磁盘上的一些数据体// 文件对象 是内存中的一个对象File file = new File (path);System.out.println (file.getPath ());// 先声明一个缓冲图片 imgBufferedImage img = null;try {// IO操作 读取到的缓冲图片对象赋给 imgimg = ImageIO.read (file);} catch (IOException e) {e.printStackTrace ();}// 方法返回值 img 对象return img;}// 缓存图片转为二维数组public int[][] getImageArray(BufferedImage img){// 根据图片的宽高 初始化一个二维数组int[][] imgarr = new int[img.getWidth ()][img.getHeight ()];// img 对象可以调用的方法// 遍历存入 img 对象中取出的像素值for(int i = 0; i < img.getWidth (); i++){for(int j = 0; j < img.getHeight (); j++){int rgb = img.getRGB (i, j);imgarr[i][j] = rgb;}}// 返回二维数组return imgarr;}// 根据二维数组 绘制滤镜效果 // 原图public void normal(BufferedImage img,Graphics g){g.drawImage (img,0,0,null);}// 黑白二值化效果public void black_white(int[][] imgarr, Graphics g){for(int i = 0; i < imgarr.length; i++){for(int j = 0; j < imgarr[i].length; j++){// 取出像素值int i1 = imgarr[i][j];// 拆分为 三原色值int red = (i1 >> 16) & 0xFF;int green = (i1 >> 8) & 0xFF;int blue = (i1 >> 0) & 0xFF;int gray = (red + green + blue) / 3;// 二值化 抠图if(gray < 100){g.setColor (Color.BLACK);} else{g.setColor (Color.WHITE);}g.fillRect (i, j , 1, 1);}}}// 灰阶效果public void graylevel (int[][] imgarr, Graphics g){for(int i = 0; i < imgarr.length; i++){for(int j = 0; j < imgarr[i].length; j++){// 取出像素值int i1 = imgarr[i][j];// 拆分为 三原色值int red = (i1 >> 16) & 0xFF;int green = (i1 >> 8) & 0xFF;int blue = (i1 >> 0) & 0xFF;// 操作三原色值 实现滤镜// 明暗度 red green blue 等值递减 递加// gray r=g=b 整个图片就会失去彩色 黑 白 灰度int gray = (red + green + blue) / 3;Color color = new Color (gray, gray, gray);g.setColor (color);g.fillRect ( i, j , 1, 1);}}}// mosaic马赛克效果public void mosaic(int[][] imgarr, Graphics g){for(int i = 0; i < imgarr.length; i+=10){for(int j = 0; j < imgarr[i].length; j+=10){// 取出像素值int i1 = imgarr[i][j];Color color = new Color(i1 );g.setColor(color);g.fillRect ( i, j , 10, 10);}}}//波点效果public void point (int[][] imgarr, Graphics g){for(int i = 0; i < imgarr.length; i+=10){for(int j = 0; j < imgarr[i].length; j+=10){// 取出像素值int i1 = imgarr[i][j];Color color = new Color(i1 );g.setColor(color);g.fillOval ( i, j , 10, 10);}}}// 清空画布public void clean (int[][] imgarr, Graphics g){g.setColor(Color.WHITE);g.fillRect ( 0,0 ,1000, 1000);}public void rotate(BufferedImage img,Graphics g){BufferedImage img1 = rotateImage(img,30,Color.WHITE);g.drawImage (img1,0,0,null);}public BufferedImage rotateImage(BufferedImage image, double theta,Color backgroundColor) {int width = image.getWidth();int height = image.getHeight();double angle = theta * Math.PI / 180; // 度转弧度double[] xCoords = getX(width / 2, height / 2, angle);double[] yCoords = getY(width / 2, height / 2, angle);int WIDTH = (int) (xCoords[3] - xCoords[0]);int HEIGHT = (int) (yCoords[3] - yCoords[0]);BufferedImage resultImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);for (int i = 0; i < WIDTH; i++) {for (int j = 0; j < HEIGHT; j++) {int x = i - WIDTH / 2;int y = HEIGHT / 2 - j;double radius = Math.sqrt(x * x + y * y);double angle1;if (y > 0) {angle1 = Math.acos(x / radius);} else {angle1 = 2 * Math.PI - Math.acos(x / radius);}x = (int) (radius * Math.cos(angle1 - angle));y = (int) (radius * Math.sin(angle1 - angle));if (x < (width / 2) & x > -(width / 2) & y < (height / 2) & y > -(height / 2)) {int rgb = image.getRGB(x + width / 2, height / 2 - y);resultImage.setRGB(i, j, rgb);}else {int rgb = ((0 & 0xff) << 24) | ((backgroundColor.getRed() & 0xff) << 16) | ((backgroundColor.getGreen() & 0xff) << 8)| ((backgroundColor.getBlue() & 0xff));resultImage.setRGB(i, j, rgb);}}}return resultImage;}// 获取四个角点旋转后Y方向坐标private double[] getY(int i, int j, double angle) {double results[] = new double[4];double radius = Math.sqrt(i * i + j * j);double angle1 = Math.asin(j / radius);results[0] = radius * Math.sin(angle1 + angle);results[1] = radius * Math.sin(Math.PI - angle1 + angle);results[2] = -results[0];results[3] = -results[1];Arrays.sort(results);return results;}// 获取四个角点旋转后X方向坐标private double[] getX(int i, int j, double angle) {double results[] = new double[4];double radius = Math.sqrt(i * i + j * j);double angle1 = Math.acos(i / radius);results[0] = radius * Math.cos(angle1 + angle);results[1] = radius * Math.cos(Math.PI - angle1 + angle);results[2] = -results[0];results[3] = -results[1];Arrays.sort(results);return results;}public void bigpro(int[][] imgarr ,Graphics g){for(int i = 0; i < imgarr.length-1; i++){for(int j = 0; j < imgarr[i].length-1; j++){// 取出像素值int i1 = imgarr[i][j];int i2 = imgarr[i+1][j];int i3 = imgarr[i][j+1];int i4 = imgarr[i+1][j+1];// 拆分为 三原色值int red1 = (i1 >> 16) & 0xFF;int green1 = (i1 >> 8) & 0xFF;int blue1 = (i1 >> 0) & 0xFF;int red2 = (i2 >> 16) & 0xFF;int green2 = (i2 >> 8) & 0xFF;int blue2 = (i2 >> 0) & 0xFF;int red3 = (i3 >> 16) & 0xFF;int green3 = (i3 >> 8) & 0xFF;int blue3 = (i3 >> 0) & 0xFF;int red4 = (i4 >> 16) & 0xFF;int green4 = (i4 >> 8) & 0xFF;int blue4 = (i4 >> 0) & 0xFF;Color color1 = new Color (red1,green1,blue1);g.setColor(color1);g.fillRect ( i*2, j*2, 1, 1);Color color2 = new Color ((red1+red2)/2,(green1+green2)/2,(blue1+blue2)/2);g.setColor(color2);g.fillRect ( i*2+1, j*2, 1, 1);Color color3 = new Color ((red1+red3)/2,(green1+green3)/2,(blue1+blue3)/2);g.setColor(color3);g.fillRect ( i*2, j*2+1, 1, 1);Color color4 = new Color ((red1+red4)/2,(green1+green4)/2,(blue1+blue4)/2);g.setColor(color4);g.fillRect ( i*2+1, j*2+1, 1, 1);}}}
}
图片工具中还封装了旋转rotate 和 插值放大 的方法,插值放大可以避免普通放大每个像素的模糊和锯齿问题。小伙伴们可以自取哦。
欢迎评论或者私信交流问题和心得~