实现原理很简单 ,自己绘制一个裁剪框, 根据手势 选择到适合的位置 ,然后将选中的区域绘制到一个新的图片上,从而完成裁剪

裁剪框的绘制  这里我是根据点来连线的  因为每个点上会绘制一个拉伸的标识符

      List<Offset> points2 = [
Offset(startX, startY),
Offset(startX + cWidth, startY),
Offset(startX + cWidth, startY + cHeight),
Offset(startX, startY + cHeight),
Offset(startX, startY),
];
canvas.drawPoints(PointMode.polygon, points2, paint);//draw the clip box
paint.color = Colors.red;
// paint..style=PaintingStyle.stroke;
double radius = 10;
canvas.drawCircle(points2[0],radius,paint); //draw the drag point
canvas.drawCircle(points2[1],radius,paint);
canvas.drawCircle(points2[2],radius,paint);
// canvas.drawLine(Offset(points2[2].dx-radius, points2[2].dy-radius), Offset(points2[2].dx+radius, points2[2].dy+radius), paint);
canvas.drawCircle(points2[3],radius,paint);

源图片的绘制 ,根据屏幕大小  把图片缩放成适合长宽比例的图片

 if (image != null) {
//draw the backgroud image
double dwidth = 0;
double dheight = 0;
if (image.width.toDouble() / width > image.height.toDouble() / height) {
dwidth = width;
dheight = image.height.toDouble() * dwidth / image.width.toDouble();
}
else {
dheight = height;
dwidth = image.width.toDouble() * dheight / image.height.toDouble();
}
if (points.length > 0) {
points[3] = Offset(dwidth, dheight);
}
canvas.drawImageRect(image,
Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()),
Rect.fromLTWH((width - dwidth) / 2,
(height - dheight) / 2, dwidth, dheight), paint);
}

绘制完后 就是根据手势的偏移量来计算裁剪框的大小位置

        GestureDetector(
onPanDown: onPanDown,
onPanUpdate:onPanUpdate,
onPanEnd: onPanEnd,
),
 List<Offset> _points = <Offset>[];

_points有4个值    [0] 代表down的坐标   [1]代表move的左边   [2]代表裁剪框的坐标  [3]代表源图大小

在touchDown的时候  先存储左边  然后我们要计算点的区域是 拉伸 还是移动   拉伸的话是以顶点为中心的放心

 onPanDown(DragDownDetails details){
RenderBox referenceBox = context.findRenderObject();
Offset localPosition =
referenceBox.globalToLocal(details.globalPosition);
setState(() {
if(_points.length<3){
_points.add(localPosition);
_points.add(localPosition);
_points.add(Offset(0, 0));
_points.add(Offset(0, 0));
}
else{
_points[0]=localPosition;
_points[1]=localPosition;
}
dHeight = cHeight;
dWidth = cWidth;
double radius = 20;
if(hitPoint(Offset(_points[2].dx+cWidth, _points[2].dy+cHeight),radius , localPosition)){
downPosition =DownPosition.RIGHT_DOWN;
isDrag = false;
}
else if(hitPoint(Offset(_points[2].dx+cWidth, _points[2].dy),radius , localPosition)){
downPosition =DownPosition.RIGHT_UP;
isDrag = false;
}
else if(hitPoint(Offset(_points[2].dx, _points[2].dy+cHeight),radius , localPosition)){
downPosition =DownPosition.LEFT_DOWN;
isDrag = false;
}
else if(hitPoint(_points[2],radius , localPosition)){
downPosition =DownPosition.LEFT_UP;
isDrag = false;
} });
}

移动的时候  因为 4个点的处理逻辑是不一样的 所以需要单独判断 这里也做了个最小区域

 onPanUpdate(DragUpdateDetails details) {
RenderBox referenceBox = context.findRenderObject();
Offset localPosition =
referenceBox.globalToLocal(details.globalPosition);
if(isDrag){
setState(() {
_points[1]=localPosition;
});
}
else{
setState(() {
if(downPosition==DownPosition.RIGHT_DOWN){
cWidth = dWidth+localPosition.dx - _points[1].dx;
cHeight = dHeight +localPosition.dy-_points[1].dy;
}
else if(downPosition==DownPosition.LEFT_UP){
cWidth = dWidth-(localPosition.dx - _points[1].dx);
cHeight = dHeight-(localPosition.dy-_points[1].dy);
_points[2]=localPosition;
}
else if(downPosition==DownPosition.RIGHT_UP){
cWidth = dWidth+localPosition.dx - _points[1].dx;
cHeight = dHeight-(localPosition.dy-_points[1].dy);
_points[2]=Offset(_points[2].dx, localPosition.dy);
}
else if(downPosition==DownPosition.LEFT_DOWN){
cWidth = dWidth-(localPosition.dx - _points[1].dx);
cHeight = dHeight +localPosition.dy-_points[1].dy;
_points[2]=Offset(localPosition.dx, _points[2].dy);
}
if(cWidth<20){
cWidth=20;
};
if(cHeight<20){
cHeight=20;
} });
} }

手指抬起的时候将一些坐标重置下

onPanEnd(DragEndDetails details){
setState(() {
isDrag = true;
double startX = _points[1].dx - _points[0].dx+_points[2].dx;
double startY = _points[1].dy - _points[0].dy+_points[2].dy;
if(startX<0)
startX = 0;
else if(startX+cWidth>width){
startX = width-cWidth;
}
if(startY<0)
startY=0;
else if(startY + cHeight>height){
startY = height-cHeight;
}
_points[0]=Offset(0, 0);
_points[1]=Offset(0, 0);
_points[2] = Offset(startX<0?0:startX, startY<0?0:startY);
});
}
 

