2013-04-24 13 views
6

Domanda: Ho il codice seguente per catturare un'immagine da una webcam.Come copiare l'immagine senza usare gli appunti?

Il mio problema è questa parte:

SendMessage(hCaptureWnd, WM_CAP_COPY, 0, 0);     // copy it to the clipboard 

Ciò che fa è copiare l'immagine dalla finestra negli appunti, e quindi creare un array di byte fuori di esso.

Funziona - finché non si utilizzano gli Appunti mentre il programma è in esecuzione.
Il problema è che questo non funziona nemmeno per me stesso, poiché a volte copio qualcosa mentre Visual Studio impiega anni per avviare il debug dell'applicazione Web e quindi si blocca.

Quindi, ecco la mia domanda:
Come posso ottenere l'immagine senza utilizzare gli Appunti? O più specificamente, come trasformare hCaptureWnd in System.Drawing.Image?


- Edit:
mi mancava di dire "senza creare un file, voglio un array di byte".
Si tratta di un'applicazione web, in modo che l'utente l'applicazione viene eseguita sotto non dovrebbe avere accesso in scrittura al file system (la scrittura su un file solo per la prova temporanea) ...
- Fine Edit:


/// <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", 0, 0, 0, // create the hidden capture window 
     350, 350, 0, 0); 
    SendMessage(hCaptureWnd, WM_CAP_CONNECT, 0, 0);     // send the connect message to it 
    Thread.Sleep(connectDelay);          // sleep the specified time 
    SendMessage(hCaptureWnd, WM_CAP_GET_FRAME, 0, 0);    // capture the frame 
    SendMessage(hCaptureWnd, WM_CAP_COPY, 0, 0);     // copy it to the clipboard 
    SendMessage(hCaptureWnd, WM_CAP_DISCONNECT, 0, 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 

Nota (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; 

codice completo per riferimento

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 Files\Microsoft Shared\DevServer\10.0\capture.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 nWidth, int nHeight, 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.Steiger\Documents\Visual Studio 2010\Projects\Post_Ipag\image3.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 Files\Microsoft Shared\DevServer\10.0\image1.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", 0, 0, 0, // create the hidden capture window 
       350, 350, 0, 0); 
      SendMessage(hCaptureWnd, WM_CAP_CONNECT, 0, 0);     // send the connect message to it 
      Thread.Sleep(connectDelay);          // sleep the specified time 
      SendMessage(hCaptureWnd, WM_CAP_GET_FRAME, 0, 0);    // capture the frame 
      SendMessage(hCaptureWnd, WM_CAP_COPY, 0, 0);     // copy it to the clipboard 
      SendMessage(hCaptureWnd, WM_CAP_DISCONNECT, 0, 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 


    } 


} 

ho provato in questo modo, ma si ottiene solo un'immagine in bianco ...

[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, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop); 

    [DllImport("gdi32.dll")] 
    static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, 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, 0, 0, width, height, windowDeviceContext, 0, 0, TernaryRasterOperations.CAPTUREBLT | TernaryRasterOperations.SRCCOPY); 
     SelectObject(destDeviceContext, oldObject); 

     DeleteDC(destDeviceContext); 
     ReleaseDC(windowHandle, destDeviceContext); 


     Image screenshot = Image.FromHbitmap(bitmapHandle); 
     DeleteObject(bitmapHandle); 

     screenshot.Save("d:\\temp\\mywebcamimage.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(); 
     } 
     */ 
    } 

E poi questo dopo SendMessage(hCaptureWnd, WM_CAP_GET_FRAME, 0, 0);

ScreenshotWindow(new IntPtr(hCaptureWnd)); 
+0

non capisco perché non solo ... * non * copiare l'immagine negli appunti e invece convertirla direttamente in un array di byte. È il gestore di messaggi 'WM_CAP_COPY' che contiene questa logica? Che biblioteca fornisce questo messaggio? Puoi ignorare il suo comportamento? –

+0

