容易画板的保存与读取

简单画板的保存与读取

(文件数据的写入顺序要与读取顺序一致)


一.用自定义的队列保存图像与读取图像


由于在画图板上每画一种图形,就相当于在自定义的队列中装入此图形,那么在保存画图板图形时,就只需从自定义队列中获取每个图形的基本属性,如颜、点的坐标,图形的种类,然后将这些基本信息写入文件,存储到硬盘。不过先要写入图形的个数,方便打开时获得队列的长度。

打开保存的图形时,只需要定义一个自定义队列,在从保存的文件中读取图形的中种类,根据种类不同,分别读取图形的属性,颜色、坐标,创建具有这些属性的图形队形,装入到队列中去。然后再根据队列中的装入的图形,通过draw方法画出来。

 

 

 

保存:

①文件头信息:int(表示队列中图形的个数)

②:文件数据信息:1)直线:int(表type)+int(表color值)+int+int+int+int

   2)矩形:int(表type)+int(表color值)+int+int+int+int

   3)椭圆:int(表type)+int(表color值)+int+int+int+int

   4)多边形;int(表type)+int(表color值)+int[]

/**
	 * 文件的保存
	 * 
	 * @param shapes
	 *            :要保存的图形队列
	 * @param path
	 *            :保存的路径
	 * @return:是否保存成功
	 */
	public boolean savefile(QueueImp<Shape> shapes, String path) {
		boolean isb = false;

		try {
			// 根据路径创建一个文件输出流对象
			java.io.FileOutputStream fos = new java.io.FileOutputStream(path);
			// 将文件流包装为基本类型数据流
			java.io.DataOutputStream dos = new java.io.DataOutputStream(fos);
			// 先写入队列中图形的个数
			dos.writeInt(shapes.size());

			// 读取队列
			for (int i = 0; i < shapes.size(); i++) {
				// 取出一个形状
				Shape sh = shapes.get(i);

				// 得到形状的类型
				byte type = sh.type;
				// 写入形状类型
				dos.writeByte(type);

				if (type == 0) { // 如果是直线
					// 将形状强制转化为直线
					Line line = (Line) sh;
					// 得到直线的属性
					int x1 = line.x1;
					int y1 = line.y1;
					int x2 = line.x2;
					int y2 = line.y2;
					int rgb = line.color.getRGB();

					// 写入属性
					dos.writeInt(rgb);
					dos.writeInt(x1);
					dos.writeInt(y1);
					dos.writeInt(x2);
					dos.writeInt(y2);
				} else if (type == 1) { // 如果是矩形
					// 将形状强制转化为矩形
					Rect rect = (Rect) sh;
					// 得到矩形的属性
					int x1 = rect.x1;
					int y1 = rect.y1;
					int x2 = rect.x2;
					int y2 = rect.y2;
					int rgb = rect.color.getRGB();

					// 写入属性
					dos.writeInt(rgb);
					dos.writeInt(x1);
					dos.writeInt(y1);
					dos.writeInt(x2);
					dos.writeInt(y2);
				} else if (type == 2) { // 如果是椭圆
					// 将形状强制转化为椭圆
					Oval oval = (Oval) sh;
					// 得到椭圆的属性
					int x1 = oval.x1;
					int y1 = oval.y1;
					int x2 = oval.x2;
					int y2 = oval.y2;
					int rgb = oval.color.getRGB();

					// 写入属性
					dos.writeInt(rgb);
					dos.writeInt(x1);
					dos.writeInt(y1);
					dos.writeInt(x2);
					dos.writeInt(y2);
				} else if (type == 3) { // 如果是多边形
					// 将形状强制转化为多边形
					Polygon polygon = (Polygon) sh;

					// 得到颜色
					int rgb = polygon.color.getRGB();
					// 写入颜色
					dos.writeInt(rgb);
					// 创建一个队列,用来得到多边形的属性
					QueueImp<Integer> gp = polygon.point;
					// 写入队列的长度
					dos.writeInt(gp.size());

					// 遍历队列,写入属性
					for (int j = 0; j < gp.size(); j++) {
						int p = gp.get(j);
						dos.writeInt(p);
					}
				}

				isb = true;
			}

			// 强制刷新
			dos.flush();
			// 关闭流
			fos.close();

		} catch (Exception ef) {
			ef.printStackTrace();
		}

		return isb;
	}

 

 

