2009-07-13 94 views
1

我使用C++編寫,gdi 我使用stretchDIBits將圖像繪製到直流。如何提高DrawDIB的質量?

 ::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模式繪製。 如何提高圖紙質量?

+2

的`DrawDib`的東西是非常過時的。你能解釋一下你的意思嗎?你是否試圖在實時視頻中做到這一點?你是否試圖將它應用於非常大的圖像?需要多少時間,你需要多快? – 2009-11-09 17:12:31

回答

0

縮小位圖圖像時,您有幾個選擇。您可以通過對「全尺寸圖像」進行「模糊和二次採樣」的緩慢方式來完成,以便您有一個像素和源圖像的位置具有2+像素,新像素將成爲平均值。如果你不這樣做,你的穿孔速度會快得多,但是你的圖像不會像你想要的那樣平滑。

StretchDIBits可能是2D中的像素平均值,這意味着它會從舊圖像中尋找4像素塊以獲得新像素的平均顏色。如果是這種情況,您可以編寫自己的1D平均值,只需對舊圖像的相同掃描線的像素進行平均,即可獲得新像素。一個windows api專家可能會知道DrawDIBDraw的一個很酷的選項,它可以做到這一點。

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); 

當然它值得銘記,你實際上並不需要創建兼容DC每次BLT時間,這將大大加快速度中。只需創建兼容的DC,並在加載圖像時選擇它的位圖對象。然後保持它直到你需要它。如上所示,關閉簡單的DeleteObject。

+0

感謝戈茲貝達,這是一個很好的解決方案時,圖像不是太大。因爲CompatibleDC佔用了顯示卡的內存,如果顯卡上沒有足夠的內存。此方法不起作用 – user25749 2009-07-20 01:37:59

-2

我不知道您在應用程序中做了些什麼,或者繪製拉伸位圖對您來說有多重要,但您可能只想使用更現代的API,如GDI +或DirectX或OpenGL。

從1995年開始,沒有人改變StretchDIBits或DrawDibDraw的工作方式 - 你真的想要利用GPU的東西。 (我預料即使是CPU,繪圖也會「足夠快」,僅僅是因爲處理器比現在快得多,但顯然不是)。

-1

如果你不想使用opengl/directx/gdi +但都卡在DIB中,我發現最快的就是自己做。

只有你需要訪問圖像的實際字節。此外,目標需要是DIBbitmap,因爲這需要blitting(而不是拉伸)到您的Windows窗體。

因此給出您有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; 
     } 
} 

的>> 8和< < 8,你還會看到通過代碼分散是使用'固定點'。

爲了使縮放更好看(因爲這個規模是使用「近鄰」做),你應該採取右側相鄰像素,相鄰像素的底部和相鄰右下像素之間的平均值。 確保不使用除法(「/」),但使用>> 2,它的速度要快得多。

p.s.啊right..the代碼是從我的頭頂,所以要小心小錯別字