解决C#全屏幕截图的实现方法

 更新时间:2013年05月20日 11:28:55   作者:  
本篇文章是对在C#中实现全屏幕截图的方法进行了详细的分析介绍,需要的朋友参考下
今天一位同事想写一个全屏幕截图的代码。当然要实现的第一步是能够获取整个屏幕的位图,记得Win32 API的CreateDC, BitBlt等函数可以使用。于是上网查了下,果然屏幕截图用这些函数。但winform已经可以把API都忘记了,所以得寻找一个无Win32 API的实现方式。综合了网上的实现,以及自己的一些设计,实现思路如下:
1. 开始截图时,创建一个与屏幕大小一样的位图,然后用Graphics.CopyFromScreen()把屏幕位图拷贝到该位图上。这是很关键的一步,这样所有的操作就都可以在该位图上进行了,而无实际屏幕无关了。 
复制代码 代码如下:

Code
int width = Screen.PrimaryScreen.Bounds.Width;
int height = Screen.PrimaryScreen.Bounds.Height;
Bitmap bmp = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(bmp)) {
    g.CopyFromScreen(0, 0, 0, 0, new Size(width, height));
}

2. 接下来为了方便在这之上进行截图,有一个很重要的设计实现方式:用全屏幕窗体代替现有真实屏幕,这样就可以把截图过程的所有操作都在那个窗体上实现(该窗体设置成无边框,高宽等于屏幕大小即可),另外为了显示掩蔽效果(只能正常显示选择的部分屏幕内容,而其实部分用一个如半透明层覆盖),就添加一层半透明位置位图。具体代码如下:
复制代码 代码如下:

Code
public partial class FullScreenForm : Form {
    private Rectangle rectSelected = Rectangle.Empty;
    private bool isClipping = false;
    private Bitmap screen;
    private Bitmap coverLayer = null;
    private Color coverColor;
    private Brush rectBrush = null;
    private Bitmap resultBmp = null;
    public FullScreenForm(Bitmap screen) {
        InitializeComponent();
        int width = Screen.PrimaryScreen.Bounds.Width;
        int height = Screen.PrimaryScreen.Bounds.Height;
        coverLayer = new Bitmap(width, height);
        coverColor = Color.FromArgb(50, 200, 0, 0);
        rectBrush = new SolidBrush(coverColor);
        using (Graphics g = Graphics.FromImage(coverLayer)) {
            g.Clear(coverColor);
        }
        this.Bounds = new Rectangle(0, 0, width, height);
        this.screen = screen;
        this.DoubleBuffered = true;
    }
    protected override void OnMouseDown(MouseEventArgs e) {
        if (e.Button == MouseButtons.Left) {
            isClipping = true;
            rectSelected.Location = e.Location;
        }
        else if (e.Button == MouseButtons.Right) {
            this.DialogResult = DialogResult.OK;
        }
    }
    protected override void OnMouseMove(MouseEventArgs e) {
        if (e.Button == MouseButtons.Left && isClipping) {
            rectSelected.Width = e.X - rectSelected.X;
            rectSelected.Height = e.Y - rectSelected.Y;

            this.Invalidate();
        }
    }
    protected override void OnMouseUp(MouseEventArgs e) {
        if (e.Button == MouseButtons.Left && isClipping) {
            rectSelected.Width = e.X - rectSelected.X;
            rectSelected.Height = e.Y - rectSelected.Y;
            this.Invalidate();
            resultBmp = new Bitmap(rectSelected.Width, rectSelected.Height);
            using (Graphics g = Graphics.FromImage(resultBmp)) {
                g.DrawImage(screen,new Rectangle(0, 0, rectSelected.Width, rectSelected.Height), rectSelected, GraphicsUnit.Pixel);
            }
            this.DialogResult = DialogResult.OK;
        }
    }
    protected override void OnPaint(PaintEventArgs e) {
        Graphics g = e.Graphics;
        g.DrawImage(screen, 0, 0);
        g.DrawImage(coverLayer, 0, 0);
        PaintRectangle();
    }
    protected override void OnPaintBackground(PaintEventArgs e) {

    }
    protected override void OnKeyDown(KeyEventArgs e) {
        if (e.KeyCode == Keys.Escape) {
            this.DialogResult = DialogResult.Cancel;
        }
    }
    private void PaintRectangle() {
        using (Graphics g = Graphics.FromImage(coverLayer)) {
            g.Clear(coverColor);
            GraphicsPath path = new GraphicsPath();
            path.AddRectangle(this.Bounds);
            path.AddRectangle(rectSelected);
            g.FillPath(rectBrush, path);
            g.DrawRectangle(Pens.Blue, rectSelected);
        }
    }
    public Bitmap ResultBitmap {
        get { return resultBmp; }
    }
}

上面的代码都很容易看明白,这里有一个技巧就是GraphicsPath,它自动会形成一个中空的区域。上面的实现很容易扩展:多区域截图,多裁判截图等都很容易实现。

相关文章

  • C#编写ActiveX网页截图控件

    C#编写ActiveX网页截图控件

    这篇文章主要介绍了C#编写ActiveX网页截图控件,作为学习C#编写ActiveX的一个简单入门教程,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • Unity实现场景漫游相机

    Unity实现场景漫游相机

    这篇文章主要为大家详细介绍了Unity实现场景漫游相机,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-10-10
  • C# Base 64 编码/解码实现代码

    C# Base 64 编码/解码实现代码

    这篇文章主要介绍了C# Base 64 编码/解码实现代码,需要的朋友可以参考下
    2016-02-02
  • C#实现基于链表的内存记事本实例

    C#实现基于链表的内存记事本实例

    这篇文章主要介绍了C#实现基于链表的内存记事本,实例分析了C#基于链表实现的记事本功能,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • Unity实战之FlyPin(见缝插针)小游戏的实现

    Unity实战之FlyPin(见缝插针)小游戏的实现

    这篇文章主要介绍了利用Unity制作FlyPin(见缝插针)小游戏的实现方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起试一试
    2022-01-01
  • C# 标准事件流实例代码

    C# 标准事件流实例代码

    这篇文章主要介绍了C# 标准事件流的实例代码,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • C#操作windows注册表的方法

    C#操作windows注册表的方法

    这篇文章主要介绍了C#操作windows注册表的方法,涉及C#针对注册表的读取与写入技巧,非常具有实用价值,需要的朋友可以参考下
    2015-04-04
  • 使用数字签名实现数据库记录防篡改(Java实现)

    使用数字签名实现数据库记录防篡改(Java实现)

    本文主要介绍了Java中使用数字签名实现数据库记录防篡改的方法与步骤。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-01-01
  • 浅谈c#开发者应该了解的15个特性

    浅谈c#开发者应该了解的15个特性

    本文列举了15个值得了解的C#特性,旨在让.NET开发人员更好的使用C#语言进行开发工作。
    2021-05-05
  • C#实现功能强大的中国农历日历操作类

    C#实现功能强大的中国农历日历操作类

    这篇文章主要介绍了C#实现功能强大的中国农历日历操作类,实例分析了C#操作时间及字符串的技巧,非常具有实用价值,需要的朋友可以参考下
    2015-03-03

最新评论