图片的打开与总结

                                    图片的打开与保存(基于画图板)

 

   上次的博客中可以看出,我们已经基本实现了画图板的基本功能。那么最后的一步,就是打开和保存。

   在此之前,我们首先要加一个菜单条(我们的画图板是模仿win自带的)。菜单条的代码如下:

                JMenuBar menubar = new JMenuBar();
                // 创建一个菜单的数组
		String[] menu1 = { "文件", "编辑", "关于" };
		String[][] menu2 = { { "新建", "打开", "保存" }, { "撤销", "还原" }, { "关于" } };
		String[][] commands = { { "xinjian", "dakai", "baocun" },
				{ "chexiao", "huanyuan" }, { "guanyu" } };
		// 创建一个菜单监听器
		Filelistener listener1 = new Filelistener(centre);
		// 遍历
		for (int i = 0; i < menu1.length; i++) {
			// 创建菜单对象
			JMenu menu = new JMenu(menu1[i]);
			menubar.add(menu);
			for (int j = 0; j < menu2[i].length; j++) {
				// 创建菜单选项
				JMenuItem item = new JMenuItem(menu2[i][j]);
				// 加在菜单上
				menu.add(item);
				// 设置选项的动作命令
				item.setActionCommand(commands[i][j]);
				// 给每个选项加监听器,注意,这是是item
				item.addActionListener(listener1);

			}
		}

		this.setJMenuBar(menubar);

 在此要注意两点:

1:加监听器时候,是给item加,也即每一个选项加。

2:菜单以数组的形式创建,例如,文件下面包括了新建,保存,和打开。

3:设置动作命令时候,要把数组commands[i][j]传进来。

 

下面就是菜单的监听器,代码如下:

import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.filechooser.FileNameExtensionFilter;

public class Filelistener implements ActionListener {
    //要把画板centre传过来
	private JPanel centre;
	//声明机器人对象
	java.awt.Robot robot;
	//创建一个重绘的二维数组
	int[][] keep;

	public Filelistener(JPanel centre) {
		this.centre=centre;
		//robot
		try {
			robot=new java.awt.Robot();
		} catch (AWTException e) {
			
			e.printStackTrace();
		}
		
	}

	public void actionPerformed(ActionEvent e) {
		String commen = e.getActionCommand();
		if ("xinjian".equals(commen)) {
			System.out.print("xinjian");
		}
		/**
		 * 这里是保存
		 */
		if ("baocun".equals(commen)) {
			// 弹出文件选择框
			javax.swing.JFileChooser c = new javax.swing.JFileChooser();
			// 过滤
			javax.swing.filechooser.FileNameExtensionFilter f = new javax.swing.filechooser.FileNameExtensionFilter(
					"BMP images", "BMP");
			c.setFileFilter(f);
			c.showSaveDialog(null);
			//得到选择文件的路径
			String path1=c.getSelectedFile().getAbsolutePath();
			//保存图像
			baocun b=new baocun(path1);
            b.keep(path1);
			System.out.print("baocun");
			/************************************保存************************************************/

			//得到centre左上角的坐标,相对于屏幕
			Point left=centre.getLocationOnScreen();
			//得到宽度 高度
			Dimension dimension=centre.getPreferredSize();
			//创建截取的区域对象
			Rectangle rectangle=new Rectangle(left,dimension);
			//截图
			java.awt.image.BufferedImage image=robot.createScreenCapture(rectangle);
			//创建二维数组
			keep=new int[image.getHeight()][image.getWidth()];
			//遍历
			for(int i=0;i<keep.length;i++){
				for(int j=0;j<keep[i].length;j++){
					//获取坐标点的颜色
					keep[i][j]=image.getRGB(j, i);
					
				}
			}
			
			
			
		}
		/**
		 * 这里是读取
		 */
		if ("dakai".equals(commen)) {
			// 弹出文件选择框
			JFileChooser chooser = new JFileChooser();
			// 过滤
			FileNameExtensionFilter filter = new FileNameExtensionFilter(
					"BMP Images", "BMP");
			chooser.setFileFilter(filter);
			System.out.print("过滤");
			chooser.showOpenDialog(null);
			// 得到选择文件的路径
			String path = chooser.getSelectedFile().getAbsolutePath();
			// 解析,显示图像
			jiexi jie = new jiexi( path, centre);
			jie.show(path);

		}

	}

}

 

 

下面我们要做的,就是写一个解析(就是打开)的类和保存的类。


下面先来说明解析类。

首先,要做保存和打开,我们要知道bmp图片的格式信息。

此段转自百度:


位图文件可看成由4个部分组成:位图文件头(bitmap-file header)、位图信息头(bitmap-information header)、彩色表(color table)和定义位图的字节阵列,它具有如下所示的形式。

