我们以美颜相机举例,分析一个程序都需要什么。
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 ());
// 先声明一个缓冲图片 img
BufferedImage img = null;
try {
// IO操作 读取到的缓冲图片对象赋给 img
img = 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 和 插值放大 的方法,插值放大可以避免普通放大每个像素的模糊和锯齿问题。小伙伴们可以自取哦。
欢迎评论或者私信交流问题和心得~



