65.9K
CodeProject 正在变化。 阅读更多。
Home

屏幕捕获

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (45投票s)

2006年1月31日

2分钟阅读

viewsIcon

267620

downloadIcon

3234

无需使用任何 Win32 API 调用即可捕获屏幕内容,仅使用 .NET (2.0) 类。

Demo application

引言

关于屏幕截图的文章有很多,但其中大多数使用 Win32 API 函数,即使在 .NET 2.0 中也是如此,而这并不是必需的,因为 .NET 2.0 拥有实现该功能所需的所有类。

背景

通常需要获取整个屏幕或部分屏幕的截图。在我们的应用程序中,我们经常使用具有多个显示器的系统,这需要我们同时捕获所有显示器或分别捕获每个屏幕。请记住,虚拟屏幕是连接到系统的所有显示器的完整视图,主屏幕是主显示器的视图,而工作屏幕是相同的,但排除了任务栏。

使用代码

类 'ScreenCapture' 提供了几个方法,允许捕获完整的虚拟屏幕、主屏幕、工作屏幕、特定窗体(完整或仅客户端区域)以及窗体中特定控件的内容。捕获的图像可以直接从您的代码中使用,也可以保存到文件中或打印。还有一个小助手类 'ImageFormatHandler',用于在保存捕获的图像时处理不同的图形文件格式。

源代码

源代码文件包含两个描述的类,可以直接在您的代码中使用。它使用 Visual Studio 2005 构建。

我们的主要捕获方法如下所示

public Bitmap[] Capture( CaptureType typeOfCapture )
{
    // used to capture then screen in memory
    Bitmap memoryImage;
    // number of screens to capture,
    // will be updated below if necessary
    int count = 1;

    try
    {
        Screen[] screens = Screen.AllScreens;
        Rectangle rc;

        // setup the area to capture
        // depending on the supplied parameter
        switch ( typeOfCapture )
        {
            case CaptureType.PrimaryScreen:
                rc = Screen.PrimaryScreen.Bounds;
                break;
            case CaptureType.VirtualScreen:
                rc = SystemInformation.VirtualScreen;
                break;
            case CaptureType.WorkingArea:
                rc = Screen.PrimaryScreen.WorkingArea;
                break;
            case CaptureType.AllScreens:
                count = screens.Length;
                typeOfCapture = CaptureType.WorkingArea;
                rc = screens[0].WorkingArea;
                break;
            default:
                rc = SystemInformation.VirtualScreen;
                break;
        }
        // allocate a member for saving the captured image(s)
        images = new Bitmap[count];

        // cycle across all desired screens
        for ( int index = 0; index < count; index++ )
        {
            if ( index > 0 )
                rc = screens[index].WorkingArea;
                // redefine the size on multiple screens

            memoryImage = new Bitmap( rc.Width, rc.Height, 
                          PixelFormat.Format32bppArgb );
            using ( Graphics memoryGrahics = 
                    Graphics.FromImage( memoryImage ) )
            {
                // copy the screen data
                // to the memory allocated above
                memoryGrahics.CopyFromScreen( rc.X, rc.Y, 
                   0, 0, rc.Size, CopyPixelOperation.SourceCopy );
            }
            images[index] = memoryImage;
            // save it in the class member for later use
        }
    }
    catch ( Exception ex )
    {
        // handle any erros which occured during capture
        MessageBox.Show( ex.ToString(), "Capture failed", 
            MessageBoxButtons.OK, MessageBoxIcon.Error );
    }
    return images;
}

使用的变量images是该类的成员,类型为Bitmap[]。此方法的参数typeOfCapture是该类中定义的 enum 类型,用于选择实际应该捕获的内容。

还有另一种捕获方法,用于选择性地捕获控件、窗体或其客户端区域的内容。它的工作方式与上面显示的方法非常相似。

private Bitmap capture( Control window, Rectangle rc )
{
    Bitmap memoryImage = null;
    images = new Bitmap[1];

    // Create new graphics object using handle to window.
    using ( Graphics graphics = window.CreateGraphics() )
    {
        memoryImage = new Bitmap( rc.Width, 
                      rc.Height, graphics );

        using ( Graphics memoryGrahics = 
                Graphics.FromImage( memoryImage ) )
        {
            memoryGrahics.CopyFromScreen( rc.X, rc.Y, 
               0, 0, rc.Size, CopyPixelOperation.SourceCopy );
        }
    }
    images[0] = memoryImage;
    return memoryImage;
}

其他几种方法用于完成保存/打印捕获图像所需的所有工作,它们都在源代码的注释中进行了描述。

public void Save( String filename, 
       ImageFormatHandler.ImageFormatTypes format )

参数filename保存所需的文件名以及完整路径,扩展名将根据参数format选择的文件类型进行替换。

此方法根据选择的文件格式加载一些参数

ImageCodecInfo info;
EncoderParameters parameters = 
  formatHandler.GetEncoderParameters( format, out info );

这就是我们使用助手类ImageFormatHandler进行所有操作的地方。我认为这是一个可以根据您自己的需要进行自定义的基础。

变更

实际示例已通过一些方法进行了更新,这些方法可用于从其他进程捕获屏幕;要做到这一点,必须使用原生代码。然后它不再是纯 .NET 2.0 解决方案。我们也没有使用分层窗体测试此解决方案,但在基本捕获方法中进行一些修改应该可以启用此功能。

© . All rights reserved.