问题
I am coding in c++, gdi I use stretchDIBits to draw Images to dc.
::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
);
However It is slow. So I changed to use DrawDib function.
::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
);
However the result is just like draw by COLORONCOLOR Mode. How can I improve the drawing quality?
回答1:
Well DrawDibDraw is outdated.
Have you considered trying to speed up StretchDIBits? There is a good answer here
You can of course do it without using StretchDIBits at all.
if you initially load your image by
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;
You can then render the bitmap as follows.
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 );
Of course its worth bearing in mind that you don't actually need to create the compatible DC each time you blt which will speed things up considerably. Just create the compatible DC and select the bitmap object to it when you load the image. Then hold it around until you need it. On shutdown simply DeleteObject as shown above.
回答2:
When you shrink your bitmap image you have a couple of choices. You can do it the slow way where you "blur and subsample" the full sized image so that places where you have one pixel and the source image had 2+ pixels, the new pixel becomes the average. If you don't do that you get a lot faster perforamce, but your image won't be as smooth as you might want.
StretchDIBits might be averaging pixels in 2D, meaning that it looks to a 4+ pixel block from the old image to get the average color of the new pixel. If that's the case you can write your own 1D averaging that just averages the pixels same scanline of the old image to get the new pixel. A windows api guru might know a cool option to DrawDIBDraw that does something like this.
回答3:
If you don't want to use opengl/directx/gdi+ but are stuck in DIBs, I found the fastest is to just do it yourself.
Only thing is you need access to the actual bytes of the image. Furthermore, the destination needs to be a DIBbitmap, since this needs to be blitted (not stretchblitted) to your windows form.
so given you have 2 byte pointers, 1 src and 1 dest. Both pointing to the rawbytes (each pixel consists of 3 bytes (RGB)) then your algorithm would look like this
//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;
}
}
The >>8 and <<8 which you see scattered through the code is the use of 'fixed point'.
To make the scaling look better (since this scale is done using 'nearest neighbour'), you should take the average between the adjacent right pixel, the adjacent bottom pixel and the adjacent bottom right pixel. Make sure not to use a division ('/') but use >>2 which is much faster.
p.s. ah right..the code is off the top of my head so beware of small typos
回答4:
I don't know what else you're doing in your app or how important drawing stretched bitmaps is for you, but you may just want to use a more modern API like GDI+ or DirectX or OpenGL.
Nobody has changed how StretchDIBits or DrawDibDraw work since 1995 or so--you really want something that will take advantage of the GPU. (I would have expected that the drawing would be "fast enough" even with the CPU just because processors are a lot faster than they were back then, but apparently not.)
来源:https://stackoverflow.com/questions/1117537/how-to-improve-drawdibs-quality