close

[Ref.http://jixiang1119.blog.163.com/blog/static/2827097320108342559871/]

SetDIBitsToDevice函數的理解  

int SetDIBitsToDevice(
  HDC hdc,                 // handle to DC
  int XDest,               // x-coord of destination upper-left corner
  int YDest,               // y-coord of destination upper-left corner 
  DWORD dwWidth,           // source rectangle width
  DWORD dwHeight,          // source rectangle height
  int XSrc,                // x-coord of source lower-left corner
  int YSrc,                // y-coord of source lower-left corner
  UINT uStartScan,         // first scan line in array
  UINT cScanLines,         // number of scan lines
  CONST VOID *lpvBits,     // array of DIB bits
  CONST BITMAPINFO *lpbmi, // bitmap information
  UINT fuColorUse          // RGB or palette indexes
);

個人對SetDIBitsToDevice函數的理解,說句實話這個函數的msdn說的讓人很晦澀難懂,我把自己的理 

解和大家分享一下,不知道正確與否。首先不要去管什麼源左下角坐標和目標左上角的說法。這個左下 

和右上的概念是相對於笛卡爾坐標系(屏幕左下角為坐標原點)而言。而我們函數使用時參數msdn指定 

的是邏輯坐標系,如果採用默認的映射方式(MM_TEXT)的映射方式,映射到設備DC上的坐標系的坐標

原點是屏幕左上角,正方向為向右和向下。換句話說對於從下而上的位圖而言,msdn的說法是有問題的

,因為存儲在內存中的從下而上的dib位圖文件相對於邏輯坐標系而言,(xSrc, ySrc)實際上是dib位圖

文件的左上角,而(xDst, yDst)是左下角。

下面就我的理解解釋一下這些參數到底做了些什麼,如果照搬msdn當然也就不用寫了,我是用我的通俗

的理解方法,希望給大家有點幫助。
1.
XSrc, YSrc,dwWidth, dwHeight這四個參數決定了一個源矩形,現在假設在內存中有這樣一塊源矩形

大小的空白畫板。現在只是有這樣一塊空白畫板,至於畫什麼,由第2步的參數決定。

2. 現在有這樣一塊空白畫板了。lpvBitscScanLines這兩個參數最為重要,他們聯合決定在空畫板上

畫什麼內容。lpvBits指向的是你要顯示的字節類型的位圖數組,cScanLines表示的是該位圖數組中的

掃瞄線數目。通俗的說就是:lpvBits指定了你要從整個位圖的哪一行開始掃瞄,cScanLines指定了你

要掃瞄多少行。這兩個參數一決定,實際上就在你從內存中加載的位圖中相當於截取了圖形的某一塊。

3.uStartScan這個參數不得不提,這個參數很容易出錯,不要將這個參數理解成用來選定位圖數據的起

始行,其實這個參數指定的是在第1步所決定的空白畫板中的什麼位置開始顯示由第2步的兩個參數截取

的圖形(這個圖形可能是整個位圖,也可能只是圖形的一部分)。

4.最後一步根據映射關係,將由源矩形確定的畫板上畫好的內容(第1,2,3步已經指明在畫板什麼位置

,畫上從內存中加載的位圖的哪一部分)映射到目標矩形,也就是我們真實的在目標設備dc中看到的圖

像。如果是默認的映射方式,查看源坐標和目標坐標的映射表會發現,就是將源矩形進行了上下翻轉,

就得到真實的在屏幕上看到目標圖像。

1.bmp     

 

參考《windows程序設計》,修改程序15-3 APOLLO11程序中的參數,我們來看看效果。具體的程序較

長,我沒有貼出來。我們就看SetDIBitsToDevice函數的修改參數後的效果。


               // Bottom-up DIB full size

          SetDIBitsToDevice (hdc, 
                             0,                   // xDst
                             0,                   // yDst
                             cxDib[0],            // cxSrc
                             cyDib[0],            // cySrc
                             0 ,                   // xSrc
                             0,                    // ySrc
                             0,                    //
從什麼位置開始顯示dib
                          
   cyDib[0]/2,            // 掃瞄多少行
                             pBits[0],              //
指定從dib的什麼位置開始掃瞄
                             pbmi[0],               
                             DIB_RGB_COLORS) ;
注意本程序中 pBits[0] = (BYTE *) pbmfh[0] + pbmfh[0]->bfOffBits ;指向的是內存中dib的第一行

那麼函數實現的效果就是。將dib位圖的上半部分截取下來,放到起始位置為0的大小為源矩形大小的

畫板中。然後上下翻轉圖形,即可看到真實顯示在屏幕上的圖形效果。

 

 2.jpg  

 

從程序運行結果來看,得到了宇航員的身體的下半部分。如果要得到上半部分即看到宇航員的頭怎麼做

呢,千萬別告訴我修改uStartScan參數啊,不然我說半天白說了。正確的方法是修改lpvBits指針,讓

它指向dib的下半部分,讓它掃瞄dib的下半部分,這樣就可以看到頭了。具體操作就是先要計算dib

圖的每一行的寬度。然後乘以高度的1/2,就可以使lpvBits指針指向dii位圖的中間。然後往下掃瞄就可以了。
     int dibWidth = cxDib[0];    //計算dib每一行的字節數,注意默認是4字節對齊的,加個判斷


    if(dibWidth % 4 == 0)
    {
     dibWidth = cxDib[0];
    }else
     dibWidth = cxDib[0] + 4 - cxDib[0] / 4;

pBits[0] = (BYTE *) pbmfh[0] + pbmfh[0]->bfOffBits + dibWidth * cyDib [0] / 2;

再次調用

          SetDIBitsToDevice (hdc, 
                             0,                   // xDst
                             0,                   // yDst
                             cxDib[0],            // cxSrc
                             cyDib[0],            // cySrc
                             0 ,                   // xSrc
                             0,                    // ySrc
                             0,                    //
從什麼位置開始顯示dib
                             cyDib[0]/2,            //
掃瞄多少行
                             pBits[0],              //
指定從dib的什麼位置開始掃瞄
                             pbmi[0],               
                             DIB_RGB_COLORS) ;

看效果:

3.jpg  

 

 

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 figer 的頭像
    figer

    日劇看不完

    figer 發表在 痞客邦 留言(0) 人氣()