转
http://blog.csdn.net/pkueecser/article/details/5579604
http://blog.csdn.net/pkueecser/article/details/5573395
http://blog.csdn.net/holybin/article/details/25792741
#####################################################################################################################
#####################################################################################################################
由于windows中所用头文件"windows.h"在linux下不可用,故自己建立相关的头文件,定义bmp文件的存储结构及格式
代码如下:
/* linux_bmp.h*/
/*
* Copyright (c)2010 Chris Grant
*
* Win32 USER structures and API
*/
#include <iostream>
typedef struct tagBITMAPFILEHEADER{
unsigned short bfType; //2 此处需留意
unsigned long bfSize; //4
/* File size in bytes */
unsigned short bfReserved1; //2
unsigned short bfReserved2; //2
unsigned long bfOffBits; //4 /* Offset to image data, bytes */
} __attribute__((packed))BITMAPFILEHEADER, *PBITMAPFILEHEADER; //Attention:"__"是两个"_"! 字边界对齐!4字节对齐 知道在linux的gcc下默认的是四字节的
typedef struct tagBITMAPINFOHEADER{
unsigned long biSize; //4 /* Header size in bytes */
long biWidth; //4 /* Width of image */
long biHeight; //4 /* Height of image */
unsigned short biPlanes; //2 /* Number of colour planes */
unsigned short biBitCount; //2 /* Bits per pixel */
unsigned long biCompression; //4 /* Compression type */
unsigned long biSizeImage; //4 /* Image size in bytes */
long biXPelsPerMeter; //4
long biYPelsPerMeter; //4 /* Pixels per meter */
unsigned long biClrUsed; //4 /* Number of colours */
unsigned long biClrImportant; //4 /* Important colours */
} __attribute__((packed))BITMAPINFOHEADER,*PBITMAPINFOHEADER;
typedef struct tagRGBQUAD {
unsigned char rgbBlue; /* Blue value */
unsigned char rgbGreen; /* Green value */
unsigned char rgbRed; /* Red value */
unsigned char rgbReserved; /* Reserved */
} RGBQUAD;
将其include即可。
参考:
1.上篇博客
2. http://m.cnblogs.com/51493/1385324.html
标题: 一个在LINUX下生成BMP的程序
很多人都搞不定内存对齐的问题,最近帮老焦他们写测试程序,用到一个BMP GENERATOR,写了个比较简单的版本,仅针对24位真彩,现把代码公布
#include <iostream>
using namespace std;
typedef long BOOL;
typedef long LONG;
typedef unsigned char BYTE;
typedef unsigned long DWORD;
......
......
......
3. http://topic.csdn.net/t/20040921/04/3392666.html
c语言实现bmp读写(linux上使用),一个奇怪的错误!欢迎诸位高手指教
我现在需要写一个程序,能够在linux上读写bmp文件,理论上十分简单,但是碰到如下错误,不知道因为什么原因.
我在读bmp文件头的时候,发现读出的数据根本不对
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_4v1h.asp是msdn上关于bmp的文档的文件头0x00 0x0D共有14byte,
文件头的数据结构其定义为
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
由于我需要在linux上运行,不能用WORD和DWORD,我将WORD 换为unsigned short将DWORD 换为unsigned int,如下:
typedef struct {
unsigned short int type;
unsigned int size;
unsigned short int reserved1;
unsigned short int reserved2;
unsigned int offset;
} FILEHEADER;
但是该结构将有4+8+4+4+8共28byte(现在cpu的字长一般均为16位)
但是我 sizeof(FILEHEADER)则只有16byte,请问这些字节是怎么分配的啊?
在Windows上的BITMAPFILEHEADER结构的长度并不是你声称的 4+8+4+4+8 = 28 字节。我在VC6下试了一下,是 2+4+2+2+4 = 14 字节。
至于你上面定义的 FILEHEADER
结构,由于内存对齐的原因,采取不同的对齐策略会得到不同的长度。在Linux上GCC的默认对齐规则下,各个成员实际占用的内存分别为(括号内为类型长
度):4(2)、4(4)、2(2)、2(2)、4(4),所以加起来就是 16 字节。
根据Windows中的测试结果,BITMAPFILEHEADER采取的内存对齐策略应该是 1 字节或者 2 字节对齐。在Linux中的程序也可采取类似的对齐规则以便统一结构的长度。
建议你不要倚赖于改变系统的默认的对齐规则的方法。最好在程序中依此读取每个成员(即你的方法二),而不是将整个文件头一次读取到结构中。这样虽然稍微麻烦一点,然而程序的通用性好。
typedef struct tagBITMAPFILEHEADER{
unsigned short bfType; /* Magic identifier */
unsigned bfSize; /* File size in bytes */
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned bfOffBits; /* Offset to image data, bytes */
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER{
unsigned biSize; /* Header size in bytes */
unsigned biWidth; /* Width of image */
unsigned biHeight; /* Height of image */
unsigned short biPlanes; /* Number of colour planes */
unsigned short biBitCount; /* Bits per pixel */
unsigned biCompression; /* Compression type */
unsigned biSizeImage; /* Image size in bytes */
int biXPelsPerMeter;
int biYPelsPerMeter; /* Pixels per meter */
unsigned biClrUsed; /* Number of colours */
unsigned biClrImportant; /* Important colours */
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;
typedef struct tagRGBQUAD {
unsigned char rgbBlue; /* Blue value */
unsigned char rgbGreen; /* Green value */
unsigned char rgbRed; /* Red value */
unsigned char rgbReserved; /* Reserved */
} RGBQUAD;
我分别用sizeof看他们的大小,分别为16,40,4,后面两个结构就和分别读出的总和一样?就是第一个不同,这是为什么啊?再一个,内存对齐策略是什么意思?
你的结构体肯定是有问题的,因为这种结构肯定是要按四个字节对奇的看看你写的,对不齐就设预留位,看看你写的。
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
bfType二字节,bfSize四个字节没对齐,你还是找找正确的结构吧。
如果你使用GCC编译器,你可以改变一个结构的对齐方式。比如,想要取消你定义的结构的默认对齐,可以这么做:
typedef struct {
unsigned short int type;
unsigned int size;
unsigned short int reserved1;
unsigned short int reserved2;
unsigned int offset;
} __attribute__ ((packed)) FILEHEADER;
则 sizeof(FILEHEADER) = 2 + 4 + 2 + 2 + 4 =
14,就变成跟Windows中的类似结构一样的了,你的方法一就能得到正确结果了。但是这样的修改内存对齐的方式在非 Intel
处理器上可能会造成运行错误(在Intel 及其兼容的处理器上运行正常,只是效率稍低些)。
想了解内存对齐(Memory Alignment)的概念,你可以在 Google 中以此为关键字进行搜索。
#####################################################################################################################
#####################################################################################################################
1.BMP文件格式
http://blog.sina.com.cn/s/blog_4a3c050a0100bex4.html
1.2 BMP文件结构及其存取
数字图像在外存储器设备中的存储形式是图像文件,图像必须按照某个已知的、公认的数据存储顺序和结构进行存储,才能使不同的程序对图像文件顺利进行打开或 存盘操作,实现数据共享。图像数据在文件中的存储顺序和结构称为图像文件格式。目前广为流传的图像文件格式有许多种,常见的格式包括BMP、GIF、 JPEG、TIFF、PSD、DICOM、MPEG等。在各种图像文件格式中,一部分是由某个软硬件厂商提出并被广泛接受和采用的格式,例如BMP、 GIF和PSD格式;另一部分是由各种国际标准组织提出的格式,例如JPEG、TIFF和DICOM,其中JPEG是国际静止图像压缩标准组织提出的格 式,TIFF是由部分厂商组织提出的格式,DICOM是医学图像国际标准组织提出的医学图像专用格式。
BMP文件是Windows操作系统所推荐和支持的图像文件格式,是一种将内存或显示器的图像数据不经过压缩而直接按位存盘的文件格式,所以称为位图 (bitmap)文件,因其文件扩展名为BMP,故称为BMP文件格式,简称BMP文件。本书对图像的算法编程都是针对BMP图像文件的,因此在本章中我 们详细介绍BMP文件结构及其读写操作,以加深对图像数据的理解。
1.2.1 BMP文件结构
如图1-7所示,BMP图像文件被分成4个部分:位图文件头(Bitmap File Header)、位图信息头(Bitmap Info Header)、颜色表(Color Map)和位图数据(即图像数据,Data Bits或Data Body)。
第1部分为位图文件头BITMAPFILEHEADER,是一个结构体类型,该结构的长度是固定的,为14个字节。其定义如下:
typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER; |
BITMAPFILEHEADER结构的各个域详细说明如下:
bfType:位图文件类型,必须是0x424D,即字符串“BM”,也就是说,所有的“*.bmp”文件的头两个字节都是“BM”。
bfSize:位图文件大小,包括这14个字节。
bfReserved1, bfReserved2:Windows保留字,暂不用。
bfOffBits:从文件头到实际的位图数据的偏移字节数,图1-7中前3个部分的长度之和。
图1-7 BMP文件结构示意图 |
第2部分为位图信息头BITMAPINFOHEADER,也是一个结构体类型的数据结构,该结构的长度也是固定的,为40个字节(WORD为无符号16位整数,DWORD为无符号32位整数,LONG为32位整数)。其定义如下:
typedef struct tagBITMAPINFOHEADER { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER; |
BITMAPINFOHEADER结构的各个域的详细说明如下:
biSize:本结构的长度,为40个字节。
biWidth:位图的宽度,以像素为单位。
biHeight:位图的高度,以像素为单位。
biPlanes:目标设备的级别,必须是1。
biBitCount:每个像素所占的位数(bit),其值必须为1(黑白图像)、4(16色图)、8(256色)、24(真彩色图),新的BMP格式支持32位色。
biCompresssion:位图压缩类型,有效的值为BI_RGB(未经压缩)、BI_RLE8、BI_RLE4、BI_BITFILEDS(均为Windows定义常量)。这里只讨论未经压缩的情况,即biCompression=BI_RGB。
biSizeImage:实际的位图数据占用的字节数,该值的大小在第4部分位图数据中有具体解释。
biXPelsPerMeter:指定目标设备的水平分辨率,单位是像素/米。
biYPelsPerMeter:指定目标设备的垂直分辨率,单位是像素/米。
biClrUsed:位图实际用到的颜色数,如果该值为零,则用到的颜色数为2的biBitCount次幂。
biClrImportant:位图显示过程中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的。
第3部分为颜色表。颜色表实际上是一个RGBQUAD结构的数组,数组的长度由biClrUsed指定(如果该值为零,则由biBitCount指定,即2的biBitCount次幂个元素)。RGBQUAD结构是一个结构体类型,占4个字节,其定义如下:
typedef struct tagRGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; }RGBQUAD; |
RGBQUAD结构的各个域的详细说明如下:
rgbBlue:该颜色的蓝色分量;
rgbGreen:该颜色的绿色分量;
rgbRed:该颜色的红色分量;
rgbReserved:保留字节,暂不用。
有些位图需要颜色表;有些位图(如真彩色图)则不需要颜色表,颜色表的长度由BITMAPINFOHEADER结构中biBitCount分量决定。对于 biBitCount值为1的二值图像,每像素占1bit,图像中只有两种(如黑白)颜色,颜色表也就有21=2个表项,整个颜色表的大小为 个字节;对于biBitCount值为8的灰度图像,每像素占8bit,图像中有 颜色,颜色表也就有256个表项,且每个表项的R、G、B分量相等,整个颜色表的大小为 个字节;而对于biBitCount=24的真彩色图像,由于每像素3个字节中分别代表了R、G、B三分量的值,此时不需要颜色表,因此真彩色图的BITMAPINFOHEADER结构后面直接就是位图数据。
第4部分是位图数据,即图像数据,其紧跟在位图文件头、位图信息头和颜色表(如果有颜色表的话)之后,记录了图像的每一个像素值。对于有颜色表的位图,位 图数据就是该像素颜色在调色板中的索引值;对于真彩色图,位图数据就是实际的R、G、B值(三个分量的存储顺序是B、G、R)。下面分别就2色、16色、 256色和真彩色位图的位图数据进行说明:
对于2色位图,用1位就可以表示该像素的颜色,所以1个字节能存储8个像素的颜色值。
对于16色位图,用4位可以表示一个像素的颜色。所以一个字节可以存储2个像素的颜色值。
对于256色位图,1个字节刚好存储1个像素的颜色值。
对于真彩色位图,3个字节才能表示1个像素的颜色值。
需要注意两点:
第一,Windows规定一个扫描行所占的字节数必须是4的倍数,不足4的倍数则要对其进行扩充。假设图像的宽为biWidth个像素、每像素biBitCount个比特,其一个扫描行所占的真实字节数的计算公式如下:
DataSizePerLine = (biWidth * biBitCount /8+ 3) / 4*4 |
那么,不压缩情况下位图数据的大小(BITMAPINFOHEADER结构中的biSizeImage成员)计算如下:
biSizeImage = DataSizePerLine * biHeight |
第二,一般来说,BMP文件的数据是从图像的左下角开始逐行扫描图像的,即从下到上、从左到右,将图像的像素值一一记录下来,因此图像坐标零点在图像左下角。
2. http://linux.chinaunix.net/techdoc/system/2009/07/06/1122029.shtml
BMP文件格式分析 | |
|
|
来源: ChinaUnix博客 日期: 2009.07.06 14:06 (共有0条评论) 我要评论 | |
BMP文件格式分析
|
#####################################################################################################################
#####################################################################################################################
#define WORD unsigned short #define DWORD unsigned int #define LONG int typedef struct { //WORD bfType ; DWORD bfSize ; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } __attribute__((packed)) ClBitMapFileHeader; typedef struct { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount ; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } __attribute__((packed)) ClBitMapInfoHeader; typedef struct { unsigned char rgbBlue; //该颜色的蓝色分量 unsigned char rgbGreen; //该颜色的绿色分量 unsigned char rgbRed; //该颜色的红色分量 unsigned char rgbReserved; //保留值 } ClRgbQuad; typedef struct { int width; int height; int channels; unsigned char* imageData; }ClImage; ClImage* clLoadImage(const char* path); bool clSaveImage(const char* path, ClImage* bmpImg); ClImage* clLoadImage(const char* path) { ClImage* bmpImg; FILE* pFile; unsigned short fileType; ClBitMapFileHeader bmpFileHeader; ClBitMapInfoHeader bmpInfoHeader; int channels = 1; int width = 0; int height = 0; int step = 0; int offset = 0; unsigned char pixVal; ClRgbQuad* quad; int i, j, k; bmpImg = (ClImage*)malloc(sizeof(ClImage)); pFile = fopen(path, "rb"); if (!pFile) { free(bmpImg); return NULL; } fread(&fileType, sizeof(unsigned short), 1, pFile); if (fileType == 0x4D42) { printf("bmp file! "); fread(&bmpFileHeader, sizeof(ClBitMapFileHeader), 1, pFile); printf("\\\\\\\\\\\\\\\\\\\\\\\n"); printf("bmp文件头信息: "); printf("文件大小:%d ", bmpFileHeader.bfSize); printf("保留字:%d ", bmpFileHeader.bfReserved1); printf("保留字:%d ", bmpFileHeader.bfReserved2); printf("位图数据偏移字节数:%d ", bmpFileHeader.bfOffBits); fread(&bmpInfoHeader, sizeof(ClBitMapInfoHeader), 1, pFile); printf("\\\\\\\\\\\\\\\\\\\\\\\n"); printf("bmp文件信息头 "); printf("结构体长度:%lu ", bmpInfoHeader.biSize); printf("位图宽度:%d ", bmpInfoHeader.biWidth); printf("位图高度:%d ", bmpInfoHeader.biHeight); printf("位图平面数:%d ", bmpInfoHeader.biPlanes); printf("颜色位数:%d ", bmpInfoHeader.biBitCount); printf("压缩方式:%lu ", bmpInfoHeader.biCompression); printf("实际位图数据占用的字节数:%lu ", bmpInfoHeader.biSizeImage); printf("X方向分辨率:%ld ", bmpInfoHeader.biXPelsPerMeter); printf("Y方向分辨率:%ld ", bmpInfoHeader.biYPelsPerMeter); printf("使用的颜色数:%lu ", bmpInfoHeader.biClrUsed); printf("重要颜色数:%lu ", bmpInfoHeader.biClrImportant); printf("\\\\\\\\\\\\\\\\\\\\\\\\n"); if (bmpInfoHeader.biBitCount == 8) { //printf("该文件有调色板,即该位图为非真彩色 "); channels = 1; width = bmpInfoHeader.biWidth; height = bmpInfoHeader.biHeight; offset = (channels*width)%4; if (offset != 0) { offset = 4 - offset; } //bmpImg->mat = kzCreateMat(height, width, 1, 0); bmpImg->width = width; bmpImg->height = height; bmpImg->channels = 1; bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char)*width*height); step = channels*width; quad = (ClRgbQuad*)malloc(sizeof(ClRgbQuad)*256); fread(quad, sizeof(ClRgbQuad), 256, pFile); free(quad); for (i=0; i<height; i++) { for (j=0; j<width; j++) { fread(&pixVal, sizeof(unsigned char), 1, pFile); bmpImg->imageData[(height-1-i)*step+j] = pixVal; } if (offset != 0) { for (j=0; j<offset; j++) { fread(&pixVal, sizeof(unsigned char), 1, pFile); } } } } else if (bmpInfoHeader.biBitCount == 24 ) { printf("该位图为位真彩色 "); bmpInfoHeader.biBitCount = 24; channels = 3; width = bmpInfoHeader.biWidth; height = bmpInfoHeader.biHeight; bmpImg->width = width; bmpImg->height = height; bmpImg->channels = 3; bmpImg->imageData = (unsigned char*)malloc(sizeof(unsigned char)*width*3*height); step = channels*width; offset = (channels*width)%4; if (offset != 0) { offset = 4 - offset; } for (i=0; i<height; i++) { for (j=0; j<width; j++) { for (k=0; k<3; k++) { fread(&pixVal, sizeof(unsigned char), 1, pFile); bmpImg->imageData[(height-1-i)*step+j*3+k] = pixVal; } //kzSetMat(bmpImg->mat, height-1-i, j, kzScalar(pixVal[0], pixVal[1], pixVal[2])); } if (offset != 0) { for (j=0; j<offset; j++) { fread(&pixVal, sizeof(unsigned char), 1, pFile); } } } } } return bmpImg; } bool clSaveImage(const char* path, ClImage* bmpImg) { FILE *pFile; unsigned short fileType; ClBitMapFileHeader bmpFileHeader; ClBitMapInfoHeader bmpInfoHeader; int step; int offset; unsigned char pixVal = '