use Bitblt with GDI+

alexying

Member
Joined
May 26, 2003
Messages
9
I try to do something like off-screen drawing. First, I create a bitmap, draw on the bitmap, then use the BitBlt() function to draw it on the panel surface.

however, all I got is a rectangle with black color. There might be the way calling BitBlt was not so correct. Can someone help me out?

thanks a lot.

Alex

using System;

using System.Drawing;

using System.Drawing.Drawing2D;

using System.Drawing.Imaging;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using System.Threading;

using System.Runtime.InteropServices;

using System.Timers;

namespace TransparentBitmap

{









/// <summary>

/// Summary description for Form1.

/// </summary>

public class Form1 : System.Windows.Forms.Form

{


private MyPanel panel;

/// <summary>

/// Required designer variable.

/// </summary>

private System.ComponentModel.Container components = null;




public Form1()

{

//

// Required for Windows Form Designer support

//

InitializeComponent();

//

// TODO: Add any constructor code after InitializeComponent call

//

}

/// <summary>

/// Clean up any resources being used.

/// </summary>

protected override void Dispose( bool disposing )

{

if( disposing )

{

if (components != null)

{

components.Dispose();

}

}

base.Dispose( disposing );

}



#region Windows Form Designer generated code

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

private void InitializeComponent()

{

this.panel = new TransparentBitmap.MyPanel();

this.SuspendLayout();

//

// panel

//

this.panel.Name = "panel";

this.panel.Size = new System.Drawing.Size(300, 300);

this.panel.TabIndex = 0;

//

// Form1

//

this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);

this.ClientSize = new System.Drawing.Size(368, 328);

this.Controls.AddRange(new System.Windows.Forms.Control[] {

this.panel});

this.Name = "Form1";

this.Text = "Form1";

this.ResumeLayout(false);

this.panel.StartTimer();

}

#endregion

/// <summary>

/// The main entry point for the application.

/// </summary>

[STAThread]

static void Main()

{

Form1 form = new Form1();

Application.Run(form);


}

}







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

public class MyPanel : System.Windows.Forms.UserControl

{

private System.Timers.Timer timer;


Bitmap myBitmap ;

Graphics bitmapGraphics;

IntPtr bitmapPtr;

public MyPanel()

{

DrawBitmap();

this.SetStyle(ControlStyles.Opaque, true);

this.SetStyle(ControlStyles.UserPaint, true);

}

[DllImport("gdi32.dll")]

public static extern bool BitBlt(

IntPtr hdcDest,

int nXDest,

int nYDest,

int nWidth,

int nHeight,

IntPtr hdcSrc,

int nXSrc,

int nYSrc,

long dwRop

);

[DllImport("user32.dll")]

public static extern IntPtr GetDC(

IntPtr hwnd

);



public void redraw(Graphics g)

{

if( this.IsDisposed )

{

return;

}

if( ! g.IsVisibleClipEmpty )

{

IntPtr hdcScreen = g.GetHdc();

bitmapPtr = bitmapGraphics.GetHdc();

BitBlt(hdcScreen, 0, 0, 300, 300, bitmapPtr,

0, 0,

0x00CC0020);

g.ReleaseHdc(hdcScreen);

bitmapGraphics.ReleaseHdc(bitmapPtr);

}

}





protected override void OnPaint(PaintEventArgs e)

{

redraw(e.Graphics);

}




protected virtual void TimerOnTick( object obj, ElapsedEventArgs ea)//EventArgs ea)

{

this.Refresh();

}

public void StartTimer()

{

timer = new System.Timers.Timer();

timer.Interval = 20;

timer.Elapsed+=new ElapsedEventHandler(TimerOnTick);

timer.Enabled = true;

}


public void DrawBitmap()

{

myBitmap = new Bitmap(300,300);


bitmapGraphics = Graphics.FromImage(myBitmap);

bitmapGraphics.FillRectangle(Brushes.Red,0,0,300,100);

bitmapGraphics.FillRectangle(Brushes.Yellow,0,100,300,100);

bitmapGraphics.FillRectangle(Brushes.Blue,0,200,300,100);

}

}

}
 
hi, mutant,

Thank you for the reply. What I try to do is I try to build a grid myself.

I dont want to draw grid line and cell content every timr the OnPaint() is called. it is not efficient.

So, I draw to the bitmap first. when OnPaint() is called, i just blit the bitmap to the screen. I can use Graphics.DrawImage() to draw the bitmap. But Graphics.DrawImage() is slow, or i can say it is taking up too much CPU power when i try to draw the bitmap 50 times per second.

that is why i would like to try out the BitBlt to see if it makes any difference in term of CPU usage.

thanks
 
Hang on,

