WinForm使用鼠标裁剪图像

2023-11-02

之前做一个试卷识别的项目的时候需要预先将各个部分裁剪开然后进行识别,而网上的裁剪函数都是记录鼠标的位置然后进行裁剪

public static Bitmap PartDraw(Image src, Rectangle cutpart)//切割图片
        {
            Bitmap rectbmp = new Bitmap(cutpart.Width, cutpart.Height, PixelFormat.Format24bppRgb);
            using (Graphics g = Graphics.FromImage(rectbmp))
            {
                g.DrawImage(src, new Rectangle(0, 0, cutpart.Width, cutpart.Height), cutpart, GraphicsUnit.Pixel);
                g.Dispose();
            }
            return rectbmp;
        }

但是这样做又带来了一个问题就是如果图片是zoom了的那么鼠标的位置和实际图像的位置就会出现偏移,导致实际截图的位置和你想截图的位置完全不一样。

最后采用了坐标比例换算的方法解决了这个问题。

本方法主要关联四个图片控件的事件

坐标换算的原型函数如下

int originalWidth = this.PicSource.Image.Width;
            int originalHeight = this.PicSource.Image.Height;

            PropertyInfo rectangleProperty = this.PicSource.GetType().GetProperty("ImageRectangle", BindingFlags.Instance | BindingFlags.NonPublic);
            Rectangle rectangle = (Rectangle)rectangleProperty.GetValue(this.PicSource, null);

            int currentWidth = rectangle.Width;
            int currentHeight = rectangle.Height;

            double rate = (double)currentHeight / (double)originalHeight;

            int black_left_width = (currentWidth == this.PicSource.Width) ? 0 : (this.PicSource.Width - currentWidth) / 2;
            int black_top_height = (currentHeight == this.PicSource.Height) ? 0 : (this.PicSource.Height - currentHeight) / 2;

            int zoom_x = e.X - black_left_width;
            int zoom_y = e.Y - black_top_height;

            double original_x = (double)zoom_x / rate;
            double original_y = (double)zoom_y / rate;

可以使用实际坐标来换算得出源坐标

所用到的全局变量如下

        bool blnDraw;
        Point start; //画框的起始点
        Rectangle rect;
        Point Pstart; //原图的起始点
        Rectangle Orect;//在原图中尺寸

然后为图片控件添加以下事件

 

private void PicSource_MouseDown(object sender, MouseEventArgs e)
        {
            int originalWidth = this.PicSource.Image.Width;
            int originalHeight = this.PicSource.Image.Height;

            PropertyInfo rectangleProperty = this.PicSource.GetType().GetProperty("ImageRectangle", BindingFlags.Instance | BindingFlags.NonPublic);
            Rectangle rectangle = (Rectangle)rectangleProperty.GetValue(this.PicSource, null);

            int currentWidth = rectangle.Width;
            int currentHeight = rectangle.Height;

            double rate = (double)currentHeight / (double)originalHeight;

            int black_left_width = (currentWidth == this.PicSource.Width) ? 0 : (this.PicSource.Width - currentWidth) / 2;
            int black_top_height = (currentHeight == this.PicSource.Height) ? 0 : (this.PicSource.Height - currentHeight) / 2;

            int zoom_x = e.X - black_left_width;
            int zoom_y = e.Y - black_top_height;

            double original_x = (double)zoom_x / rate;
            double original_y = (double)zoom_y / rate;

            Pstart = new Point((int)original_x, (int)original_y);

            start = e.Location;
            Invalidate();
            blnDraw = true;
        }
