您的位置:首页 > 编程语言 > C#

C# GDI+实现截图功能源码

2013-06-27 10:16 253 查看
代码内容来自于 “我不是圣人” 博客。地址:点击打开链接

他的原理及实现细节都讲得非常详细。我把他的源码优化了下,贴出来给GDI+新手学习。

在读此代码前,必须先读他的博客,这一点切记。

截屏窗体:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace WindowsFormsApplication2
{
    public partial class Catch : Form
    {
        public Catch()
        {
            InitializeComponent();
        }

        #region 用户变量
        private Point _downPoint = Point.Empty;//记录鼠标按下坐标,用来确定绘图起点
        private bool _catchFinished = false;//用来表示是否截图完成
        private bool _catchStart = false;//表示截图开始
        private Bitmap _originBmp;//用来保存原始图像
        private Rectangle _catchRectangle;//用来保存截图的矩形
        #endregion

        //窗体初始化操作
        private void Catch_Load(object sender, EventArgs e)
        {
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
            this.UpdateStyles();
            //以上两句是为了设置控件样式为双缓冲,这可以有效减少图片闪烁的问题,关于这个大家可以自己去搜索下

            _originBmp = new Bitmap(this.BackgroundImage);//BackgroundImage为全屏图片,我们另用变量来保存全屏图片
        }

        //鼠标右键点击结束截图;没有直接的右键相应事件
        private void Catch_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                this.DialogResult = DialogResult.OK;
                this.Close();
            }
        }

        //鼠标左键按下时动作
        private void Catch_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (!_catchStart)
                {
                    //如果捕捉没有开始
                    _catchStart = true;
                    _downPoint = new Point(e.X, e.Y);//保存鼠标按下坐标
                }
            }
        }

        private void Catch_MouseMove(object sender, MouseEventArgs e)
        {
            //如果捕捉开始
            if (_catchStart)
            {
                Point newStartPoint = new Point(_downPoint.X, _downPoint.Y);

                //如果是反向截图,终点就变成了起点,无论如何,长度和宽度是绝对值,都是从左向右、从上往下画
                if (e.X < _downPoint.X)
                {
                    newStartPoint.X = e.X;
                }

                if (e.Y < _downPoint.Y)
                {
                    newStartPoint.Y = e.Y;
                }

                //获取矩形的长和宽
                int width = Math.Abs(e.X - _downPoint.X);
                int height = Math.Abs(e.Y - _downPoint.Y);

                Bitmap destBmp = (Bitmap)_originBmp.Clone();
                Graphics g = Graphics.FromImage(destBmp);
                Pen p = new Pen(Color.Blue, 1);
                _catchRectangle = new Rectangle(newStartPoint, new Size(width, height));

                g.DrawRectangle(p, _catchRectangle);

                g.Dispose();
                p.Dispose();

                //如果之前那个画板不释放,而直接g=this.CreateGraphics()这样的话无法释放掉第一次创建的g,因为只是把地址转到新的g了.如同string一样
                Graphics gNew = this.CreateGraphics();

                gNew.DrawImage(destBmp, new Point(0, 0));//这个也可以属于二次缓冲技术,如果直接将矩形画在窗体上,会造成图片抖动并且会有无数个矩形.

                gNew.Dispose();
                destBmp.Dispose();//要及时释放,不然内存将会被大量消耗
            }
        }

        private void Catch_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (_catchStart)
                {
                    _catchStart = false;
                    _catchFinished = true;

                }
            }
        }

        //鼠标双击事件,如果鼠标位于矩形内,则将矩形内的图片保存到剪贴板中
        private void Catch_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && _catchFinished)
            {
                if (_catchRectangle.Contains(new Point(e.X, e.Y)))
                {
                    Bitmap cachedBmp = new Bitmap(_catchRectangle.Width, _catchRectangle.Height);//新建一个于矩形等大的空白图片
                    Graphics g = Graphics.FromImage(cachedBmp);
                    g.DrawImage(_originBmp,
                        new Rectangle(0, 0, _catchRectangle.Width, _catchRectangle.Height),
                        _catchRectangle,
                        GraphicsUnit.Pixel);//把orginBmp中的指定部分按照指定大小画在画板上

                    Clipboard.SetImage(cachedBmp);//将图片保存到剪贴板

                    g.Dispose();
                    _catchFinished = false;

                    this.BackgroundImage = _originBmp;
                    cachedBmp.Dispose();

                    this.DialogResult = DialogResult.OK;
                    this.Close();
                }
            }
        }

    }
}


OK,响应截图事件:

private void button3_Click(object sender, EventArgs e)
        {
            //this.Hide();//隐藏当前窗体
            //Thread.Sleep(50);//让线程睡眠一段时间,窗体消失需要一点时间

            Bitmap catchBmp = new Bitmap(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height);//新建一个和屏幕大小相同的图片         
            Graphics g = Graphics.FromImage(catchBmp);

            g.CopyFromScreen(new Point(0, 0), new Point(0, 0),
                new Size(Screen.AllScreens[0].Bounds.Width, Screen.AllScreens[0].Bounds.Height));//保存全屏图片

            Catch catchForm = new Catch();
            catchForm.BackgroundImage = catchBmp;//将Catch窗体的背景设为全屏时的图片

            if (catchForm.ShowDialog() == DialogResult.OK)
            {
                //如果Catch窗体结束,就将剪贴板中的图片放到richTextBox中去
                IDataObject iData = Clipboard.GetDataObject();
                DataFormats.Format myFormat = DataFormats.GetFormat(DataFormats.Bitmap);

                if (iData.GetDataPresent(DataFormats.Bitmap))
                {
                    this.richTextBox1.Paste(myFormat);
                    Clipboard.Clear();//清除剪贴板中的对象
                }
                //   this.Show();//重新显示窗体

            }
        }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: