问题描述
初学,我先简单说下我的思路吧!首先获得图片信息,然后根据位图信息头中相应的字节得到源图的宽和高,然后将宽和高转换成整型(int)。随后是获得图片的颜色信息。后来的是第二个类,这个类的作用是将得到的图片写入另一个bmp文件。我先把颜色的信息放到一个叫pointArray的数组,就是这个地方我不知道有没有问题,然后用java.awt.color中的getRed(),getBlue()...等方法获得像素中的颜色分量,最后可能是颜色存储的地方有问题,思绪混乱了,希望能得到帮助如下是源代码://ReadBmp24.javaimportjava.io.FileInputStream;importjava.io.IOException;publicclassReadBmp24{/***位图宽*/publicstaticintwidth;/***位图高*/publicstaticintheight;/***像素三分量数据*/publicstaticint[][]red1,green1,blue1;publicvoidinit(){try{FileInputStreamfis=newFileInputStream("D:\MyEclipse-8.6\test.bmp");java.io.BufferedInputStreambis=newjava.io.BufferedInputStream(fis);intbflen=14;//BitmapFileHeadbytebf[]=newbyte[bflen];fis.read(bf,0,bflen);intbilen=40;//BitmapInfoHeadbytebi[]=newbyte[bilen];fis.read(bi,0,bilen);//获取图片数据intnwidth=(((int)bi[7]&0xff)<<24)//源图宽度|(((int)bi[6]&0xff)<<16)|(((int)bi[5]&0xff)<<8)|(int)bi[4]&0xff;System.out.println("宽:"+nwidth);intnheight=(((int)bi[11]&0xff)<<24)//源图高度|(((int)bi[10]&0xff)<<16)|(((int)bi[9]&0xff)<<8)|(int)bi[8]&0xff;System.out.println("高:"+nheight);width=ChangeInt(bi,7);height=ChangeInt(bi,11);getInfo(bis);}catch(Exceptione){System.out.println(e);}}/***实现可将四个字节翻译int数据的方法**@parambi*存储字节的字节数组*@paramstart*起始字节*@return返回翻译后的int数据*/publicintChangeInt(byte[]array2,intstart){//因为char,byte,short这些数据类型经过运算符后会自动转为成int数据类,//所以array2[start]&0xff的实际意思就是通过&0xff将字符数据转化为正int数据,然后在进行位运算。inti=(int)((array2[start]&0xff)<<24)|((array2[start-1]&0xff)<<16)|((array2[start-2]&0xff)<<8)|(array2[start-3]&0xff);returni;}publicvoidgetInfo(java.io.BufferedInputStreambis){red1=newint[height][width];green1=newint[height][width];blue1=newint[height][width];intskip_width=0;intm=width*3%4;if(m!=0){skip_width=4-m;}for(inti=height-1;i>=0;i--){for(intj=0;j<width;j++){try{blue1[i][j]=bis.read();green1[i][j]=bis.read();red1[i][j]=bis.read();if(j==0){bis.skip(skip_width);}}catch(IOExceptione){e.printStackTrace();}}}}}//WriteBmp24importjava.awt.Color;publicclassWriteBmp24extendsReadBmp24{/***图形数据数组*/privatestaticColor[][]pointArray;/***图形的宽*/staticintwidth;/***图形的高*/staticintheight;/***将数据传入内存*/publicWriteBmp24(Color[][]pointArray){this.pointArray=pointArray;this.width=pointArray.length;this.height=pointArray[0].length;this.write();}publicvoidwrite(){try{//创建输出流文件对象java.io.FileOutputStreamfos=newjava.io.FileOutputStream("D:\MyEclipse-8.6\success.bmp");//创建原始数据输出流对象java.io.DataOutputStreamdos=newjava.io.DataOutputStream(fos);//给文件头的变量赋值intbfType=0x424d;//位图文件类型(0—1字节)intbfSize=54+width*height*3;//bmp文件的大小(2—5字节)intbfReserved1=0;//位图文件保留字,必须为0(6-7字节)intbfReserved2=0;//位图文件保留字,必须为0(8-9字节)intbfOffBits=54;//文件头开始到位图实际数据之间的字节的偏移量(10-13字节)//输入数据的时候要注意输入的数据在内存中要占几个字节,//然后再选择相应的写入方法,而不是它自己本身的数据类型//输入文件头数据dos.writeShort(bfType);//输入位图文件类型'BM'dos.write(changeByte(bfSize),0,4);//输入位图文件大小dos.write(changeByte(bfReserved1),0,2);//输入位图文件保留字dos.write(changeByte(bfReserved2),0,2);//输入位图文件保留字dos.write(changeByte(bfOffBits),0,4);//输入位图文件偏移量//给信息头的变量赋值intbiSize=40;//信息头所需的字节数(14-17字节)intbiWidth=width;//位图的宽(18-21字节)intbiHeight=height;//位图的高(22-25字节)intbiPlanes=1;//目标设备的级别,必须是1(26-27字节)intbiBitcount=24;//每个像素所需的位数(28-29字节),必须是1位(双色)、4位(16色)、8位(256色)或者24位(真彩色)之一。intbiCompression=0;//位图压缩类型,必须是0(不压缩)(30-33字节)、1(BI_RLEB压缩类型)或2(BI_RLE4压缩类型)之一。intbiSizeImage=width*height;//实际位图图像的大小,即整个实际绘制的图像大小(34-37字节)intbiXPelsPerMeter=0;//位图水平分辨率,每米像素数(38-41字节)这个数是系统默认值intbiYPelsPerMeter=0;//位图垂直分辨率,每米像素数(42-45字节)这个数是系统默认值intbiClrUsed=0;//位图实际使用的颜色表中的颜色数(46-49字节),如果为0的话,说明全部使用了intbiClrImportant=0;//位图显示过程中重要的颜色数(50-53字节),如果为0的话,说明全部重要//因为java是大端存储,那么也就是说同样会大端输出。//但计算机是按小端读取,如果我们不改变多字节数据的顺序的话,那么机器就不能正常读取。//所以首先调用方法将int数据转变为多个byte数据,并且按小端存储的顺序。//输入信息头数据dos.write(changeByte(biSize),0,4);//输入信息头数据的总字节数dos.write(changeByte(biWidth),0,4);//输入位图的宽dos.write(changeByte(biHeight),0,4);//输入位图的高dos.write(changeByte(biPlanes),0,2);//输入位图的目标设备级别dos.write(changeByte(biBitcount),0,2);//输入每个像素占据的字节数dos.write(changeByte(biCompression),0,4);//输入位图的压缩类型dos.write(changeByte(biSizeImage),0,4);//输入位图的实际大小dos.write(changeByte(biXPelsPerMeter),0,4);//输入位图的水平分辨率dos.write(changeByte(biYPelsPerMeter),0,4);//输入位图的垂直分辨率dos.write(changeByte(biClrUsed),0,4);//输入位图使用的总颜色数dos.write(changeByte(biClrImportant),0,4);//输入位图使用过程中重要的颜色数//因为是24位图,所以没有颜色表//通过遍历输入位图数据//这里遍历的时候注意,在计算机内存中位图数据是从左到右,从下到上来保存的,//也就是说实际图像的第一行的点在内存是最后一行for(inti=height-1;i>=0;i--){for(intj=0;j<width;j++){//这里还需要注意的是,每个像素是有三个RGB颜色分量组成的,//而数据在windows操作系统下是小端存储,对多字节数据有用。intred=pointArray[i][j].getRed();//得到位图点的红色分量intgreen=pointArray[i][j].getGreen();//得到位图点的绿色分量intblue=pointArray[i][j].getBlue();//得到位图点的蓝色分量byte[]red2=changeByte(red);byte[]green2=changeByte(green);byte[]blue2=changeByte(blue);dos.write(blue2,0,1);dos.write(green2,0,1);dos.write(red2,0,1);}}//关闭数据的传输dos.flush();dos.close();fos.close();System.out.println("success!!!"+height+width);}catch(Exceptione){e.printStackTrace();}}/***将一个int数据转为按小端顺序排列的字节数组*@paramdataint数据*@return按小端顺序排列的字节数组*/publicbyte[]changeByte(intdata){byteb4=(byte)((data)>>24);byteb3=(byte)(((data)<<8)>>24);byteb2=(byte)(((data)<<16)>>24);byteb1=(byte)(((data)<<24)>>24);byte[]bytes={b1,b2,b3,b4};returnbytes;}publicstaticvoidmain(String[]args){ReadBmp24rb=newReadBmp24();rb.init();Color[][]pointArray=newColor[height][width];{for(inti=height-1;i>=0;i--){for(intj=0;j<width;j++){pointArray[i][j]=newColor(ReadBmp24.red1[i][j],ReadBmp24.green1[i][j],ReadBmp24.blue1[i][j]);}}}WriteBmp24wb=newWriteBmp24(pointArray);wb.write();}}
解决方案
解决方案二:
真头痛,搞不清楚是颜色存储的问题还是什么其他的东西