http://baike.baidu.com/view/189487.htm

网址如下,我就不在这里黏贴一次了。


打开有两步:

1:显示出bmp文件。

2:将其转成int。

 

1:显示出,代码如下:

 

import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JPanel;

public class jiexi {
	// 画布
	private JPanel centre;
	// 窗口的画笔
	private java.awt.Graphics g;
	// 文件打开的路径
	private String path = null;
	// 图像大小
	//private int size;
	// 读取的两个保留字
	//private int c1, c2;
	// 数据偏移量
	//private int dataoffset;
	// 图片的宽高
	private int width, heigh;
	// 存放像素点的颜色
	private int R[][], G[][], B[][];
	// 宽取模??
	int skipwidth = 0;

	public jiexi(String path, JPanel centre) {
		this.path = path;
		this.centre = centre;
	}

	// public void paint(java.awt.Graphics g) {pubi
	// for (int i = 0; i < heigh; i++) {
	// for (int j = 0; j < width; j++) {
	// g.setColor(new java.awt.Color(R[i][j], G[i][j], B[i][j]));
	// g.fillOval(j, i, 1, 1);
	// }
	//
	// }

	// }

	/**
	 * 显示出BMP文件
	 */
	public void show(String path) {
		try {
			// 文件输入流
			java.io.FileInputStream input = new java.io.FileInputStream(path);
			// 将文件流包装成可写基本数据类型的输出流
			java.io.DataInputStream input1 = new java.io.DataInputStream(input);

			// 读取14字节bmp文件头
			// int bflen = 14;
			// 定义数组来存放
			// byte bf[] = new byte[bflen];
			// input1.read(bf, 0, bflen);
			// 读取40字节的信息头
			// int bilen = 40;
			// byte bi[] = new byte[bilen];
			// input1.read(bi, 0, bilen);
			// 获取重要数据
			// 原图宽
			// width = ChangeInt(bi, 7);
			// 原图高
			// heigh = ChangeInt(bi, 11);
			
			
			//bmp图片的信息头
			int len = 54;
			byte b[] = new byte[len];
			input1.read(b, 0, len);
			width = ChangeInt(b, 21);
			heigh = ChangeInt(b, 25);

			// 存入重绘的数组
			Drawlistener.keep = new int[heigh][width];
			centre.setPreferredSize(new Dimension(width, heigh));
			// 按照行读取
			if (width * 3 % 4 != 0) {
				input1.skip(width * 3 % 4);
			}
			//
			// (从下往上,从左往右)
			for (int i = heigh - 1; i >= 0; i--) {
				for (int j = 0; j < width; j++) {
					// 读取三原色
					int blue = input1.read();
					int green = input1.read();
					int red = input1.read();
					// 将三原色转换为颜色
					Color color = new Color(red, green, blue);

					// 将相对应的颜色转为整形存入数组中(下标极为重要)
					Drawlistener.keep[i][j] = color.getRGB();
				}
			}
			centre.repaint();// 调用重绘的方法

			// ???
			// int nbitcount = (((int) bi[15] & 0xff) << 8) | (int) bi[14] &
			// 0xff;
			// / System.out.println("位数:" + nbitcount);
			// int nsizeimage = ChangeInt(bi, 23);
			// System.out.println("源图大小:" + nsizeimage);

			// 关闭文件流
			input.close();
			input1.close();

		} catch (Exception e) {

			e.printStackTrace();
		}
	}

	// public void showRGB24(DataInputStream input1) {
	// this.setTitle(path);
	// 弹出一个图片的窗口的大小
	// this.setSize(width, heigh);
	// this.setResizable(false);
	// this.setVisible(true);
	// g = this.getGraphics();
	// 如果图像的宽度不为0
	// //if (!(width * 3 % 4 == 0)) {
	// skipwidth = 4 - width * 3 % 4;
	// }
	// R = new int[heigh][width];
	// G = new int[heigh][width];
	// B = new int[heigh][width];
	// 按行读取,如果i,j为正则倒着来 i=heigh,j=width
	// for (int i = heigh - 1; i >= 0; i--) {
	// for (int j = 0; j < width; j++) {
	// 读入三原色
	// try {
	// int red = input1.read();
	// int green = input1.read();
	// int blue = input1.read();
	// R[i][j] = red;
	// G[i][j] = green;
	// B[i][j] = blue;
	// 这里小心
	// if(j==width-1){
	// System.out.print(input1.skipBytes(skipwidth));
	// }

	// / } catch (IOException e) {
	// e.printStackTrace();
	// / }

	// }repaint();
	// }

