tag 标签: bmp

相关博文
  • 热度 17
    2016-4-29 17:59
    2496 次阅读|
    0 个评论
    Our Caveman Diorama is going to boast a Time Portal, thereby explaining my presence in the scene.   Cardboard prototype of Time Portal (Source: Max Maxfield Mike Mittlebeeler)   Well, we've finally gotten around to powering up our 2.8" display from Adafruit and, as usual, there are a few "ups and downs" to ponder. With regard to the display itself, this is a TFT LCD touchscreen on a breakout board with a Micro-SD card socket mounted on the back (we're not planning on using the touchscreen capability). We're currently driving this using an Arduino Uno, but we'll be swapping over to an Arduino Nano when we come to deploy this little scamp in the cave.   As always, Adafruit supplies great support in the form of wiring diagrams and instructions, libraries, and example sketches. The display itself can be driven using a variety of techniques, including a fast 8-bit parallel interface and a slower SPI interface.   In our case, we wish to display a series of BMP files that will be stored on a Micro-SD card plugged into the back of the breakout board. The idea is to alternate between a Stargate mirror effect image and hundreds, perhaps thousands, of random images showing things like alien landscapes, post-apocalyptic scenes, and weird, wonderful, and beautiful visions of the past, present, and future (as you can see, we don’t believe in limiting ourselves).   For some reason, Adafruit only supports the display of BMPs using the SPI interface, which is slower than the 8-bit interface approach. Since observers will be looking downwards towards the Time Portal in the diorama, this means that we want the SPI interface and any associated wires to be on the bottom of the display so as to be minimally visually intrusive.   Based on this, the first question we had was "Which way up will the images be displayed?" If the images were to appear upside down, for example, then we would have to pre-invert them on our host computer before copying them over to the Micro-SD card. Thus, we started out by creating a small 40 x 80 pixel image with different color blocks in diagonally opposite corners and displaying it at X-Y location on the display. Happily, this image appeared in the desired location and orientation as illustrated below.   (Source: Max Maxfield Mike Mittlebeeler)   We had originally envisaged the portal as appearing to be levitating above the floor of the cave. If you look at the image above, however, you will observe a black border around the actual image. This is quite narrow at the sides and the top, but it's pretty significant at the bottom of the display.   This dictates the minimum width of the door frame at the bottom. I was just on the phone to my chum, Adam Carlson (a.k.a. AerospaceEngineer). Adam is creating the 3D printed door frame for the portal. If we made the entire frame as wide as it needs to be at the bottom, then it would be overwhelmingly out of proportion to the actual display area. Thus, we are now thinking of mounting the portal on a small pedestal standing on the floor of the cave with integral steps coming down from the display, thereby disguising the size of the bottom lintel. Adam will be throwing some preliminary sketches together over the weekend and we'll take things from there.   The next step was to see how fast the images can be displayed, so we loaded two full-size (240 wide x 320 high) images onto the card. The first was a Stargate mirror image; the second was of the back of a man sitting on a chair viewing a post-apocalyptic vista as illustrated below.   (Source: Max Maxfield Mike Mittlebeeler)   We then tweaked the example sketch from Adafruit so as to alternate back and forth between these two images with a one second pause between each reload. The result is shown in this video .   As an aside, Adafruit's libraries require us to use 24-bit color BMPs, which means each image consumes 3 x 240 x 320 = 259,200 bytes. Since there are 1,048,576 bytes in a megabyte (MB), this means we can store four images per megabyte.   I predate the days of 3.5" floppy disks that could store only 1.44 MB of data, so my knee-jerk reaction was to ruminate on the fact that I would have been able to store only five of our (uncompressed) BMPs on a single floppy. How times have changed.   Looking at this another way, since we can store four images per megabyte, this equates to 4,000 images per gigabyte, which should be more than enough for our needs. So I trotted down to my local Staples store looking for a 1 GB Micro-SD card, only to discover that the smallest card they offer stores 16 GB (I think it cost around $10). This means we can store 64,000 BMPs on our Micro-SD card, which should keep us busy for a while (LOL).   It's not-so-long-ago that 16 GB would have been an almost unimaginable quantity, and the fact the Micro-SD card is about the same size as my fingernail makes things even more surreal, but we digress...   We had originally hoped to be able to have the default Stargate mirror image somehow "rippling" on the screen. We had also hoped to be able to perform some sort of crossover-fade effect from the mirror image to the scene images, and vice versa.   As you can see in the above video, however, it actually takes about four seconds to present each new image onto the display. This occurs as a slow "wipe" starting at the top of the display and working its way to the bottom. The image below shows the "Man on Chair" image (top) in the process of being "wiped" over the "Stargate Mirror" image (bottom).   (Source: Max Maxfield Mike Mittlebeeler)   On the one hand, we can certainly live with this; on the other hand, it would nice if we could do it better (e.g., smoother, faster, more interesting transitions).   This is where you come in. We've reached the limit of our programming skills. This time-portal-stuff.zip file contains the two 240 x 320 BMPs we've been playing with, the Adafruit_GFX (graphics) library, the Adafruit_ILI9341 (display) library, and the Time_Portal_01 sketch, which is based on Adafruit's SPI BMP display example sketch.   In the case of the rippling mirror effect, could we achieve this by drawing expanding circles using the graphics library rather than by displaying BMP images? Alternatively could we start off by displaying the BMP, and then "tweak" individual pixels using the graphics library to provide some sort of visual interest? Any suggestions here would be very much appreciated.   Furthermore, in the case of transitioning to a new BMP image, is there anything we can do to speed things up? Looking at Adafruit's sketch, it seems that there's a lot of error-checking to make sure the BMP files are of the right size and format and suchlike. Since we know our BMPs are all going to be guaranteed to be 240 x 320 x 24-bits, and they will all be generated in exactly the same way from Paint.net, can we strip out a lot of this error checking and -- if we do so -- will this speed things up?   It may be that we are fundamentally speed-limited by the fact that the Arduino Uno (and Arduino Nano) has only 2 KB of SRAM. As we've already discussed, each of our BMPs is 3 x 240 x 320 = 259,200 bytes in size. This means that we have to bounce back and forth streaming small groups of pixels from the Micro-SD card and writing these pixels to the display.   If we do have this fundamental limit, it may be that we can still achieve a more interesting image-to-image transition effect. We don’t know how BMP files represent their data, but let's visualize it as being something like the following:   (Source: Max Maxfield Mike Mittlebeeler)   It would be nice if we could read out pixel data from any specified location from the BMP file and write that data to any specified location on the display. However, our understanding is that we can do the latter, but not the former. That is, we think that when we open the file on the Micro-SD card and start reading pixel data, this data is presented to us (something like) in the order , , ... , , , , ... , ... , .   But what if we created a simple pre-processor program on the PC that could take our original BMP file, "shuffle" its contents in some way, and generate a modified BMP file as output? (Source: Max Maxfield Mike Mittlebeeler)   If our sketch running on the Arduino "knows" that the data will be presented in this way, it could read Row 0 from the file and write it to Row 159 on the display, read Row 1 from the file and write it to Row 160 on the display, and so forth. This would mean that the new image would "wipe" over the old image starting from the center and working outwards, which -- we think -- would offer a much better effect.   Maybe we could go even more sophisticated than this -- starting at the center of the display and working outwards in all dimensions. What do you think? Is this possible and -- if so -- can you help us to achieve it?
  • 热度 18
    2015-11-25 10:23
    2110 次阅读|
    0 个评论
    图像文件头 1)1-2:(这里的数字代表的是字节,下同)图像文件头。0x4d42=’BM’,表示是Windows支持的 BMP格式 。( 注意:查 ascii 表 B 0x42,M0x4d,bfType 为两个字节, B 为 low 字节, M 为 high 字节所以 bfType=0x4D42 ,而不是 0x424D ,请注意 ) 2)3-6:整个文件大小。4690 0000,为00009046h=36934。 3)7-8:保留,必须设置为0。 4)9-10:保留,必须设置为0。 5)11-14:从文件开始到位图数据之间的 偏移量 (14+40+4*(2^biBitCount))(在有颜色板的情况下)。4600 0000,为00000046h=70,上面的文件头就是35字=70字节。 位图信息头 6)15-18:位图图信息头长度。 7) 19-22:位图宽度,以像素为单位。8000 0000,为00000080h=128。 8)23-26:位图高度,以像素为单位。9000 0000,为00000090h=144。 9)27-28:位图的位面数,该值总是1。0100,为0001h=1。 10)29-30:每个像素的位数。有1(单色),4(16色),8(256色),16(64K色,高彩色),24(16M色,真彩色),32(4096M色,增强型真彩色)。1000为0010h=16。 11)31-34:压缩说明:有0(不压缩),1(RLE 8,8位RLE压缩),2(RLE 4,4位RLE压缩,3(Bitfields,位域存放)。RLE简单地说是采用像素数+像素值的方式进行压缩。T408采用的是位域存放方式,用两个字节表示一个像素,位域分配为r5b6g5。图中0300 0000为00000003h=3(这张图片不存在颜色板)。 12)35-38:用字节数表示的位图数据的大小,该数必须是4的倍数, 数值 上等于:一行所占的字节数×位图高度。0090 0000为00009000h=80×90×2h=36864。假设位图是24位,宽为41,高为30,则数值= (biWidth*biBitCount+31)/32*4*biHeight,即=(41*24+31)/32*4*30=3720 13)39-42:用 象素 /米表示的 水平分辨率 。A00F 0000为0000 0FA0h=4000。 14)43-46:用象素/米表示的垂直分辨率。A00F 0000为0000 0FA0h=4000。 15)47-50:位图使用的颜色索引数。设为0的话,则说明使用所有调色板项。 16)51-54:对图象显示有重要影响的颜色索引的数目。如果是0,表示都重要。 彩色板 17)(55+0)到(50-1+2^biBitCount):彩色板规范。对于调色板中的每个表项,用下述方法来描述RGB的值:1字节用于蓝色分量 1字节用于绿色分量 1字节用于红色分量 1字节用于填充符(设置为0) 对于24-位 真彩色图像 就不使用彩色板,因为位图中的RGB值就代表了每个象素的颜色。 如,彩色板为00F8 0000 E007 0000 1F00 0000 0000 0000,其中: 00F8为F800h = 1111 1000 0000 0000(二进制),是蓝色分量的掩码。 E007 为 07E0h = 0000 0111 1110 0000(二进制),是绿色分量的掩码。 1F00为001Fh = 0000 0000 0001    1111(二进制),是红色分量的掩码。 0000 总设置为0。 将掩码跟像素值进行“与”运算再进行移位操作就可以得到各色分量值。看看掩码,就可以明白事实上在每个像素值的两个字节16位中,按从高到低取5、6、5位分别就是r、g、b分量值。取出分量值后把r、g、b值分别乘以8、4、8就可以补齐第个分量为一个字节,再把这三个字节按rgb组合,放入存储器(同样要反序),就可以转换为24位标准BMP格式了。 图像数据阵列 18)55(无调色板)-bfSize:每两个字节表示一个像素。阵列中的第一个字节表示位图左下角的 象素 ,而最后一个字节表示位图右上角的象素。 需要提醒的是 ,bmp位图的颜色阵列部分,像素数据的存储是以左下角为原点。也就是说,当你打开一个bmp图片并显示在电脑屏幕上的时,实际在存储的时候,这个图片的最左下角的像素是首先被存储在bmp文件中的。之后,按照从左到右,从下到上的顺序,依次进行像素数据的存储。如果,你存储的是3通道的位图数据(也就是我们通常说的彩图),那么它是按照B0G0R0B1G1R1B2G2R2...的顺序进行存储的, /******************************************************************************************/ 到这里BMP就解读完了,下面是百度里BMP文件的说明:   BMP   (图像文件格式 (Bitmap) )   编辑 BMP(全称Bitmap)是Windows操作系统中的标准图像文件格式,可以分成两类:设备相关 位图 (DDB)和设备无关位图(DIB),使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可选lbit、4bit、8bit及24bit。BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式。 中文名 图像文件格式 外文名 Bitmap 简      称 BMP 系      统 Windows操作系统 应      用 设备相关 位图 设备无关位图 目录 1.     1  格式组成 2.     2  格式类型 3.     3  对应数据结构 4.     4  读取方法 5.     5  文件部分 格式组成 编辑 典型的BMP图像文件由四部分组成: 1:位图头文件数据结构,它包含BMP图像文件的类型、显示内容等信息; 2: 位图 信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息; 3:调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP)就不需要调色板; 4:位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在24位图中直接使用RGB,而其他的小于24位的使用调色板中颜色索引值。 格式类型 编辑 位图一共有两种类型,即:设备相关位图(DDB)和设备无关位图(DIB)。DDB位图在早期的Windows系统(Windows 3.0以前)中是很普遍的,事实上它也是唯一的。然而,随着显示器制造技术的进步,以及显示设备的多样化,DDB位图的一些固有的问题开始浮现出来了。比如,它不能够存储(或者说获取)创建这张图片的原始设备的分辨率,这样,应用程序就不能快速的判断客户机的显示设备是否适合显示这张图片。为了解决这一难题,微软创建了DIB 位图 格式。 设备无关位图 (Device-Independent Bitmap) DIB位图包含下列的颜色和尺寸信息: * 原始设备(即创建图片的设备)的颜色格式。 * 原始设备的分辨率。 * 原始设备的调色板 * 一个位 数组 ,由红、绿、蓝(RGB)三个值代表一个像素。 * 一个数组压缩标志,用于表明数据的压缩方案(如果需要的话)。 以上这些信息保存在BITMAPINFO结构中,该结构由BITMAPINFOHEADER结构和两个或更多个RGBQUAD结构所组成。BITMAPINFOHEADER结构所包含的成员表明了图像的尺寸、原始设备的颜色格式、以及数据压缩方案等信息。RGBQUAD结构标识了像素所用到的颜色数据。 DIB位图也有两种形式,即:底到上型DIB(bottom-up),和顶到下型DIB(top-down)。底到上型DIB的原点(origin)在图像的左下角,而顶到下型DIB的原点在图像的左上角。如果DIB的高度值(由BITMAPINFOHEADER结构中的biHeight成员标识)是一个正值,那么就表明这个DIB是一个底到上型DIB,如果高度值是一个负值,那么它就是一个顶到下型DIB。注意:顶到下型的DIB位图是不能被压缩的。 位图的颜色格式是通过颜色面板值(planes)和颜色位值(bitcount)计算得来的,颜色面板值永远是1,而颜色位值则可以是1、4、8、16、24、32其中的一个。如果它是1,则表示位图是一张单色位图(译者注:通常是黑白位图,只有黑和白两种颜色,当然它也可以是任意两种指定的颜色),如果它是4,则表示这是一张VGA位图,如果它是8、16、24、或是32,则表示该位图是其他设备所产生的位图。如果应用程序想获取当前显示设备(或打印机)的颜色位值(或称位深度),可调用API函数GetDeviceCaps(),并将第二个参数设为BITSPIXEL即可。 显示设备的分辨率是以每米多少个像素来表明的,应用程序可以通过以下三个步骤来获取显示设备或打印机的 水平分辨率 : 1. 调用GetDeviceCaps()函数,指定第二个参数为HORZRES。 2. 再次调用GetDeviceCaps()函数,指定第二个参数为HORZSIZE。 3. 用第一个返回值除以第二个返回值。即:GetDeviceCaps(hDC,HORZRES)/GetDeviceCaps(hDC,HORZSIZE); 应用程序也可以使用相同的三个步骤来获取设备的垂直分辨率,不同之处只是要将HORZRES替换为VERTRES,把HORZSIZE替换为VERTSIZE,即可。 调色板是被保存在一个RGBQUAD结构的 数组 中,该结构指出了每一种颜色的红、绿、蓝的分量值。位数组中的每一个索引都对应于一个调色板项(即一个RGBQUAD结构),应用程序将根据这种对应关系,将像素索引值转换为像素RGB值(真实的像素颜色)。应用程序也可以通过调用GetDeviceCaps()函数来获取当前显示设备的调色板尺寸(将该函数的第二个参数设为NUMCOLORS即可)。 Win32 API支持位数据的压缩(只对8位和4位的底到上型DIB位图)。压缩方法是采用运行长度编码方案(RLE),RLE使用两个字节来描述一个句法,第一个字节表示重复像素的个数,第二个字节表示重复像素的索引值。有关压缩位图的详细信息请参见对BITMAPINFOHEADER结构的解释。 应用程序可以从一个DDB位图创建出一个DIB位图,步骤是,先初始化一些必要的结构,然后再调用GetDIBits()函数。不过,有些显示设备有可能不支持这个函数,你可以通过调用GetDeviceCaps()函数来确定一下(GetDeviceCaps()函数在调用时指定RC_DI_BITMAP作为RASTERCAPS的标志)。 应用程序可以用DIB去设置显示设备上的像素(译者注:也就是显示DIB),方法是调用SetDIBitsToDevice()函数或调用StretchDIBits()函数。同样,有些显示设备也有可能不支持以上这两个函数,这时你可以指定RC_DIBTODEV作为RASTERCAPS标志,然后调用GetDeviceCaps()函数来判断该设备是否支持SetDIBitsToDevice()函数。也可以指定RC_STRETCHDIB作为RASTERCAPS标志来调用GetDeviceCaps()函数,来判断该设备是否支持StretchDIBits()函数。 如果应用程序只是要简单的显示一个已经存在的DIB位图,那么它只要调用SetDIBitsToDevice()函数就可以。比如一个电子表格软件,它可以打开一个图表文件,在窗口中简单的调用SetDIBitsToDevice()函数,将图形显示在窗口中。但如果应用程序要重复的绘制位图的话,则应该使用BitBlt()函数,因为BitBlt()函数的执行速度要比SetDIBitsToDevice()函数快很多。 设备相关位图 (Device-Dependent Bitmaps) 设备相关位图(DDB)之所以现在还被系统支持,只是为了兼容旧的Windows 3.0软件,如果程序员现在要开发一个与位图有关的程序,则应该尽量使用或生成DIB格式的位图。 DDB位图是被一个单个结构BITMAP所描述,这个结构的成员标明了该位图的宽度、高度、设备的颜色格式等信息。 DDB位图也有两种类型,即:可废弃的(discardable)DDB和不可废弃的(nondiscardable)DDB。可废弃的DDB位图就是一种当 系统内存 缺乏,并且该位图也没有被选入设备描述表(DC)的时候,系统就会把该DDB位图从内存中清除(即废弃)。不可废弃的DDB则是无论系统内存多少都不会被系统清除的DDB。API函数CreateDiscardableBitmap()函数可用于创建可废弃位图。而函数CreateBitmap()、CreateCompatibleBitmap()、和CreateBitmapIndirect()可用于创建不可废弃的位图。 应用程序可以通过一个DIB位图而创建一个DDB位图,只要先初始化一些必要的结构,然后再调用CreateDIBitmap()函数就可以。如果在调用该函数时指定了CBM_INIT标志,那么这一次调用就等价于先调用CreateCompatibleBitmap()创建当前设备格式的DDB位图,然后又调用SetDIBits()函数转换DIB格式到DDB格式。(可能有些设备并不支持SetDIBits()函数,你可以指定RC_DI_BITMAP作为RASTERCAPS的标志,然后调用GetDeviceCaps()函数来判断一下)。 对应数据结构 编辑 1:BMP文件组成 BMP文件由文件头、位图信息头、颜色信息和 图形数据 四部分组成。 2:BMP文件头(14字节) BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。 其结构定义如下: 1 2 3 4 5 6 7 8 9 typedef   struct   tagBITMAPFILEHEADER {     WORD   bfType;// 位图文件的类型,必须为BM(1-2字节)     DWORD   bfSize;// 位图文件的大小,以字节为单位(3-6字节,低位在前)     WORD   bfReserved1;// 位图文件保留字,必须为0(7-8字节)     WORD   bfReserved2;// 位图文件保留字,必须为0(9-10字节)     DWORD   bfOffBits;// 位图数据的起始位置,以相对于位图(11-14字节,低位在前)     // 文件头的偏移量表示,以字节为单位 }BITMAPFILEHEADER; 3:位图信息头(40字节) BMP位图信息头数据用于说明位图的尺寸等信息。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 typedef   struct   tagBITMAPINFOHEADER{ DWORD   biSize;// 本结构所占用字节数(15-18字节) LONG   biWidth;// 位图的宽度,以像素为单位(19-22字节) LONG   biHeight;// 位图的高度,以像素为单位(23-26字节) WORD   biPlanes;// 目标设备的级别,必须为1(27-28字节) WORD   biBitCount;// 每个像素所需的位数,必须是1(双色),(29-30字节) //4(16 色),8(256色)16(高彩色)或24(真彩色)之一 DWORD   biCompression;// 位图压缩类型,必须是0(不压缩),(31-34字节) //1(BI_RLE8 压缩类型)或2(BI_RLE4压缩类型)之一 DWORD   biSizeImage;// 位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位(35-38字节) LONG   biXPelsPerMeter;// 位图水平分辨率,每米像素数(39-42字节) LONG   biYPelsPerMeter;// 位图垂直分辨率,每米像素数(43-46字节) DWORD   biClrUsed;// 位图实际使用的颜色表中的颜色数(47-50字节) DWORD   biClrImportant;// 位图显示过程中重要的颜色数(51-54字节) }BITMAPINFOHEADER; 4:颜色表 颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下: 1 2 3 4 5 6 typedefstructtagRGBQUAD{ BYTErgbBlue;// 蓝色的亮度(值范围为0-255) BYTErgbGreen;// 绿色的亮度(值范围为0-255) BYTErgbRed;// 红色的亮度(值范围为0-255) BYTErgbReserved;// 保留,必须为0 }RGBQUAD; 颜色表中RGBQUAD结构数据的个数有biBitCount来确定: 当biBitCount=1,4,8时,分别有2,16,256个表项; 当biBitCount=24时,没有颜色表项。 位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下: 1 2 3 4 typedefstructtagBITMAPINFO{ BITMAPINFOHEADERbmiHeader;// 位图信息头 RGBQUADbmiColors ;// 颜色表 }BITMAPINFO; 5:位图数据 位图 数据记录 了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数: 当biBitCount=1时,8个像素占1个字节; 当biBitCount=4时,2个像素占1个字节; 当biBitCount=8时,1个像素占1个字节; 当biBitCount=24时,1个像素占3个字节,按顺序分别为B,G,R; Windows规定一个扫描行所占的字节数必须是 4的倍数(即以long为单位),不足的以0填充, biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) ~31) / 8) * bi.biHeight; 具体数据举例: 如某BMP文件开头: 424D 46900000 0000 0000 4600 0000 2800 0000 8000 0000 9000 0000 0100*1000 0300 0000 0090 0000 A00F 0000 A00F0000 0000 00000000 0000*00F8 E007 1F00 0000*02F1 84F1 04F1 84F1 84F1 06F2 84F1 06F2 04F2 86F2 06F2 86F2 86F2 .... .... 读取方法 编辑 /* 功能:在图片的第50行画一条黑线 为简化代码,只支持24位色的图片 codeblocks下正确运行。VC下需要将二维数组img改为malloc动态分配。需要添加#include "stdlib.h"。 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include #include typedef   struct { BYTE   b; BYTE   g; BYTE   r; }RGB; int   main(void) { BITMAPFILEHEADER fileHeader; BITMAPINFOHEADER infoHeader; FILE*pfin=fopen(" 原始图像.bmp","rb"); FILE*pfout=fopen(" 修改后的图像.bmp","wb"); //ReadtheBitmapfileheader; fread(fileHeader,sizeof(BITMAPFILEHEADER),1,pfin); //ReadtheBitmapinfoheader; fread(infoHeader,sizeof(BITMAPINFOHEADER),1,pfin); // 为简化代码,只处理24位彩色 if(infoHeader.biBitCount==24) { int   size=infoHeader.biWidth*infoHeader.biHeight; RGB img ;  // 这里有错误,尺度改为常亮 fread(img,sizeof(RGB),size,pfin); // 把第50行染成黑色 int   i=0; for(;i;i++) { img .b=img .g=img .r=0; } // 将修改后的图片保存到文件 fwrite(fileHeader,sizeof(fileHeader),1,pfout); fwrite(infoHeader,sizeof(infoHeader),1,pfout); fwrite(img,sizeof(RGB),size,pfout); } fclose(pfin); fclose(pfout); } 文件部分 编辑 图像文件头 1)1-2:(这里的数字代表的是字节,下同)图像文件头。0x4d42=’BM’,表示是Windows支持的 BMP格式 。( 注意:查 ascii 表 B 0x42,M0x4d,bfType 为两个字节, B 为 low 字节, M 为 high 字节所以 bfType=0x4D42 ,而不是 0x424D ,请注意 ) 2)3-6:整个文件大小。4690 0000,为00009046h=36934。 3)7-8:保留,必须设置为0。 4)9-10:保留,必须设置为0。 5)11-14:从文件开始到位图数据之间的 偏移量 (14+40+4*(2^biBitCount))(在有颜色板的情况下)。4600 0000,为00000046h=70,上面的文件头就是35字=70字节。 位图信息头 6)15-18:位图图信息头长度。 7) 19-22:位图宽度,以像素为单位。8000 0000,为00000080h=128。 8)23-26:位图高度,以像素为单位。9000 0000,为00000090h=144。 9)27-28:位图的位面数,该值总是1。0100,为0001h=1。 10)29-30:每个像素的位数。有1(单色),4(16色),8(256色),16(64K色,高彩色),24(16M色,真彩色),32(4096M色,增强型真彩色)。1000为0010h=16。 11)31-34:压缩说明:有0(不压缩),1(RLE 8,8位RLE压缩),2(RLE 4,4位RLE压缩,3(Bitfields,位域存放)。RLE简单地说是采用像素数+像素值的方式进行压缩。T408采用的是位域存放方式,用两个字节表示一个像素,位域分配为r5b6g5。图中0300 0000为00000003h=3(这张图片不存在颜色板)。 12)35-38:用字节数表示的位图数据的大小,该数必须是4的倍数, 数值 上等于:一行所占的字节数×位图高度。0090 0000为00009000h=80×90×2h=36864。假设位图是24位,宽为41,高为30,则数值= (biWidth*biBitCount+31)/32*4*biHeight,即=(41*24+31)/32*4*30=3720 13)39-42:用 象素 /米表示的 水平分辨率 。A00F 0000为0000 0FA0h=4000。 14)43-46:用象素/米表示的垂直分辨率。A00F 0000为0000 0FA0h=4000。 15)47-50:位图使用的颜色索引数。设为0的话,则说明使用所有调色板项。 16)51-54:对图象显示有重要影响的颜色索引的数目。如果是0,表示都重要。 彩色板 17)(55+0)到(50-1+2^biBitCount):彩色板规范。对于调色板中的每个表项,用下述方法来描述RGB的值: 1字节用于蓝色分量 1字节用于绿色分量 1字节用于红色分量 1字节用于填充符(设置为0) 对于24-位 真彩色图像 就不使用彩色板,因为位图中的RGB值就代表了每个象素的颜色。 如,彩色板为00F8 0000 E007 0000 1F00 0000 0000 0000,其中: 00F8为F800h = 1111 1000 0000 0000(二进制),是蓝色分量的掩码。 E007 为 07E0h = 0000 0111 1110 0000(二进制),是绿色分量的掩码。 1F00为001Fh = 0000 0000 0001    1111(二进制),是红色分量的掩码。 0000 总设置为0。 将掩码跟像素值进行“与”运算再进行移位操作就可以得到各色分量值。看看掩码,就可以明白事实上在每个像素值的两个字节16位中,按从高到低取5、6、5位分别就是r、g、b分量值。取出分量值后把r、g、b值分别乘以8、4、8就可以补齐第个分量为一个字节,再把这三个字节按rgb组合,放入存储器(同样要反序),就可以转换为24位标准BMP格式了。 图像数据阵列 18)55(无调色板)-bfSize:每两个字节表示一个像素。阵列中的第一个字节表示位图左下角的 象素 ,而最后一个字节表示位图右上角的象素。 //----图像处理-----BMP为DIB类型,从底向上显示--------- //阵列中的第一个字节表示位图左下角的象素,而最后一个字节表示位图右上角的象素。 //下面的代码可以完成第一个字节表示位图左上角的象素,而最后一个字节表示位图右下角的象素,即正常的显示状态,便于操作。 int m,n; unsigned char k; m = BMPPIC.BMPInfoHead.biWidth/8; //24 n = BMPPIC.BMPInfoHead.biHeight; //96, 24*96 = 2304 bytes for(int i=0; i n/2; i++ ) { for(int a=0; a m; a++ ) { k = pbufout1 ; pbufout1 = pbufout1 ; pbufout1 = k; } } 存储算法 BMP文件通常是不压缩的,所以它们通常比同一幅图像的压缩图像文件格式要大很多。例如,一个800×600的24位几乎占据1.4MB空间。因此它们通常不适合在因特网或者其它低速或者有容量限制的媒介上进行传输。根据颜色深度的不同,图像上的一个像素可以用一个或者多个 字节 表示,它由n/8所确定(n是位深度,1字节包含8个 数据位 )。图片浏览器等基于字节的ASCII值计算像素的颜色,然后从调色板中读出相应的值。更为详细的信息请参阅下面关于 位图 文件的部分。n位2n种颜色的位图近似字节数可以用下面的公式计算:BMP文件大小约等于 54+4*2的n次方+(w*h*n)/8,其中高度和宽度都是像素数。需要注意的是上面公式中的54是位图文件的文件头,是彩色调色板的大小。另外需要注意的是这是一个近似值,对于n位的位图图像来说,尽管可能有最多2n中颜色,一个特定的图像可能并不会使用这些所有的颜色。由于彩色调色板仅仅定义了图像所用的颜色,所以实际的彩色调色板将小于。如果想知道这些值是如何得到的,请参考下面文件格式的部分。由于存储算法本身决定的因素,根据几个图像参数的不同计算出的大小与实际的文件大小将会有一些细小的差别  
相关资源