bitmap格式分析(轉)

源:bitmap格式分析html

參考:bitmap圖像介紹算法

 

  最近正在着手開發一個圖片庫,也就是實現對常見圖片格式的度寫操做。做爲總結與積累,我會把這些圖片格式以及加載的實現寫在個人Blog上。測試

  說到圖片,位圖(Bitmap)固然是最簡單的,它Windows顯示圖片的基本格式,其文件擴展名爲*.BMP。在Windows下,任何各式的圖片文件(包括視頻播放)都要轉化爲位圖個時候才能顯示出來,各類格式的圖片文件也都是在位圖格式的基礎上採用不一樣的壓縮算法生成的(Flash中使用了適量圖,是按相同顏色區域存儲的)。
 
1、下面咱們來看看位圖文件(*.BMP)的格式。
位圖文件主要分爲以下3個部分:
 
塊名稱
對應Windows結構體定義
大小(Byte
文件信息頭
BITMAPFILEHEADER
14
位圖信息頭
BITMAPINFOHEADER
40
RGB顏色陣列
BYTE*
由圖像長寬尺寸決定
 
一、   文件信息頭BITMAPFILEHEADER
  結構體定義以下:
  typedef struct tagBITMAPFILEHEADER { /* bmfh */
    UINT bfType;  
    DWORD bfSize;
    UINT bfReserved1;
    UINT bfReserved2;
    DWORD bfOffBits;
  } BITMAPFILEHEADER;

  其中:spa

bfType
說明文件的類型,該值必需是0x4D42,也就是字符'BM'。
bfSize
說明該位圖文件的大小,用字節爲單位
bfReserved1
保留,必須設置爲0
bfReserved2
保留,必須設置爲0
bfOffBits
說明從文件頭開始到實際的圖象數據之間的字節的偏移量。這個參數是很是有用的,由於位圖信息頭和調色板的長度會根據不一樣狀況而變化,因此你能夠用這個偏移值迅速的從文件中讀取到位數據。
  
二、位圖信息頭BITMAPINFOHEADER
  結構體定義以下:
  typedef struct tagBITMAPINFOHEADER { /* bmih */
    DWORD biSize;
    LONG biWidth;
    LONG biHeight;
    WORD biPlanes;
    WORD biBitCount;
    DWORD biCompression;
    DWORD biSizeImage;
    LONG biXPelsPerMeter;
    LONG biYPelsPerMeter;
    DWORD biClrUsed;
    DWORD biClrImportant;
  } BITMAPINFOHEADER;

  其中:code

biSize
說明BITMAPINFOHEADER結構所須要的字數。
biWidth
說明圖象的寬度,以象素爲單位。
biHeight
說明圖象的高度,以象素爲單位。注:這個值除了用於描述圖像的高度以外,它還有另外一個用處,就是指明該圖像是倒向的位圖,仍是正向的位圖。若是該值是一個正數,說明圖像是倒向的,若是該值是一個負數,則說明圖像是正向的。大多數的BMP文件都是倒向的位圖,也就是時,高度值是一個正數。
biPlanes
爲目標設備說明位面數,其值將老是被設爲1。
biBitCount
說明比特數/象素,其值爲一、四、八、1六、2四、或32。可是因爲咱們平時用到的圖像絕大部分是24位和32位的,因此咱們討論這兩類圖像。
biCompression
說明圖象數據壓縮的類型,一樣咱們只討論沒有壓縮的類型:BI_RGB
biSizeImage
說明圖象的大小,以字節爲單位。當用BI_RGB格式時,可設置爲0
biXPelsPerMeter
說明水平分辨率,用象素/米表示。
biYPelsPerMeter
說明垂直分辨率,用象素/米表示。
biClrUsed
說明位圖實際使用的彩色表中的顏色索引數(設爲0的話,則說明使用全部調色板項)。
biClrImportant
說明對圖象顯示有重要影響的顏色索引的數目,若是是0,表示都重要。
 
三、RGB顏色陣列
  有關RGB三色空間我想你們都很熟悉,這裏我想說的是在Windows下,RGB顏色陣列存儲的格式其實BGR。也就是說,對於24位的RGB位圖像素數據格式是:
藍色B
綠色G
紅色R
對於32位的RGB位圖像素數據格式是:
藍色B
綠色G
紅色R
透明通道A
  透明通道也稱Alpha通道,該值是該像素點的透明屬性,取值在0(全透明)到255(不透明)之間。對於24位的圖像來講,由於沒有Alpha通道,故整個圖像都不透明。
 
2、搞清了文件格式,下一步咱們要實現加載。
  加載文件的目的是要獲得圖片屬性,以及RGB數據,而後能夠將其繪製在DC(GDI),或是生成紋理對象(3D:OpenGL/Direct3D)。這兩種用途在數據處理上有點區別,咱們主要按前一種用法講,在和3D有不一樣的地方,咱們再提出來。
 
1、加載文件頭
  //Load the file header
  BITMAPFILEHEADER header;
  memset(&header, 0, sizeof(header));
  inf.read((char*)&header, sizeof(header));
  if(header.bfType != 0x4D42)
    return false;

  這個很簡單,沒有什麼好說的。orm

 
2、加載位圖信息頭
  //Load the image information header
  BITMAPINFOHEADER infoheader;
  memset(&infoheader, 0, sizeof(infoheader));
  inf.read((char*)&infoheader, sizeof(infoheader));
  m_iImageWidth = infoheader.biWidth;
  m_iImageHeight = infoheader.biHeight;
  m_iBitsPerPixel = infoheader.biBitCount;

  這裏咱們獲得了3各重要的圖形屬性:寬,高,以及每一個像素顏色所佔用的位數。視頻

 
三、行對齊
因爲Windows在進行行掃描的時候最小的單位爲4個字節,因此當
    圖片寬 X 每一個像素的字節數 !=  4的整數倍
時要在每行的後面補上缺乏的字節,以0填充(通常來講當圖像寬度爲2的冪時不須要對齊)。位圖文件裏的數據在寫入的時候已經進行了行對齊,也就是說加載的時候不須要再作行對齊。可是這樣一來圖片數據的長度就不是:寬 X X 每一個像素的字節數  了,咱們須要經過下面的方法計算正確的數據長度:
  //Calculate the image data size
  int iLineByteCnt = (((m_iImageWidth*m_iBitsPerPixel) + 31) >> 5) << 2;
  m_iImageDataSize = iLineByteCnt * m_iImageHeight;

 

四、加載圖片數據
對於24位和32位的位圖文件,位圖數據的偏移量爲sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER),也就是說如今咱們能夠直接讀取圖像數據了。
  if(m_pImageData) delete []m_pImageData;
  m_pImageData = new unsigned char[m_iImageDataSize];
  inf.read((char*)m_pImageData, m_iImageDataSize);

