日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

Windows DIB文件操作详解-4.使用DIB Section

發(fā)布時(shí)間:2024/3/26 windows 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Windows DIB文件操作详解-4.使用DIB Section 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前面講了為了提高DIB的顯示性能和效率,我們將DIB轉(zhuǎn)換成DDB,但是這又遇到一個問題,如果我想操作DIB的數(shù)據(jù)的話,顯然是不能使用DDB:一是因?yàn)镈IB轉(zhuǎn)DDB時(shí)發(fā)生了顏色轉(zhuǎn)換,再就是DDB無法直接提取指定像素點(diǎn)的數(shù)據(jù)。那么我們怎么辦呢,Windows使用一種折中的方式來達(dá)到這一目標(biāo)(既提高了顯示效率和性能,又可以直接操作像素點(diǎn))。


1.DIB Section存儲和顯示

Windows使用DIB塊(DIB Section)來存儲DIB數(shù)據(jù),其內(nèi)存結(jié)構(gòu)示意圖如下



其實(shí),和我們自己讀入DIB數(shù)據(jù)到自己分配的各個數(shù)據(jù)區(qū)感覺是一樣的,只是現(xiàn)在這些DIB的各個數(shù)據(jù)區(qū)是由Windows自己分配維護(hù)的,值得注意的是這些Windows自己維護(hù)的DIB數(shù)據(jù)區(qū)是通過HBITMAP句柄來組織的,這個HBITMAP句柄和BITMAP的HBITMAP句柄是不一樣的,至于為什么同一種句柄可表示不同的對象可以查看筆者的博文“深入了解Windows句柄到底是什么”。

繼續(xù)說現(xiàn)在的問題,這里存儲的是DIB的數(shù)據(jù),只有在使用BitBlt和StretchBlt顯示的時(shí)候,才會發(fā)生DIB->DDB的轉(zhuǎn)換,顯然這里BitBlt和StretchBlt會對句柄屬性做一個判斷來確認(rèn)指向BITMAP的HBITMAP及指向DIB Section的HBITMAP的不同操作。當(dāng)然,這里的DIB Section各個區(qū)不一定是連續(xù)的,這是一定要注意的。

這里Windows自己維護(hù)DIB各個數(shù)據(jù)區(qū),做了一定優(yōu)化,所以比我們自己分配和存儲DIB各個數(shù)據(jù)區(qū)的顯示效率和性能要高。


2.DIB Section的相關(guān)函數(shù)使用

明白了Windows對于DIB Section的存儲原理和轉(zhuǎn)換規(guī)則以后,我們說一下DIB Section的相關(guān)函數(shù)使用。


1.CreateDIBSection

