Memory DC 與hBitmap

來源:cww

DC 即Device Context,是GDI內部的一個資料結構,一個DC會和某個特定的顯示設備(
如印表機、螢幕等)產生關聯。我們如果能取得該DC的handle	那我們便可以在這顯示
設備上寫字、畫圖。

在Form 或Picturebox中都有一個hdc的屬性,指的便是這東西,但是,怎麼又會有一個
Memory DC呢?這是一個存在記憶體內的 dc ,它除了不像form picturebox能將圖形、文
字顯示出來之外,其他的幾乎都相同,它也可以用在所有的 GDI API 呼叫之上,其實我
們在VB中早就有使用上這 Memory DC 了,只是沒有自覺。當我們設 form picturebox的
AutoRedraw = True時, hdc所指的便是Momoory DC,這時我們在其上作繪圖動作,都
沒有顯示在form上,這便是先前說的,它只是在記憶體中,不會真的畫出圖。而我們下
refresh指令時,便是將這MemoryDC上的圖,copy到 form/PictureBox上。

另外我們也可以使用

CreateCompatibleDC() API 它傳入一個 hDc ,代表產生的 Memory DC和 hdc相容,若
傳0則是與螢幕相容的 Memory DC

 hMemDC = CreateCompatibleDC(0)

 這時候,該hMemDC所指的繪圖區有多大呢?其實只有一個單色Pixel,直到我們使用

 SelectObject( hMemDC, hBitmap)

 那hMemDC顯示區就會有和hBitmap一樣的寬度、高度、顏色選擇等。 而且我們在hMemDC
上的任何繪圖,也都會反映在 hBitMap上,也就是說,原本hBitMap所指的圖,於
 SelectObject(hMemDC, hBitMap)後,我們使用gdi函式在hMemDC上畫一條線,那麼該
hBitmap所指的圖也會有一條線了。

接下來令人心煩的是hBitmap如何取得,在vb可以使用以下的兩個方式:

1.使用Form/PictureBox上Image屬性(它是個物件),不管我們放入Form/PictureBox中
  Picture屬性的圖是否是Bitmap圖,Image所指的,是一份存在記憶體中的Bitmap圖,
  (這是我的想法,因我查了一下,Image.Type 永遠說是BitMap圖,而不管Picture屬性
  的圖是那一種類型),而Image.Handle所指,便是這bitmap圖的hBitmap。但是,不要高
  興太早,這hBitmap的範圍可比你想像中的大,如果有一個PictureBox大小100*100
  而設定一個50*50 的圖於其上, 那PictureBox.Image的大小是100*100,因為它所指
  的是整個PictureBox的圖,而剛好PictureBox上有圖形顯示於其上。而如何才能取得
  50*50的hBitMap呢,我會用"偷吃部",指定 PictureBox比50*50小(如:1*1)而且設定
  AutoSize = True,BorderStyle = 0 當我們用LoadPicture把圖形放進來時,
  PictureBox會放大成與該圖的大小相同,那麼,PictureBox.Image的大小也會隨之放大
2.使用StdPicture物,而後用LoadPicture將圖放進來,但是這一定只能使用BitMap圖,
  要不然StdPicture.Handle不會是hBitmap,而是其他Handle( 如:hIcon)


如果使用api,可以使用

hBitMap = CreateCompatibleBitmap(hDc, Height, Width)

那會產生一個高Height * 寬 Width大小(Pixels)的BitMap圖,而且該BitMap圖和Hdc所
指的物件有相同的顏色數,且Bits Per Pixels也相同。然而該BitMap圖裡什麼也沒有,
一般我們接著使用

SelectObject(hdc, hBitMap)

而利用hDc來繪圖,這一切的繪圖就會反映在hBitMap上,而我們一般會以MemoryDC來當
作hdc的傳入值,等繪圖動作完了,我們便可以把這Memory DC刪除(DeleteDC()),而只
單純的留下hBitmap。如:

hMemDc = CreateCompatibleDc(0)
hBitMap = CreateCompatibleBitMap(Screen.ActiveForm.hDc, 100,100)
Call SelectObject(hMemDc, hBitMap)

'執行一些繪圖指令,如:Textout() StretchBltStretchBlt()  BitBlt()
DeleteDC hMemDc

當然,如果我們不知道圖形的大小時,CreateCompatibleBitMap就不是那麼方便了,要 知道圖形的大小我們也可以由PictureBox.Picture中Width/Height這兩個屬性來做,但 是還得經過一下轉換,因為這兩個值的單位是HiMetric,要使用ScaleX() ScaleY()來轉 成Pixels即 ScaleX(picture1.Picture.Width, vbHiMetric, vbPixels)才是我們想要的 寬度,ScaleY(picture1.Picture.Height, vbHiMetric, vbPixels)才是我們想要的高度 。另外也可以使用以下的方式來取得hBitmap '假設有一個PictureBox而我們事先已Load一個圖進來了。 Dim bm As Bitmap, hBmp as Long GetObject Picture1.Picture, Len(bm), bm '取得PictureBox內圖形的的BitMap結構 hBmp = CreateBitmapIndirect(bm) '產生一個Bitmap圖,該圖的大小顏色數由bm所控制 hmemDC = CreateCompatibleDC(Picture1.hDC) SelectObject hmemDC, hBmp 'hmemDC的大小和hBmp相同了 picture1.AutoRedraw = True '將Picture1的圖畫在hmemDc上,如此,hBmp便是我們所要的。 BitBlt hmemDC, 0, 0, bm.bmWidth, bm.bmHeight, picture1.hDC, 0, 0, vbSrcCopy 詳細例子請查 有 BitMap 之Menu中 Function GetBitMapHandle