1. 程式人生 > >windows程式設計學習筆記-裝置無關點陣圖

windows程式設計學習筆記-裝置無關點陣圖

GIF,JPEG格式壓縮了影象資料。DIB一般都不壓縮。
Windows API直接支援DIB。
DIB提供了一個用來交換影象的檔案格式。

Windows應用程式用到的點陣圖一般作為DIB,存在可執行檔案的只讀資源中。
程式可把DIB檔案除去開始的14位元組,載入到一塊連續記憶體。也可在記憶體建立DIB,然後存至檔案。

DIB檔案格式:

1.檔案頭
2.資訊頭
3.RGB顏色表[又時沒有]
4.點陣圖畫素位

2,3,4稱記憶體中緊湊格式的DIB。剪下板傳輸DIB時使用。

DIB檔案頭:
typedef struct tagBITMAPFILEHEADER
{
WORD bfType; // 檔案簽名,”BM”或0x4D42
DWORD bfSize; // 整個檔案長度
WORD bfReserved1; // 0
WORD bfReserved2; // 0
DWORD bfOffBits; // 到點陣圖畫素位的位移
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

DIB資訊頭
typedef struct tagBITMAPCOREHEADER
{
DWORD bcSize; // 結構大小,固定12位元組
WORD bcWidth; // 以畫素為單位的影象寬
WORD bcHeight; // 以畫素為單位的影象高
WORD bcPlanes; // = 1
WORD bcBitCount; // 每個畫素的位數1,4,8,24
} BITMAPCOREHEADER, FAR *LPBITMAPCOREHEADER, *PBITMAPCOREHEADER;

當畫素位是1,4,8時,後面是顏色表。24後面不要顏色表。
DIB顏色表是一個數組。
DIB顏色表陣列元素型別:
typedef struct tagRGBTRIPLE
{
BYTE rgbtBlue; // 藍色值
BYTE rgbtGreen; // 綠色值
BYTE rgbtRed; // 紅色值
} RGBTRIPLE, *PRGBTRIPLE, NEAR *NPRGBTRIPLE, FAR *LPRGBTRIPLE;

typedef struct tagBITMAPCOREINFO
{
BITMAPCOREHEADER bmciHeader;
RGBTRIPLE bmciColors[1];
} BITMAPCOREINFO, FAR *LPBITMAPCOREINFO, *PBITMAPCOREINFO;
這個結構用來同時包含 資訊頭和顏色表。
顏色表元素個數為2的畫素位數 的次方。

後面資料就是畫素位本身。

DIB從影象最下面一行開始,逐漸向上來儲存影象。每一行的畫素從左往右安排。
每一行所用的位元組數必須是4的倍數。不夠可以補。
RowLength = 4 * ((bmch.bcWidth * bmch.bcBitCount + 31) / 32);
所有畫素佔用的位元組數:
RowLength * bmch.bcHeight.

對DIB畫素部分資料解釋。
以畫素部分前3個位元組為例。每個位元組排開後,對應位元組從7-0。0最低位,7最高位。
畫素位為1時:
1的7-0,分別對應畫素0-7在顏色表裡的資料下標。
2的7-0,分別對應畫素8-15在顏色表裡的資料下標。
3的7-0,分別對應畫素16-23在顏色表裡的資料下標。

畫素位為4時:
1的7-4表示畫素0在顏色表裡的資料下標。
1的3-0表示畫素1在顏色表裡的資料下標。

2的7-4表示畫素2在顏色表裡的資料下標。
2的3-0表示畫素3在顏色表裡的資料下標。

3的7-4表示畫素4在顏色表裡的資料下標。
3的3-0表示畫素5在顏色表裡的資料下標。

畫素位為8時:
1的7-0表示畫素0在顏色表裡的資料下標。
2的7-0表示畫素1在顏色表裡的資料下標。
3的7-0表示畫素2在顏色表裡的資料下標。

畫素位為24時:
1的7-0表示畫素0的藍色值。
2的7-0表示畫素0的綠色值。
3的7-0表示畫素0的紅色值。

windows擴充套件的DIB格式。

擴充套件DIB檔案頭:
typedef struct tagBITMAPFILEHEADER
{
WORD bfType; // 檔案簽名,”BM”或0x4D42
DWORD bfSize; // 整個檔案長度
WORD bfReserved1; // 0
WORD bfReserved2; // 0
DWORD bfOffBits; // 到點陣圖畫素位的位移
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

擴充套件DIB資訊頭
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize; // 結構大小。固定為40.
LONG biWidth; // 以畫素計的影象的寬度
LONG biHeight; // 以畫素計的影象的高度
WORD biPlanes; // = 1
WORD biBitCount; // 每個畫素的位數。1,4,8,16,24,32
DWORD biCompression; // 壓縮編碼
DWORD biSizeImage; // 影象的位元組數
LONG biXPelsPerMeter; // 水平解析度
LONG biYPelsPerMeter; // 垂直解析度
DWORD biClrUsed; // 用到的顏色數。
DWORD biClrImportant; // 重要顏色的數目
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

對1,4,8位的DIB。接在擴充套件DIB後面的是一個指明顏色的陣列。
陣列元素的結構是:
typedef struct tagRGBQUAD
{
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved; // 0
} RGBQUAD;

typedef struct tagBITMAPINFO
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO, FAR *LPBITMAPINFO, *PBITMAPINFO;
改結構包含了擴充套件的DIB資訊頭和擴充套件的顏色表陣列。

biClrUsed在後面跟擴充套件顏色表時,用來指出顏色表中需要出現的元素個數。為0,表示2的畫素位數的次方個數組都要出現。

對1,4,8,24的DIB畫素位的組織和非擴充套件DIB中一樣。

biCompression:
DIB位數:1,4,8,24
BI_RGB, BI_RLE8, BI_RLE4

行程長度編碼:
1.1,該欄位總是 BI_RGB
2.4,該欄位為 BI_RGB或BI_RLE4.
3.8,該欄位為 BI_RGB或BI_RLE8.
4.24,該欄位總為 BI_RGB.
為BI_RGB畫素位按 之前的DIB中那樣儲存。否則,畫素位按行程長度編碼來壓縮。

行程長度編碼:
DIB影象一行中存在多個連續的相同元素。對此段,記錄重複次數和值。也能用於儲存非矩形影象。

以biCompression為BI_RLE8為例:
位元組1 位元組2 位元組3 位元組4
00 00 一行的結尾
00 01 影象的結尾
00 02 dx dy 移動到(x+dx,y+dy)
00 03-FF 使用接下來n個畫素。n為奇數時,後面再補一個0x00
01-FF 畫素 重複畫素n次

只要biCompression是BI_RLE4或BI_RLE8,biSizeImage欄位儲存以位元組為單位的DIB畫素資料的大小。

DIB位數:16,32
BI_RGB,BI_BITFIELDS。

該欄位為 BI_RGB或BI_BITFIELDS。
16,32為 BI_RGB下,由畫素值變數得到RGB,顏色遮罩略過。

int SetDIBitsToDevice
(
In HDC hdc,
In int xDst,
In int yDst,
In DWORD cxSrc,
In DWORD cySrc,
In int xSrc,
In int ySrc,
In UINT yScan,
In UINT cyScans,
In const VOID *pBits,
In const BITMAPINFO *pInfo,
In UINT fClrUse
);
在關聯與目的裝置環境的裝置的指定矩形中設定畫素。用來自於DIB,JPEG或PNG圖片的資料。

hdc:裝置環境控制代碼
XDst:目的矩形左上角X座標。
YDst:目的矩形左上角Y座標。
cxSrc:圖片寬度。畫素單位。
cySrc :圖片高度。畫素單位。
xSrc:圖片左下角X座標。畫素單位。
ySrc:圖片左下角Y座標。畫素單位。
yScan:圖片中開始掃描行。掃描總是從圖片的下面往上面掃描的。故對自下而上存的DIB,yScan從0-n.對自上而下存的DIB,yScan從n-0.
cyScans:lpvBits指向的陣列內DIB掃描行的數目
pBits:指向顏色資料,存在一個位元組位陣列內。
pInfo:指向一個BITMAPINFO結構,其中包含了DIB檔案的資訊。
fClrUse:
1.DIB_PAL_COLORS:表示DIB裡的顏色表將被由裝置環境選中並實現的16位索引的邏輯調色盤取代。
0.DIB_RGB_COLORS:顏色表包含RGB值。

返回值
成功,設定的掃描行行數。
失敗,0或GDI_ERROR

In DWORD cxSrc,
In DWORD cySrc,
In int xSrc,
In int ySrc,

自下而上儲存的DIB。記憶體結構和引數位置。
0-n行分別表示圖形的n-0行。

                  xSrc                xSrc + cxSrc

ySrc

ySrc + cySrc

自上而下儲存的DIB。記憶體結構和引數位置。
0-n行分別表示圖形的0-n行
ySrc + cySrc

ySrc

                   xSrc                        xSrc + cxSrc

SetDIBitsToDevicez支援多次呼叫,每次設定若干掃描行,來實現DIB顯示。多次呼叫其它引數不變,改變
In UINT yScan, // 從DIB儲存角度的本次掃描開始行
In UINT cyScans, // 掃描行數
In const VOID *pBits, // 從DIB儲存角度的本次掃描開始地址。
三個引數即可。

呼叫一次顯示整個影象,yScan為0,cyScan為總行數。不用考慮儲存順序問題。

int StretchDIBits(
In HDC hdc,
In int XDest,
In int YDest,
In int nDestWidth,
In int nDestHeight,
In int XSrc,
In int YSrc,
In int nSrcWidth,
In int nSrcHeight,
In const VOID *lpBits,
In const BITMAPINFO *lpBitsInfo,
In UINT iUsage,
In DWORD dwRop
);

hdc:目的裝置環境控制代碼
XDest:目標矩形左上角X座標。邏輯單位。
YDest:目標矩形左上角Y座標。邏輯單位。
nDestWidth:目標矩形寬。邏輯單位。
nDestHeight :目標矩形高。邏輯單位。
XSrc:圖片裡源矩形X座標。畫素單位。
YSrc:圖片裡源矩形Y座標。畫素單位。
nSrcWidth:圖片裡源矩形寬。畫素單位。
nSrcHeight:圖片裡源矩形高。畫素單位。
lpBits :指向圖片畫素位陣列。
lpBitsInfo:指向包含DIB資訊的BITMAPINFO
iUsage:
DIB_PAL_COLORS
DIB_RGB_COLORS
dwRop:光柵操作。指定源矩形中畫素和目的裝置環境畫素和目的裝置環境當前畫刷結合方式。

返回值:
被拷貝的掃描行數目
0:沒有掃描行被拷貝或失敗
GDI_ERROR:源圖片不被支援。

剪下板使用舉例:

            HGLOBAL hGlobal = GlobalAlloc (GHND | GMEM_SHARE, pbmfh->bfSize -
                                        sizeof (BITMAPFILEHEADER)) ;

               pGlobal = GlobalLock (hGlobal) ;

               CopyMemory (pGlobal, (BYTE *) pbmfh + sizeof (BITMAPFILEHEADER),
                           pbmfh->bfSize - sizeof (BITMAPFILEHEADER)) ;

               GlobalUnlock (hGlobal) ;

               OpenClipboard (hwnd) ;
               EmptyClipboard () ;
               SetClipboardData (CF_DIB, hGlobal) ;
               CloseClipboard () ;



              OpenClipboard (hwnd) ;

               hGlobal = GetClipboardData (CF_DIB) ;
               pGlobal = GlobalLock (hGlobal) ;

               if (pGlobal)
               {
                    pGlobal  // 指向你之前放入的資料,可以從指向的地方把資料拷貝出來
               }

               GlobalUnlock (hGlobal) ;
               CloseClipboard () ;

DDB的API速度快於DIB,DDB支援選入點陣圖後在其上畫圖。

DIB和DDB的相互轉化:

從DIB到DDB

方法1:
1.1.BOOL CreateCompatibleBitmap(
CDC* pDC,
int nWidth,
int nHeight
);
建立裝置相容點陣圖。
1.2.點陣圖選入記憶體裝置環境
1.3.利用SetDIBitsToDevice在記憶體裝置環境上繪圖。

使點陣圖和DIB有相同影象。但點陣圖是裝置相容的。

方法2:
2.1.HBITMAP CreateDIBitmap(
In HDC hdc,
In const BITMAPINFOHEADER *lpbmih,
In DWORD fdwInit,
In const VOID *lpbInit,
In const BITMAPINFO *lpbmi,
In UINT fuUsage
);

從一個裝置無關點陣圖中建立一個裝置相關點陣圖。

從DDB到DIB

int GetDIBits(
In HDC hdc,
In HBITMAP hbmp,
In UINT uStartScan,
In UINT cScanLines,
Out LPVOID lpvBits,
Inout LPBITMAPINFO lpbi,
In UINT uUsage
);

接收指定的相容點陣圖的位然後按指定的格式把他們拷貝到一個DIB緩衝
hdc:裝置環境的控制代碼
hbmp:點陣圖控制代碼。點陣圖需要是裝置相容點陣圖。
uStartScan:開始掃描行
cScanLines:掃描行數目
lpvBits :指向一個接收點陣圖資料的緩衝。
lpbi :指向一個BITMAPINfO結構,來指定期望得到的DIB資料的格式。
uUsage:
DIB_PAL_COLORS
DIB_RGB_COLORS

如果lpvBits非NULL且執行成功,返回值是拷貝的掃描行數目。
如果lpvBits為NULL且執行成功,返回值非0.
執行失敗,返回0
ERROR_INVALID_PARAMETER:引數無效

HBITMAP CreateDIBSection(
In HDC hdc,
In const BITMAPINFO *pbmi,
In UINT iUsage,
Out VOID **ppvBits,
In HANDLE hSection,
In DWORD dwOffset
);

建立一個DIB,應用可以直接寫。
函式給你一個指標,指向點陣圖位值地址。
你可提供一個指向檔案對映物件控制代碼,函式將用來建立點陣圖 或這 你能讓系統為點陣圖分配記憶體。

hdc:裝置環境控制代碼
pbmi:指向BITMAPINFO結構,指定DIB屬性。
iUsage:
DIB_PAL_COLORS
DIB_RGB_COLORS
ppvBits :指向一個變數,接受DIB位值地址。
hSection:檔案對映物件控制代碼 ,函式用來建立DIB。可為NULL。
dwOffset:hSection不為NULL時,有意義。

返回值:
成功,新建立DIB的控制代碼。
失敗,NULL
ERROR_INVALID_PARAMETER:引數無效

pvBits:指向的記憶體區域由系統管理。用DeleteObject刪除這個點陣圖時,記憶體會被自動釋放。

用於顯示DIB的三種方式:
1.SetDIBitsToDevice或StretchDIBits直接顯示。
2.CreateDIBitmap或SetDIBits把DIB轉成DDB,用BitBlt或StretchBlt顯示。
3.CreateDIBSection建立DIB區塊,允許你通過pBits手動修改畫素位。
CreateDIBSection返回的點陣圖可以選入與裝置相容的記憶體裝置環境。

返回的點陣圖還能用
GetObject(hBitmap, sizeof(DIBSECTION), &dibsection);

在把此點陣圖選入記憶體裝置環境後,還可以用
GetDIBColorTable(hdcMem, uFirstIndex, uNumEntries, &rgb);

檔案對映物件讓你可以把一個檔案當作已經在記憶體一樣。好處是檔案過大時可減少記憶體需求,但速度會變慢。