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

TeboScreen:一个基础的 C# 屏幕捕获应用程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.76/5 (75投票s)

2007 年 12 月 7 日

CPOL

5分钟阅读

viewsIcon

486882

downloadIcon

38666

一个 C# 屏幕保护程序应用程序,用于说明简单的屏幕捕获原理

Screenshot -

引言

此应用程序以两种不同的方式捕获屏幕

  • 捕获屏幕:顾名思义;它基本上会在指定结果图像的文件名后捕获整个屏幕。
  • 捕获区域:按住鼠标左键,用户绘制一个矩形以指定他们希望捕获的屏幕部分。双击后,用户选择一个文件名,并且绘制矩形后面的区域将被捕获到此文件中。绘制完成后,可以在双击保存图像之前在屏幕上调整矩形的大小并移动矩形。

背景

此应用程序是我为自己设定的 C# 练习。初学 C# 时,我想了解创建屏幕捕获应用程序的简单程度。最终,我花了一个下午的时间编写了这个应用程序(不算太费力)。

我选择了一个简单的解决方案来回答如何在屏幕上允许用户绘制矩形的问题。
该应用程序最大化了一个透明度为 30% 的窗体。矩形的绘制涉及绘制一个矩形,然后通过绘制一个窗体背景色的矩形来擦除之前的矩形。
由于窗体被最大化,因此此窗体上的任何坐标都对应于其下方的屏幕坐标。
然后,只需将绘制矩形的坐标返回到 ScreenShot.CaptureImage 方法即可。

一些附加功能包括将图像保存到剪贴板、将光标包含在图像中(在这种情况下,通过按 'S' 键)以及允许用户在绘制初始选择区域后调整和拖动选择区域的大小。

Using the Code

有两种屏幕捕获模式 - 捕获屏幕捕获区域

捕获屏幕

我们只需要将屏幕区域传递给 ScreenShot.CaptureImage 方法。这里唯一需要注意的是,我们会暂停 250 毫秒以允许屏幕刷新自身。如果不这样做,可能会导致调用该命令的窗体被包含在捕获中,即使它已被指示最小化。

//Allow 250 milliseconds for the screen to repaint itself 
//(we don't want to include this form in the capture)
System.Threading.Thread.Sleep(250);

Rectangle bounds = Screen.GetBounds(Screen.GetBounds(Point.Empty));
string fi = "";

if (ScreenPath != "")
{
    fi = new FileInfo(ScreenPath).Extension;
}

ScreenShot.CaptureImage(showCursor, curSize, curPos, 
    Point.Empty, Point.Empty, bounds, ScreenPath, fi);

捕获区域

按住鼠标左键,用户绘制一个矩形以指定他们希望捕获的屏幕部分。释放鼠标左键后,用户可以调整选择区域的大小或移动它,或者双击以选择一个文件名 - 然后将绘制矩形后面的内容捕获到选定的文件中。

mouse_Move 事件用于确定用户是在绘制、拖动(移动)还是调整选择区域的大小。
每种方法都会擦除之前的矩形,并在每次鼠标移动时(按住鼠标左键时)创建一个新矩形。这给人一种矩形移动的错觉。

private void mouse_Move(object sender, MouseEventArgs e)
{
    if (LeftButtonDown && !RectangleDrawn)
    {
        DrawSelection();
    }

    if (RectangleDrawn)
    {
        CursorPosition();

        if (CurrentAction == ClickAction.Dragging)
        {
            DragSelection();
        }

        if (CurrentAction != ClickAction.Dragging && CurrentAction != ClickAction.Outside)
        {
            ResizeSelection();
        }
    }
}

以下是我们为捕获区域调用 ScreenShot.CaptureImage 的方法。

Point StartPoint = new Point(CurrentTopLeft.X, CurrentTopLeft.Y);
Rectangle bounds = new Rectangle(CurrentTopLeft.X, CurrentTopLeft.Y, 
    CurrentBottomRight.X - CurrentTopLeft.X, CurrentBottomRight.Y - CurrentTopLeft.Y);
...
ScreenShot.CaptureImage(showCursor, curSize, curPos, StartPoint, 
        Point.Empty, bounds, ScreenPath, fi);

