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); }); }