如何提高DrawDIB的质量?

时间:2009-07-13 02:43:44

标签: c++ performance gdi drawdib

我用c ++,gdi编码 我使用stretchDIBits将图像绘制为直流。

        ::SetStretchBltMode(hDC, HALFTONE);
        ::StretchDIBits(
            hDC,
            des.left,des.top,des.right - des.left,des.bottom - des.top,
            0, 0,
            img.getWidth(),
            img.getHeight(),
            (img.accessPixels()), 
            (img.getInfo()),
            DIB_RGB_COLORS,
            SRCCOPY
            );

然而它很慢。 所以我改为使用DrawDib函数。

::SetStretchBltMode(hDC, HALFTONE);
DrawDibDraw(
                        hdd,
                        hDC,
                        des.left,des.top,des.right - des.left,des.bottom - des.top,
                        (LPBITMAPINFOHEADER)(img.getInfo()),
                        (img.accessPixels()), 
                        0, 0,
                        img.getWidth(),
                        img.getHeight(),
                        DDF_HALFTONE
                        );

然而结果就像是COLORONCOLOR Mode画的。 如何提高绘图质量?

4 个答案:

答案 0 :(得分:2)

DrawDibDraw已经过时了。

您是否考虑过尝试加速StretchDIBits?答案很好here

你当然可以在不使用StretchDIBits的情况下完成它。

如果您最初加载图片

hBitmap = LoadImage( NULL, _T( "c:\\Path\File.bmp" ), IMAGE_BITMAP, LR_DEFAULTSIZE, LR_DEFAULTSIZE, LR_LOADFROMFILE );

SIZE size;
BITMAP bmp;
GetObject( (HGDIOBJ)hBitmap, sizeof( BITMAP ), &bmp );
size.cx = bmp.bmWidth;
size.cy = bmp.bmHeight;

然后,您可以按如下方式渲染位图。

HDC hBitmapDC   = CreateCompatibleDC( hDC );

HGDIOBJ hOld    = SelectObject( hBitmapDC, (HGDIOBJ)hBitmap );

SetStretchBltMode( hDc, HALFTONE );

StretchBlt( hDC, rcItem.left,rcItem.top, rcItem.right,rcItem.bottom, hBitmapDC, 0, 0, size.cx, size.cy, SRCCOPY );

SelectObject( hBitmapDC, hOld );
DeleteObject( hBitmapDC );

当然值得注意的是,每次进行blt时实际上并不需要创建兼容的DC,这会大大加快速度。只需创建兼容的DC,并在加载图像时为其选择位图对象。然后抓住它直到你需要它。关闭时只需删除DeleteObject,如上所示。

答案 1 :(得分:0)

缩小位图图像时,您有几个选择。你可以用“模糊和子采样”全尺寸图像的慢速方式,这样你有一个像素的地方和源图像有2+像素,新的像素就变成了平均值。如果你不这样做,你会得到更快的性能,但是你的图像不会像你想要的那样平滑。

StretchDIBits可能会对2D中的像素求平均值,这意味着它会从旧图像中查找4+像素块以获得新像素的平均颜色。如果是这种情况,您可以编写自己的1D平均值,只需平均旧图像的相同扫描线的像素即可获得新像素。一个windows api guru可能知道DrawDIBDraw的一个很酷的选项就是这样。

答案 2 :(得分:-1)

如果您不想使用opengl / directx / gdi +但是卡在DIB中,我发现最快的就是自己动手。

只有你需要访问图像的实际字节。此外,目标需要是DIBbitmap,因为这需要对您的Windows窗体进行blitted(而不是stretchblitted)。

所以给你2个字节的指针,1个src和1个dest。两者都指向rawbytes(每个像素由3个字节(RGB)组成),那么你的算法看起来像这样

 //these need to be filled out by you
 //byte *src;   //points to the first raw byte of your source RGB picture
 //byte *dest;  //points to the first raw byte of your destination RGB picture
 //int srcWidth = 640; //width of original image
 //int srcHeight = 480; //height of original image
 //int destWidth = 200; //width of destination image
 //int destHeight = 100; //height of destination image


 void scaleImage(byte *src, byte*dest, int srcWidth, int srcHeight, int destWidth, int destHeight)
 {
      //these are internal counters
      register int srcx;
      register int srcy;
      register int skipx;
      register int skipy;

      skipx = (destWidth>>8)/srcWidth;
      skipy = (destHeight>>8)/srcHeight;

      for(int y=0; y<destHeight; y++)
      {
           //calc from which y coord we need to copy pixel
           register byte *src2 = src + ((srcy>>8)*srcWidth*3);

           for(int x=0; x<destWidth; x++)
           {
                //calc from which x coord we need to copy pixel
                register byte *src3 = src2 + ((srcx>>8)*3);

                //copy rgb
                *dest++ = *src3++;
                *dest++ = *src3++;
                *dest++ = *src3++;

                //go to next x pixel
                srcx += skipx;
           }

           //go to next y pixel
           srcy += skipy;
      }
 }

&gt;&gt; 8和&lt;&lt; 8你看到分散在代码中的是使用'固定点'。

要使缩放看起来更好(因为此缩放是使用“最近邻居”完成的),您应该取相邻右像素,相邻底部像素和相邻右下像素之间的平均值。 确保不要使用除法('/'),但要使用&gt;&gt; 2,这要快得多。

P.S。啊对啊..代码不在我的头顶所以要小心小错字

答案 3 :(得分:-2)

我不知道你在你的应用程序中做了什么,或者绘制拉伸位图对你有多重要,但你可能只想使用更现代的API,如GDI +或DirectX或OpenGL。

自1995年左右以来,没有人改变StretchDIBits或DrawDibDraw的工作方式 - 你真的想要利用GPU的东西。 (我原本预计,即使使用CPU,绘图也会“足够快”,因为处理器比当时处理器要快得多,但显然不是。)