读取:按照写入文件的顺序,将数据包装成形状一个个读取出来,保存到队列中去

/**
	 * 读取文件
	 * 
	 * @param path
	 *            :所读取的文件的路径
	 * @return:图形数组
	 */
	public QueueImp<Shape> openfile(String path) {
		// 创建一个用来保存图形的队列
		QueueImp<Shape> shapes = new QueueImp<Shape>();

		try {
			// 根据路径创建输入流对象
			java.io.FileInputStream fis = new java.io.FileInputStream(path);
			// 将输入流包装成基本类型的数据流
			java.io.DataInputStream dis = new java.io.DataInputStream(fis);

			// 读取一个int,表示图形队列中图形的个数
			int len = dis.readInt();

			// 循环读取每一个图形信息
			for (int i = 0; i < len; i++) {
				// 读取图形类型
				byte type = dis.readByte();

				if (type == 0) { // 如果是直线
					// 读取直线的属性
					int rgb = dis.readInt();
					int x1 = dis.readInt();
					int y1 = dis.readInt();
					int x2 = dis.readInt();
					int y2 = dis.readInt();

					Color color = new Color(rgb);
					// 创建一个直线对象
					Line line = new Line(x1, y1, x2, y2, color);
					// 将直线装入队列
					shapes.add(line);
				} else if (type == 1) { // 如果是矩形
					// 读取矩形的属性
					int rgb = dis.readInt();
					int x1 = dis.readInt();
					int y1 = dis.readInt();
					int x2 = dis.readInt();
					int y2 = dis.readInt();

					Color color = new Color(rgb);
					// 创建一个矩形对象
					Rect rect = new Rect(x1, y1, x2, y2, color);
					// 将矩形装入队列
					shapes.add(rect);
				} else if (type == 2) { // 如果是椭圆
					// 读取椭圆的属性
					int rgb = dis.readInt();
					int x1 = dis.readInt();
					int y1 = dis.readInt();
					int x2 = dis.readInt();
					int y2 = dis.readInt();

					Color color = new Color(rgb);
					// 创建一个椭圆对象
					Oval oval = new Oval(x1, y1, x2, y2, color);
					// 将椭圆装入队列
					shapes.add(oval);
				} else if (type == 3) {

					// 读取多边形的颜色
					int rgb = dis.readInt();
					// 读取队列的长度
					int size = dis.readInt();

					// 创建队列,得到数组的内容
					QueueImp<Integer> qi = new QueueImp<Integer>();
					// 遍历数组,写入多边形的属性
					for (int j = 0; j < size; j++) {
						int s = dis.readInt();
						qi.add(s);
					}

					Color color = new Color(rgb);
					// 创建一个多边形对象
					Polygon polygon = new Polygon(qi, color);
					// 将多边形装入队列
					shapes.add(polygon);
				}
			}
			
		} catch (Exception ef) {
			ef.printStackTrace();
		}

		return shapes;
	}

 // 读取图像

 

			QueueImp<Shape> getshapes = fu.openfile("D:\\jm.hu");
			// 将getshapes中的图形装入到shapes中
			for (int i = 0; i < getshapes.size(); i++) {
				shapes.add(getshapes.get(i));
			}

			// 将队列中的形状取出来绘制
			for (int i = 0; i < shapes.size(); i++) {
				// 根据下标取出一个形状对象
				Shape sh = shapes.get(i);
				// 绘制
				sh.draw(g);
			}

 

由于每种格式的文件都有固定的格式,而文件的后缀只是方便系统快速的找到打开此类文件的程序,故文件的类型不是由文件的后缀名决定的,而是文件固定的写入格式。我们用队列保存的这个文件格式,故也只能由我们自己的画图板才能打开。



二.仿BMP格式保存读取(以相位点的形式保存读取)

画板的画布,是由一个个相位点组成的,如果在画布上画了图形,那么一定会有一些相位点的颜色发生了改变,那么只要保存每一个相位点的颜色值就可以了。定义一个二维数组来实现,读取时,在根据二维数组的信息,把每个相位点画出来。


抓取一张图片,而图片的大小由画布的大小决定,比如我们在JPanel上加的画布,则图片的大小就是JPanel的大小,再将图片每一个相位点的颜色值保存到数组中去。

