質問:ウェブカメラから画像をキャプチャするためのコードは次のとおりです。クリップボードを使用せずに画像をコピーする方法は?
私の問題は、この部分です:
SendMessage(hCaptureWnd, WM_CAP_COPY, 0, 0); // copy it to the clipboard
何それがないことはクリップボードに窓から画像をコピーして、そこからバイト配列を作成することです。
プログラムの実行中にクリップボードを使用しない限り機能します。
問題は、Visual StudioがWebアプリケーションのデバッグを開始するまでに何かをコピーしてクラッシュすることがあるので、これは自分自身では機能しません。
ここで私の質問:
クリップボードを使用せずに画像を取得するにはどうすればよいですか? さらに具体的には、hCaptureWndをSystem.Drawing.Imageに変換する方法は?
- 編集:
私は、「ファイルを作成せずに、私はバイト配列をしたい」と言って逃しました。
それはWebアプリケーションなので、ユーザはアプリケーションが下の(一時的なテストのためのファイルへの書き込み)ファイルシステムへの書き込みアクセス権を持つべきではありません実行されます...
- エンド編集:
/// <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
注(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 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
}
}
私はこのようにしようとしたが、それが唯一の黒画像を取得...そして
[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();
}
*/
}
そしてこのSendMessage(hCaptureWnd, WM_CAP_GET_FRAME, 0, 0);
ScreenshotWindow(new IntPtr(hCaptureWnd));
これらの追加のものと
あなただけ... * *画像をクリップボードにコピーしないで、代わりにバイト配列に直接変換しない理由を私は理解していません。このロジックを含む 'WM_CAP_COPY'メッセージハンドラですか?このメッセージを提供するライブラリは何ですか?その行動を無効にすることはできますか? –
@Cody Grey:そのライブラリはWindowsです! WinAPI!そして、いいえ、私は窓を変更することはできません、私はソースコードを持っていません(私は分解してパッチを当てることはできませんでしたが、ここでは間違ったアプローチです);そしてあなたの質問に答えるために:ちなみに質問であるhCaptureWndから画像を作成するには... –
うーん、なぜドキュメントが見つかりませんか?私はここで私のリーグを離れていると思う。聞いたことがない。 –