-
自己写了个截图工具
很简单,就是先全屏截图,然后再按需要裁剪就可以了。
所以,首先要获取桌面的大小,代码如下:
public class PrimaryScreen { #region Win32 API [DllImport("user32.dll")] static extern IntPtr GetDC(IntPtr ptr); [DllImport("gdi32.dll")] static extern int GetDeviceCaps( IntPtr hdc, // handle to DC int nIndex // index of capability ); [DllImport("user32.dll", EntryPoint = "ReleaseDC")] static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc); #endregion #region DeviceCaps常量 const int HORZRES = 8; const int VERTRES = 10; const int LOGPIXELSX = 88; const int LOGPIXELSY = 90; const int DESKTOPVERTRES = 117; const int DESKTOPHORZRES = 118; #endregion #region 属性 /// <summary> /// 获取屏幕分辨率当前物理大小 /// </summary> public static Size WorkingArea { get { IntPtr hdc = GetDC(IntPtr.Zero); Size size = new Size(); size.Width = GetDeviceCaps(hdc, HORZRES); size.Height = GetDeviceCaps(hdc, VERTRES); ReleaseDC(IntPtr.Zero, hdc); return size; } } /// <summary> /// 当前系统DPI_X 大小 一般为96 /// </summary> public static int DpiX { get { IntPtr hdc = GetDC(IntPtr.Zero); int DpiX = GetDeviceCaps(hdc, LOGPIXELSX); ReleaseDC(IntPtr.Zero, hdc); return DpiX; } } /// <summary> /// 当前系统DPI_Y 大小 一般为96 /// </summary> public static int DpiY { get { IntPtr hdc = GetDC(IntPtr.Zero); int DpiX = GetDeviceCaps(hdc, LOGPIXELSY); ReleaseDC(IntPtr.Zero, hdc); return DpiX; } } /// <summary> /// 获取真实设置的桌面分辨率大小 /// </summary> public static Size DESKTOP { get { IntPtr hdc = GetDC(IntPtr.Zero); Size size = new Size(); size.Width = GetDeviceCaps(hdc, DESKTOPHORZRES); size.Height = GetDeviceCaps(hdc, DESKTOPVERTRES); ReleaseDC(IntPtr.Zero, hdc); return size; } } /// <summary> /// 获取宽度缩放百分比 /// </summary> public static float ScaleX { get { IntPtr hdc = GetDC(IntPtr.Zero); int t = GetDeviceCaps(hdc, DESKTOPHORZRES); int d = GetDeviceCaps(hdc, HORZRES); float ScaleX = (float)GetDeviceCaps(hdc, DESKTOPHORZRES) / (float)GetDeviceCaps(hdc, HORZRES); ReleaseDC(IntPtr.Zero, hdc); return ScaleX; } } /// <summary> /// 获取高度缩放百分比 /// </summary> public static float ScaleY { get { IntPtr hdc = GetDC(IntPtr.Zero); float ScaleY = (float)(float)GetDeviceCaps(hdc, DESKTOPVERTRES) / (float)GetDeviceCaps(hdc, VERTRES); ReleaseDC(IntPtr.Zero, hdc); return ScaleY; } } #endregion }
使用 PrimaryScreen.DESKTOP 就可以获取桌面分辨率的大小了,有了这个大小,就可以开始全屏截图了,代码如下:
public class ImageHelper { /// <summary> /// 截取全屏 /// </summary> /// <returns></returns> public static Bitmap GetScreen() { Size ScreenSize = PrimaryScreen.DESKTOP; Bitmap bmp = new Bitmap(ScreenSize.Width, ScreenSize.Height); using (Graphics g = Graphics.FromImage(bmp)) g.CopyFromScreen(0, 0, 0, 0, new Size(ScreenSize.Width, ScreenSize.Height)); return bmp; } /// <summary> /// 图像明暗调整 /// </summary> /// <param name="b">原始图</param> /// <param name="degree">亮度[-255, 255]</param> public static void Lighten(Bitmap b, int degree) { if (b == null) { //return null; return; } if (degree < -255) degree = -255; if (degree > 255) degree = 255; try { int width = b.Width; int height = b.Height; int pix = 0; BitmapData data = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); unsafe { byte* p = (byte*)data.Scan0; int offset = data.Stride - width * 3; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // 处理指定位置像素的亮度 for (int i = 0; i < 3; i++) { pix = p[i] + degree; if (degree < 0) p[i] = (byte)Math.Max(0, pix); if (degree > 0) p[i] = (byte)Math.Min(255, pix); } // i p += 3; } // x p += offset; } // y } b.UnlockBits(data); //return b; } catch { //return null; } } // end of Lighten }
调用 ImageHelper.GetScreen() 即可以获取全屏截图
再然后,为了实现区域截图,我们需要把全屏截图放到一个窗体里面进行裁剪,弹出裁剪窗体的代码如下:
private void button1_Click(object sender, EventArgs e) { this.Opacity = 0; //先隐藏自己 Bitmap bitmap = ImageHelper.GetScreen(); //截取全屏 GetScreenForm frm = new GetScreenForm(bitmap); //准备区域截图 frm.ShowDialog(); //弹出区域截图界面 this.Opacity = 1; //显示自己 }
区域截图的代码有点多,无非就是鼠标按下、移动、松开的相关处理,以对全屏截图进行裁剪处理,代码如下:
public partial class GetScreenForm : Form { /// <summary> /// 亮图(原图) /// </summary> public Bitmap bitmap { get; set; } /// <summary> /// 暗图 /// </summary> public Bitmap bitmap2 { get; set; } /// <summary> /// 屏幕的宽 /// </summary> public int W { get; set; } /// <summary> /// 屏幕的高 /// </summary> public int H { get; set; } /// <summary> /// 适用于高DPI的宽度 /// </summary> public int W2 { get; set; } /// <summary> /// 适用于高DPI的高度 /// </summary> public int H2 { get; set; } Graphics g; Bitmap cache; Graphics gMain; /// <summary> /// 构造方法 /// </summary> public GetScreenForm(Bitmap bitmap) { //亮图 (也就是原图) this.bitmap = bitmap; this.W = bitmap.Width; this.H = bitmap.Height; //暗图 this.bitmap2 = new Bitmap(bitmap.Width, bitmap.Height); using (Graphics g = Graphics.FromImage(bitmap2)) g.DrawImage(bitmap, 0, 0); ImageHelper.Lighten(bitmap2, -100); //求出适用于高DPI的宽和高 W2 = (int)(bitmap2.Width * PrimaryScreen.ScaleX); H2 = (int)(bitmap2.Height * PrimaryScreen.ScaleY); //初始化 InitializeComponent(); this.Width = (int)(this.W / PrimaryScreen.ScaleX); this.Height = (int)(this.H / PrimaryScreen.ScaleY); //绘图相关 cache = new Bitmap(this.W, this.H); gMain = this.CreateGraphics(); g = Graphics.FromImage(cache); } /// <summary> /// 双击关闭 /// </summary> protected override void OnDoubleClick(EventArgs e) { //获取截图 if (SX > int.MinValue && SY > int.MinValue) { //获取区域 int x1 = SX, x2 = SX + SW; if (x1 > x2) { x2 = x1 + x2; x1 = x2 - x1; x2 = x2 - x1; }; int y1 = SY, y2 = SY + SH; if (y1 > y2) { y2 = y1 + y2; y1 = y2 - y1; y2 = y2 - y1; }; //截图 Bitmap bmp = new Bitmap(x2 - x1, y2 - y1); Graphics g6 = Graphics.FromImage(bmp); g6.DrawImage(bitmap, new Rectangle(0, 0, bmp.Width, bmp.Height), new Rectangle((int)(x1 * PrimaryScreen.ScaleX), (int)(y1 * PrimaryScreen.ScaleY), (int)((x2 - x1) * PrimaryScreen.ScaleX), (int)((y2 - y1) * PrimaryScreen.ScaleY)), GraphicsUnit.Pixel); bmp.Save("x.jpg", ImageFormat.Jpeg); } this.Close(); } private void GetScreenForm_Load(object sender, EventArgs e) { } protected override void OnShown(EventArgs e) { DrawForm(); } void DrawForm() { //画暗图 g.DrawImage(bitmap2, new Rectangle(0, 0, W, H), //目标 new Rectangle(0, 0, W2, H2), //源 GraphicsUnit.Pixel); //画亮图 if (SX > int.MinValue && SY > int.MinValue) { g.DrawImage(bitmap, new Rectangle(SX, SY, SW, SH), new Rectangle((int)(SX * PrimaryScreen.ScaleX), (int)(SY * PrimaryScreen.ScaleY), (int)(SW * PrimaryScreen.ScaleX), (int)(SH * PrimaryScreen.ScaleY)), GraphicsUnit.Pixel); //new Rectangle(SX, SY, SW, SH), //目标 //new Rectangle(SX, SY, SW, SH), //源 //GraphicsUnit.Pixel); } //翻转 gMain.DrawImage(cache, 0, 0); } /// <summary> /// 选择的区域 /// </summary> public int SX { get; set; } = int.MinValue; public int SY { get; set; } = int.MinValue; public int SW { get; set; } public int SH { get; set; } /// <summary> /// 工作类型 0未工作 1画框 2移框 /// </summary> public int WorkType { get; set; } /// <summary> /// 移动的起点 /// </summary> public int MoveX { get; set; } public int MoveY { get; set; } protected override void OnMouseDown(MouseEventArgs e) { //判断是不是点击在框里 bool inside = false; if (SX > int.MinValue && SY > int.MinValue) { int x1 = SX, x2 = SX + SW; if (x1 > x2) { x2 = x1 + x2; x1 = x2 - x1; x2 = x2 - x1; }; int y1 = SY, y2 = SY + SH; if (y1 > y2) { y2 = y1 + y2; y1 = y2 - y1; y2 = y2 - y1; }; if (e.X > x1 && e.X < x2 && e.Y > y1 && e.Y < y2) { inside = true; } } if (inside) { //在框里,则进行移框 this.MoveX = e.X; this.MoveY = e.Y; this.WorkType = 2; DrawForm(); } else { //在框外,则重新画框 this.SX = e.X; this.SY = e.Y; this.SW = 0; this.SH = 0; this.WorkType = 1; DrawForm(); } } protected override void OnMouseMove(MouseEventArgs e) { if (e.Button == MouseButtons.Left) { if (this.WorkType == 1) { //画框 this.SW = e.X - this.SX; this.SH = e.Y - this.SY; } else { //移框 this.SX += e.X - this.MoveX; this.SY += e.Y - this.MoveY; this.MoveX = e.X; this.MoveY = e.Y; } DrawForm(); } } protected override void OnMouseUp(MouseEventArgs e) { if (this.WorkType == 1) { this.SW = e.X - this.SX; this.SH = e.Y - this.SY; } this.WorkType = 0; DrawForm(); } }
栏目列表
最新更新
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
Python初学者友好丨详解参数传递类型
如何有效管理爬虫流量?
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比
一款纯 JS 实现的轻量化图片编辑器
关于开发 VS Code 插件遇到的 workbench.scm.
前端设计模式——观察者模式
前端设计模式——中介者模式
创建型-原型模式