Flutter 实现图片裁剪的更多相关文章

  1. iOS常见用户头像的圆形图片裁剪常见的几种方法

    在开发中,基本上APP的用户头像的处理都需要把用户所上传的方形图片,处理为圆形图片.在这里就总结三种常见的处理圆形图片的方法. 1.使用位图上下文 2.使用UIView的layer进行处理 3.使用r ...

  2. Cropper – 简单的 jQuery 图片裁剪插件

    Cropper 是一个简单的 jQuery 图像裁剪插件.它支持选项,方法,事件,触摸(移动),缩放,旋转.输出的裁剪数据基于原始图像大小,这样你就可以用它们来直接裁剪图像. 如果你尝试裁剪跨域图像, ...

  3. 自己积累的一些Emgu CV代码(主要有图片格式转换,图片裁剪,图片翻转,图片旋转和图片平移等功能)

    using System; using System.Drawing; using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Structure; na ...

  4. web开发实战--图片裁剪和上传

    前言: 最近的开发中, 有一个上传头像的任务. 由于头像本身的特殊性, 其一般流程为选择图片, 编辑裁剪区域, 再继而上传图片操作. 看似简单的东西, 实则是挺麻烦的一件事. 借助这次开发机会, 来具 ...

  5. PHP图片裁剪_图片缩放_PHP生成缩略图

    在制作网页过程中,为了排版整齐美观,对网页中的图片处理成固定大小尺寸的图片,或是要截去图片边角中含有水印的图片,对于图片量多,每天更新大量图,靠人工PS处理是不现实的,那么有没有自动处理图片的程序了! ...

  6. Croppic – 免费开源的 jQuery 图片裁剪插件

    Croppic 这款开源的 jQuery 图片裁剪插件能够满足网站开发人员各种不同的使用需要.只需要简单的上传图片,就可以实现你想要的图像缩放和裁剪功能.因为使用了 HTML5 FormData  对 ...

  7. Android大图片裁剪终极解决方案(上:原理分析)

    转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-)  http://my.oschina.net/ryanhoo/blog/86842 约几个月前,我正 ...

  8. apiCloud中图片裁剪模块FNImageClip的使用

    思路 1.获取需裁剪图片的地址 2.跳转到裁剪页面 3.裁剪成功返回新图片地址 4.替换原有图片地址 增加修饰和事件 str += '<li class="tu image" ...

  9. ASP.NET MVC在服务端把异步上传的图片裁剪成不同尺寸分别保存,并设置上传目录的尺寸限制

    我曾经试过使用JSAjaxFileUploader插件来把文件.照片以异步的方式上传,就像"MVC文件图片ajax上传轻量级解决方案,使用客户端JSAjaxFileUploader插件01- ...

随机推荐

  1. debian10使用国内源安装docker以及一些使用方法

    首先, 我的环境是debian, 容器是centos debian 安装添加新存储库所需的依赖项 1 sudo apt install ca-certificates curl software-pr ...

  2. MacBook Air装Windows7双系统后的一些(未尝试)想法

    转载请标注原地址:https://www.cnblogs.com/lixiaojing/p/11458477.html 运行环境: macOS在Mojave下的Boot Camp Assistant只 ...

  3. IE安全限制

    在安全级别下面设置置进行如下调整: A.ActiveX控件自动提示:启用 B.对标记为可安全执行脚本的ActiveX控件执行脚本:启用 C.对未标记为可安全执行脚本的ActiveX控件初始化并执行脚本 ...

  4. 范仁义html+css课程---3、图片和超链接

    范仁义html+css课程---3.图片和超链接 一.总结 一句话总结: img标签是图片标签,定义 HTML 页面中的图像 a标签是超链接标签,用于从一个页面链接到另一个页面. 1.img标签要点? ...

  5. NGINX Cache Management (.imh nginx)

    In this article, we will explore the various NGINX cache configuration options, and tips on tweaking ...

  6. 深入分析GCC

    深入分析GCC 目录 前言章 GCC概述 11.1 GCC的产生与发展 11.2 GCC的特点 21.3 GCC代码分析 3第2章 GCC源代码分析工具 42.1 vim ctags代码阅读工具 42 ...

  7. postgrelsql 的 wm_concat : string_agg

    string_agg,array_agg 这两个函数的功能大同小异,只不过合并数据的类型不同 array_agg(expression) 把表达式变成一个数组 一般配合 array_to_string ...

  8. (生鲜项目)01. Vue环境搭建

    第一步: nodejs安装 https://nodejs.org/en/download/ 说明安装成功 第二步: cnpm 由于npm需要很多的依赖包,这些包下载都很慢,所以就有了cnpm : ht ...

  9. laravel 配置自动加载多路由文件

    在 app\Providers\RouteServiceProvider文件下增加方法&注册: 增加之后就可以在routers下建立api文件夹,在里面添加路由了

  10. 对get post等http请求方式的理解

    本文是关于get,post等几种请求方式的资料搜集和学习,HTTP,HTTP2协议的涉及点,然后提到了socket协议,RPC 先是和朋友的一些交流对话,问着问着就到了我的知识盲区.需要恶补一下这方面 ...