private void PicSource_MouseMove(object sender, MouseEventArgs e)
        {
            if (blnDraw)
            {
                if (e.Button != MouseButtons.Left)//判断是否按下左键
                    return;
                Point tempEndPoint = e.Location; //记录框的位置和大小
                rect.Location = new Point(
                Math.Min(start.X, tempEndPoint.X),
                Math.Min(start.Y, tempEndPoint.Y));
                rect.Size = new Size(
                Math.Abs(start.X - tempEndPoint.X),
                Math.Abs(start.Y - tempEndPoint.Y));
                //记录绘制大小

                int originalWidth = this.PicSource.Image.Width;
                int originalHeight = this.PicSource.Image.Height;

                PropertyInfo rectangleProperty = this.PicSource.GetType().GetProperty("ImageRectangle", BindingFlags.Instance | BindingFlags.NonPublic);
                Rectangle rectangle = (Rectangle)rectangleProperty.GetValue(this.PicSource, null);

                int currentWidth = rectangle.Width;
                int currentHeight = rectangle.Height;

                double rate = (double)currentHeight / (double)originalHeight;

                int black_left_width = (currentWidth == this.PicSource.Width) ? 0 : (this.PicSource.Width - currentWidth) / 2;
                int black_top_height = (currentHeight == this.PicSource.Height) ? 0 : (this.PicSource.Height - currentHeight) / 2;

                int zoom_x = e.X - black_left_width;
                int zoom_y = e.Y - black_top_height;

                double original_x = (double)zoom_x / rate;
                double original_y = (double)zoom_y / rate;

                Orect.Location = new Point(
                Math.Min(Pstart.X, (int)original_x),
                Math.Min(Pstart.Y, (int)original_y));
                Orect.Size = new Size(
                Math.Abs(Pstart.X - (int)original_x),
                Math.Abs(Pstart.Y - (int)original_y));

                PicSource.Invalidate();

            }
        }
private void PicSource_MouseUp(object sender, MouseEventArgs e)
        {
            blnDraw = false; //结束绘制
        }
private void PicSource_Paint(object sender, PaintEventArgs e)
        {
            if (blnDraw)
            {
                if (PicSource.Image != null)
                {
                    if (rect != null && rect.Width > 0 && rect.Height > 0)
                    {
                        e.Graphics.DrawRectangle(new Pen(Color.Red, 3), rect);//重新绘制颜色为红色
                    }
                }
            }
        }

最后效果如图

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WinForm使用鼠标裁剪图像 的相关文章

  • 在 xaml 中编写嵌套类型时出现设计时错误

    我创建了一个用户控件 它接受枚举类型并将该枚举的值分配给该用户控件中的 ComboBox 控件 很简单 我在数据模板中使用此用户控件 当出现嵌套类型时 问题就来了 我使用这个符号来指定 EnumType x Type myNamespace
  • C# 异步等待澄清?

    我读了here http blog stephencleary com 2012 02 async and await html that 等待检查等待的看看它是否有already完全的 如果 可等待已经完成 那么该方法将继续 运行 同步
  • 没有特殊字符的密码验证器

    我是 RegEx 的新手 已经进行了大量搜索 但没有找到任何具体内容 我正在编写一个验证密码字符串的正则表达式 可接受的字符串必须至少具有 4 种字符类型中的 3 种 数字 小写字母 大写字母 特殊字符 我对包含有一个想法 也就是说 如果这
  • 机器Epsilon精度差异

    我正在尝试计算 C 中双精度数和浮点数的机器 epsilon 值 作为学校作业的一部分 我在 Windows 7 64 位中使用 Cygwin 代码如下 include
  • C++11 删除重写方法

    Preface 这是一个关于最佳实践的问题 涉及 C 11 中引入的删除运算符的新含义 当应用于覆盖继承父类的虚拟方法的子类时 背景 根据标准 引用的第一个用例是明确禁止调用某些类型的函数 否则转换将是隐式的 例如最新版本第 8 4 3 节
  • 如何从 Visual Studio 将视图导航到其控制器?

    问题是解决方案资源管理器上有 29 个项目 而且项目同时具有 ASP NET MVC 和 ASP NET Web 表单结构 在MVC部分中 Controller文件夹中有大约100个子文件夹 每个文件夹至少有3 4个控制器 视图完全位于不同
  • free 和 malloc 在 C 中如何工作?

    我试图弄清楚如果我尝试 从中间 释放指针会发生什么 例如 看下面的代码 char ptr char malloc 10 sizeof char for char i 0 i lt 10 i ptr i i 10 ptr ptr ptr pt
  • 为什么 GCC 不允许我创建“内联静态 std::stringstream”?

    我将直接前往 MCVE include
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • C# 列表通用扩展方法与非通用扩展方法

    这是一个简单的问题 我希望 集合类中有通用和非通用方法 例如List
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • LINQ:使用 INNER JOIN、Group 和 SUM

    我正在尝试使用 LINQ 执行以下 SQL 最接近的是执行交叉联接和总和计算 我知道必须有更好的方法来编写它 所以我向堆栈团队寻求帮助 SELECT T1 Column1 T1 Column2 SUM T3 Column1 AS Amoun
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • C++ 继承的内存布局

    如果我有两个类 一个类继承另一个类 并且子类仅包含函数 那么这两个类的内存布局是否相同 e g class Base int a b c class Derived public Base only functions 我读过编译器无法对数
  • 对于某些 PDF 文件,LoadIFilter() 返回 -2147467259

    我正在尝试使用 Adob e IFilter 搜索 PDF 文件 我的代码是用 C 编写的 我使用 p invoke 来获取 IFilter 的实例 DllImport query dll SetLastError true CharSet
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置
  • 从 mvc 控制器使用 Web api 控制器操作

    我有两个控制器 一个mvc控制器和一个api控制器 它们都在同一个项目中 HomeController Controller DataController ApiController 如果我想从 HomeController 中使用 Dat