/**
 * 山寨BMP保存
 * 
 * @author 
 * 
 */
public class Save4Bit {

	static int width;
	static int height;
	static int[][] colors;// 用来保存每一个像素点颜色的数组
	static java.awt.Robot robot;

	public static void savePic(JPanel panel) {

		try {
			robot = new java.awt.Robot();
		} catch (Exception ef) {
			ef.printStackTrace();
		}
		width = panel.getWidth();
		height = panel.getHeight();
		colors = new int[height][width];

		// 得到panel左上角的点相对于屏幕的坐标
		Point p = panel.getLocationOnScreen();

		java.awt.Rectangle rect = new java.awt.Rectangle(p.x, p.y,
				panel.getWidth(), panel.getHeight());
		// 从屏幕上抓取一张图片
		java.awt.image.BufferedImage img = robot.createScreenCapture(rect);

		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				colors[i][j] = img.getRGB(j, i);  //数组行列分别与画板的y坐标和x坐标对应
			}
		}

	}

 

 

文件头:画面的大小 int(高)+int(宽)

      文件数据:画面的每个点的颜色值  int

 /* 图像的保存
 * @author 
 *
 */
public class FileUtil {

	/**
	 * 保存成文件
	 * 
	 * @param path
	 *            :保存路径
	 */
	public void saveFile(String path, int[][] color, JPanel jp) {
		
		try {
			// 创建一个文件输出流
			java.io.FileOutputStream fos = new FileOutputStream(path);
			// 将文件输出输出到缓冲流
			java.io.BufferedOutputStream bos = new BufferedOutputStream(fos);
			// 将缓冲流包装成Data的数据流
			java.io.DataOutputStream dos = new java.io.DataOutputStream(bos);

			// 首先保存画面的大小
			dos.writeInt(jp.getHeight());
			dos.writeInt(jp.getWidth());
			// 遍历列队
			for (int i = 0; i < jp.getHeight(); i++) {
				for (int j = 0; j < jp.getWidth(); j++) {

					dos.writeInt(color[i][j]);

				}
			}
			dos.flush();	//强制刷新
			fos.close();
		} catch (Exception ef) {
			ef.printStackTrace();
		}
		
	}

 

 

/**
	 * 打开文件
	 * 
	 * @param path
	 * @return
	 */
	public int[][] openFile(String path) {
		
		//创建一个二维数组,用来装入位点
		int[][] color = null;
		
		try {
			// 创建文件输入流
			java.io.FileInputStream fit = new FileInputStream(path);
			// 将文件输入流输入缓冲流
			java.io.BufferedInputStream bis = new BufferedInputStream(fit);
			// 把缓冲流打包成Data输入流
			java.io.DataInputStream dos = new DataInputStream(bis);
			// 先读取大小
			int width = dos.readInt();
			int height = dos.readInt();
			//创建一个二维数组,用来保存相位点的值
			color=new int[height][width];
			// 把文件中的数据加入队列中
			for (int i = 0; i < height; i++) {
				for (int j = 0; j < width; j++) {
					color[i][j] = dos.readInt();
				}
			}

		} catch (Exception ef) {
			ef.printStackTrace();
		}
		
		return color;
	}

 

重绘,从二维数组中读取颜色值,再画点

public void paint(Graphics g) {
			// 调用父类的方法来绘制窗体
			super.paint(g);
			
			if (Save4Bit.colors != null) {
				for (int i = 0; i < Save4Bit.colors.length; i++) {
					for (int j = 0; j < Save4Bit.colors[i].length; j++) {
						int rgb = Save4Bit.colors[i][j];
						if (panel.getBackground().getRGB() != rgb) {
							Color color = new Color(rgb);
							g.setColor(color);
							g.drawLine(i, j, i, j);
						}
					}
				}

			}
			
		}
 

 

 

通过两种方法的保存与读取,不难看出第一种方法写入文件和读取出来的过程都比较繁琐,而好处则是保存的文件在所画的图形个数不多的情况下,占用空间较少;第二种方法是每个每个相位点的保存,不难看出,无论什么情况下,文件的大小都是跟画板的大小相关的,好处是保存与读取的过程简单,但在画了很多图形情况下,画布的重载速度会很慢。

 


容易画板的保存与读取