c# – 如何在不使用剪贴板的情况下复制图像?
问题:我有以下代码从网络摄像头捕获图像.
我的问题是这部分: SendMessage(hCaptureWnd,WM_CAP_COPY,0); // copy it to the clipboard 它的作用是将图像从窗口复制到剪贴板,然后从中创建一个字节数组. 它可以工作 – 只要你在程序运行时不使用剪贴板. 所以我的问题在这里: – 编辑: /// <summary> /// Captures a frame from the webcam and returns the byte array associated /// with the captured image /// </summary> /// <param name="connectDelay">number of milliseconds to wait between connect /// and capture - necessary for some cameras that take a while to 'warm up'</param> /// <returns>byte array representing a bitmp or null (if error or no webcam)</returns> private static byte[] InternalCaptureToByteArray(int connectDelay = 500) { Clipboard.Clear(); // clear the clipboard int hCaptureWnd = capCreateCaptureWindowA("ccWebCam",// create the hidden capture window 350,350,0); SendMessage(hCaptureWnd,WM_CAP_CONNECT,0); // send the connect message to it Thread.Sleep(connectDelay); // sleep the specified time SendMessage(hCaptureWnd,WM_CAP_GET_FRAME,0); // capture the frame SendMessage(hCaptureWnd,0); // copy it to the clipboard SendMessage(hCaptureWnd,WM_CAP_DISCONNECT,0); // disconnect from the camera Bitmap bitmap = (Bitmap)Clipboard.GetDataObject().GetData(DataFormats.Bitmap); // copy into bitmap if (bitmap == null) return null; using (MemoryStream stream = new MemoryStream()) { bitmap.Save(stream,ImageFormat.Bmp); // get bitmap bytes return stream.ToArray(); } // End Using stream } // End Function InternalCaptureToByteArray 注(http://msdn.microsoft.com/en-us/library/windows/desktop/dd756879(v=vs.85).aspx): HWND VFWAPI capCreateCaptureWindow( LPCTSTR lpszWindowName,DWORD dwStyle,int x,int y,int nWidth,int nHeight,HWND hWnd,int nID ); #define VFWAPI WINAPI typedef HANDLE HWND; typedef PVOID HANDLE; typedef void *PVOID; 完整代码供参考 using System; using System.IO; using System.Drawing; using System.Threading; using System.Windows.Forms; using System.Drawing.Imaging; using System.Collections.Generic; using System.Runtime.InteropServices; // http://www.creativecodedesign.com/node/66 // http://www.barebonescoder.com/2012/01/finding-your-web-cam-with-c-directshow-net/ // http://www.codeproject.com/Articles/15219/WebCam-Fast-Image-Capture-Service-using-WIA // http://www.c-sharpcorner.com/uploadfile/yougerthen/integrate-the-web-webcam-functionality-using-C-Sharp-net-and-com-part-viii/ // http://forums.asp.net/t/1410057.aspx namespace cc.Utility { // bool isCaptured = ccWebCam.CaptureSTA("capture.jpg"); // Access to path C:Program Files (x86)Common FilesMicrosoft SharedDevServer10.0capture.jpg" denied. // byte[] captureBytes = ccWebCam.CaptureSTA(); /// <summary> /// Timur Kovalev (http://www.creativecodedesign.com): /// This class provides a method of capturing a webcam image via avicap32.dll api. /// </summary> public static class ccWebCam { #region *** PInvoke Stuff - methods to interact with capture window *** [DllImport("user32",EntryPoint = "SendMessage")] private static extern int SendMessage(int hWnd,uint Msg,int wParam,int lParam); [DllImport("avicap32.dll",EntryPoint = "capCreateCaptureWindowA")] private static extern int capCreateCaptureWindowA(string lpszWindowName,int dwStyle,int X,int Y,int hwndParent,int nID); private const int WM_CAP_CONNECT = 1034; private const int WM_CAP_DISCONNECT = 1035; private const int WM_CAP_COPY = 1054; private const int WM_CAP_GET_FRAME = 1084; #endregion private static object objWebCamThreadLock = new object(); //CaptureToFile(@"D:Stefan.SteigerDocumentsVisual Studio 2010ProjectsPost_Ipagimage3.jpg"): public static bool Capture(string filePath,int connectDelay = 500) { lock (objWebCamThreadLock) { return cc.Utility.ccWebCam.InternalCaptureAsFileInThread(filePath,connectDelay); } } // End Treadsafe Function Capture public static byte[] Capture(int connectDelay = 500) { lock (objWebCamThreadLock) { return InternalCaptureToByteArrayInThread(connectDelay); } } // End Treadsafe Function Capture /// <summary> /// Captures a frame from the webcam and returns the byte array associated /// with the captured image. The image is also stored in a file /// </summary> /// <param name="filePath">path the file wher ethe image will be saved</param> /// <param name="connectDelay">number of milliseconds to wait between connect /// and capture - necessary for some cameras that take a while to 'warm up'</param> /// <returns>true on success,false on failure</returns> private static bool InternalCaptureAsFileInThread(string filePath,int connectDelay = 500) { bool success = false; Thread catureThread = new Thread(() => { success = InternalCaptureAsFile(filePath,connectDelay); }); catureThread.SetApartmentState(ApartmentState.STA); catureThread.Start(); catureThread.Join(); return success; } // End Function InternalCaptureAsFileInThread /// <summary> /// Captures a frame from the webcam and returns the byte array associated /// with the captured image. The image is also stored in a file /// </summary> /// <param name="filePath">path the file wher ethe image will be saved</param> /// <param name="connectDelay">number of milliseconds to wait between connect /// and capture - necessary for some cameras that take a while to 'warm up'</param> /// <returns>true on success,false on failure</returns> private static bool InternalCaptureAsFile(string filePath,int connectDelay = 500) { byte[] capture = ccWebCam.InternalCaptureToByteArray(connectDelay); if (capture != null) { // Access to path C:Program Files (x86)Common FilesMicrosoft SharedDevServer10.0image1.jpg" denied. File.WriteAllBytes(filePath,capture); return true; } return false; } // End Function InternalCaptureAsFile /// <summary> /// Captures a frame from the webcam and returns the byte array associated /// with the captured image. Runs in a newly-created STA thread which is /// required for this method of capture /// </summary> /// <param name="connectDelay">number of milliseconds to wait between connect /// and capture - necessary for some cameras that take a while to 'warm up'</param> /// <returns>byte array representing a bitmp or null (if error or no webcam)</returns> private static byte[] InternalCaptureToByteArrayInThread(int connectDelay = 500) { byte[] bytes = null; Thread catureThread = new Thread(() => { bytes = InternalCaptureToByteArray(connectDelay); }); catureThread.SetApartmentState(ApartmentState.STA); catureThread.Start(); catureThread.Join(); return bytes; } // End Function InternalCaptureToByteArrayInThread /// <summary> /// Captures a frame from the webcam and returns the byte array associated /// with the captured image /// </summary> /// <param name="connectDelay">number of milliseconds to wait between connect /// and capture - necessary for some cameras that take a while to 'warm up'</param> /// <returns>byte array representing a bitmp or null (if error or no webcam)</returns> private static byte[] InternalCaptureToByteArray(int connectDelay = 500) { Clipboard.Clear(); // clear the clipboard int hCaptureWnd = capCreateCaptureWindowA("ccWebCam",// create the hidden capture window 350,0); SendMessage(hCaptureWnd,0); // send the connect message to it Thread.Sleep(connectDelay); // sleep the specified time SendMessage(hCaptureWnd,0); // capture the frame SendMessage(hCaptureWnd,0); // copy it to the clipboard SendMessage(hCaptureWnd,0); // disconnect from the camera Bitmap bitmap = (Bitmap)Clipboard.GetDataObject().GetData(DataFormats.Bitmap); // copy into bitmap if (bitmap == null) return null; using (MemoryStream stream = new MemoryStream()) { bitmap.Save(stream,ImageFormat.Bmp); // get bitmap bytes return stream.ToArray(); } // End Using stream } // End Function InternalCaptureToByteArray } } 我试过这样,但它只得到一个黑色的图像…… [DllImport("user32.dll")] static extern IntPtr GetWindowDC(IntPtr hWnd); [DllImport("gdi32.dll",SetLastError = true)] static extern IntPtr CreateCompatibleDC(IntPtr hdc); enum TernaryRasterOperations : uint { /// <summary>dest = source</summary> SRCCOPY = 0x00CC0020,/// <summary>dest = source OR dest</summary> SRCPAINT = 0x00EE0086,/// <summary>dest = source AND dest</summary> SRCAND = 0x008800C6,/// <summary>dest = source XOR dest</summary> SRCINVERT = 0x00660046,/// <summary>dest = source AND (NOT dest)</summary> SRCERASE = 0x00440328,/// <summary>dest = (NOT source)</summary> NOTSRCCOPY = 0x00330008,/// <summary>dest = (NOT src) AND (NOT dest)</summary> NOTSRCERASE = 0x001100A6,/// <summary>dest = (source AND pattern)</summary> MERGECOPY = 0x00C000CA,/// <summary>dest = (NOT source) OR dest</summary> MERGEPAINT = 0x00BB0226,/// <summary>dest = pattern</summary> PATCOPY = 0x00F00021,/// <summary>dest = DPSnoo</summary> PATPAINT = 0x00FB0A09,/// <summary>dest = pattern XOR dest</summary> PATINVERT = 0x005A0049,/// <summary>dest = (NOT dest)</summary> DSTINVERT = 0x00550009,/// <summary>dest = BLACK</summary> BLACKNESS = 0x00000042,/// <summary>dest = WHITE</summary> WHITENESS = 0x00FF0062,/// <summary> /// Capture window as seen on screen. This includes layered windows /// such as WPF windows with AllowsTransparency="true" /// </summary> CAPTUREBLT = 0x40000000 } [DllImport("gdi32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool BitBlt(IntPtr hdc,int nXDest,int nYDest,IntPtr hdcSrc,int nXSrc,int nYSrc,TernaryRasterOperations dwRop); [DllImport("gdi32.dll")] static extern IntPtr CreateCompatibleBitmap(IntPtr hdc,int nHeight); [DllImport("gdi32.dll",ExactSpelling = true,PreserveSig = true,SetLastError = true)] static extern IntPtr SelectObject(IntPtr hdc,IntPtr hgdiobj); [DllImport("gdi32.dll")] static extern bool DeleteDC(IntPtr hdc); [DllImport("user32.dll")] static extern bool ReleaseDC(IntPtr hWnd,IntPtr hDC); [DllImport("gdi32.dll")] static extern bool DeleteObject(IntPtr hObject); public static void ScreenshotWindow(IntPtr windowHandle) { Rect Rect = new Rect(); GetWindowRect(windowHandle,ref Rect); int width = Rect.Right - Rect.Left; int height = Rect.Bottom - Rect.Top; IntPtr windowDeviceContext = GetWindowDC(windowHandle); IntPtr destDeviceContext = CreateCompatibleDC(windowDeviceContext); IntPtr bitmapHandle = CreateCompatibleBitmap(windowDeviceContext,width,height); IntPtr oldObject = SelectObject(destDeviceContext,bitmapHandle); BitBlt(destDeviceContext,height,windowDeviceContext,TernaryRasterOperations.CAPTUREBLT | TernaryRasterOperations.SRCCOPY); SelectObject(destDeviceContext,oldObject); DeleteDC(destDeviceContext); ReleaseDC(windowHandle,destDeviceContext); Image screenshot = Image.FromHbitmap(bitmapHandle); DeleteObject(bitmapHandle); screenshot.Save("d:tempmywebcamimage.png",System.Drawing.Imaging.ImageFormat.Png); /* // TODO - Remove above save when it works using (MemoryStream stream = new MemoryStream()) { screenshot.Save(stream,System.Drawing.Imaging.ImageFormat.Png); return stream.ToArray(); } */ } 然后在SendMessage之后(hCaptureWnd,0); ScreenshotWindow(new IntPtr(hCaptureWnd)); 解决方法
没有WM_CAP_GET_FRAME这样的东西.消息的正确名称是
WM_CAP_GRAB_FRAME ,它在MSDN上描述.
它的作用是:
要获得实际数据,您需要使用frame callback as described further on MSDN.回调可以获取图片字节,您可以将其写入文件或用于任何处理而无需通过剪贴板传输.
同样,这个API是视频捕获的不吉利的选择.太旧了,太有限了. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |