BMP格式以及用纯C实现Load和Save
来源:互联网 发布:ios更新无法连接网络 编辑:程序博客网 时间:2024/05/09 03:14
BMP格式以及用纯C实现Load和Save
1 存储结构
BMP文件存储结构的格式可以在Windows中的WINGDI.h文件中找到定义。
BMP文件总体上由4部分组成,分别是位图文件头、位图信息头、调色板和图像数据,如表5-1所示。
BMP文件的组成结构
位图文件头(bitmap-file header)
位图信息头(bitmap-information header)
彩色表/调色板(color table)
位图数据(bitmap-data)
下面来详细看一下每个组成部分的细节。
1.1 位图文件头(bitmap-file header)
位图文件头(bitmap-file header)包含了图像类型、图像大小、图像数据存放地址和两个保留未使用的字段。
打开WINGDI.h文件,搜索"BITMAPFILEHEADER"就可以定位到BMP文件的位图文件头的数据结构定义。
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
tagBITMAPFILEHEADER结构
字 段 名
大小(单位:字节)
描 述
bfType
2
位图类别,根据不同的操作
系统而不同,在Windows
中,此字段的值总为'BM'
bfSize
4
BMP图像文件的大小
bfReserved1
2
总为0
bfReserved2
2
总为0
bfOffBits
4
BMP图像数据的地址
1.2 位图信息头(bitmap-information header)
位图信息头(bitmap-information header)包含了位图信息头的大小、图像的宽高、图像的色深、压缩说明图像数据的大小和其他一些参数。
打开WINGDI.h文件,搜索"tagBITMAPINFOHEADER"就可以定位到BMP文件的位图信息头的数据结构定义。
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;
tagBITMAPFILEHEADER结构
字 段 名
大小
(单位:
字节)
描 述
biSize
4
本结构的大小,根据不同的操作系统而不同,在Windows中,此字段的值总为28h字节=40字节
biWidth
4
BMP图像的宽度,单位像素
biHeight
4
总为0
biPlanes
2
总为0
biBitCount
2
BMP图像的色深,即一个像素用多少位表示,常见有1、4、8、16、24和32,分别对应单色、16色、256色、16位高彩色、24位真彩色和32位增强型真彩色
biCompression
4
压缩方式,0表示不压缩,1表示RLE8压缩,2表示RLE4压缩,3表示每个像素值由指定的掩码决定
biSizeImage
4
BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足
biXPelsPerMeter
4
水平分辨率,单位像素/m
biYPelsPerMeter
4
垂直分辨率,单位像素/m
biClrUsed
4
BMP图像使用的颜色,0表示使用全部颜色,对于256色位图来说,此值为100h=256
biClrImportant
4
重要的颜色数,此值为0时所有颜色都重要,对于使用调色板的BMP图像来说,当显卡不能够显示所有颜色时,此值将辅助驱动程序显示颜色
2 BMP种类
按照单个像素占用的位数,有1,4,8,16,24,32几种
常用的几种说明如下:
(1)8位,灰度图,像素值范围[0,255]
(2)16位
biBitCount=16 表示位图最多有216种颜色。每个色素用16位(2个字节)表示。这种格式叫作高彩色,或叫增强型16位色,或64K色。它的情况比较复杂,当biCompression成员的值是BI_RGB时,它没有调色板。16位中,最低的5位表示蓝色分量,中间的5位表示绿色分量,高的5位表示红色分量,一共占用了15位,最高的一位保留,设为0。这种格式也被称作555 16位位图。如果biCompression成员的值是BI_BITFIELDS,那么情况就复杂了,首先是原来调色板的位置被三个DWORD变量占据,称为红、绿、蓝掩码。分别用于描述红、绿、蓝分量在16位中所占的位置。在Windows 95(或98)中,系统可接受两种格式的位域:555和565,在555格式下,红、绿、蓝的掩码分别是:0x7C00、0x03E0、0x001F,而在565格式下,它们则分别为:0xF800、0x07E0、0x001F。你在读取一个像素之后,可以分别用掩码"与"上像素值,从而提取出想要的颜色分量(当然还要再经过适当的左右移操作)。在NT系统中,则没有格式限制,只不过要求掩码之间不能有重叠。(注:这种格式的图像使用起来是比较麻烦的,不过因为它的显示效果接近于真彩,而图像数据又比真彩图像小的多,所以,它更多的被用于游戏软件)。
(3)24位,一个通道占用一个字节
(4)32位,32位的BMP一个象素占3个字节,还有8位的alpha
3 C语言实现Load和Save
3.1 从磁盘读入BMP文件代码
// 自定义结构体
typedef struct s_MIImage
{
byte* pData; // 图像数据
int nImgW; // 图像宽度
int nImgH; // 图像高度
int nBits; // 1,4,8,24,32
BOOL bInit; // 是否已进行初始化,TRUE:已初始化。不能直接用指针来判断pData是否已初始化,因为pData的初始值不为NULL
// 也不能用(!bInit)来判断是否初始化,必须用(TRUE!=bInit)
}s_MIImage;
int MILoadBMP(OUT s_MIImage* pMIImg, char* pImgPath)
{
BITMAPFILEHEADER bf; //BMP文件头结构体
BITMAPINFOHEADER bi; //BMP信息头结构体
FILE* fp; //指向文件的指针
RGBQUAD *ipRGB = NULL;
DWORD LineBytes; // 每行的字节数
DWORD ImgBytesSize; // 图像总字节数
DWORD NumColors;
int i;
// 先释放图像空间
if (pMIImg->bInit == TRUE)
{
// 不能用FREE,因为pMIImg->pData的初始值不为NULL
free(pMIImg->pData);
}
pMIImg->pData = NULL;
// 打开文件
fp=fopen(pImgPath,"rb");
if(fp == NULL)
{
return -1;
}
//读取信息头、文件头
fread(&bf,sizeof(BITMAPFILEHEADER),1,fp); //把指针fp所指向的文件的头信息写入bf(地址)
fread(&bi,sizeof(BITMAPINFOHEADER),1,fp);
// 计算行字节数和总字节数
LineBytes=(DWORD)WIDTHBYTES(bi.biWidth*bi.biBitCount); //计算位图的实际宽度并确保它为32的倍数
ImgBytesSize=(DWORD)LineBytes*bi.biHeight;
if (bi.biClrUsed != 0 )
{
NumColors=(DWORD)bi.biClrUsed;
}
else
{
switch (bi.biBitCount)
{
case 1:
NumColors=2;
break;
case 4:
NumColors=16;
break;
case 8:
NumColors=256;
break;
case 24:
NumColors=0;
break;
case 32:
NumColors=0;
break;
}
}
//分配调色板内存
if ( (bi.biBitCount!=24) && (bi.biBitCount!=32) )
{
ipRGB=(RGBQUAD *)malloc(NumColors*sizeof(RGBQUAD));
fread(ipRGB,sizeof(RGBQUAD),NumColors,fp);
}
// 初始化图像
pMIImg->pData = (byte*)malloc(sizeof(byte) * ImgBytesSize); // 分配图像内存, 外部释放
if (!pMIImg->pData)
{
FREE(ipRGB);
return -1;
}
pMIImg->nBits = bi.biBitCount;
pMIImg->nImgW = bi.biWidth;
pMIImg->nImgH = bi.biHeight;
pMIImg->bInit = TRUE;
if ( (bi.biBitCount==32) || (bi.biBitCount==24) )
{
fseek(fp, 4, SEEK_CUR); //sizeof(RGBQUAD)
for (i=pMIImg->nImgH-1; i>=0; --i)
{
fread(pMIImg->pData+i*LineBytes, 1, LineBytes, fp);
}
}
else
{
for (i=pMIImg->nImgH-1; i>=0; --i)
{
fread(pMIImg->pData+i*LineBytes, 1, LineBytes, fp);
}
}
fclose(fp);
fp = NULL;
FREE(ipRGB);
return 0;
}
3.2 将内存中的图像数组写入磁盘BMP
int MISaveBMP(OUT char* pImgPath, s_MIImage* pMIImg)
{
BITMAPFILEHEADER bf; //BMP文件头结构体
BITMAPINFOHEADER bi; //BMP信息头结构体
RGBQUAD *ipRGB = NULL;
DWORD NumColors;
int i;
DWORD nLineBytes = (DWORD)WIDTHBYTES(pMIImg->nImgW * pMIImg->nBits);
FILE* fp = NULL;
if ( (!pImgPath) || (!pImgPath) || (TRUE!=pMIImg->bInit))
{
return -1;
}
// 写入另一个文件
fp = fopen(pImgPath, "wb");
memset(&bf, 0, sizeof(bf));
*((char*)&(bf.bfType)) = 'B';
*(((char*)&(bf.bfType))+1) = 'M';
bf.bfReserved1 = 0;
bf.bfReserved2 = 0;
bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bf.bfSize = pMIImg->nImgW * pMIImg->nImgH * (pMIImg->nBits>>3) + bf.bfOffBits;
memset(&bi, 0, sizeof(bi));
bi.biSize = sizeof(bi);
bi.biBitCount = pMIImg->nBits;
bi.biWidth = pMIImg->nImgW;
bi.biHeight = pMIImg->nImgH;
bi.biCompression = BI_RGB;
bi.biPlanes = 1;
bi.biClrUsed = 0;
fwrite(&bf,sizeof(BITMAPFILEHEADER),1,fp);
fwrite(&bi,sizeof(BITMAPINFOHEADER),1,fp);
if (bi.biClrUsed != 0 )
{
NumColors=(DWORD)bi.biClrUsed;
}
else
{
switch (bi.biBitCount)
{
case 1:
NumColors=2;
break;
case 4:
NumColors=16;
break;
case 8:
NumColors=256;
break;
case 24:
NumColors=0;
break;
case 32:
NumColors=0;
break;
}
}
//分配调色板内存
if ( (bi.biBitCount!=24) && (bi.biBitCount!=32) )
{
ipRGB=(RGBQUAD *)malloc(NumColors*sizeof(RGBQUAD));
fread(ipRGB,sizeof(RGBQUAD),NumColors,fp);
}
if ( (bi.biBitCount!=24) && (bi.biBitCount!=32) )
{
fwrite(ipRGB,sizeof(RGBQUAD),NumColors,fp);
for (i=(bi.biHeight)-1 ;i>=0;i--)
{
fwrite(pMIImg->pData+nLineBytes*i, sizeof(byte), nLineBytes, fp);
}
}
else
{
for (i=(bi.biHeight)-1 ;i>=0;i--)
{
fwrite(pMIImg->pData+nLineBytes*i, sizeof(byte), nLineBytes, fp);
}
}
fclose(fp);
fp = NULL;
FREE(ipRGB);
return 0;
}
[注:此文档非原创,文字资料均收集于互联网,代码本人有改动]
- BMP格式以及用纯C实现Load和Save
- BMP格式以及用纯C实现Load和Save
- 数据文件格式(使用save和load命令)
- save和load
- 位图文件(BMP)格式以及Linux下C程序实现
- 位图文件(BMP)格式以及Linux下C程序实现
- 位图文件(BMP)格式以及Linux下C程序实现
- 位图文件(BMP)格式以及Linux下C程序实现
- 位图文件(BMP)格式以及Linux下C程序实现
- 位图文件(BMP)格式以及Linux下C程序实现
- BMP图像生成 纯C
- matlab中save和load
- matlab 的load和save
- numpy.load和numpy.save
- Tensorflow的save和load
- 位图文件(BMP)格式分析以及程序实现
- 位图文件(BMP)格式分析以及程序实现
- 位图文件(BMP)格式分析以及程序实现
- Internet 和 Intranet
- jquery 的 bind(click)
- web.xml xsd 2.4 2.5
- android edittext弹出输入法的窗口问题
- 通过匿名管道实现进程间通信
- BMP格式以及用纯C实现Load和Save
- OIM11 Ldap Sync & OAM & BI Publisher配置文档
- 进制,原码,反码,补码
- 面向对象分析过程案例实战
- MySQL性能优化的最佳20+条经验
- android ANR
- 英语:真正有效的英语学习心得,把英语当母语学习!(转载)
- 一、Oracle Access Manager 11g安装指南
- Oracle备份与恢复案例