DIB位图(Bitmap)的读取和保存
2016-09-30 21:15
585 查看
设备无关位图(Device Independent Bitmap)是可以保存在磁盘的位图文件,可以从磁盘读取到内存或者从内存保存到磁盘上。它的文件结构是标准化的,可以在Windows/Linux/Unix等平台上显示相同的效果。本文主要介绍了
1. 如果将位图文件从磁盘读到内存中
2. 在内存中对位图文件进行操作后,如何将位图保存到磁盘
1. 文件表头,主要包含了文件的类型(必须是BM),文件的大小(所占用的字节数)和位图的像素矩阵的便宜量。
2. 信息表头,包含了两部分内容:位图的相关信息(位图的大小、位深度、位面数、压缩和编码等)和指向RGB颜色表(调色盘)的指针。
3. RGB色彩对照表,也就是调色板,不一定会有。16位及以上直接使用RGB通道表示颜色,一般不需要调色板。
4. 位图的像素信息矩阵,表示具体的像素。1,4,8位颜色,保存的是调色板的索引,具体的颜色根据索引在调色板中查找;16位及其以上不使用调色板,直接使用RGB组成像素颜色。
引用自 http://blog.csdn.net/wenzhou1219/article/details/26162869
将DIB读取到内存只需要将磁盘数据填充到相应到结构体即可。在磁盘上DIB需要连续的结构存储,在内存中则不需要连续的存储空间,可以分段将数据读取到相应的结构体中。
读取DIB到内存的具体步骤:
1. 将文件头信息读取到BITMAPFILEHEADER结构体中。
2. 将位图头信息读取到BITMAPINFOHEADER结构体中。
3. 如果有调色板,则将其信息读取到RGBQUAD中。
4. 读取位图像素信息到像素矩阵中。
代表文件头信息的结构体BITMAPFILEHEADER的声明如下:
其中,
* bfType是文件类型,该字段必须是BM,如果不是则说明该文件不是DIB。
* bfSize是位图文件的大小(字节数)
* bfReserved1和bfReserved2 是保留字段
* bfOffBits 从BITMAPFILEHEADER的起始位置到位图像素的字节偏移量。
BITMAPINFO
在上面提到,位图信息和位图的调色板是存放在同一个结构体中的,该结构体就是BITMAPINFO,其声明如下
bmiHeader是位图头信息
bmiColors是调色板
BITMAPINFOHEADER
位图的头信息结构BITMAPINFOHEADER,该结构包含了DIB的尺寸和颜色格式等信息,声明如下
其中,
* biSize是该结构体所占用的字节说
* biWidth DIB的宽(以像素为单位),如果biCompression是BI_JPEG或者BI_PNG,则biWidth是解压缩后JPEG或者PNG图像的宽度。
* biHeight,DIB的高(以像素为单位)。
* 如果biHeight是正的,则DIB的像素是按照从下往上(bottom-up,也就是像素数组的第一行保存的实际是DIB的最后一行像素值),图像源点在左下角。
* 如果biHeight是负的,则DIB的像素是按照从上往下保存的(up-bottom),而且像素的数据是不能被压缩的其biCompression必须是BI_RGB或者BI_FIELDS
* 如果biCompression是BI_JPEG或者BI_PNG,则biHeight是解压缩后JPEG或者PNG的高
* biPlanes 目标设备的平面数,总是设为1.
* biBitCount,每个像素所占用的位数。0,表示JPEG或者PNG指定每个像素所占用的位数。还可以是1,4,8,16,24,32。
* biCompression,数据的压缩方法(up-down的DIB不能被压缩),可以是以下值:
* BI_RGB / BI_FIELDS未被压缩
* BI_RLE4 / BI_RLE8 使用游程长度编码 (RLE,run-length encode)
* BI_JPEG / BI_PNG 指示该图像是JPEG或者PNG图像。
* biSizeImage 图像的字节数,对于BI_RGB的DIB其值为0.
* biXPelsPerMeter / biYPelsPerMeter 显示该DIB的目标设备所需的分辨率(单位是像素每米)
* biClrUsed DIB实际使用调色板中的颜色个数,通常为0表示使用调色板中的全部颜色。
* biClrImportant 显示DIB所必须的颜色个数,通常为0表示全部颜色都是必须的。
详细的解释参见 https://msdn.microsoft.com/en-us/library/dd183376(v=vs.85).aspx
RGBQUAD
注意,其存储顺序是BGR。
是一幅宽和高都是32的位图(放大后,可以看到表示像素的一个个方块),其有16种颜色。下面是该图像的16进制数据
* 首先是文件的头信息 BITMAPFILEINFO 共有14个字节(0x00-0x0D),其起始的两个字节为0x4d42(大端存储,高位在前)表示文件类型为BM,最后4个字节 0x0076是位图的像素信息相对于文件头的偏移量,也就是从0x0076为图像的像素信息。
* 下面是位图的头信息 BITMAPINFOHEADER共有40个字节(0x0E-0x35),起始的4个字节是0x0028就是该结构体的大小,紧接着的4个字节是图像的宽0x0020
* 跟着是图像的调色板,0x36 - 0x75。调色板共有16种颜色,也就是说有调色板中有16个RGBQUAD,其大小为16 * 4.
* 最后是位图的数据 0x76-0x275
知道了DIB的文件结构后,读取其到内存还是挺简单的,需要注意的是DIB的像素数组的大小。由于DIB的宽度需要时4的倍数,不是的话需要填充0将其凑成4的倍数,所以其像素数组的大小不能简单的width * height * biBitCount / 8,其中biBitCount是每个像素占用的位数。其具体的计算方法如下
1. 首先计算一行所占用的字节数 bytesPerLine
2. 将bytesPerLine乘以图像的高
一直对位图结构不是很了解,趁着在公司实习没有具体的工作安排,对DIB的结构作了个总结。至于如何将处理后的位图数据写回磁盘文件,在知道位图结构的情况下,只需要填充相应的结构字段就行了,需要注意的还是位图的宽需要是4的倍数,不是的话要用0补齐。
1. 如果将位图文件从磁盘读到内存中
2. 在内存中对位图文件进行操作后,如何将位图保存到磁盘
1 读取位图到内存中
1.1 DIB文件结构
要将位图文件(.bmp)从磁盘读取到内存,首先要了解其文件结构。DIB的文件组成有以下4个部分:1. 文件表头,主要包含了文件的类型(必须是BM),文件的大小(所占用的字节数)和位图的像素矩阵的便宜量。
2. 信息表头,包含了两部分内容:位图的相关信息(位图的大小、位深度、位面数、压缩和编码等)和指向RGB颜色表(调色盘)的指针。
3. RGB色彩对照表,也就是调色板,不一定会有。16位及以上直接使用RGB通道表示颜色,一般不需要调色板。
4. 位图的像素信息矩阵,表示具体的像素。1,4,8位颜色,保存的是调色板的索引,具体的颜色根据索引在调色板中查找;16位及其以上不使用调色板,直接使用RGB组成像素颜色。
1.2 在Windows下DIB的内存结构
要将DIB数据读取到内存,就需要在内存中分配相应的空间。Windows提供了几种结构体,结构体中的字段对应着DIB文件的各个信息值,具体如下引用自 http://blog.csdn.net/wenzhou1219/article/details/26162869
将DIB读取到内存只需要将磁盘数据填充到相应到结构体即可。在磁盘上DIB需要连续的结构存储,在内存中则不需要连续的存储空间,可以分段将数据读取到相应的结构体中。
读取DIB到内存的具体步骤:
1. 将文件头信息读取到BITMAPFILEHEADER结构体中。
2. 将位图头信息读取到BITMAPINFOHEADER结构体中。
3. 如果有调色板,则将其信息读取到RGBQUAD中。
4. 读取位图像素信息到像素矩阵中。
fp.Read(&bmfileHeader, sizeof(BITMAPFILEHEADER)); // 读取BMP文件头 ... //读取文件信息头 ret = fp.Read(&bmHeader, sizeof(BITMAPINFOHEADER)); ... fp.Read(m_dibBits, GetBodySize()); //读取像素信息
1.3 结构体各字段信息
BITMAPFILEHEADER代表文件头信息的结构体BITMAPFILEHEADER的声明如下:
typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER
其中,
* bfType是文件类型,该字段必须是BM,如果不是则说明该文件不是DIB。
* bfSize是位图文件的大小(字节数)
* bfReserved1和bfReserved2 是保留字段
* bfOffBits 从BITMAPFILEHEADER的起始位置到位图像素的字节偏移量。
BITMAPINFO
在上面提到,位图信息和位图的调色板是存放在同一个结构体中的,该结构体就是BITMAPINFO,其声明如下
typedef struct tagBITMAPINFO { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[1]; } BITMAPINFO, *PBITMAPINFO;
bmiHeader是位图头信息
bmiColors是调色板
BITMAPINFOHEADER
位图的头信息结构BITMAPINFOHEADER,该结构包含了DIB的尺寸和颜色格式等信息,声明如下
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
其中,
* biSize是该结构体所占用的字节说
* biWidth DIB的宽(以像素为单位),如果biCompression是BI_JPEG或者BI_PNG,则biWidth是解压缩后JPEG或者PNG图像的宽度。
* biHeight,DIB的高(以像素为单位)。
* 如果biHeight是正的,则DIB的像素是按照从下往上(bottom-up,也就是像素数组的第一行保存的实际是DIB的最后一行像素值),图像源点在左下角。
* 如果biHeight是负的,则DIB的像素是按照从上往下保存的(up-bottom),而且像素的数据是不能被压缩的其biCompression必须是BI_RGB或者BI_FIELDS
* 如果biCompression是BI_JPEG或者BI_PNG,则biHeight是解压缩后JPEG或者PNG的高
* biPlanes 目标设备的平面数,总是设为1.
* biBitCount,每个像素所占用的位数。0,表示JPEG或者PNG指定每个像素所占用的位数。还可以是1,4,8,16,24,32。
* biCompression,数据的压缩方法(up-down的DIB不能被压缩),可以是以下值:
* BI_RGB / BI_FIELDS未被压缩
* BI_RLE4 / BI_RLE8 使用游程长度编码 (RLE,run-length encode)
* BI_JPEG / BI_PNG 指示该图像是JPEG或者PNG图像。
* biSizeImage 图像的字节数,对于BI_RGB的DIB其值为0.
* biXPelsPerMeter / biYPelsPerMeter 显示该DIB的目标设备所需的分辨率(单位是像素每米)
* biClrUsed DIB实际使用调色板中的颜色个数,通常为0表示使用调色板中的全部颜色。
* biClrImportant 显示DIB所必须的颜色个数,通常为0表示全部颜色都是必须的。
详细的解释参见 https://msdn.microsoft.com/en-us/library/dd183376(v=vs.85).aspx
RGBQUAD
typedef struct tagRGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; } RGBQUAD;
注意,其存储顺序是BGR。
1.3 DIB的结构实例
是一幅宽和高都是32的位图(放大后,可以看到表示像素的一个个方块),其有16种颜色。下面是该图像的16进制数据
* 首先是文件的头信息 BITMAPFILEINFO 共有14个字节(0x00-0x0D),其起始的两个字节为0x4d42(大端存储,高位在前)表示文件类型为BM,最后4个字节 0x0076是位图的像素信息相对于文件头的偏移量,也就是从0x0076为图像的像素信息。
* 下面是位图的头信息 BITMAPINFOHEADER共有40个字节(0x0E-0x35),起始的4个字节是0x0028就是该结构体的大小,紧接着的4个字节是图像的宽0x0020
* 跟着是图像的调色板,0x36 - 0x75。调色板共有16种颜色,也就是说有调色板中有16个RGBQUAD,其大小为16 * 4.
* 最后是位图的数据 0x76-0x275
1.4 读取
CFile fp(dibName, CFile::modeRead | CFile::typeBinary); BITMAPFILEHEADER bmfileHeader; BITMAPINFOHEADER bmHeader; ULONGLONG headpos; int paletteSize = 0; int ret, cbHeaderSize; headpos = fp.GetPosition(); // 获取文件指针的位置 ret = fp.Read(&bmfileHeader, sizeof(BITMAPFILEHEADER)); // 读取BMP文件头 if (bmfileHeader.bfType != 0x4d42) //判断文件类型标头是不是x4d42,表示该文件为BMP类型文件 { AfxMessageBox(_T("文件不是bmp!")); return; } //读取文件信息头 ret = fp.Read(&bmHeader, sizeof(BITMAPINFOHEADER)); // 计算RGBQUAD的大小 switch (bmHeader.biBitCount) { case 1: paletteSize = 2; break; case 4: paletteSize = 16; break; case 8: paletteSize = 256; break; } // 为BITMAPINFO分配存储空间 cbHeaderSize = sizeof(BITMAPINFOHEADER)+paletteSize * sizeof(RGBQUAD); m_dibInfo = (BITMAPINFO*) new char[cbHeaderSize]; m_dibInfo->bmiHeader = bmHeader; if (paletteSize) //是否有调色板 { ret = fp.Read(&(m_dibInfo->bmiColors[0]), paletteSize * sizeof(RGBQUAD)); if (ret != int(paletteSize * sizeof(RGBQUAD) ) ) { delete[] m_dibInfo; m_dibInfo = NULL; return; } } //为像素数组分配存储空间,大小由GetBodySize决定 m_dibBits = (void*) new char[GetBodySize()]; fp.Seek(headpos + bmfileHeader.bfOffBits, CFile::begin); // 将文件指针移动到DIB像素数组 ret = fp.Read(m_dibBits, GetBodySize()); if (ret != int(GetBodySize())) { delete[] m_dibInfo; delete[] m_dibBits; m_dibInfo = NULL; m_dibBits = NULL; } fp.Close();
知道了DIB的文件结构后,读取其到内存还是挺简单的,需要注意的是DIB的像素数组的大小。由于DIB的宽度需要时4的倍数,不是的话需要填充0将其凑成4的倍数,所以其像素数组的大小不能简单的width * height * biBitCount / 8,其中biBitCount是每个像素占用的位数。其具体的计算方法如下
1. 首先计算一行所占用的字节数 bytesPerLine
bytesPerLine = ((m_dibInfo->bmiHeader.biWidth * m_dibInfo->bmiHeader.biBitCount + 31) / 32 ) * 4
2. 将bytesPerLine乘以图像的高
bytesPerLine * m_dibInfo->bmiHeader.biHeight
1.5 总结
本文主要对DIB的文件结构以及其对应的内存中的结构体做了一个总结,并对一个具体的DIB16进制数据结构进行分析,最后实现了如何将一个DIB数据读取到内存中。一直对位图结构不是很了解,趁着在公司实习没有具体的工作安排,对DIB的结构作了个总结。至于如何将处理后的位图数据写回磁盘文件,在知道位图结构的情况下,只需要填充相应的结构字段就行了,需要注意的还是位图的宽需要是4的倍数,不是的话要用0补齐。
相关文章推荐
- DIB位图(Bitmap)的读取和保存
- DIB位图文件的格式、读取、保存和显示
- DIB位图文件的格式、读取、保存和显示(转载)
- DIB位图文件的格式、读取、保存和显示
- DIB位图文件的格式、读取、保存和显示
- Bitmap位图文件读取、保存、屏幕截图
- Bitmap位图文件读取、保存、屏幕截图
- DIB(Device-Independent Bitmap,即设备无关位图)小知识
- 位图BitMap图像的读取与存储
- 如何将OpenGL中的场景保存为Bitmap位图文件
- win10 uwp 读取保存WriteableBitmap 、BitmapImage
- 读取到的bitmap,转成buffer并保存
- DIB(Device-Independent Bitmap) 设备无关位图
- 读取Bitmap(设备无关位图)数据的经典C代码
- 用到Bitmap(位图,显示图片)、compress(压缩并保存图片)、自定义更换背景图的范例
- 位图BitMap图像的读取与存储
- win10 uwp 读取保存WriteableBitmap 、BitmapImage
- C#读取Win32标准DLL文件中的Bitmap(位图)
- WINAPI 读取位图Bitmap
- Android数据存储:获取网络图片把图片保存到SD卡中并从SDk卡中读取(通过Bitmap方法)