现在的位置: 首页 > 综合 > 正文

SetDIBitsToDevice函数的理解

2012年10月08日 ⁄ 综合 ⁄ 共 3545字 ⁄ 字号 评论关闭

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. 现在有这样一块空白画板了。lpvBits,cScanLines这两个参数最为重要,他们联合决定在空画板上

画什么内容。lpvBits指向的是你要显示的字节类型的位图数组,cScanLines表示的是该位图数组中的

扫描线数目。通俗的说就是:lpvBits指定了你要从整个位图的哪一行开始扫描,cScanLines指定了你

要扫描多少行。这两个参数一决定,实际上就在你从内存中加载的位图中相当于截取了图形的某一块。

3.uStartScan这个参数不得不提,这个参数很容易出错,不要将这个参数理解成用来选定位图数据的起

始行,其实这个参数指定的是在第1步所决定的空白画板中的什么位置开始显示由第2步的两个参数截取

的图形(这个图形可能是整个位图,也可能只是图形的一部分)。

4.最后一步根据映射关系,将由源矩形确定的画板上画好的内容(第1,2,3步已经指明在画板什么位置

,画上从内存中加载的位图的哪一部分)映射到目标矩形,也就是我们真实的在目标设备dc中看到的图

像。如果是默认的映射方式,查看源坐标和目标坐标的映射表会发现,就是将源矩形进行了上下翻转,

就得到真实的在屏幕上看到目标图像。

本人对SetDIBitsToDevice函数的理解 - jixiang1119 - jixiang

 
参考《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的大小为源矩形大小的

画板中。然后上下翻转图形,即可看到真实显示在屏幕上的图形效果。

本人对SetDIBitsToDevice函数的理解 - jixiang1119 - jixiang

 

 

从程序运行结果来看,得到了宇航员的身体的下半部分。如果要得到上半部分即看到宇航员的头怎么做

呢,千万别告诉我修改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) ;

抱歉!评论已关闭.