uni-app图片路径和base64转换


uni-app 做图片处理时,路径问题很容易踩坑,同一张图片在 H5、App、小程序里面可能完全不是一种处理方式

图片编辑组件里面有一个很重要的工具文件。

它主要做两件事:

1
2
pathToBase64()
base64ToPath()

一开始会觉得这两个方法没什么特别。

但是做跨端以后会发现,图片路径和 base64 的转换其实是很关键的一层。

为什么需要转换

用户选择图片后,uni.chooseImage 会返回临时路径。

但是不同端返回的路径格式不一样。

H5 里可能是浏览器可以访问的 blob 或本地地址。

App 里可能是 _doc_wwwfile:///storage/emulated/0/ 这类路径。

微信小程序里又是小程序自己的临时文件路径。

如果只是拿这个路径直接给所有端使用,很容易某一端正常,另一端就加载失败。

所以组件里会把本地图片先转成 base64。

base64 对页面显示和截图来说更稳定。

本地路径处理

App 端里面,本地路径还需要先转换一下。

工具方法里有一个 getLocalFilePath

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function getLocalFilePath(path) {
if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0) {
return path
}

if (path.indexOf('file://') === 0) {
return path
}

if (path.indexOf('/storage/emulated/0/') === 0) {
return path
}

if (path.indexOf('/') === 0) {
var localFilePath = plus.io.convertAbsoluteFileSystem(path)
if (localFilePath !== path) {
return localFilePath
} else {
path = path.substr(1)
}
}

return '_www/' + path
}

这个方法主要是为了把不同形式的本地路径统一成 App 能识别的路径。

这就是 uni-app 跨端项目里经常遇到的问题。

代码写起来像是一套,但是底层文件系统不是一套。

H5转base64

H5 里面比较常见的方式是 FileReader

代码里面是通过 XMLHttpRequest 拿到 blob,然后用 FileReader 读取:

1
2
3
4
5
6
7
8
9
10
11
var xhr = new XMLHttpRequest()
xhr.open('GET', path, true)
xhr.responseType = 'blob'

xhr.onload = function() {
let fileReader = new FileReader()
fileReader.onload = function(e) {
resolve(e.target.result)
}
fileReader.readAsDataURL(this.response)
}

这里得到的结果就是 base64。

H5 这条线相对直接,因为浏览器本身就有这些能力。

App转base64

App 端不能只按浏览器方式来。

这里要走 plus.io

1
2
3
4
5
6
7
8
9
plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), function(entry) {
entry.file(function(file) {
var fileReader = new plus.io.FileReader()
fileReader.onload = function(data) {
resolve(data.target.result)
}
fileReader.readAsDataURL(file)
})
})

这也是为什么组件里会判断:

1
2
3
if (typeof plus === 'object') {
...
}

plus 是 App 端的能力。

如果项目跑在 H5 或小程序里,就不能直接使用它。

微信小程序转base64

微信小程序里面要走文件系统管理器:

1
2
3
4
5
6
7
wx.getFileSystemManager().readFile({
filePath: path,
encoding: 'base64',
success: function(res) {
resolve('data:image/png;base64,' + res.data)
}
})

这里需要自己补上 base64 的头:

1
data:image/png;base64,

否则后面当作图片显示时可能识别不了。

base64转路径

编辑完成后,html2canvas 生成的是 base64。

但是保存到相册时,uni.saveImageToPhotosAlbum 要的是本地路径。

所以还要把 base64 转回路径。

H5 里可以转成 blob 地址:

1
2
3
4
5
return resolve(
(window.URL || window.webkitURL).createObjectURL(
new Blob([array], { type: type })
)
)

App 端可以用 plus.nativeObj.Bitmap

1
2
3
4
5
6
7
8
var bitmap = new plus.nativeObj.Bitmap(fileName)

bitmap.loadBase64Data(base64, function() {
bitmap.save(filePath, {}, function() {
bitmap.clear()
resolve(filePath)
})
})

微信小程序则是写入用户临时目录:

1
2
3
4
5
6
7
var filePath = wx.env.USER_DATA_PATH + '/' + fileName

wx.getFileSystemManager().writeFile({
filePath: filePath,
data: dataUrlToBase64(base64),
encoding: 'base64'
})

三端处理方式完全不一样。

这也是为什么我把它单独封装成工具函数。

为什么不统一都用base64

base64 看起来跨端都能用,但它也有问题。

  1. 字符串很长
  2. 不适合频繁传递
  3. 保存相册 API 不一定接受
  4. 上传文件时通常还是需要本地路径或文件对象

所以组件内部可以用 base64 做中间状态,但对外最好还是返回本地路径。

这次组件返回的是:

1
2
3
4
{
base64: url,
filePath: path
}

这样使用方可以按自己的场景选择。

总结

uni-app 的图片路径问题,本质上是多端文件系统差异。

H5 有浏览器 API。

App 有 plus 能力。

小程序有自己的文件系统。

所以图片编辑组件不能只写一种路径处理方式。

先把路径转成 base64,编辑完成后再把 base64 转成本地临时路径,这样整个流程会稳很多。

以上就是我对 uni-app 图片路径和 base64 转换的理解,如有错误,欢迎大佬指出。

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