티스토리 뷰



C#에서 화면을 캡처하는 두가지 방법이 있습니다. 첫번째는 GDI32, USER32 API를 사용하는 방법이고 다른 하나는 닷넷에서 제공하는 Graphics.CopyFromScreen()를 사용하는 방법입니다.

class GDI32
{

    public const int SRCCOPY = 0x00CC0020; // BitBlt dwRop parameter

    [DllImport("gdi32.dll")]
    public static extern long BitBlt(IntPtr hdcDest, int nXDest, int nYDest, 
        int nWidth, int nHeight, IntPtr hdcSrc, 
        int nXSrc, int nYSrc, int dwRop);
    [DllImport("gdi32.dll")]
    public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth,
        int nHeight);
    [DllImport("gdi32.dll")]
    public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
    [DllImport("gdi32.dll")]
    public static extern bool DeleteDC(IntPtr hDC);
    [DllImport("gdi32.dll")]
    public static extern bool DeleteObject(IntPtr hObject);
    [DllImport("gdi32.dll")]
    public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
}

/// <summary>
/// Helper class containing User32 API functions
/// </summary>
class User32
{
    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }

    [DllImport("user32.dll")]
    public static extern IntPtr GetDesktopWindow();
    [DllImport("user32.dll")]
    public static extern IntPtr GetWindowDC(IntPtr hWnd);
    [DllImport("user32.dll")]
    public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
    [DllImport("user32.dll")]
    public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);
}


public static Image memoryImage; 
public static void CaptureScreen(Panel scr)
{
    
    // get te hDC of the target window
    IntPtr hdcSrc = User32.GetWindowDC(scr.Handle);
    // get the size
    User32.RECT windowRect = new User32.RECT();
    User32.GetWindowRect(scr.Handle, ref windowRect);
    int width = windowRect.right - windowRect.left;
    int height = windowRect.bottom - windowRect.top;
    // create a device context we can copy to
    IntPtr hdcDest = GDI32.CreateCompatibleDC(hdcSrc);
    // create a bitmap we can copy it to,
    // using GetDeviceCaps to get the width/height
    IntPtr hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc, width, height);
    // select the bitmap object
    IntPtr hOld = GDI32.SelectObject(hdcDest, hBitmap);
    // bitblt over
    GDI32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, GDI32.SRCCOPY);
    // restore selection
    GDI32.SelectObject(hdcDest, hOld);
    // clean up 
    GDI32.DeleteDC(hdcDest);
    User32.ReleaseDC(scr.Handle, hdcSrc);
    // get a .NET image object for it
    memoryImage = Image.FromHbitmap(hBitmap);
    // free up the Bitmap object
    GDI32.DeleteObject(hBitmap);
}

위의 예제는 사용자 화면에서 판넬 오브젝트로(scr) 인식하는 특정 영역만을 캡처하는 코드입니다. gdi32.dll, user32.dll과 같은 윈도우 시스템 DLL을 통한 작업이기 때문에 호환성에 제약이 있는 방법이기는 합니다.  실제로 리눅스나 맥의 mono에서는 동작하지 않습니다.


public static Bitmap bmpScreenCapture;
public static void CaptureScreen(Panel prtscr, PrintDocument pdoc, String title)
{
    bmpScreenCapture = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
                                Screen.PrimaryScreen.Bounds.Height);
    using (Graphics g = Graphics.FromImage(bmpScreenCapture))
    {
        g.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
                            Screen.PrimaryScreen.Bounds.Y,
                            0, 0,
                            bmpScreenCapture.Size,
                            CopyPixelOperation.SourceCopy);
    }
}

두번째 방법은 닷넷 클래스(Graphics) 에서 제공하는 CopyFromScreen()메소드를 사용하는 것으로 위의 코드는 화면 전체 영역을 캡처하는 것이지만 특정 위치와 크기로 조정하면 API를 사용하는 첫번째 방법과 동일한 효과를 거둘 수 있습니다. 두번째 방법은 리눅스 mono에서도 정상적으로 동작합니다. 시스템간 호환성을 위해서는 두번째 방법을 추천합니다.


댓글
댓글쓰기 폼