@Cody Gray: Quella libreria è Windows! WinAPI! E no, non posso cambiare windows, non ho il codice sorgente (non che non potrei smontare e correggere, ma questo è l'approccio sbagliato qui);) E per rispondere alla tua domanda: Perché non so come per creare un'immagine da un hCaptureWnd, che è incidentalmente la domanda ... –

+0

Hmm, perché non riesco a trovare alcuna documentazione per questo? Immagino di essere fuori dal mio campionato qui, non ne ho mai sentito parlare. –

risposta

1

Sulla risposta di Romano R.:

Il punto più fine della morale è che è necessario registrare il telaio callback, e quindi chiamare grabframe, e che non si può lanciare direttamente in stile C char [] a byte [], e che ottieni dati bitmap non elaborati, non bitmap e che la dimensione dell'immagine è 640x480, indipendentemente da ciò che è impostato in capCreateCaptureWindowA e che lpData deve essere un IntPtr, non un UIntPtr, perché Marshal.Copy non ha sovraccarico per UIntPtr, e che usando WriteBitmapFile, è possibile scrivere dati bitmap grezzi in una bitmap SENZA usare codice non sicuro o mappare le intestazioni dei file bitmap, e che chiunque abbia scritto Marshal.Copy ha permesso di copiare un valore negativo, perché lunghezza è int, non uint ...

Inoltre, è necessario ruotare l'immagine 180 oldDegrees per qualsiasi motivo ...
Inoltre, ho modificato le costanti WM con i nomi corretti.

SendMessage(hCaptureWnd, WM_CAP_SET_CALLBACK_FRAME, 0, capVideoStreamCallback); 
    SendMessage(hCaptureWnd, WM_CAP_GRAB_FRAME, 0, 0);    // capture the frame 

Con queste cose aggiuntive

// http://msdn.microsoft.com/en-us/library/windows/desktop/dd757688(v=vs.85).aspx 
    [StructLayout(LayoutKind.Sequential)] 
    private struct VIDEOHDR 
    { 
     // http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx 


     // typedef unsigned char BYTE; 
     // typedef BYTE far *LPBYTE; 
     // unsigned char* lpData 


     //public byte[] lpData; // LPBYTE lpData; // Aaargh, invalid cast, not a .NET byte array... 
     public IntPtr lpData; // LPBYTE lpData; 
     public UInt32 dwBufferLength; // DWORD  dwBufferLength; 
     public UInt32 dwBytesUsed; // DWORD  dwBytesUsed; 
     public UInt32 dwTimeCaptured; // DWORD  dwTimeCaptured; 


     // typedef ULONG_PTR DWORD_PTR; 
     // #if defined(_WIN64) 
     // typedef unsigned __int64 ULONG_PTR; 
     // #else 
     // typedef unsigned long ULONG_PTR; 
     // #endif 
     public IntPtr dwUser; // DWORD_PTR dwUser; 
     public UInt32 dwFlags; // DWORD  dwFlags; 

     [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 4)] 
     public System.UIntPtr[] dwReserved; // DWORD_PTR dwReserved[4]; 

     // Does not make a difference 
     //public System.UIntPtr[] dwReserved = new System.UIntPtr[4]; // DWORD_PTR dwReserved[4]; 
    } 




    private delegate System.IntPtr capVideoStreamCallback_t(System.UIntPtr hWnd, ref VIDEOHDR lpVHdr); 
    [DllImport("user32", EntryPoint = "SendMessage")] 
    private static extern int SendMessage(int hWnd, uint Msg, int wParam, capVideoStreamCallback_t routine); 




    // http://eris.liralab.it/yarpdoc/vfw__extra__from__wine_8h.html 
    private const int WM_USER = 0x0400; // 1024 
    private const int WM_CAP_START = WM_USER; 
    private const int WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10; 
    private const int WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11; 

    private const int WM_CAP_FILE_SAVEDIB = WM_CAP_START + 25; 
    private const int WM_CAP_SET_CALLBACK_FRAME = WM_CAP_START + 5; 
    private const int WM_CAP_GRAB_FRAME = WM_CAP_START + 60; 
    private const int WM_CAP_EDIT_COPY = WM_CAP_START + 30; 




    // http://lists.ximian.com/pipermail/mono-devel-list/2011-March/037272.html 

    private static byte[] baSplendidIsolation; 


    private static System.IntPtr capVideoStreamCallback(System.UIntPtr hWnd, ref VIDEOHDR lpVHdr) 
    { 
     //System.Windows.Forms.MessageBox.Show("hello"); 
     //System.Windows.Forms.MessageBox.Show(lpVHdr.dwBufferLength.ToString() + " " + lpVHdr.dwBytesUsed.ToString()); 
     byte[] _imageTemp = new byte[lpVHdr.dwBufferLength]; 
     Marshal.Copy(lpVHdr.lpData, _imageTemp, 0, (int) lpVHdr.dwBufferLength); 
     //System.IO.File.WriteAllBytes(@"d:\temp\mycbfile.bmp", _imageTemp); // AAaaarg, it's raw bitmap data... 

     // http://stackoverflow.com/questions/742236/how-to-create-a-bmp-file-from-byte-in-c-sharp 
     // http://stackoverflow.com/questions/2654480/writing-bmp-image-in-pure-c-c-without-other-libraries 

     // Tsssss... 350 x 350 was the expected setting, but never mind... 
     // fortunately alex told me about WM_CAP_FILE_SAVEDIB, so I could compare to the direct output 
     int width = 640; 
     int height = 480; 
     int stride = width*3; 

     baSplendidIsolation = null; 
     baSplendidIsolation = WriteBitmapFile(@"d:\temp\mycbfilecc.bmp", width, height, _imageTemp); 

     /* 
     unsafe 
     { 
      fixed (byte* ptr = _imageTemp) 
      { 
       using (Bitmap image = new Bitmap(width, height, stride, PixelFormat.Format24bppRgb, new IntPtr(ptr))) 
       { 
        image.Save(@"d:\temp\mycbfile2.bmp"); 
       } 
      } 
     } 
     */ 

     //var hdr = (Elf32_Phdr)Marshal.PtrToStructure(ptr, typeof(Elf32_Phdr)); 
     return System.IntPtr.Zero; 
    } 


    private static byte[] WriteBitmapFile(string filename, int width, int height, byte[] imageData) 
    { 
     using (var stream = new MemoryStream(imageData)) 
     using (var bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb)) 
     { 
      BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0,bmp.Width, bmp.Height) 
               ,ImageLockMode.WriteOnly 
               ,bmp.PixelFormat 
      ); 

      Marshal.Copy(imageData, 0, bmpData.Scan0, imageData.Length); 

      bmp.UnlockBits(bmpData); 


      if (bmp == null) 
       return null; 

      bmp.RotateFlip(RotateFlipType.Rotate180FlipNone); 
      bmp.Save(filename); // For testing only 

      using (MemoryStream ms = new MemoryStream()) 
      { 
       bmp.Save(ms, ImageFormat.Png); // get bitmap bytes 
       return ms.ToArray(); 
      } // End Using stream 

     } 

    } // End Function WriteBitmapFile 


    /// <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(); 
     int hCaptureWnd = capCreateCaptureWindowA("ccWebCam", 0, 0, 0, 
      350, 350, 0, 0); // create the hidden capture window 
     SendMessage(hCaptureWnd, WM_CAP_DRIVER_CONNECT, 0, 0); // send the connect message to it 
     //SendMessage(hCaptureWnd, WM_CAP_DRIVER_CONNECT, i, 0); // i device number retval != 0 --> valid device_id 

     Thread.Sleep(connectDelay);          // sleep the specified time 
     SendMessage(hCaptureWnd, WM_CAP_SET_CALLBACK_FRAME, 0, capVideoStreamCallback); 
     SendMessage(hCaptureWnd, WM_CAP_GRAB_FRAME, 0, 0);    // capture the frame 

     //SendMessage(hCaptureWnd, WM_CAP_FILE_SAVEDIB, 0, "d:\\temp\\testmywebcamimage.bmp"); 
     //ScreenshotWindow(new IntPtr(hCaptureWnd)); 

     //SendMessage(hCaptureWnd, WM_CAP_EDIT_COPY, 0, 0); // copy it to the clipboard 


     // using (Graphics g2 = Graphics.FromHwnd(new IntPtr(hCaptureWnd))) 

     SendMessage(hCaptureWnd, WM_CAP_DRIVER_DISCONNECT, 0, 0);    // disconnect from the camera 

     return baSplendidIsolation; 

     /* 
     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 
+0

Qual è il valore esadecimale di WM_CAP_GRAB_FRAME e WM_CAP_SET_CALLBACK_FRAME che hai usato nel tuo codice. sto usando altri come sotto public const uint WM_CAP_DRIVER_CONNECT = 0x40a; public const uint WM_CAP_DRIVER_DISCONNECT = 0x40b; public const uint WM_CAP_EDIT_COPY = 0x41e; public const uint WM_CAP_SET_PREVIEW = 0x432; public const uint WM_CAP_SET_OVERLAY = 0x433; public const uint WM_CAP_SET_PREVIEWRATE = 0x434; –

3

Si deve inviare un messaggio diverso, in particolare WM_CAP_FILE_SAVEDIB, per salvare i dati in un file su disco. Sarà quindi possibile caricarlo in un oggetto Bitmap per un'ulteriore elaborazione (non sono a conoscenza di alcuna funzionalità incorporata cam-to-byte []).

[DllImport("user32", EntryPoint = "SendMessage")] 
private static extern int SendMessage(
    int hWnd, uint Msg, int wParam, string strFileName); 

private const int WM_USER = 0x0400; 
private const int WM_CAP_START = WM_USER; 
private const int WM_CAP_FILE_SAVEDIB = WM_CAP_START + 25; 

//before 
SendMessage(hCaptureWnd, WM_CAP_COPY, 0, 0); 

//after 
string tempFile = Server.MapPath("~/App_Data/tempCap.bmp"); 
SendMessage(hCaptureWnd, WM_CAP_FILE_SAVEDIB, 0, tempFile); //create tempfile 
Bitmap bitmap = new Bitmap(tempFile); //read tempfile 
using (MemoryStream stream = new MemoryStream()) 
{ 
    bitmap.Save(stream, ImageFormat.Bmp); 
    return stream.ToArray(); 
} 
+0

OK, questo è per il file e cosa per l'array di byte (senza caricare il file)? –

+0

Non penso che la dll fornisca un messaggio dritto cam-to-byte [] – Alex

+0

Ovviamente no, ma si spera che WinAPI fornisca un modo per trasformare un hCaptureWnd in un bitmap. –

6

Non esiste una cosa come la WM_CAP_GET_FRAME. Il nome corretto del messaggio è WM_CAP_GRAB_FRAME ed è descritto su MSDN.

Ciò che fa è:

messaggio

Il WM_CAP_GRAB_FRAME recupera e visualizza un singolo fotogramma dal driver di acquisizione. Dopo l'acquisizione, l'overlay e l'anteprima sono disabilitati . È possibile inviare questo messaggio in modo esplicito o utilizzando la macro capGrabFrame .

Per ottenere i dati effettivi è necessario utilizzare frame callback as described further on MSDN. Il callback ottiene i byte delle immagini, che è possibile scrivere su file o utilizzare per qualsiasi elaborazione senza necessità di trasferire negli appunti.

... è la funzione di callback utilizzata con lo streaming capture per fare in modo che elabori un fotogramma di video catturato. Il nome capVideoStreamCallback è un segnaposto per il nome della funzione fornita dall'applicazione.

[E si dispone di un] ... Puntatore a una struttura VIDEOHDR contenente informazioni sul fotogramma acquisito.

Ancora una volta, questa API è la scelta sfortunata per l'acquisizione video. Troppo vecchio, troppo limitato.

Problemi correlati