制作类似QQ截图软件

    最近在学习GDI,发现网上几篇文章在讲截图软件制作方法,学习了一点知识,在这里分享一下.  

    主要是调用WinAPI中的函数来完成主要功能.关键的函数有2个,一个是CreateDC,利用这个函数来创建一个显示器屏幕的DC(设备环境),作为源DC,再创建一个Image图像,通过这个图像的Graphics.GetHdc()方法来获取另一个DC,作为目标DC,这2个DC主要是留给第二个函数用的;第二个函数是BitBlt,这个函数将源DC上的像素扫描到目标DC中,在这里就是将显示器屏幕的像素扫描到我们创建的Image图片上.

    扫描完成之后得到的Image图像就是现在的全屏图,可以将图片保存或者拷贝待用.这就实现了全屏截图的功能.

    接下来是实现局部截图.首先将全屏截图Image通过画图画在Winform窗体上,这个可以用窗体的Paint事件来实现,当窗体改变的时候,Paint事件就会被触发.局部截图就是在已经画上了全屏图片的Winform窗体上面再画矩形,然后调用Graphics的方法DrawImage,将矩形区域的截图保存在开始创建的Image中,这样就得到了局部截图,可以将图片保存或者拷贝待用.

    功能基本上就实现了.需要注意的是,在窗体中画的矩形是可反转矩形,调用的是ControlPaint.DrawReversibleFrame()方法,这个方法需要执行2次才能画出矩形.

    主窗口代码:

    public partial class Form1 : Form
{
//*******************Global Varibles******************
private Bitmap MyImage = null;
private bool StartedCrop = false;

Point StartPoint = new Point(0, 0);
Rectangle SelectRect = new Rectangle();
int DeltaX = 0;
int DeltaY = 0;
//****************************************************

[DllImport("gdi32.dll", EntryPoint = "BitBlt")]
public static extern int BitBlt(
IntPtr hDestDC,
int x,
int y,
int nWidth,
int nHeight,
IntPtr hSrcDC,
int xSrc,
int ySrc,
System.Int32 dwRop
);
[DllImport("gdi32.dll", EntryPoint = "CreateDC")]
public static extern IntPtr CreateDC(
string lpDriverName,
string lpDeviceName,
string lpOutput,
IntPtr lpInitData
);

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
this.Visible = false;
Thread.Sleep(100);
IntPtr dc1 = CreateDC("DISPLAY", null, null, (IntPtr)null);
Graphics g1 = Graphics.FromHdc(dc1);
MyImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, g1);
Graphics g2 = Graphics.FromImage(MyImage);
//Visible = false;
dc1 = g1.GetHdc();
IntPtr dc2 = g2.GetHdc();
BitBlt(dc2, 0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height,
dc1, 0, 0, 13369376);

g1.ReleaseHdc(dc1);
g2.ReleaseHdc(dc2);
this.Visible = true;
this.SetBounds(0, 0, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
this.Cursor = Cursors.Cross;
}

private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (StartedCrop == false)
{
DeltaX = 0;
DeltaY = 0;
}
StartedCrop = true;
StartPoint = new Point(e.X,e.Y);
SelectRect.Width = 0;
SelectRect.Height = 0;
SelectRect.X = e.X;
SelectRect.Y = e.Y;
Invalidate();
}

private void Form1_MouseMove(object sender, MouseEventArgs e)
{
Form thisform = (Form)sender;
if (StartedCrop)
{
DeltaX = e.X - StartPoint.X;
if (DeltaX < 0)
DeltaX = 0;
DeltaY = e.Y - StartPoint.Y;
if (DeltaY < 0)
DeltaY = 0;
ControlPaint.DrawReversibleFrame(thisform.RectangleToScreen(SelectRect), Color.Black, FrameStyle.Dashed);
SelectRect.Width = e.X - SelectRect.X;
SelectRect.Height = e.Y - SelectRect.Y;
ControlPaint.DrawReversibleFrame(thisform.RectangleToScreen(SelectRect), Color.Black, FrameStyle.Dashed);
}
}

private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (DeltaX == 0 || DeltaY == 0)
{
return;
}

StartedCrop = false;
SelectRect.X = e.X - StartPoint.X;
SelectRect.Y = e.Y - StartPoint.Y;
this.Cursor = Cursors.Cross;


Bitmap theImage = new Bitmap(DeltaX, DeltaY);
Graphics g = Graphics.FromImage(theImage);
Rectangle destRect = new Rectangle(0, 0, DeltaX, DeltaY);
g.DrawImage(MyImage, destRect, StartPoint.X, StartPoint.Y, theImage.Width, theImage.Height, GraphicsUnit.Pixel);
MyImage = (Bitmap)theImage.Clone();
this.SetBounds(0, 0, MyImage.Width, MyImage.Height);
this.Visible = false;

frmOptions optionsForm = new frmOptions();
optionsForm.imageToSaveOrCopy = MyImage;
optionsForm.ShowDialog();
}

private void Form1_Paint(object sender, PaintEventArgs e)
{
if (MyImage != null)
e.Graphics.DrawImage(MyImage, ClientRectangle, 0, 0, MyImage.Width, MyImage.Height, GraphicsUnit.Pixel);
}

private void Form1_Resize(object sender, EventArgs e)
{
Invalidate();
}

private void Form1_DoubleClick(object sender, EventArgs e)
{
Application.Exit();
}
}

    选项窗口代码(frmOptions)主要有2个按钮,用来保存或者拷贝截取的图片:

    public partial class frmOptions : Form
{
public Image imageToSaveOrCopy;

public frmOptions()
{
InitializeComponent();
}

private void frmOptions_Load(object sender, EventArgs e)
{

}

private void btnSave_Click(object sender, EventArgs e)
{
if (imageToSaveOrCopy == null) {
MessageBox.Show("You have not choose the image! Please restart this program!");
Application.Exit();
}

SaveFileDialog sfd = new SaveFileDialog();
sfd.Filter = "*.jpg|*.jpg";
sfd.AddExtension = true;
sfd.FileName = "1.jpg";
if (sfd.ShowDialog() == DialogResult.OK)
{
imageToSaveOrCopy.Save(sfd.FileName);
}
Application.Exit();
}

private void btnCopy_Click(object sender, EventArgs e)
{
if (imageToSaveOrCopy == null)
{
MessageBox.Show("You have not choose the image! Please restart this program!");
Application.Exit();
}
try
{
Clipboard.SetImage(imageToSaveOrCopy);
}
catch (Exception ex)
{
MessageBox.Show("Copy to clipboard error:\r\n"+ex.Message);
}
Application.Exit();
}
}

    由于局部截图的时候需要在屏幕上面画图,而要想屏幕位置(Point)和我们主窗体的位置一一对应起来,就需要将主窗体最大化到全屏幕,为了效果好点,可以将
窗体的BorderStyle属性设置为None.这样整个工作就完成了.

原文地址:https://www.cnblogs.com/johnsmith/p/2309775.html