1. *.bmp文件结构
*.bmp文件和大多数图形文件一样,分为文件描述区(头文件信息)和图象存储区(象素数据)两部分。而头文件信息中又包含了信息区和调色板区两部分,信息区又可以细分为文件信息区和图象信息区两部分。
这里以256色320*200的bmp图象为例。头文件描述区的偏移长度是1078个字节,也就是说图象存储区是从文件偏移1078后开始读取的。在头文件描述区中头信息区的偏移长度是54个字节,也就是说调色板数据区是从54-1078之间的1024字节。在头信息区中文件信息区占14个字节而图象信息区占40字节。
(1) 文件信息区
typedef struct BMP_file
{
unsigned int bfType; //文件类型
unsigned long bfSize; //bmp文件长度
unsigned int Reserved1;
unsigned int Reserved2;
unsigned long bfOffset; //文件描述区长度,16色为118,256色为1078
}bitmapfile;
现在算一下,有3个int,2个long,正好3*2+2*4=14字节
(2) 图象信息区
type struct BMP_info
{
unsigned long biSize;
unsigned long biWidth;
unsigned long biHeight;
unsigned int biPlanes;
unsigned int biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
unsigned long biXplosPerMeter;
unsigned long biYplosPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
}bitmapinfo;
现在算一下,2个int,9个long,正好是2+2*9*4=40字节。
(3)调色板区
typedef struct RGB_BMP_typ
{
unsigned char blue;
unsigned char green;
unsigned char red;
unsigned char reserved;
}RGB_BMP,*RGB_BMP_ptr;
说明:三原色+灰度,共4*256=1024字节。
下面是bmp文件的完整的结构定义:
typedef struct bmp_picture_typ
{
bitmapfile file;
bitmapinfo info;
RGB_BMP palette[256];
char far *buffer;
}bmp_picture, *bmp_picture_ptr;
2. bmp文件的显示
(1)图象存储区的读取
由于bmp图象是从下至上存储的,所以我们不能进行直接顺序读取。详细的说,bmp图象存储区数据是从1078偏移字节开始。文件内第一个图象点实际上是对应图象(320*200)第200行的最左边的第一个点,而从1078开始的320个点则是图象最下面一行对应的点,之后的321个点是图象倒数第二行最左边的第一个点。这样,bmp文件最后一个字节对应的点是第一行最后边的点了。
下面是实现bmp文件图象存储区数据读取到内存的代码:
for(i=info.biHeight-1;i>=0;i--)
{
lseek(fp,1078+(long)(info.biHeight-i-1)*info.biWidth,0);
read(fp,&bmp256->buffer[i*info.biWidth],info.biWidth);
}
(2)调色板的读取
除了图象存储区的存放规则是倒序的以外,bmp文件调色板内容也是以B,G,R,灰度的顺序存放的。所以读取时不要将文件中的三原色中的兰色对应给调色板结构体变量中的红色。
同时,由于三原色只使用64种(6位)色阶,而三原色的存放空间是1字节(8位),所以要将bmp文件三原色的6位数据都放在1个字节的高位,则在读取调色板结构体变量的时候必须进行右移2位。
以下给出读取文件调色板数据的代码
for(i=0;i<256;i++)
{
read(fp,&bmp256->palette.blue,1);
read(fp,&bmp256->palette.green,1);
read(fp,&bmp256->palette.red,1);
read(fp,&bmp256->palette.reserved,1);
bmp256->palette.blue=bmp256->palette.blue>>2;
bmp256->palette.green=bmp256->palette.green>>2;
bmp256->palette.red=bmp256->palette.red>>2;
}
以下给出写入调色板函数
void Set_BMP_Palette_Register(int index,RGB_BMP_ptr color)
{
outp(PALETTE_MASK,0XFF);
outp(PALETTE_REGISTER_WR,index); /*确定调色板序号*/
outp(PALETTE_DATA,color->red); /*设置该序号为红色*/
outp(PALETTE_DATA,color->green); /*设置该序号为绿色*/
outp(PALETTE_DATA,color->blue); /*设置该序号为兰色*/
}
调用调色板的代码:
for(i=0;i<256,i++)
Set_BMP_Palette_Register(i,(RGB_BMP_ptr) &bmp256->palette);
现在我们开始进行完整的读取
(1)申请内存空间
(2)检查头文件信息区
(3)读取调色板数据
(4)读取位图到内存
(5)显示图象
(6)内存释放
(1)申请内存:
由于320*200是64K,而C程序允许用户申请的内存空间也只有64K,为了防止一次申请不到,我们可以分几次申请。使用malloc()函数就可以。
(2)检查头文件信息区:
A:判断是不是bmp文件(若不是,则无法显示)
B:文件是否为压缩格式(若是,则无法处理)
C:文件是否为256色
以下给出读取头文件信息到内存的代码:
read(fp,&bmp256->file,sizeof(bitmapfile));
read(fp,&bmp256->info,sizeof(bitmapinfo));
以下是检测bmp文件格式的函数:
void Check_Bmp(bmp_picture_ptr bmp_ptr)
{
if(bmp_ptr->file.bfType!=0x4d42) /*检测是不是bmp文件*/
{
printf("Not a BMP file! ");
exit(1);
}
if(bmp_ptr->info.biCompression!=0) /*检测是不是压缩文件,1表示压缩,0表示没压缩*/
{
printf("Can not display a compressed bmp file! ");
exit(1);
}
if(bmp_ptr->info.biBitCount!=8) /*检测是不是256色*/
{
printf("Not a index 256color bmp file! ");
exit(1);
}
}
(3)和(4)前面有介绍,这儿省略。
(5)显示图象
假设bmp文件的调色板区已写入计算机调色板,bmp文件图象存储区也已写到内存,以下给出具体的显示到屏幕的函数
void BMP_Show_Buffer2(bmp_picture_ptr image)
{
memcpy((char far *)video_buffer,(char far *)image->buffer,(unsigned int)info->biWidth*info->biHight/2)
}
(6)释放内存
void BMP_Delete(bmp_picture_ptr image)
{
free(image->buffer);
}
好了,经过以上几步,基本上你的bmp文件就能在C中显示了。当然前提是你使用256色的图形驱动。也就是你的int gdrive=DETECT应该改为int gdrive=6;如果你仅仅显示16色的文件,就没有必要了。