Windows DIB檔案操作詳解-4.使用DIB Section

來源:互聯網
上載者:User

標籤:dib   bitmap   createdibsection   getdibcolortable   dibsection   

前面講了為了提高DIB的顯示效能和效率,我們將DIB轉換成DDB,但是這又遇到一個問題,如果我想操作DIB的資料的話,顯然是不能使用DDB:一是因為DIB轉DDB時發生了色彩轉換,再就是DDB無法直接提取指定像素點的資料。那麼我們怎麼辦呢,Windows使用一種折中的方式來達到這一目標(既提高了顯示效率和效能,又可以直接操作像素點)。


1.DIB Section儲存和顯示

Windows使用DIB塊(DIB Section)來儲存DIB資料,其記憶體結構如下



其實,和我們自己讀入DIB資料到自己分配的各個資料區感覺是一樣的,只是現在這些DIB的各個資料區是由Windows自己分配維護的,值得注意的是這些Windows自己維護的DIB資料區是通過HBITMAP控制代碼來組織的,這個HBITMAP控制代碼和BITMAP的HBITMAP控制代碼是不一樣的,至於為什麼同一種控制代碼可表示不同的對象可以查看筆者的博文“深入瞭解Windows控制代碼到底是什麼”。

繼續說現在的問題,這裡儲存的是DIB的資料,只有在使用BitBlt和StretchBlt顯示的時候,才會發生DIB->DDB的轉換,顯然這裡BitBlt和StretchBlt會對控制代碼屬性做一個判斷來確認指向BITMAP的HBITMAP及指向DIB Section的HBITMAP的不同操作。當然,這裡的DIB Section各個區不一定是連續的,這是一定要注意的。

這裡Windows自己維護DIB各個資料區,做了一定最佳化,所以比我們自己分配和儲存DIB各個資料區的顯示效率和效能要高。


2.DIB Section的相關函數使用

明白了Windows對於DIB Section的儲存原理和轉換規則以後,我們說一下DIB Section的相關函數使用。


1.CreateDIBSection

