DIB位图(Bitmap)的读取和保存
設備無關位圖(Device Independent Bitmap)是可以保存在磁盤的位圖文件,可以從磁盤讀取到內(nèi)存或者從內(nèi)存保存到磁盤上。它的文件結構是標準化的,可以在Windows/Linux/Unix等平臺上顯示相同的效果。本文主要介紹了
1 讀取位圖到內(nèi)存中
1.1 DIB文件結構
要將位圖文件(.bmp)從磁盤讀取到內(nèi)存,首先要了解其文件結構。DIB的文件組成有以下4個部分:
1.2 在Windows下DIB的內(nèi)存結構
要將DIB數(shù)據(jù)讀取到內(nèi)存,就需要在內(nèi)存中分配相應的空間。Windows提供了幾種結構體,結構體中的字段對應著DIB文件的各個信息值,具體如下
引用自 http://blog.csdn.net/wenzhou1219/article/details/26162869
將DIB讀取到內(nèi)存只需要將磁盤數(shù)據(jù)填充到相應到結構體即可。在磁盤上DIB需要連續(xù)的結構存儲,在內(nèi)存中則不需要連續(xù)的存儲空間,可以分段將數(shù)據(jù)讀取到相應的結構體中。
讀取DIB到內(nèi)存的具體步驟:
1.3 結構體各字段信息
BITMAPFILEHEADER
代表文件頭信息的結構體BITMAPFILEHEADER的聲明如下:
typedef struct tagBITMAPFILEHEADER {WORD bfType;DWORD bfSize;WORD bfReserved1;WORD bfReserved2;DWORD bfOffBits; } BITMAPFILEHEADER其中,
- bfType是文件類型,該字段必須是BM,如果不是則說明該文件不是DIB。
- bfSize是位圖文件的大小(字節(jié)數(shù))
- bfReserved1和bfReserved2 是保留字段
bfOffBits 從BITMAPFILEHEADER的起始位置到位圖像素的字節(jié)偏移量。
BITMAPINFO
在上面提到,位圖信息和位圖的調(diào)色板是存放在同一個結構體中的,該結構體就是BITMAPINFO,其聲明如下
bmiHeader是位圖頭信息
bmiColors是調(diào)色板
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是該結構體所占用的字節(jié)說
- biWidth DIB的寬(以像素為單位),如果biCompression是BI_JPEG或者BI_PNG,則biWidth是解壓縮后JPEG或者PNG圖像的寬度。
- biHeight,DIB的高(以像素為單位)。
- 如果biHeight是正的,則DIB的像素是按照從下往上(bottom-up,也就是像素數(shù)組的第一行保存的實際是DIB的最后一行像素值),圖像源點在左下角。
- 如果biHeight是負的,則DIB的像素是按照從上往下保存的(up-bottom),而且像素的數(shù)據(jù)是不能被壓縮的其biCompression必須是BI_RGB或者BI_FIELDS
- 如果biCompression是BI_JPEG或者BI_PNG,則biHeight是解壓縮后JPEG或者PNG的高
- biPlanes 目標設備的平面數(shù),總是設為1.
- biBitCount,每個像素所占用的位數(shù)。0,表示JPEG或者PNG指定每個像素所占用的位數(shù)。還可以是1,4,8,16,24,32。
- biCompression,數(shù)據(jù)的壓縮方法(up-down的DIB不能被壓縮),可以是以下值:
- BI_RGB / BI_FIELDS未被壓縮
- BI_RLE4 / BI_RLE8 使用游程長度編碼 (RLE,run-length encode)
- BI_JPEG / BI_PNG 指示該圖像是JPEG或者PNG圖像。
- biSizeImage 圖像的字節(jié)數(shù),對于BI_RGB的DIB其值為0.
- biXPelsPerMeter / biYPelsPerMeter 顯示該DIB的目標設備所需的分辨率(單位是像素每米)
- biClrUsed DIB實際使用調(diào)色板中的顏色個數(shù),通常為0表示使用調(diào)色板中的全部顏色。
biClrImportant 顯示DIB所必須的顏色個數(shù),通常為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進制數(shù)據(jù)
- 首先是文件的頭信息 BITMAPFILEINFO 共有14個字節(jié)(0x00-0x0D),其起始的兩個字節(jié)為0x4d42(大端存儲,高位在前)表示文件類型為BM,最后4個字節(jié) 0x0076是位圖的像素信息相對于文件頭的偏移量,也就是從0x0076為圖像的像素信息。
- 下面是位圖的頭信息 BITMAPINFOHEADER共有40個字節(jié)(0x0E-0x35),起始的4個字節(jié)是0x0028就是該結構體的大小,緊接著的4個字節(jié)是圖像的寬0x0020
- 跟著是圖像的調(diào)色板,0x36 - 0x75。調(diào)色板共有16種顏色,也就是說有調(diào)色板中有16個RGBQUAD,其大小為16 * 4.
- 最后是位圖的數(shù)據(jù) 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) //是否有調(diào)色板{ret = fp.Read(&(m_dibInfo->bmiColors[0]), paletteSize * sizeof(RGBQUAD));if (ret != int(paletteSize * sizeof(RGBQUAD) ) ){delete[] m_dibInfo;m_dibInfo = NULL;return;}}//為像素數(shù)組分配存儲空間,大小由GetBodySize決定m_dibBits = (void*) new char[GetBodySize()];fp.Seek(headpos + bmfileHeader.bfOffBits, CFile::begin); // 將文件指針移動到DIB像素數(shù)組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的文件結構后,讀取其到內(nèi)存還是挺簡單的,需要注意的是DIB的像素數(shù)組的大小。由于DIB的寬度需要時4的倍數(shù),不是的話需要填充0將其湊成4的倍數(shù),所以其像素數(shù)組的大小不能簡單的width * height * biBitCount / 8,其中biBitCount是每個像素占用的位數(shù)。其具體的計算方法如下
bytesPerLine = ((m_dibInfo->bmiHeader.biWidth * m_dibInfo->bmiHeader.biBitCount + 31) / 32 ) * 4
bytesPerLine * m_dibInfo->bmiHeader.biHeight
1.5 總結
本文主要對DIB的文件結構以及其對應的內(nèi)存中的結構體做了一個總結,并對一個具體的DIB16進制數(shù)據(jù)結構進行分析,最后實現(xiàn)了如何將一個DIB數(shù)據(jù)讀取到內(nèi)存中。
一直對位圖結構不是很了解,趁著在公司實習沒有具體的工作安排,對DIB的結構作了個總結。至于如何將處理后的位圖數(shù)據(jù)寫回磁盤文件,在知道位圖結構的情況下,只需要填充相應的結構字段就行了,需要注意的還是位圖的寬需要是4的倍數(shù),不是的話要用0補齊。本來想寫個DEMO的但是太累,明天再說吧。
轉載于:https://www.cnblogs.com/wangguchangqing/p/5417444.html
總結
以上是生活随笔為你收集整理的DIB位图(Bitmap)的读取和保存的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2-5:套接字(Socket)编程之从内
- 下一篇: 周总结2