具有椭圆、矩形、箭头、画笔、文字涂鸦功能的截图工具,效果如图:
思路:
用泛型集合存储涂鸦的数据,每一次涂鸦后都存储进去,最后在OnPaint中遍历该集合,通过GDI绘出。
重点讲涂鸦部分:
1、椭圆、矩形、箭头,都只需确定起点和终点。
2、画笔需要确定点集合。
3、文字涂鸦通过透明Richtextbox写上内容后将该控件转成一个bitmap。
实现方法:
涂鸦通过GDI画图实现:
private void DrawTools(Graphics g, DrawToolData data)
{
Point beginPoint = data.beginPoint;
Point endPoint = data.endPoint;
ColorToolChose();
Rectangle rect = GetToolRect(beginPoint, endPoint);
Pen pen = new Pen(data.penColor, data.penWidth);
g.SmoothingMode = SmoothingMode.AntiAlias;
switch (data.Type)
{
case 1://椭圆
using (pen)
{
g.DrawEllipse(pen, rect);
}
break;
case 2://矩形
using (pen)
{
g.DrawRectangle(pen, rect);
}
break;
case 3://箭头
using (pen)
{
pen.EndCap = LineCap.ArrowAnchor;
pen.EndCap = LineCap.Custom;
pen.CustomEndCap = new AdjustableArrowCap(4, 4, true);
g.DrawLine(pen, beginPoint, endPoint);
}
break;
case 4://画笔
if (data.pointList.Count < 2) return;
Point[] points = data.pointList.ToArray();
using (pen)
{
g.DrawLines(new Pen(data.penColor, data.penWidth), points);
}
break;
case 5://文字
if (data.textBmp.Width < 2) return;
g.DrawImage(data.textBmp, data.beginPoint);
break;
}
}
写一个类用来存储涂鸦数据,然后用“List<>” 把每一次涂鸦的数据存起来。
//存储画笔工具 所有线段的 点集合、画笔颜色宽度的类 的集合
private List<DrawToolData> drawData = new List<DrawToolData>();
/// <summary>
/// 存储画图信息
/// </summary>
public class DrawToolData
{
public int Type { get; set; } = 0;
/// <summary>
/// 画笔工具线段点集合
/// </summary>
public List<Point> pointList { get; set; } = new List<Point>();
public Color penColor { get; set; }
public int penWidth { get; set; }
public Point beginPoint { get; set; } = Point.Empty;
public Point endPoint { get; set; } = Point.Empty;
public float textSize { get; set; } = 16;
//存文字分割后的字符串数组
public string textInfo { get; set; }
public Bitmap textBmp { get; set; } = new Bitmap(1, 1);
}
每次画完一个图形后都调用存储数据的方法,存储到数据集合的末尾。
private void addDrawData()
{
if (drawData.Count == 0) drawData.Add(new DrawToolData());
drawData[drawData.Count - 1].Type = clickType;
drawData[drawData.Count - 1].penColor = selectedColor;
drawData[drawData.Count - 1].penWidth = penWidth;
switch (clickType)
{
case 1:
case 2:
case 3:
drawData[drawData.Count - 1].beginPoint = BeginPoint;
drawData[drawData.Count - 1].endPoint = EndPoint;
break;
case 4:
(drawData[drawData.Count - 1].pointList).Add(EndPoint);
break;
case 5:
drawData[drawData.Count - 1].beginPoint = BeginPoint;
drawData[drawData.Count - 1].textSize = colorWithText1.textSize;
drawData[drawData.Count - 1].textInfo = drawTextTool1.Text;
drawData[drawData.Count - 1].textBmp = GetTextBmp();
break;
}
最后在OnPaint中遍历数据画出图形。
foreach (DrawToolData data in drawData)
{
DrawTools(g, data);
}
文字涂鸦:做一个透明的RichtextBox控件:
public class DrawTextTool:RichTextBox
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr LoadLibrary(string lpFileName);
protected override CreateParams CreateParams
{
get
{
CreateParams prams = base.CreateParams;
if (LoadLibrary("msftedit.dll") != IntPtr.Zero)
{
prams.ExStyle |= 0x020; // transparent
prams.ClassName = "RICHEDIT50W";
this.BorderStyle = BorderStyle.None;
}
return prams;
}
}
}
然后用“gdi32.dll”得到该控件的bitmap。
private const Int32 SRCCOPY = 0xCC0020;
[DllImport("gdi32.dll")]
internal static extern bool BitBlt(
IntPtr hdcDest, // handle to destination DC
int nXDest, // x-coord of destination upper-left corner
int nYDest, // y-coord of destination upper-left corner
int nWidth, // width of destination rectangle
int nHeight, // height of destination rectangle
IntPtr hdcSrc, // handle to source DC
int nXSrc, // x-coordinate of source upper-left corner
int nYSrc, // y-coordinate of source upper-left corner
Int32 dwRop // raster operation code
);
public static Bitmap GetImageOfControl(Control control)
{
var w = control.Size.Width;
var h = control.Size.Height;
Graphics gOfCtrl = control.CreateGraphics();
var bmp = new Bitmap(w, h, gOfCtrl);
Graphics gOfBmp = Graphics.FromImage(bmp);
IntPtr dc1 = gOfCtrl.GetHdc();
IntPtr dc2 = gOfBmp.GetHdc();
BitBlt(dc2, 0, 0, w, h, dc1, 0, 0, SRCCOPY);
gOfCtrl.ReleaseHdc(dc1);
gOfBmp.ReleaseHdc(dc2);
gOfCtrl.Dispose();
gOfBmp.Dispose();
return bmp;
}