uni-app图片编辑组件整理


之前整理过一个 uni-app 图片编辑组件,主要用来处理头像裁剪、拖拽、缩放、旋转和镜像,这里先记录一下整体思路

一开始只是想做一个简单的头像编辑。

用户选择一张图片,然后可以拖动位置,放大缩小,最后保存成一张新的图片。

如果只是在 H5 里面做,这件事并不算复杂。

但是放到 uni-app 里面以后,会发现它不是单纯写一个 canvas 或者一个 img 标签就能解决的。

因为 uni-app 的目标是多端运行,H5、App、小程序虽然写法看起来差不多,但是底层能力并不完全一样。

遇到的问题

这次图片编辑组件里面主要遇到几个问题:

  1. 图片来源不固定,可能是本地图片,也可能是网络图片
  2. 图片路径在 H5、App、小程序里面不是一种格式
  3. 触摸操作需要同时支持单指拖拽和双指缩放旋转
  4. CSS 变换只是页面效果,保存时还要生成真正的新图片
  5. App 端逻辑层不能随便直接操作页面 DOM
  6. 保存到相册需要的是本地临时路径,而不是 base64 字符串

所以这个组件最后不是一个简单的图片预览组件,而是分成了几层处理。

组件结构

页面里面使用组件的方式大概是这样:

1
2
3
4
5
<cs-ImageEditor
ref="csImageEditor"
:imageSrc="imageSrc"
@sendUrl="updata"
/>

外部页面只负责选择图片和调用方法:

1
2
3
4
5
6
7
8
9
10
chooseImage() {
uni.chooseImage({
count: 1,
sourceType: ['album', 'camera'],
success: (res) => {
this.imageSrc = res.tempFilePaths[0]
this.$refs.csImageEditor.init()
}
})
}

组件内部负责图片显示、手势计算、最终保存。

这样做的好处是,页面不需要关心里面到底是怎么处理拖拽、旋转和截图的,只要调用组件暴露出来的方法就行。

暴露的方法

这次组件主要暴露了几个方法:

1
2
3
4
init()
rotateCounterClockwise()
mirrorImage()
saveImage()

init 用来重新初始化图片。

rotateCounterClockwise 用来做 90 度旋转。

mirrorImage 用来做水平镜像。

saveImage 用来生成最终图片,并通过事件把结果返回给外部页面。

外部页面保存图片时,只需要监听 sendUrl

1
2
3
4
5
updata(obj) {
uni.saveImageToPhotosAlbum({
filePath: obj.filePath
})
}

这里有一个比较关键的点,saveImageToPhotosAlbum 需要的是 filePath

也就是说组件内部如果生成的是 base64,还需要再把 base64 转成临时文件路径。

为什么不直接用canvas

一开始很容易想到直接用 canvas 做。

但是在 uni-app 里面,canvas 跨端细节比较多,尤其是 App、小程序、H5 的接口和限制不完全一致。

而这个组件的编辑过程主要是通过 DOM 和 CSS transform 来完成的。

图片移动、缩放、旋转、镜像,都可以先通过样式表现出来:

1
2
transform: translate(x, y) scale(1, 1)
transform: scale(scale) rotate(deg)

最后保存时,再把当前编辑区域转成图片。

所以这里用了 renderjs + html2canvas 的方式,让视图层去处理 DOM 截图。

这也是这个组件里面比较重要的一块。

为什么要做路径转换

还有一个很容易忽略的问题是图片路径。

H5 里面可以用 FileReader

App 里面要用 plus.io 或者 plus.nativeObj.Bitmap

微信小程序里面要用 wx.getFileSystemManager

同样是选择一张图片,不同端返回的路径和可操作方式是不一样的。

所以组件里面单独整理了两个方法:

1
2
pathToBase64()
base64ToPath()

一个负责把本地路径转成 base64,方便页面显示和处理。

另一个负责把 base64 转成本地临时路径,方便保存到相册。

整体流程

整个组件大概可以理解成下面这个流程:

1
2
3
4
5
6
7
8
9
10
选择图片
-> 判断图片来源
-> 本地图片转 base64
-> 根据图片宽高决定 widthFix 或 heightFix
-> 用户拖拽、缩放、旋转、镜像
-> renderjs 截取编辑区域
-> 生成 base64
-> base64 转临时路径
-> 触发 sendUrl
-> 页面保存到相册

看起来步骤有点多,但是拆开以后会清楚很多。

uni-app 做这种图片编辑,真正麻烦的地方不是某一个 API,而是不同端的能力边界不一样。

总结

这次组件整理下来,我感觉 uni-app 里面做图片编辑,最重要的是不要只站在 H5 的角度去想。

页面上的图片只是第一步。

后面还有手势、路径、截图、保存相册、跨端兼容这些问题。

所以组件最后才会拆成:显示层、手势层、截图层、路径转换层。

以上就是我对 uni-app 图片编辑组件整体思路的记录,如有错误,欢迎大佬指出。

-------------本文结束感谢您的阅读-------------