HBITMAP CreateDIBSection(  HDC hdc,          // 裝置描述表控制代碼  CONST BITMAPINFO *pbmi,// 包含Info Header、Mask、Color Table資料的BITMAPINFO指標  UINT iUsage,      // DIB_PAL_COLORS或DIB_RGB_COLORS  VOID *ppvBits,    // 指向儲存位元影像資料的地址的指標  HANDLE hSection,    DWORD dwOffset    );


使用如下:

1.一般不考慮後兩個參數


2.傳入包含DIB位元影像資訊頭(Info Header)、壓縮掩碼(Mask)及調色盤資訊(Color Table,主要針對位元影像深度<=8)的BITMAPINFO* pbmi指標,這三者必須是連續儲存的,一般指明DIB_RGB_COLORS參數,這樣Windows會自動按照pbmi提供的資訊分配對應的DIB Section,包括Info Header、Mask、Color Table及Bits四個區,其中分配的Bits區的地址被寫到ppvBits指向的指標中。

即常用調用步驟如下:

a.讀入DIB的位元影像資訊頭(Info Header)、壓縮掩碼(Mask)及調色盤資訊(Color Table)到pbmi指向記憶體中

b.hBitmap = CreateDIBSection(NULL, pbmi, DIB_RGB_COLORS, &pBits, NULL, 0);

c.讀入DIB的Bits資料到pBits指向的記憶體中

d.BitBlt或StretchBlt顯示hBitmap


3.只有使用DIB_PAL_COLORS參數時才需要hdc參數。只有DIB的調色盤使用索引儲存方式才需要使用這兩個參數。實際上,這裡的hdc和DIB_PAL_COLORS實際上最終被SetDIBitsToDevice和StretchDIBits函數調用,可以查看他們兩個的參數。

4.pBits指向的記憶體由Windows作業系統託管,但是使用者可以操作pBits資料,刪除hBitmap時pBits記憶體區同時也會釋放掉。


2.GetDIBColorTable和SetDIBColorTable兩個函數定義如下:
UINT GetDIBColorTable(  HDC hdc,          // 裝置描述表控制代碼  UINT uStartIndex, // 調色盤起始索引  UINT cEntries,    // 要擷取的調色盤項個數  RGBQUAD *pColors  // 儲存調色盤項的地址);UINT SetDIBColorTable(  HDC hdc,          // 裝置描述表控制代碼  UINT uStartIndex, // 調色盤起始索引  UINT cEntries,    // 要設定的調色盤項個數  RGBQUAD *pColors  // 儲存調色盤項的地址);

分別用來擷取和設定指定的調色盤項,一般如下使用。
hdcMem = CreateCompatibleDC(NULL);SelectObject(hdcMem, hBitmap);GetDIBColorTable(hdcMem, uFirstIndex, uNumEntries, &prgb);DeleteDC(hdcMem);

hdcMem = CreateCompatibleDC(NULL);SelectObject(hdcMem, hBitmap);SetDIBColorTable(hdcMem, uFirstIndex, uNumEntries, &prgb);DeleteDC(hdcMem);

通過DIB Section來擷取和設定調色盤,可以屏蔽OS/2相容位元影像帶來的差異(BITMAPCOREINFO調色盤項採用RGBTRIPLE結構體而不是BITMAPINFOHEADER採用的RGBQUAD)。
3.擷取DIBSECTIONDIBSECTION定義如下:
typedef struct tagDIBSECTION {     BITMAP              dsBm;     BITMAPINFOHEADER    dsBmih;     DWORD               dsBitfields[3];     HANDLE              dshSection;     DWORD               dsOffset; } DIBSECTION; 

使用
GetObject(hBitmap, sizeof(DIBSECTION), &dibsection);
不同於BITMAP,DIB Section使用GetObject擷取的是DIB Section,可以看到DIBSECTION將BITMAP設為第一個屬性,這是為了保證和BITMAP的相容,萬一你不知道hBitmap的屬性是指向DIB Section的,那麼GetObject(hBitmap, sizeof(BITMAP), &bitmap)也不至於發生錯誤。
通過DIB Section來擷取位元影像資訊,可以不考慮不同DIB位元影像格式帶來的差異,位元影像資訊頭均使用BITMAPINFOHEADER,壓縮掩碼使用DWORD來單獨指定,不用考慮BITMAPCOREHEADER、BITMAPV4HEADER、BITMAPV5HWEADER帶來的差異。


3.代碼示範
在示範程式中,我們讀入一幅圖片(8bit、16bit、24bit)建立成DIB Section形式顯示、查看調色盤及壓縮掩碼
//讀入DIB檔案並轉換成DIB SectionHBITMAP CreateDibSectionFromDibFile(PTSTR szFileName){BITMAPFILEHEADERbmfh;BITMAPINFO*pbmi;BYTE*pBits;BOOLbSuccess;DWORDdwInfoSize, dwBytesRead;HANDLEhFile;HBITMAPhBitmap;//開啟檔案hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);if (INVALID_HANDLE_VALUE == hFile){return NULL;}//讀入DIB檔案頭bSuccess = ReadFile(hFile, &bmfh, sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL);if (!bSuccess || (dwBytesRead != sizeof(BITMAPFILEHEADER)) || (bmfh.bfType != *(WORD *)"BM")){CloseHandle(hFile);return NULL;}//為DIB BITMAPINFO分配記憶體,並讀入DIB資料dwInfoSize = bmfh.bfOffBits - sizeof(BITMAPFILEHEADER);pbmi = malloc(dwInfoSize);if (NULL == pbmi){CloseHandle(hFile);return NULL;}bSuccess = ReadFile(hFile, pbmi, dwInfoSize, &dwBytesRead, NULL);if (!bSuccess || (dwBytesRead != dwInfoSize)){free(pbmi);CloseHandle(hFile);return NULL;}//建立DIB SectionhBitmap = CreateDIBSection(NULL, pbmi, DIB_RGB_COLORS, &pBits, NULL, 0);free(pbmi);if (NULL == hBitmap){CloseHandle(hFile);return NULL;}//讀入位元影像資料到分配的DIB Section的Bits區(pBits指向)bSuccess = ReadFile(hFile, pBits, bmfh.bfSize-bmfh.bfOffBits, &dwBytesRead, NULL);CloseHandle(hFile);if (!bSuccess || (dwBytesRead != (bmfh.bfSize-bmfh.bfOffBits))){return NULL;}return hBitmap;}//如果有調色盤則獲得第一個調色盤項BOOL GetFirstColorTableItem(HBITMAP hBitmap, RGBQUAD *prgb){HDC hdcMem;intiNum;hdcMem = CreateCompatibleDC(NULL);SelectObject(hdcMem, hBitmap);iNum = GetDIBColorTable(hdcMem, 0, 1, prgb);DeleteDC(hdcMem);return 0==iNum ?  FALSE : TRUE;}//獲得第一個調色盤項DWORD GetFirstMaskItem(HBITMAP hBitmap){DIBSECTION ds;GetObject(hBitmap, sizeof(DIBSECTION), &ds);return ds.dsBitfields[0];}


在後續我會講解使用DIB Section來完成映像指定像素點的讀寫,實際上,一旦能夠操作pBits,那麼完成指定像素點的讀寫也不是什麼難事。
完整示範代碼下載連結原創,轉載請註明來自http://blog.csdn.net/wenzhou1219

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.