Youre saying you dont want to use the OnPaint method (which will draw when needed, the most common method of doing it) because its efficient, but youre trying to draw it 50 times per second?

You should be using DrawImage. You could interop with GDI, but why? .NET uses GDI+.
 
sorry for the confusion.

I am using OnPaint(), inside OnPaint() i want to call Bitblt to draw a GDI+ bitmap instead of calling DrawImage() to draw it.

the grid I am creating will be used for displaying real-time data. so, i need to fresh the grid quite often. Maybe 50 times per second is too much, but, it can happen.

Does anyone ever use Bitblt to draw a GDI+ bitmap?

thanks
 
Whats the point just draw DrawImage(Same as BitBlt for GDI+), using GDI would be slower because you would have to get a DC for the GDI+ Bitmap before BitBlt could be used, if you want to continually refresh the pictures just use a loop similar to a game loop to continually redraw the images
 
hi,

i find out how to make GDI+ bitmap work with Bitblt. Thanks, Rehan.

http://www.codeproject.com/csharp/flicker_free.asp


Try both Bitblt and drawImage. Event with get DC before Bitblt, Bitblt is about 1.5 times faster than drawImage.

here is the testing code:

1) for Bitblt

long start = System.DateTime.Now.Ticks;

for(int j =0; j<100;j++)
{
IntPtr hdcScreen = g.GetHdc();//GetDC(IntPtr.Zero);
//IntPtr hdcSurface = myBitmap2.GetHdc();

bitmap2Ptr = bitmap2Graphics.GetHdc();
BitBlt(hdcScreen, 0, 0, 300, 300, bitmap2Ptr,
0, 0,
0x00CC0020);//
g.ReleaseHdc(hdcScreen);
bitmap2Graphics.ReleaseHdc(bitmap2Ptr);
}
//surface.ReleaseHdc(hdcSurface);
long TimeTaken = System.DateTime.Now.Ticks - start;
System.Console.WriteLine("time "+TimeTaken);

2) for drawImage

long start = System.DateTime.Now.Ticks;

for(int j =0; j<100;j++)
{
gg.DrawImage(myBitmap2,destRect,srcRect,GraphicsUnit.Pixel);
}
//surface.ReleaseHdc(hdcSurface);
long TimeTaken = System.DateTime.Now.Ticks - start;
System.Console.WriteLine("time "+TimeTaken);

On average, Bitblt is 2000000 ticks, drawImage is 5000000 ticks


if somebody is interested in the comparison of speeds of GDI+ and GDI, go here

http://www.appdevadvisor.co.uk/Readers/Source_Code/main.htm

download file: AdaExampleApp.zip
 
GDI+ is optimized to be very fast with .NET -- using Win32 API with
.NET will almost always be slower than using managed code optimized
for .NET.
 
GDI+ might draw lines or text faster, i dont know. As far as raster graphics go, GDI+ is useless. The DrawImage() function is very slow compared to the GDI bitblt. I made a program that drew an image composed of 16x11 tiles, drawing it one tile at a time. With GDI the image essentially appeared in the graphics container. With GDI+ you can see the image being draw from left to right; it is much too slow. The only qualm I have with Visual Studio.net is that they intentionally make it difficult to use the Windows API when it is potentially a useful tool. I might help you Alexying, but your code is a huge and needs to be summarized, and i dont really know much about c# anyways.
 
I am just curious

1. when you tested, did you put
SetStyle(ControlStyles.DoubleBuffer,true);
SetStyle(ControlStyles.AllPaintingInWmPaint,true);
in your C# constructor?

2. the article did not mention anything about DrawImage being slower. In, fact it reccomended using DrawImage instead of Bitblt.

3. the article also said that DrawImage uses Bitblt already...I dont know if it is completely accurate or not though.
 
Originally posted by marble_eater
GDI+ might draw lines or text faster, i dont know. As far as raster graphics go, GDI+ is useless. The DrawImage() function is very slow compared to the GDI bitblt. I made a program that drew an image composed of 16x11 tiles, drawing it one tile at a time. With GDI the image essentially appeared in the graphics container. With GDI+ you can see the image being draw from left to right; it is much too slow. The only qualm I have with Visual Studio.net is that they intentionally make it difficult to use the Windows API when it is potentially a useful tool. I might help you Alexying, but your code is a huge and needs to be summarized, and i dont really know much about c# anyways.

DId you turn on DoubleBuffering and things like that? I have been working with both BitBlt and DrawImage and GDI+ does a lot better job. It uses the fastest drawing method available.
 
Apparently in Windows XP, Microsoft dumped GDI and replaced it with GDI+, the GDI32.dll only exists for compatibility reasons, so if you use WinXP GDI+ should be faster.
 

Similar threads

Back
Top