做编程的网站有哪些内容,河北邯郸中考成绩查询网站,网站群内容管理系统的设计与实现,网页导航视频网站在线制作教程转自#xff1a;https://www.cnblogs.com/wangguchangqing/p/5417444.html
设备无关位图#xff08;Device Independent Bitmap#xff09;是可以保存在磁盘的位图文件#xff0c;可以从磁盘读取到内存或者从内存保存到磁盘上。它的文件结构是标准化的#xff0c;可以在W…转自https://www.cnblogs.com/wangguchangqing/p/5417444.html
设备无关位图Device Independent Bitmap是可以保存在磁盘的位图文件可以从磁盘读取到内存或者从内存保存到磁盘上。它的文件结构是标准化的可以在Windows/Linux/Unix等平台上显示相同的效果。本文主要介绍了
如果将位图文件从磁盘读到内存中在内存中对位图文件进行操作后如何将位图保存到磁盘
1 读取位图到内存中
1.1 DIB文件结构
要将位图文件.bmp从磁盘读取到内存首先要了解其文件结构。DIB的文件组成有以下4个部分
文件表头主要包含了文件的类型必须是BM文件的大小所占用的字节数和位图的像素矩阵的便宜量。信息表头包含了两部分内容位图的相关信息位图的大小、位深度、位面数、压缩和编码等和指向RGB颜色表调色盘的指针。RGB色彩对照表也就是调色板不一定会有。16位及以上直接使用RGB通道表示颜色一般不需要调色板。位图的像素信息矩阵表示具体的像素。148位颜色保存的是调色板的索引具体的颜色根据索引在调色板中查找16位及其以上不使用调色板直接使用RGB组成像素颜色。
1.2 在Windows下DIB的内存结构
要将DIB数据读取到内存就需要在内存中分配相应的空间。Windows提供了几种结构体结构体中的字段对应着DIB文件的各个信息值具体如下 引用自 http://blog.csdn.net/wenzhou1219/article/details/26162869 将DIB读取到内存只需要将磁盘数据填充到相应到结构体即可。在磁盘上DIB需要连续的结构存储在内存中则不需要连续的存储空间可以分段将数据读取到相应的结构体中。 读取DIB到内存的具体步骤
将文件头信息读取到BITMAPFILEHEADER结构体中。将位图头信息读取到BITMAPINFOHEADER结构体中。如果有调色板则将其信息读取到RGBQUAD中。读取位图像素信息到像素矩阵中。
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图像的宽度。biHeightDIB的高以像素为单位。 如果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 使用游程长度编码 RLErun-length encodeBI_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(vvs.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是每个像素占用的位数。其具体的计算方法如下
首先计算一行所占用的字节数 bytesPerLinebytesPerLine ((m_dibInfo-bmiHeader.biWidth * m_dibInfo-bmiHeader.biBitCount 31) / 32 ) * 4将bytesPerLine乘以图像的高bytesPerLine * m_dibInfo-bmiHeader.biHeight
1.5 总结
本文主要对DIB的文件结构以及其对应的内存中的结构体做了一个总结并对一个具体的DIB16进制数据结构进行分析最后实现了如何将一个DIB数据读取到内存中。
一直对位图结构不是很了解趁着在公司实习没有具体的工作安排对DIB的结构作了个总结。至于如何将处理后的位图数据写回磁盘文件在知道位图结构的情况下只需要填充相应的结构字段就行了需要注意的还是位图的宽需要是4的倍数不是的话要用0补齐。本来想写个DEMO的但是太累明天再说吧。