若是你足夠細心,就會發現內存m_pImageData裏的數據的確是BGR格式,能夠用個純藍色或者是純紅色的圖片測試一下。htm

 
五、繪製
好了,數據和屬性咱們都有了,如今就能夠拿來隨便用了,就和吃饅頭同樣,愛粘白糖粘白糖,愛粘紅糖粘紅糖。下面是個人GDI繪製代碼,僅做參考。
void CImage::DrawImage(HDC hdc, int iLeft, int iTop, int iWidth, int iHeight)
{
  if(!hdc || m_pImageData == NULL)
     return;

  BITMAPINFO bmi;

  memset(&bmi, 0, sizeof(bmi));
  bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
  bmi.bmiHeader.biWidth = m_iImageWidth;
  bmi.bmiHeader.biHeight = m_iImageHeight;
  bmi.bmiHeader.biPlanes = 1;
  bmi.bmiHeader.biBitCount = m_iBitsPerPixel;
  bmi.bmiHeader.biCompression = BI_RGB;
  bmi.bmiHeader.biSizeImage = m_iImageDataSize;
  StretchDIBits(hdc, iLeft, iTop, iWidth, iHeight, 
                 0, 0, m_iImageWidth, m_iImageHeight, 
                 m_pImageData, &bmi, DIB_RGB_COLORS, SRCCOPY);
}

 

 
六、3D(OpenGL)的不一樣之處
  若是你是想用剛纔咱們獲得的數據生成紋理對象,那麼你還要請出下面的問題。
首先,用來生成紋理的數據不須要對齊,也就是說不能在每行的後面加上對齊的字節。固然在OpenGL裏要求紋理圖片的尺寸爲2的冪,因此這個問題實際上不存在;
  其次,咱們獲得的圖形數據格式是BGR(BGRA),因此在生成紋理的時候,需指定格式爲GL_BGR_EXT(GL_BGRA_EXT);不然須要作BGR->RGB(BGRA->RGBA)的轉化。
相關文章
相關標籤/搜索