Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gdi+ Graphics::DrawImage really slow~~

I am using a GDI+ Graphic to draw a 4000*3000 image to screen, but it is really slow. It takes about 300ms. I wish it just occupy less than 10ms.

Bitmap *bitmap = Bitmap::FromFile("XXXX",...);

//-------------------------------------------- // this part takes about 300ms, terrible!

int width = bitmap->GetWidth();
int height = bitmap->GetHeight();
DrawImage(bitmap,0,0,width,height);

//------------------------------------------

I cannot use CachedBitmap, because I want to edit the bitmap later.

How can I improve it? Or is any thing wrong?

This native GDI function also draws the image into the screen, and it just take 1 ms:

SetStretchBltMode(hDC, COLORONCOLOR);   
StretchDIBits(hDC, rcDest.left, rcDest.top, 
        rcDest.right-rcDest.left, rcDest.bottom-rcDest.top, 
        0, 0, width, height,
        BYTE* dib, dibinfo, DIB_RGB_COLORS, SRCCOPY);

//--------------------------------------------------------------

If I want to use StretchDIBits, I need to pass BITMAPINFO, But how can I get BITMAPINFO from a Gdi+ Bitmap Object? I did the experiment by FreeImage lib, I call StretchDIBits using FreeImageplus object, it draw really fast. But now I need to draw Bitmap, and write some algorithm on Bitmap's bits array, how can I get BITMAPINFO if I have an Bitmap object? It's really annoying -___________-|

like image 511
user25749 Avatar asked Nov 05 '08 09:11

user25749


4 Answers

If you're using GDI+, the TextureBrush class is what you need for rendering images fast. I've written a couple of 2d games with it, getting around 30 FPS or so.

I've never written .NET code in C++, so here's a C#-ish example:

Bitmap bmp = new Bitmap(...)
TextureBrush myBrush = new TextureBrush(bmp)

private void Paint(object sender, PaintEventArgs e):
{
    //Don't draw the bitmap directly. 
    //Only draw TextureBrush inside the Paint event.
    e.Graphics.FillRectangle(myBrush, ...)
}
like image 101
Cybis Avatar answered Nov 15 '22 05:11

Cybis


You have a screen of 4000 x 3000 resolution? Wow!

If not, you should draw only the visible part of the image, it would be much faster...

[EDIT after first comment] My remark is indeed a bit stupid, I suppose DrawImage will mask/skip unneeded pixels.

After your edit (showing StretchDIBits), I guess a possible source of speed difference might come from the fact that StretchDIBits is hardware accelerated ("If the driver cannot support the JPEG or PNG file image" is a hint...) while DrawImage might be (I have no proof for that!) coded in C, relying on CPU power instead of GPU's one...

If I recall correctly, DIB images are fast (despite being "device independent"). See High Speed Win32 Animation: "use CreateDIBSection to do high speed animation". OK, it applies to DIB vs. GDI, in old Windows version (1996!) but I think it is still true.

[EDIT] Maybe Bitmap::GetHBITMAP function might help you to use StretchDIBits (not tested...).

like image 37
PhiLho Avatar answered Nov 15 '22 05:11

PhiLho


Just a thought; instead of retrieving the width and height of the image before drawing, why not cache these values when you load the image?

like image 2
Patrik Svensson Avatar answered Nov 15 '22 06:11

Patrik Svensson


Explore the impact of explicitly setting the interpolation mode to NearestNeighbor (where, in your example, it looks like interpolation is not actually needed! But 300ms is the kind of cost of doing high-quality interpolation when no interpolation is needed, so its worth a try)

Another thing to explore is changing the colour depth of the bitmap.

like image 2
Will Avatar answered Nov 15 '22 06:11

Will