1.我们先来了解BMP文件的格式:
(很重要的一点就是,存储完特定的BMP文件格式之后,记下来便是位图数据存储,这个时候我们只需要保存图片每一个点的颜色信息,这样就可以完成了保存过程)
1.(格式参考学长的) 2.① BMP文件头(14)字节 3.byte bfType1;//位图文件的类型,必须位’B’’1个字母(’B ‘ 1个字节) 4.byte bfType2;//位图文件的类型,必须位’B’1个个字母(’M ‘ 1个字节) 5. 6.int bfSize;//位图文件的大小,以字节位单位(4个字节) 7.short usignedshort bfReserved1;//位图文件保留字,必须为0(2个字节) 8.short usignedshort bfReserved2;//位图文件保留字,必须为0(2个字节) 9.int bfOffBits;//位图数据的起始位置,以相对于位图(文件头的偏移量表示,以字节为单位)(4个字节) 10.① BMP位图信息头(40)字节 11.BMP位图信息头数据用于说明位图的尺寸等信息 12.int Size;//本结构所占用字节数(4个字节) 13.int image_width;//位图的宽度,以像素为单位(4个字节) 14.int image_heigh;//位图的高度,以像素位单位(4个字节) 15.short Planes;//目标设备的级别,必须位1(2个字节) 16.short biBitCount;//每个像素所需的位数,必须是1(双色),4(16色), 17.8(256色)或24(//真彩色)之一(2个字节) 18.int biCompression;//位图压缩类型,必须是0(不压缩),1(BI_RLE8 压缩类型)或2(BI_RLE4)之一(4个字节) 19.int SizeImage;//位图的大小,以字节位单位(4个字节) 20.int biXPelsPerMeter;//位图水平分辨率,每米像素数(4个字节) 21.int biYPelsPerMeter;//位图垂直分辨率,每米像素数(4个字节) 22.int biClrUsed;//位图实际使用的颜色表中的颜色数(4个字节) 23.int biClrImportant;//位图显示过程中重要的颜色数(4个字节)
2.我先给出保存图片的代码然后再对照上面的格式要求来分析:
String command = e.getActionCommand(); JFileChooser chooser = new JFileChooser(); if (command.equals("保存")) { int t = chooser.showSaveDialog(null); if (t == JFileChooser.APPROVE_OPTION) { String path = chooser.getSelectedFile().getAbsolutePath(); try { FileOutputStream fos = new FileOutputStream(path); DataOutputStream dos = new DataOutputStream(fos); savebmpTop(dos);// 存储文件头 savebmpInfo(dos);// 存储位图信息头 savebmpDate(dos);//// 图像数据阵列 fos.flush(); fos.close(); } catch (Exception ef) { JOptionPane.showMessageDialog(null, "文件保存失败!!"); ef.printStackTrace(); } } }
我们会发现,保存图片调用了三个方法:
savebmpTop(dos);// 存储文件头
savebmpInfo(dos);// 存储位图信息头
savebmpDate(dos);// 图像数据阵列
分别用来按顺序存储文件头,位图信息头,就像开始给出的bmp图片格式要求,,,,接下来就是存我们图像数据阵列了;
savebmpTop(dos);// 存储文件头的方法:
// bmp文件头 public void savebmpTop(OutputStream ops) throws Exception { // 位图文件的类型,必须为BM ops.write('B'); ops.write('M'); int height = DrawListener.array.length; int width = DrawListener.array[0].length; // 位图文件的大小,以字节为单位 int size = 14 + 40 + height * width * 3 + (4 - width * 3 % 4) * 3 * height; writeInt(ops, size); // 保留字节,必须为零 writeShort(ops, (short) 0); writeShort(ops, (short) 0); // 位图偏移量 writeInt(ops, 54); }
savebmpInfo(dos);// 存储位图信息头
// 位图信息头 public void savebmpInfo(OutputStream ops) throws Exception { int height = DrawListener.array.length; int width = DrawListener.array[0].length; // 位图信息头长度 writeInt(ops, 40); // 位图宽 writeInt(ops, width); // 位图高 writeInt(ops, height); // 位图位面数总是为1 writeShort(ops, (short) 1); // 位图24位像素 writeShort(ops, (short) 24); // 位图是否被压缩,0为不压缩 writeInt(ops, 0); // 字节数代表位图大小 writeInt(ops, height * width * 3 + (4 - width * 3 % 4) * 3 * height); // 水平分辨率 每米像素数 writeInt(ops, 0); // 垂直分辨率 每米像素数 writeInt(ops, 0); // 颜色索引,0为所有调色板 writeInt(ops, 0); // 对图象显示有重要影响的颜色索引的数目。如果是0,表示都重要 writeInt(ops, 0); }
savebmpDate(dos);// 图像数据阵列方法(其中还有一些数据进制转换的方法我没有吧代码列出来,文件里面有完整代码,在后面我会写这个进制转换)
// 图像数据阵列 public void savebmpDate(OutputStream ops) throws Exception { int height = DrawListener.array.length; int width = DrawListener.array[0].length; int m = 0; // 进行补0 if (width * 3 % 4 > 0) { m = 4 - width * 3 % 4; } for (int i = height - 1; i >= 0; i--) { for (int j = 0; j < width; j++) { int t = DrawListener.array[i][j]; writeColor(ops, t); } for (int k = 0; k < m; k++) { ops.write(0); } } }
到这里我们的存储过程就完成了
然而我们存储Int类型的数据需要用到这个代码:
// 传入一个int值,转化成4个8位的二进制,刚好四个字节 public void writeInt(OutputStream ops, int t) throws Exception { int a = (t >> 24) & 0xff; int b = (t >> 16) & 0xff; int c = (t >> 8) & 0xff; int d = t & 0xff; ops.write(d); ops.write(c); ops.write(b); ops.write(a); }
上面的t是一个int类型(32位的)的,0xff是16进制它的二进制是
1111 1111 t>>24表示t的二进制右移24位与1111 1111做位运算,得到t的二进制的前8位,同理t>>16 右移16得到t的次8位,这里右移16,剩下16位怎么会是得到t的次8位呢,注意啊0xff的二进制是1111 1111 只有8位,在计算的b的时候它会把0xff前面用0补成16位就是0000 00
00 1111 1111,前面8个0在进行与位运算的时候不管怎么样都是0,所以是得到t的次8位的数据,就这样将一个int值的t按照8位8位的一次取出数据。
为什么要进行位运算呢?
Windows规定一个扫描行所占的字节数必须是4的倍数,不足的以0补充。关键就是要搞清楚Windows里面数据是怎么存的?Windows储存数据是从地位到高位来储存的,我们一般都是从高位到地位进行保存。所以就需要我们进行位运算将数据来转化成Windows储存数据的方式。
然而:
如果不进行位运算取出4个8位的byte类型,int是32位不会进行补0,而8位的byte会进行补0;
整个位图数据存储,就只需要存储每一个点的颜色:
// 总共是24位的色图,分成3个字节来存储(每8位二进制数据为一个字节) public void writeColor(OutputStream ops, int t) throws Exception { int b = (t >> 16) & 0xff; int c = (t >> 8) & 0xff; int d = t & 0xff; ops.write(d); ops.write(c); ops.write(b); }
保存文件最重要的步骤都在上面了;
-------------------------------------------------------------------------
3.怎么读取BMP格式的文件呢?
这个最简单了,就是你怎么存的数据,就按那个顺序来读取,当然还有一些位运算需要进行,就是存储的时候我们把int转化成byte类型,现在我们要转换回来:
// 由于读取的是字节,把读取到的4个byte转化成1个int public int changeInt(InputStream ips) throws IOException { int t1 = ips.read() & 0xff; int t2 = ips.read() & 0xff; int t3 = ips.read() & 0xff; int t4 = ips.read() & 0xff; int num = (t4 << 24) + (t3 << 16) + (t2 << 8) + t1; System.out.println(num); return num; } // 24位的图片是1个像素3个字节。 public int readColor(InputStream ips) throws IOException { int b = ips.read() & 0xff; int g = ips.read() & 0xff; int r = ips.read() & 0xff; int c = (r << 16) + (g << 8) + b; return c; }
4.使用的时候要注意(如图):保存图片后缀名为 .bmp 这样其他的照片查看器都可以打开,你自己也可以在菜单栏里面打开(还有一些其他的功能没有实现)!
其他全部完整可以运行的代码在上传的文件里面;
相关推荐
实例123 JPG转换成BMP格式 182 实例124 位图转化为WMF格式 183 实例125 ICO文件转化为位图 184 实例126 图片批量转换工具 185 4.3 图像预览 187 实例127 局部图像放大 187 实例128 浏览大图片 188 实例129 ...
实例123 JPG转换成BMP格式 182 实例124 位图转化为WMF格式 183 实例125 ICO文件转化为位图 184 实例126 图片批量转换工具 185 4.3 图像预览 187 实例127 局部图像放大 187 实例128 浏览大图片 188 实例129 ...
实例123 JPG转换成BMP格式 182 实例124 位图转化为WMF格式 183 实例125 ICO文件转化为位图 184 实例126 图片批量转换工具 185 4.3 图像预览 187 实例127 局部图像放大 187 实例128 浏览大图片 188 实例129 ...
实例123 JPG转换成BMP格式 182 实例124 位图转化为WMF格式 183 实例125 ICO文件转化为位图 184 实例126 图片批量转换工具 185 4.3 图像预览 187 实例127 局部图像放大 187 实例128 浏览大图片 188 实例129 ...