Flutter 实现图片裁剪
实现原理很简单 ,自己绘制一个裁剪框, 根据手势 选择到适合的位置 ,然后将选中的区域绘制到一个新的图片上,从而完成裁剪
裁剪框的绘制 这里我是根据点来连线的 因为每个点上会绘制一个拉伸的标识符
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 实现图片裁剪的更多相关文章
- iOS常见用户头像的圆形图片裁剪常见的几种方法
在开发中,基本上APP的用户头像的处理都需要把用户所上传的方形图片,处理为圆形图片.在这里就总结三种常见的处理圆形图片的方法. 1.使用位图上下文 2.使用UIView的layer进行处理 3.使用r ...
- Cropper – 简单的 jQuery 图片裁剪插件
Cropper 是一个简单的 jQuery 图像裁剪插件.它支持选项,方法,事件,触摸(移动),缩放,旋转.输出的裁剪数据基于原始图像大小,这样你就可以用它们来直接裁剪图像. 如果你尝试裁剪跨域图像, ...
- 自己积累的一些Emgu CV代码(主要有图片格式转换,图片裁剪,图片翻转,图片旋转和图片平移等功能)
using System; using System.Drawing; using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Structure; na ...
- web开发实战--图片裁剪和上传
前言: 最近的开发中, 有一个上传头像的任务. 由于头像本身的特殊性, 其一般流程为选择图片, 编辑裁剪区域, 再继而上传图片操作. 看似简单的东西, 实则是挺麻烦的一件事. 借助这次开发机会, 来具 ...
- PHP图片裁剪_图片缩放_PHP生成缩略图
在制作网页过程中,为了排版整齐美观,对网页中的图片处理成固定大小尺寸的图片,或是要截去图片边角中含有水印的图片,对于图片量多,每天更新大量图,靠人工PS处理是不现实的,那么有没有自动处理图片的程序了! ...
- Croppic – 免费开源的 jQuery 图片裁剪插件
Croppic 这款开源的 jQuery 图片裁剪插件能够满足网站开发人员各种不同的使用需要.只需要简单的上传图片,就可以实现你想要的图像缩放和裁剪功能.因为使用了 HTML5 FormData 对 ...
- Android大图片裁剪终极解决方案(上:原理分析)
转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-) http://my.oschina.net/ryanhoo/blog/86842 约几个月前,我正 ...
- apiCloud中图片裁剪模块FNImageClip的使用
思路 1.获取需裁剪图片的地址 2.跳转到裁剪页面 3.裁剪成功返回新图片地址 4.替换原有图片地址 增加修饰和事件 str += '<li class="tu image" ...
- ASP.NET MVC在服务端把异步上传的图片裁剪成不同尺寸分别保存,并设置上传目录的尺寸限制
我曾经试过使用JSAjaxFileUploader插件来把文件.照片以异步的方式上传,就像"MVC文件图片ajax上传轻量级解决方案,使用客户端JSAjaxFileUploader插件01- ...
随机推荐
- debian10使用国内源安装docker以及一些使用方法
首先, 我的环境是debian, 容器是centos debian 安装添加新存储库所需的依赖项 1 sudo apt install ca-certificates curl software-pr ...
- MacBook Air装Windows7双系统后的一些(未尝试)想法
转载请标注原地址:https://www.cnblogs.com/lixiaojing/p/11458477.html 运行环境: macOS在Mojave下的Boot Camp Assistant只 ...
- IE安全限制
在安全级别下面设置置进行如下调整: A.ActiveX控件自动提示:启用 B.对标记为可安全执行脚本的ActiveX控件执行脚本:启用 C.对未标记为可安全执行脚本的ActiveX控件初始化并执行脚本 ...
- 范仁义html+css课程---3、图片和超链接
范仁义html+css课程---3.图片和超链接 一.总结 一句话总结: img标签是图片标签,定义 HTML 页面中的图像 a标签是超链接标签,用于从一个页面链接到另一个页面. 1.img标签要点? ...
- NGINX Cache Management (.imh nginx)
In this article, we will explore the various NGINX cache configuration options, and tips on tweaking ...
- 深入分析GCC
深入分析GCC 目录 前言章 GCC概述 11.1 GCC的产生与发展 11.2 GCC的特点 21.3 GCC代码分析 3第2章 GCC源代码分析工具 42.1 vim ctags代码阅读工具 42 ...
- postgrelsql 的 wm_concat : string_agg
string_agg,array_agg 这两个函数的功能大同小异,只不过合并数据的类型不同 array_agg(expression) 把表达式变成一个数组 一般配合 array_to_string ...
- (生鲜项目)01. Vue环境搭建
第一步: nodejs安装 https://nodejs.org/en/download/ 说明安装成功 第二步: cnpm 由于npm需要很多的依赖包,这些包下载都很慢,所以就有了cnpm : ht ...
- laravel 配置自动加载多路由文件
在 app\Providers\RouteServiceProvider文件下增加方法&注册: 增加之后就可以在routers下建立api文件夹,在里面添加路由了
- 对get post等http请求方式的理解
本文是关于get,post等几种请求方式的资料搜集和学习,HTTP,HTTP2协议的涉及点,然后提到了socket协议,RPC 先是和朋友的一些交流对话,问着问着就到了我的知识盲区.需要恶补一下这方面 ...