	// }
 

 

 

我将第一次做的代码也贴上来,方便对比。(就是屏蔽掉的部分)


1:我第一次写的时候,将bmp的文件头拆开来写,实际上,并没有必要。因为现在是读取,没有必要将文件头和信息头分      开两个数组来存放。我们直接将其存在同一个数组里面就可。

2:关于颜色的储存方式。首先,没必要去弹窗口神马的。第二,我第一次写的时候,将三原色分别储存在一个二维的数组      里面,这样显得十分麻烦(并且有时候也会出bug)。实际上,我们直接用的文件流来读取(在前一篇blog里面有关于      文件流的详细分析和代码示例),所以直接用文件流来读取三原色就可以了。然后,将颜色存入同一个数组就可以。这      就和文件头和信息头一样,既无必要分开,也不容易出错。


最后一步,就是转成int,因为bmp格式的图片是以byte保存的,我们要读取出来,就要专程成int,代码如下:

 

/**
	 * 转成int
	 * 
	 * @param bi
	 * @param i
	 * @return
	 */
	public int ChangeInt(byte[] bi, int i) {
		return (((int) bi[i] & 0xff) << 24) | (((int) bi[i - 1] & 0xff) << 16)
				| (((int) bi[i - 2] & 0xff) << 8) | (int) bi[i - 3] & 0xff;
	}

}
 

至此,我们的打开就完成了。

 

下面,是将图片保存成bmp格式。首先,代码如下:

 

import java.awt.Color;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class baocun {

	private String path1;
	private int width, heigh;

	public baocun(String path1) {
		this.path1 = path1;
	}

	public void keep(String path1) {
		// 输出
		try {
			java.io.FileOutputStream output = new java.io.FileOutputStream(
					path1);
			java.io.BufferedOutputStream op1 = new java.io.BufferedOutputStream(
					output);
			/**
			 * 文件头 14个字节
			 */
			op1.write((byte) 66);// b
			op1.write((byte) 77);// m
			// 图片文件的大小,这里要自己算出来
			int size = (4 - (width * 3) % 4) * heigh + heigh * width * 3 + 54;
			// 2--5字节,转成int
			op1.write(turnByte((int) size));
			// 有4个字节的保留字
			op1.write(0);
			op1.write(0);
			op1.write(0);
			op1.write(0);
			/**
			 * 信息头 54字节
			 */
			// 10--13字节,起始位置
			op1.write(turnByte((int) 54));
			// 存入信息头数据40
			// 14--17,4个字节
			op1.write(turnByte((int) 40));
			op1.write(turnByte(width)); // 18-21 4个字节 图片宽度
			op1.write(turnByte(heigh));// 22-25 4个字节 图片高度

			// 26-27 2个字节 必须1
			op1.write((byte) 1);
			op1.write((byte) 0);
			// 28-29 2个字节 必须24
			op1.write((byte) 24);
			op1.write((byte) 0);
			op1.write(turnByte((int) 0)); // 30-34 4个字节 必须0
			// 未完成
			op1.write(turnByte((int) (size - 54))); // 34-37 4个字节 位图的大小,以字节为单位
			op1.write(turnByte((int) 0)); // 38-41 4个字节 位图水平分辨率,
			op1.write(turnByte((int) 0)); // 42-45 4个字节 位图垂直分辨率,
			op1.write(turnByte((int) 0)); // 46-49 4个字节 位图实际使用的颜色表中的颜色数(全选)
			op1.write(turnByte((int) 0)); // 50-53 4个字节 位图显示过程中重要的颜色数(都重要)

			// 因为是24bmp图像,不需要颜色表
			// 位图数据
			int wid = 0;
			// 判断是否后面有补0 的情况
			if ((width * 3) % 4 != 0) {
				wid = 4 - (width * 3) % 4;
			}
			// (从下往上,从左往右)
			for (int i = heigh - 1; i >= 0; i--) {
				for (int j = 0; j < width; j++) {
					int[][] aa = new int[heigh][width];
					Color c = new Color(aa[i][j]);
					op1.write((byte) c.getBlue());
					op1.write((byte) c.getGreen());
					op1.write((byte) c.getRed());
				}
				for (int j = 0; j < wid; j++) {
					op1.write((byte) 0);
				}
			}

			// 关闭流
			op1.flush();
			op1.close();

		} catch (Exception e) {

			e.printStackTrace();
		}

	}

	// 将其转成byte保存
	private byte[] turnByte(int a) {
		byte[] b = new byte[4];
		for (int i = 0; i < 4; i++) {
			b[i] = (byte) ((a >>> (8 * i)) & 0xFF); // 将int从低8位到高8位加入到byte数组中
		}
		return b;
	}
}

 

我觉得保存的重点,1是要写出他的文件头和信息头,2是要记得转成byte来保存!

 

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值