PageRenderTime 31ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/Skimpt3/Skimpt3/classes/skImageCapture.cs

http://skimpt.googlecode.com/
C# | 312 lines | 69 code | 64 blank | 179 comment | 1 complexity | 3d22f4d211f624bd31b430d84f5e38a8 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Drawing;
  6. using System.Windows.Forms;
  7. namespace Skimpt3.classes {
  8. class skImageCapture {
  9. /// Intro to DCs:
  10. /// If you are familiar, skip ahead. If not, read on.
  11. /// Device contexts are just generic ways to represent devices,
  12. /// or things you can draw on or interact with graphically.
  13. /// This is hugely over simplified, and I'm going to get flamed, but for the sake of brevity,
  14. /// let's just go with that for now. You can get device context's, or dc's as
  15. /// they are commonly referred to, from images, windows, monitors, and even printers.
  16. /// Every window has them, and you can use them to draw with. Everything you see on your screen is being
  17. /// drawn upon a device context. The desktop, every window, your taskbar, and anything you see.
  18. /// You can draw upon them, or copy what they have drawn upon them. If you can get a hold of them,
  19. /// you can pretty much draw or steal whatever you want graphically speaking.
  20. /// Working with device contexts is fast, and both GDI and GDI+ are based on them.
  21. /// in the case of capturing the screen, we know that somewhere Windows is drawing upon a device context, so that we can see it.
  22. /// In fact, there's one for each monitor you have attached to your system, and that desktop that you are seeing on it,
  23. /// is being drawn on that monitor's device context.
  24. /// All we have to do is grab a hold of that device context, create another one of our own,
  25. /// and copy the screen's device context image data to our own, and we've got a screen capture
  26. ///
  27. public static Bitmap GetDesktopWindowCaptureAsBitmap()
  28. {
  29. //SEE HOW THIS FUNCTION WORKS AT THE END OF THIS FUNCTION.
  30. Rectangle rcScreen = Rectangle.Empty;
  31. Screen[] screens = Screen.AllScreens;
  32. // Create a rectangle encompassing all screens...
  33. foreach (Screen screen in Screen.AllScreens)
  34. rcScreen = Rectangle.Union(rcScreen, screen.Bounds);
  35. // Create a composite bitmap of the size of all screens...
  36. Bitmap finalBitmap = new Bitmap(rcScreen.Width, rcScreen.Height);
  37. // Get a graphics object for the composite bitmap and initialize it...
  38. Graphics g = Graphics.FromImage(finalBitmap);
  39. g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
  40. g.FillRectangle(
  41. SystemBrushes.Desktop,
  42. 0,
  43. 0,
  44. rcScreen.Width - rcScreen.X,
  45. rcScreen.Height - rcScreen.Y);
  46. // Get an HDC for the composite area...
  47. IntPtr hdcDestination = g.GetHdc();
  48. // Now, loop through screens,
  49. // Blting each to the composite HDC created above...
  50. foreach (Screen screen in Screen.AllScreens)
  51. {
  52. // Create DC for each source monitor...
  53. IntPtr hdcSource = Win32.CreateDC(
  54. IntPtr.Zero,
  55. screen.DeviceName,
  56. IntPtr.Zero,
  57. IntPtr.Zero);
  58. // Blt the source directly to the composite destination...
  59. int xDest = screen.Bounds.X - rcScreen.X;
  60. int yDest = screen.Bounds.Y - rcScreen.Y;
  61. bool success = Win32.StretchBlt(
  62. hdcDestination,
  63. xDest,
  64. yDest,
  65. screen.Bounds.Width,
  66. screen.Bounds.Height,
  67. hdcSource,
  68. 0,
  69. 0,
  70. screen.Bounds.Width,
  71. screen.Bounds.Height,
  72. (int)Win32.TernaryRasterOperations.SRCCOPY);
  73. // System.Diagnostics.Trace.WriteLine(screen.Bounds);
  74. if (!success)
  75. {
  76. System.ComponentModel.Win32Exception win32Exception =
  77. new System.ComponentModel.Win32Exception();
  78. System.Diagnostics.Trace.WriteLine(win32Exception);
  79. }
  80. // Cleanup source HDC...
  81. Win32.DeleteDC(hdcSource);
  82. }
  83. // Cleanup destination HDC and Graphics...
  84. g.ReleaseHdc(hdcDestination);
  85. g.Dispose();
  86. // Return composite bitmap which will become our Form's PictureBox's image...
  87. return finalBitmap;
  88. ///Looking at the code, the first thing you'll see is that I'm using a mixture of GDI and GDI+.
  89. ///This is due largely to the fact that there is a bug present in GDI+ and the BtBlt API.
  90. ///This issue only manifests itself on systems with multiple monitors, and if I remember correctly,
  91. ///the system had to have a NVida display adapter on the non-primary monitor, and of course, our old friend Windows 98 running as the OS.
  92. ///What happens is the primary monitor captures fine, the secondary (or any non-primary) monitor stands a chance of returning garbage for an image.
  93. ///It looks like cable channel with no signal.
  94. ///Instead of relying on purely managed code, do copy the images,
  95. ///or backing up to the BtBlt API, we instead fall back to it's somewhat slower cousin, StretchBlt.
  96. ///first up we just grab all of the monitors using the Screen class' AllScreens property.
  97. ///This does two things for us. First it allows us to figure out how big the entire desktop is,
  98. ///and create an image just big enough to hold all of the screens inside.
  99. ///And secondly, it allows us to figure out just where each monitor is positioned in relation to the other.
  100. ///Remember, with multiple monitor support you can "arrange" your monitors in different ways,
  101. ///and with different resolutions, so don't think in terms of a pure rectangle when you think of
  102. ///how your monitors are positioned.
  103. ///Once we have those screens, it's a trivial matter to calculate the size of the entire bitmap
  104. ///by using the Rectangle.Union method to build up the size of the overall image.
  105. ///After we've figured out the size of the final image, we'll grab a Graphics object from the image.
  106. ///The GDI+ Graphics object is just the .NET wrapper around a device context.
  107. ///Using that graphics context, we can draw on the bitmap with the graphics object.
  108. ///Next, we'll enumerate through each monitor, and draw what that monitor has on it's device context,
  109. ///upon the image we just created that will hold the final screen shot.
  110. ///Well draw it using it's coordinates so that in case the monitors have different resolutions or positioning
  111. ///we'll be able to see them as the Display Control Panel applet sees them.
  112. ///Go check it out if you have multiple monitors, and you didn't know you could move them.
  113. ///Chances are there if you have multiple monitors, you know this already, but if not so harm no foul.
  114. ///Open the settings tab and drag one of the monitors around and
  115. ///you'll see you can reposition it in relation to the other monitors.
  116. ///For each monitor, we'll simply use the StretchBlt API to copy that monitor's device context contents,
  117. ///to the bitmap that will serve as the screen capture of the desktop.
  118. ///Notice that I'm creating a device context each time, this gives us access to that monitor's device context so
  119. ///that we can copy from it. Keep in mind that if we create it, we must destroy it,
  120. ///so we delete the device context when we are finished with it. If you don't, you'll have a memory leak,
  121. ///so keep a watchful eye on your dc's and make sure to release or destroy them.
  122. ///A simple rule is, if you "acquire" it, you're required to "release" it.
  123. ///And if you "create" it, then you must "destroy" it.
  124. ///I quote those because if you look at the GDI APIs, with that in mind you'll find the necessary APIs to do exactly what you want.
  125. ///Finally, after copying the contents of each device context to that bitmap we created,
  126. ///we'll release the Graphics object we acquired from the bitmap, and dispose it.
  127. ///That's the proper way to clean up a graphics object, if you've acquired a device context from it.
  128. }
  129. public static Bitmap CaptureDeskTopRectangle(Rectangle CapRect, int CapRectWidth, int CapRectHeight)
  130. {
  131. //This function just calls the GetDesktop, and just crops it.
  132. Bitmap bmpImage = new Bitmap(GetDesktopWindowCaptureAsBitmap());
  133. Bitmap bmpCrop = new Bitmap(CapRectWidth, CapRectHeight, bmpImage.PixelFormat);
  134. Rectangle recCrop = new Rectangle(CapRect.X, CapRect.Y, CapRectWidth, CapRectHeight);
  135. Graphics gphCrop = Graphics.FromImage(bmpCrop);
  136. Rectangle recDest = new Rectangle(0, 0, CapRectWidth, CapRectHeight);
  137. gphCrop.DrawImage(bmpImage, recDest, recCrop.X, recCrop.Y, recCrop.Width, recCrop.Height, GraphicsUnit.Pixel);
  138. return bmpCrop;
  139. }
  140. //
  141. // Credits: Mark (Code6) Belles C# version
  142. // Me :+)) for the porting code
  143. // Thanks to EVA for g->ReleaseHDC or you may have a black screen
  144. // and MSDN http://msdn2.microsoft.com/en-us/library/ms533843(VS.85).aspx
  145. // Enjoy: Feel free to use it....
  146. //
  147. //#include "stdafx.h"
  148. //#include <windows.h>
  149. //#include <gdiplus.h>
  150. //#pragma comment(lib, "gdiplus.lib")
  151. //#define SAFE_DELETE(ptrToDelete) if (ptrToDelete != NULL) { delete ptrToDelete; ptrToDelete = NULL; }
  152. //ULONG_PTR gdiplusToken;
  153. //int m_nScreenCount;
  154. //RECT m_ScreensRect[8];
  155. //TCHAR m_ScreensName[8][CCHDEVICENAME];
  156. //BOOL CALLBACK MyInfoEnumProcs( HMONITOR hMonitor, HDC hdcMonitor,
  157. // LPRECT lprcMonitor, LPARAM dwData )
  158. //{
  159. // MONITORINFOEX monitorInfo;
  160. // memcpy(&m_ScreensRect[m_nScreenCount], lprcMonitor, sizeof(RECT));
  161. // memset(&monitorInfo, 0x0, sizeof(MONITORINFOEX));
  162. // monitorInfo.cbSize = sizeof(MONITORINFOEX);
  163. // GetMonitorInfo(hMonitor, &monitorInfo);
  164. // strcpy_s((char *) &m_ScreensName[m_nScreenCount], CCHDEVICENAME, monitorInfo.szDevice);
  165. // m_nScreenCount++;
  166. // return TRUE;
  167. //}
  168. //int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
  169. //{
  170. // UINT num = 0; // number of image encoders
  171. // UINT size = 0; // size of the image encoder array
  172. // // in bytes
  173. // Gdiplus::ImageCodecInfo* pImageCodecInfo = NULL;
  174. // Gdiplus::GetImageEncodersSize(&num, &size);
  175. // if(size == 0)
  176. // return -1;
  177. // pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size));
  178. // if(pImageCodecInfo == NULL)
  179. // return -1;
  180. // GetImageEncoders(num, size, pImageCodecInfo);
  181. // for(UINT j = 0; j < num; ++j)
  182. // {
  183. // if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
  184. // {
  185. // *pClsid = pImageCodecInfo[j].Clsid;
  186. // free(pImageCodecInfo);
  187. // return j; // Success
  188. // }
  189. // }
  190. // free(pImageCodecInfo);
  191. // return -1;
  192. //}
  193. //int _tmain(int argc, _TCHAR* argv[])
  194. //{
  195. // Gdiplus::GdiplusStartupInput gdiplusStartupInput;
  196. // gdiplusToken = NULL;
  197. // if (GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL) != Gdiplus::Ok)
  198. // {
  199. // gdiplusToken = NULL;
  200. // }
  201. // memset(&m_ScreensRect, 0x0, sizeof(m_ScreensRect));
  202. // memset(&m_ScreensName, 0x0, sizeof(m_ScreensName));
  203. // EnumDisplayMonitors(NULL, NULL, MyInfoEnumProcs, 0);
  204. // HDC hdcDestination = NULL;
  205. // RECT rcScreen;
  206. // memset(&rcScreen, 0x0, sizeof(rcScreen));
  207. // for(int screenCount=0; screenCount < m_nScreenCount; screenCount++)
  208. // {
  209. // UnionRect(&rcScreen, &rcScreen, &m_ScreensRect[screenCount]);
  210. // }
  211. // // Create a composite bitmap of the size of all screens...
  212. // Gdiplus::Bitmap* finalBitmap = new Gdiplus::Bitmap(rcScreen.right, rcScreen.bottom);
  213. // // Get a graphics object for the composite bitmap and initialize it...
  214. // Gdiplus::Graphics * g = Gdiplus::Graphics::FromImage(finalBitmap);
  215. // g->SetCompositingQuality(Gdiplus::CompositingQualityHighSpeed);
  216. // Gdiplus::SolidBrush solidBrush(Gdiplus::Color(0,0,0));
  217. // g->FillRectangle(&solidBrush, 0, 0, rcScreen.right, rcScreen.bottom);
  218. // // Get an HDC for the composite area...
  219. // hdcDestination = g->GetHDC();
  220. // // Now, loop through screens, BitBlting each to the composite HDC created above...
  221. // for(int screenCount=0; screenCount < m_nScreenCount; screenCount++)
  222. // {
  223. // // Create DC for each source monitor...
  224. // HDC hdcSource = CreateDC(NULL, m_ScreensName[screenCount], NULL, NULL);
  225. // // Blt the source directly to the composite destination...
  226. // int xDest = m_ScreensRect[screenCount].left - rcScreen.left;
  227. // int yDest = m_ScreensRect[screenCount].top - rcScreen.top;
  228. // StretchBlt(hdcDestination, xDest, yDest, m_ScreensRect[screenCount].right, m_ScreensRect[screenCount].bottom,
  229. // hdcSource, 0, 0, m_ScreensRect[screenCount].right, m_ScreensRect[screenCount].bottom, SRCCOPY | CAPTUREBLT);
  230. // // Cleanup source HDC...
  231. // DeleteDC(hdcSource);
  232. // }
  233. // g->ReleaseHDC(hdcDestination);
  234. // CLSID clsidJPEG;
  235. // GetEncoderClsid(L"image/jpeg", &clsidJPEG);
  236. // finalBitmap->Save(L"c:\\screenshot.jpg", &clsidJPEG);
  237. // GetEncoderClsid(L"image/gif", &clsidJPEG);
  238. // finalBitmap->Save(L"c:\\screenshot.gif", &clsidJPEG);
  239. // GetEncoderClsid(L"image/bmp", &clsidJPEG);
  240. // finalBitmap->Save(L"c:\\screenshot.bmp", &clsidJPEG);
  241. // // Cleanup destination HDC and Graphics...
  242. // DeleteDC(hdcDestination);
  243. // SAFE_DELETE(g);
  244. // SAFE_DELETE(finalBitmap);
  245. // return 0;
  246. //}
  247. }
  248. }