uni-app图片编辑组件整理
之前整理过一个 uni-app 图片编辑组件,主要用来处理头像裁剪、拖拽、缩放、旋转和镜像,这里先记录一下整体思路
一开始只是想做一个简单的头像编辑。
用户选择一张图片,然后可以拖动位置,放大缩小,最后保存成一张新的图片。
如果只是在 H5 里面做,这件事并不算复杂。
但是放到 uni-app 里面以后,会发现它不是单纯写一个 canvas 或者一个 img 标签就能解决的。
因为 uni-app 的目标是多端运行,H5、App、小程序虽然写法看起来差不多,但是底层能力并不完全一样。
遇到的问题
这次图片编辑组件里面主要遇到几个问题:
- 图片来源不固定,可能是本地图片,也可能是网络图片
- 图片路径在 H5、App、小程序里面不是一种格式
- 触摸操作需要同时支持单指拖拽和双指缩放旋转
- CSS 变换只是页面效果,保存时还要生成真正的新图片
- App 端逻辑层不能随便直接操作页面 DOM
- 保存到相册需要的是本地临时路径,而不是 base64 字符串
所以这个组件最后不是一个简单的图片预览组件,而是分成了几层处理。
组件结构
页面里面使用组件的方式大概是这样:
1 | <cs-ImageEditor |
外部页面只负责选择图片和调用方法:
1 | chooseImage() { |
组件内部负责图片显示、手势计算、最终保存。
这样做的好处是,页面不需要关心里面到底是怎么处理拖拽、旋转和截图的,只要调用组件暴露出来的方法就行。
暴露的方法
这次组件主要暴露了几个方法:
1 | init() |
init 用来重新初始化图片。
rotateCounterClockwise 用来做 90 度旋转。
mirrorImage 用来做水平镜像。
saveImage 用来生成最终图片,并通过事件把结果返回给外部页面。
外部页面保存图片时,只需要监听 sendUrl:
1 | updata(obj) { |
这里有一个比较关键的点,saveImageToPhotosAlbum 需要的是 filePath。
也就是说组件内部如果生成的是 base64,还需要再把 base64 转成临时文件路径。
为什么不直接用canvas
一开始很容易想到直接用 canvas 做。
但是在 uni-app 里面,canvas 跨端细节比较多,尤其是 App、小程序、H5 的接口和限制不完全一致。
而这个组件的编辑过程主要是通过 DOM 和 CSS transform 来完成的。
图片移动、缩放、旋转、镜像,都可以先通过样式表现出来:
1 | transform: translate(x, y) scale(1, 1) |
最后保存时,再把当前编辑区域转成图片。
所以这里用了 renderjs + html2canvas 的方式,让视图层去处理 DOM 截图。
这也是这个组件里面比较重要的一块。
为什么要做路径转换
还有一个很容易忽略的问题是图片路径。
H5 里面可以用 FileReader。
App 里面要用 plus.io 或者 plus.nativeObj.Bitmap。
微信小程序里面要用 wx.getFileSystemManager。
同样是选择一张图片,不同端返回的路径和可操作方式是不一样的。
所以组件里面单独整理了两个方法:
1 | pathToBase64() |
一个负责把本地路径转成 base64,方便页面显示和处理。
另一个负责把 base64 转成本地临时路径,方便保存到相册。
整体流程
整个组件大概可以理解成下面这个流程:
1 | 选择图片 |
看起来步骤有点多,但是拆开以后会清楚很多。
uni-app 做这种图片编辑,真正麻烦的地方不是某一个 API,而是不同端的能力边界不一样。
总结
这次组件整理下来,我感觉 uni-app 里面做图片编辑,最重要的是不要只站在 H5 的角度去想。
页面上的图片只是第一步。
后面还有手势、路径、截图、保存相册、跨端兼容这些问题。
所以组件最后才会拆成:显示层、手势层、截图层、路径转换层。
以上就是我对 uni-app 图片编辑组件整体思路的记录,如有错误,欢迎大佬指出。