捕获屏幕的代码位于一个名为 ScreenShot 的类中,该类包含一个名为 CaptureImagestatic 方法。
这是代码应用所有选定选项的地方 - 包括/排除光标、保存到剪贴板/文件以及图像保存的文件类型。

class ScreenShot
    {
        public static bool saveToClipboard = false;

        public static void CaptureImage(bool showCursor, Size curSize, Point curPos, 
    Point SourcePoint, Point DestinationPoint, Rectangle SelectionRectangle, 
    string FilePath, string extension)
        {
            using (Bitmap bitmap = new Bitmap(SelectionRectangle.Width, 
        SelectionRectangle.Height))
            {
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    g.CopyFromScreen(SourcePoint, DestinationPoint, 
            SelectionRectangle.Size);

                    if (showCursor)
                    {
                        Rectangle cursorBounds = new Rectangle(curPos, curSize);
                        Cursors.Default.Draw(g, cursorBounds);                            
                    }
                }

                if (saveToClipboard)
                {
                    Image img = (Image)bitmap;
                    Clipboard.SetImage(img);
                }
                else
                {
                    switch (extension)
                    {
                        case ".bmp":
                            bitmap.Save(FilePath, ImageFormat.Bmp);
                            break;
                        case ".jpg":
                            bitmap.Save(FilePath, ImageFormat.Jpeg);
                            break;
                        case ".gif":
                            bitmap.Save(FilePath, ImageFormat.Gif);
                            break;
                        case ".tiff":
                            bitmap.Save(FilePath, ImageFormat.Tiff);
                            break;
                        case ".png":
                            bitmap.Save(FilePath, ImageFormat.Png);
                            break;
                        default:
                            bitmap.Save(FilePath, ImageFormat.Jpeg);
                            break;
                    }
                }
            }
        }

最近(2012 年 1 月)添加的两个方法是 Clipboard.SetImageCursors.Default.Draw。第一个方法会将捕获的屏幕或区域复制到剪贴板,第二个方法会将光标(作为箭头)包含在图像中。
添加光标非常有用,尤其是在需要指示截图中的某项内容(如按钮)时。

为了在图像中包含光标,应用程序的 KeyUp 事件会监听 'S' 键 - 这会触发 ScreenCapture 方法,并指定包含光标。
我已将此事件添加到应用程序中的每个按钮 - 更有效的方法是处理应用程序打开时按下的任何键 - 我选择这种方法的原因是为了让安全软件不将该软件标记为键盘记录器。

private void keyTest(KeyEventArgs e)
{
    if (e.KeyCode.ToString() == "S")
    {
      screenCapture(true);
    }
}

光标和剪贴板功能都是根据请求添加的,因此请继续提出您的建议和请求,因为我倾向于对它们采取行动。

我也知道 Windows 7 现在自带了一个截图工具 - 这篇文章最初创建于 2007 年,当时 Windows 7 尚未发布。
我认为这篇文章在说明屏幕上对象的绘制和移动以及截屏方面仍然具有一定的相关性。

开发

TeboScreen 已被分支到一个名为 ScreenCap 的新项目和文章中,由 Patrick Harris 创建。
ScreenCap 提供了一些额外的功能,包括

在后台运行,并在按下 Print Screen 键时激活。
支持双显示器,无论显示器尺寸是否存在差异。
自动将屏幕截图发送到三个设备:剪贴板、打印机和电子邮件。

作为一名开发人员,我对这一新发展感到非常满意,并期待看到 Patrick 将这个新分支发展到何种程度。

历史

  • 2007 年 12 月 4 日 -- 发布原始版本
  • 2007 年 12 月 18 日 -- 更新了下载和文章内容
    • 新的下载代码修复了选择矩形绘制中的错误
    • 替换了 mouse_Move 事件的文章文本
  • 2011 年 7 月 3 日 -- 更新的代码包括允许用户调整和移动图像捕获选择区域的更改。还有一个提示按钮,点击后会显示基本使用说明。
  • 2011 年 12 月 28 日 -- 更新了下载
  • 2012 年 1 月 19 日 -- 更新了文章和下载
  • 2012 年 2 月 18 日 -- 添加了对 Patrick Harris 的 ScreenCap 文章的引用
© . All rights reserved.