随机推荐

  • 电源纹波的测量

    测试手法 A 使用纹波探头 DC 50ohm 用弹簧地连接到地上 然后将探头点到测试电源上 示波器打开20MHz的带宽限制 打开余晖模式 将测试通道的输出电压值移到示波器屏幕中间 让让示波器采样1 3分钟 最后看示波器上的峰峰值即可 B 使
  • CCSpriteFrameCache的用法

    转自 https www cnblogs com pengyingh articles 2436648 html 让我们首先创建一个工程骨架 使用cocos2d工程模板创建一个新的项目并取名为AnimBear 接下来 下载一些由我的老婆制作
  • qt day 5

    1 gt 实现闹钟功能 pro QT core gui texttospeech greaterThan QT MAJOR VERSION 4 QT widgets CONFIG c 11 The following define make
  • C# USB通讯

    关注 星标公众号 及时获取更多技术分享 作者 冰茶奥利奥 微信公众号 嵌入式电子创客街 项目工程文件下载 工程文件下载地址 看了很多网上的博客 讲述如何用C 进行USB设备操作 很多都是不对的 以至于南辕北辙 我们可以使用usb库 在c下有
  • 打开方式中无法添加程序,无法用指定程序打开

    用T32打开 ts2文件时 右击 打开方式 中 浏览 到t32start exe的安装目录 点击 确定 可是在 打开方式 中找不到t32start exe程序 可能是因为注册表中t32start exe程序的路径指定错误 原因 解压安装包
  • 通过自定义 Vue 指令实现前端曝光埋点

    前言 互联网发展至今 数据的重要性已经不言而喻 尤其是在电商公司 数据的统计分析尤为重要 通过数据分析可以提升用户的购买体验 方便运营和产品调整销售策略等等 埋点就是网站分析的一种常用的数据采集方法 埋点按照获取数据的方式一般可以分为以下
  • flink学习day05:checkpoint 原理与实践

    flink checkpoint checkpointe是什么 基于state出发 flink基于与state可以做非常多复杂的事情 但是state是存储在内存中 内存中的数据是不安全的易丢失的 所以flink为了解决这个问题就引入了che
  • 牛客网C语言编程初学者入门训练135题

    文章目录 1 实践出真知 2 我是大V 3 有容乃大 4 小飞机 5 反向输出四位数 6 大小写转换 7 缩短二进制 8 十六进制转十进制 9 printf的返回值 10 成绩输入输出 11 学生基本信息输入输出 12 字符金字塔 13 判
  • 线稿图视频制作--从此短视频平台不缺上传视频了

    博客首页 knighthood2001 欢迎点赞 评论 热爱python 期待与大家一同进步成长 给大家推荐一款很火爆的刷题 面试求职网站 跟我一起来巩固基础 开启刷题之旅吧 这年头还不来尝试线稿图视频 之前笔者也写过将视频转换为线稿图视频
  • 基于Docker的mysql主从复制

    目录 一 拉取mysql 二 启动两个mysql容器 2 1 主master 2 2 从slave 三 配置master 3 1 进入master内部配置 3 2 安装vim命令 3 3 重启mysql 3 4 创建数据同步用户 可不建 直
  • Linux重启nfs出现没有权限,Linux NFS搭建与错误提示解决

    Linux NFS搭建与错误提示解决 服务端设置 root server cat etc redhat release 查看操作系统版本信息 CentOS release 5 5 Final root server uname r 查看当前
  • 常见的错误-04

    引言 在公司配置新电脑环境时候 在安装和配置完所有VSCode软件以及C 环境后 ubuntun环境下 尝试使用debug进行代码调试 遇到了在debug过程中不输出结果的bug 如下图 未输出array以及zheli 解决方法 在ubun
  • vue3+ts中对getCurrentInstance的使用

    1 在main js中挂载一个全局属性 拿axios举例 import App from App vue import axios from http 封装的axios方法 const app createApp App 创建应用 app
  • 【100%通过率 】【华为OD机试 c++/java/python】对称字符串【 2023 Q1 A卷

    华为OD机试 题目列表 2023Q1 点这里 2023华为OD机试 刷题指南 点这里 题目描述 对称美学 对称就是最大的美学 现有一道关于对称字符串的美学 已知 第 1 个字符串 R 第 2 个字符串 BR 第 3 个字符串 RBBR 第
  • resetlog

    来自于itpub的一篇文章 http space itpub net 16628454 很多人说 resetlogs就是不完全恢复 这是不对的 做不完全恢复必须使用resetlogs 但resetlogs也可以做完全恢复 而noresetl
  • # 第四届蓝桥杯JavaB组省赛-马虎的算式

    第四届蓝桥杯JavaB组省赛 马虎的算式 题目描述 小明是个急性子 上小学的时候经常把老师写在黑板上的题目抄错了 有一次 老师出的题目是 36 x 495 他却给抄成了 396 x 45 但结果却很戏剧性 他的答案竟然是对的 因为 36 4
  • 解决idea文件properties中文乱码问题

    有时候将项目代码拉取至本地用idea打开时会出现中文乱码问题 遇到这种问题不要慌 重新设置一下编码为UTF 8即可 那么如何将idea的编码统一设置为UTF 8格式呢 接下来我们一一解决此类问题 1 打开idea编译器 有时候会看到打开的文
  • WebGIS工程师进阶训练营

    WebGIS工程师进阶训练营 1 WebGIS课程综述 2 多类情景部署SuperMap iServer 2 1 Linux环境部署SuperMap iServer 2 2 war包部署 2 3 常见问题排查 3 SuperMap iSer
  • word添加、更新目录

    1 显示导航窗口 视图 导航窗口 2 文档中的目录 2 1 插入目录 引用 目录 2 2 更新目录 方式一 点击下图 更新目录 方式二 引用 更新目录
  • WinForm使用鼠标裁剪图像

    之前做一个试卷识别的项目的时候需要预先将各个部分裁剪开然后进行识别 而网上的裁剪函数都是记录鼠标的位置然后进行裁剪 public static Bitmap PartDraw Image src Rectangle cutpart 切割图片