HBITMAP CreateDIBSection(HDC hdc, // 設(shè)備描述表句柄CONST BITMAPINFO *pbmi, // 包含Info Header、Mask、Color Table數(shù)據(jù)的BITMAPINFO指針UINT iUsage, // DIB_PAL_COLORS或DIB_RGB_COLORSVOID *ppvBits, // 指向存儲位圖數(shù)據(jù)的地址的指針HANDLE hSection, DWORD dwOffset );


使用如下:

1.一般不考慮后兩個參數(shù)


2.傳入包含DIB位圖信息頭(Info Header)、壓縮掩碼(Mask)及調(diào)色板信息(Color Table,主要針對位圖深度<=8)的BITMAPINFO* pbmi指針,這三者必須是連續(xù)存儲的,一般指明DIB_RGB_COLORS參數(shù),這樣Windows會自動按照pbmi提供的信息分配對應(yīng)的DIB Section,包括Info Header、Mask、Color Table及Bits四個區(qū),其中分配的Bits區(qū)的地址被寫到ppvBits指向的指針中。

即常用調(diào)用步驟如下:

a.讀入DIB的位圖信息頭(Info Header)、壓縮掩碼(Mask)及調(diào)色板信息(Color Table)到pbmi指向內(nèi)存中

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

c.讀入DIB的Bits數(shù)據(jù)到pBits指向的內(nèi)存中

d.BitBlt或StretchBlt顯示hBitmap


3.只有使用DIB_PAL_COLORS參數(shù)時(shí)才需要hdc參數(shù)。只有DIB的調(diào)色板使用索引存儲方式才需要使用這兩個參數(shù)。實(shí)際上,這里的hdc和DIB_PAL_COLORS實(shí)際上最終被SetDIBitsToDevice和StretchDIBits函數(shù)調(diào)用,可以查看他們兩個的參數(shù)。

4.pBits指向的內(nèi)存由Windows操作系統(tǒng)托管,但是用戶可以操作pBits數(shù)據(jù),刪除hBitmap時(shí)pBits內(nèi)存區(qū)同時(shí)也會釋放掉。


2.GetDIBColorTable和SetDIBColorTable

兩個函數(shù)定義如下: UINT GetDIBColorTable(HDC hdc, // 設(shè)備描述表句柄UINT uStartIndex, // 調(diào)色板起始索引UINT cEntries, // 要獲取的調(diào)色板項(xiàng)個數(shù)RGBQUAD *pColors // 存儲調(diào)色板項(xiàng)的地址 );UINT SetDIBColorTable(HDC hdc, // 設(shè)備描述表句柄UINT uStartIndex, // 調(diào)色板起始索引UINT cEntries, // 要設(shè)置的調(diào)色板項(xiàng)個數(shù)RGBQUAD *pColors // 存儲調(diào)色板項(xiàng)的地址 );
分別用來獲取和設(shè)置指定的調(diào)色板項(xiàng),一般如下使用。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來獲取和設(shè)置調(diào)色板,可以屏蔽OS/2兼容位圖帶來的差異(BITMAPCOREINFO調(diào)色板項(xiàng)采用RGBTRIPLE結(jié)構(gòu)體而不是BITMAPINFOHEADER采用的RGBQUAD)。

3.獲取DIBSECTION

DIBSECTION定義如下: 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設(shè)為第一個屬性,這是為了保證和BITMAP的兼容,萬一你不知道hBitmap的屬性是指向DIB Section的,那么GetObject(hBitmap, sizeof(BITMAP), &bitmap)也不至于發(fā)生錯誤。
通過DIB Section來獲取位圖信息,可以不考慮不同DIB位圖格式帶來的差異,位圖信息頭均使用BITMAPINFOHEADER,壓縮掩碼使用DWORD來單獨(dú)指定,不用考慮BITMAPCOREHEADER、BITMAPV4HEADER、BITMAPV5HWEADER帶來的差異。


3.代碼演示


在演示程序中,我們讀入一幅圖片(8bit、16bit、24bit)創(chuàng)建成DIB Section形式顯示、查看調(diào)色板及壓縮掩碼 //讀入DIB文件并轉(zhuǎn)換成DIB Section HBITMAP CreateDibSectionFromDibFile(PTSTR szFileName) {BITMAPFILEHEADER bmfh;BITMAPINFO *pbmi;BYTE *pBits;BOOL bSuccess;DWORD dwInfoSize, dwBytesRead;HANDLE hFile;HBITMAP hBitmap;//打開文件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分配內(nèi)存,并讀入DIB數(shù)據(jù)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;}//創(chuàng)建DIB SectionhBitmap = CreateDIBSection(NULL, pbmi, DIB_RGB_COLORS, &pBits, NULL, 0);free(pbmi);if (NULL == hBitmap){CloseHandle(hFile);return NULL;}//讀入位圖數(shù)據(jù)到分配的DIB Section的Bits區(qū)(pBits指向)bSuccess = ReadFile(hFile, pBits, bmfh.bfSize-bmfh.bfOffBits, &dwBytesRead, NULL);CloseHandle(hFile);if (!bSuccess || (dwBytesRead != (bmfh.bfSize-bmfh.bfOffBits))){return NULL;}return hBitmap; }//如果有調(diào)色板則獲得第一個調(diào)色板項(xiàng) BOOL GetFirstColorTableItem(HBITMAP hBitmap, RGBQUAD *prgb) {HDC hdcMem;int iNum;hdcMem = CreateCompatibleDC(NULL);SelectObject(hdcMem, hBitmap);iNum = GetDIBColorTable(hdcMem, 0, 1, prgb);DeleteDC(hdcMem);return 0==iNum ? FALSE : TRUE; }//獲得第一個調(diào)色板項(xiàng) DWORD GetFirstMaskItem(HBITMAP hBitmap) {DIBSECTION ds;GetObject(hBitmap, sizeof(DIBSECTION), &ds);return ds.dsBitfields[0]; }

在后續(xù)我會講解使用DIB Section來完成圖像指定像素點(diǎn)的讀寫,實(shí)際上,一旦能夠操作pBits,那么完成指定像素點(diǎn)的讀寫也不是什么難事。
完整演示代碼下載鏈接 原創(chuàng),轉(zhuǎn)載請注明來自http://blog.csdn.net/wenzhou1219

總結(jié)

以上是生活随笔為你收集整理的Windows DIB文件操作详解-4.使用DIB Section的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。