代码内容来自于 “我不是圣人” 博客。地址:点击打开链接
他的原理及实现细节都讲得非常详细。我把他的源码优化了下,贴出来给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();//重新显示窗体
}
}