BitBlt performance in C#
-
I'm using the following code to capture a screenshot : Image myImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); Graphics gr1 = Graphics.FromImage(myImage); IntPtr dc1 = gr1.GetHdc(); IntPtr dc2 = GetDC(GetDesktopWindow()); BitBlt(dc1, 0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, dc2, 0, 0, 13369376); gr1.ReleaseHdc(dc1); GC.Collect(); return myImage; I'm trying to capture a screenshot of the entire desktop and transferring it to a remote PC (to create a program like PcAnywhere). The thing is, i set my screenshot timer to something like 450 ms and on my machine (Athlon XP 2000+), it uses up around 30% of the CPU power. However, if i test it on my old P3-700 Mhz machine, the CPU utilisation is very high, ranging between 75-90%. Is there any way to reduce the CPU utilisation (maybe like reducing the color depth of the image? but how)?
-
I'm using the following code to capture a screenshot : Image myImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); Graphics gr1 = Graphics.FromImage(myImage); IntPtr dc1 = gr1.GetHdc(); IntPtr dc2 = GetDC(GetDesktopWindow()); BitBlt(dc1, 0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, dc2, 0, 0, 13369376); gr1.ReleaseHdc(dc1); GC.Collect(); return myImage; I'm trying to capture a screenshot of the entire desktop and transferring it to a remote PC (to create a program like PcAnywhere). The thing is, i set my screenshot timer to something like 450 ms and on my machine (Athlon XP 2000+), it uses up around 30% of the CPU power. However, if i test it on my old P3-700 Mhz machine, the CPU utilisation is very high, ranging between 75-90%. Is there any way to reduce the CPU utilisation (maybe like reducing the color depth of the image? but how)?
You should be releasing the DC you get with
GetDC()
, usingReleaseDC()
, and if you aren't going to be usinggr1
anymore, you should call Dispose() on it. What's making it slow is probably the transfer, not the capturing. I don't know if this will make it faster, or slower, but you could make a newBitmap
with a lower color depth, create aGraphics
from it, and useGraphics.DrawImage()
to draw the image onto the newBitmap
."Blessed are the peacemakers, for they shall be called sons of God." - Jesus
"You must be the change you wish to see in the world." - Mahatma Gandhi -
You should be releasing the DC you get with
GetDC()
, usingReleaseDC()
, and if you aren't going to be usinggr1
anymore, you should call Dispose() on it. What's making it slow is probably the transfer, not the capturing. I don't know if this will make it faster, or slower, but you could make a newBitmap
with a lower color depth, create aGraphics
from it, and useGraphics.DrawImage()
to draw the image onto the newBitmap
."Blessed are the peacemakers, for they shall be called sons of God." - Jesus
"You must be the change you wish to see in the world." - Mahatma GandhiNo, that doesn't make much difference. The code is now : Image myImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); Graphics gr1 = Graphics.FromImage(myImage); IntPtr dc1 = gr1.GetHdc(); IntPtr dc2 = GetDC(GetDesktopWindow()); BitBlt(dc1, 0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, dc2, 0, 0, 13369376); gr1.ReleaseHdc(dc1); ReleaseDC(GetDesktopWindow(), dc2); GC.Collect(); return myImage; I fail to mention earlier that i am utilising a savejpgwithcompression function and after some checking, it appears that it is the cause of the problem. It could be the compression part, but it is essential to make the file size smaller. Here's the code : private void SaveJPGWithCompressionSetting( Image image, string szFileName, long lCompression ) { EncoderParameters eps = new EncoderParameters(1); eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, lCompression ); ImageCodecInfo ici = GetEncoderInfo("image/jpeg"); image.Save( szFileName, ici, eps ); } private ImageCodecInfo GetEncoderInfo(string mimeType) { ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); foreach (ImageCodecInfo codec in codecs) { if (codec.MimeType == mimeType){return codec;} } return null; }
-
No, that doesn't make much difference. The code is now : Image myImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); Graphics gr1 = Graphics.FromImage(myImage); IntPtr dc1 = gr1.GetHdc(); IntPtr dc2 = GetDC(GetDesktopWindow()); BitBlt(dc1, 0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, dc2, 0, 0, 13369376); gr1.ReleaseHdc(dc1); ReleaseDC(GetDesktopWindow(), dc2); GC.Collect(); return myImage; I fail to mention earlier that i am utilising a savejpgwithcompression function and after some checking, it appears that it is the cause of the problem. It could be the compression part, but it is essential to make the file size smaller. Here's the code : private void SaveJPGWithCompressionSetting( Image image, string szFileName, long lCompression ) { EncoderParameters eps = new EncoderParameters(1); eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, lCompression ); ImageCodecInfo ici = GetEncoderInfo("image/jpeg"); image.Save( szFileName, ici, eps ); } private ImageCodecInfo GetEncoderInfo(string mimeType) { ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); foreach (ImageCodecInfo codec in codecs) { if (codec.MimeType == mimeType){return codec;} } return null; }
Well your first problem BitBlt is the slowest drawing technique. DirectX has BitBltFast or FastBitBlt which is twice as fast. If your trying to accomplish fast rasterization your first problem is using the GDI. You should really use directX fucntionsin the framework or even just write c++ blocks in your cde and access the directx directly. If possible create pages and store the bitmap data within the pages then show them at times needed check out gamedev.net for a lot of pointers on graphics. nick I'm not an expert yet, but I play one at work. Yeah and here too.