关键词:小程序AR 图片 base64 相机 Camera onCameraFrame Canvas ArrayBuffer Uint8Array Uint8ClampedArray upng-js
核心步骤:
1 相机原始图像数据frame.data,即ArrayBuffer数组,转成Uint8Array数组
2 Uint8Array数组转成Uint8ClampedArray数组
3 wx.canvasPutImageData(Uint8ClampedArray)
详细流程如下:
最近因为项目需求,需要上传base64去做AR识别功能,和大家一起分享讨论下具体的实现方式。
首先说下实现原理,通过Camera的onCameraFrame获取实时帧数据,将实时帧数据添加到Canvas上,然后将Canvas保存为临时图片,再将临时图片转换为base64。
贴上核心实现代码:
wxml:
js:
var nCounter = 0;
openCamera: function (res) {
var that = this
var camera_ctx = wx.createCameraContext()
listener = camera_ctx.onCameraFrame((frame) => {
// nCounter等于30 是因为一开始相机会有一个对焦的过程,如果一开始获取数据,就是模糊的图片
if (nCounter == 30) {
console.log(frame.data instanceof ArrayBuffer, frame.width, frame.height)
var data = new Uint8Array(frame.data);
var clamped = new Uint8ClampedArray(data);
// 实时帧数据添加到Canvas上
wx.canvasPutImageData({
canvasId: 'myCanvas',
x: 0,
y: 0,
width: frame.width,
height: frame.height,
data: clamped,
success(res) {
// 转换临时文件
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: frame.width,
height: frame.height,
canvasId: 'myCanvas',
fileType: 'jpg',
destWidth: frame.width,
destHeight: frame.height,
// 精度修改
quality: 0.8,
success(res) {
// 临时文件转base64
wx.getFileSystemManager().readFile({
filePath: res.tempFilePath, //选择图片返回的相对路径
encoding: 'base64', //编码格式
success: res => {
// 保存base64
that.data.mybase64 = res.data;
}
})
},
fail(res) {
console.log(res);
}
}, that)
}
})
}
nCounter++
// console.log(nCounter);
if (nCounter >= 100) {
nCounter = 0
}
})
listener.start()
}
目前网上有两种转换方式并对比下:
1:upng-js等第三方转码js库,将相机流转换成base64,一般需要1-2s左右
2.使用canvas将相机流转变base64,都是使用js或者小程序官方的api进行转换,一般转换时间在1秒以下:
重点说明下:
如何使用wx.canvasPutImageData()将相机流添加canvas,我们查看该官方api,添加的data类型为:Uint8ClampedArray
而我们通过onCameraFrame获取的data类型为:ArrayBuffer
所有两者类型不一致,就需要转换,将ArrayBuffer=>Uint8Array=>Uint8ClampedArray
var data = new Uint8Array(frame.data);
var clamped = new Uint8ClampedArray(data);
成功的把onCameraFrame获取实时帧数据转换并canvasPutImageData在canvas上,并通过canvasToTempFilePath获取临时文件,如何获取临时文件getFileSystemManager转换为base64,传入云端进行AR识别,就大功告成!
技术分享来自于:北京晞翼科技有限公司
技术作者:le3d618、xiaoz0816
微信商务联系:le3d618
在测试机发现,这个方法,会造成越来越卡顿? 如何解决?
https://github.com/eugeneware/jpeg-js
用jpeg-js代替了,感觉还不错
var clamped = new Uint8ClampedArray(this.frameData);
let rawImageData = {
data: clamped,
width: this.width,
height: this.height,
}
var jpegImageData = jpeg.encode(rawImageData,70)
const base64 = 'data:image/jpg;base64,'+uni.arrayBufferToBase64(jpegImageData.data)
还请大佬粘贴出源码啊
errMsg: "canvasPutImageData:fail invalid data format"}
请问 报错The provided value is not of type '(CSSImageValue or HTMLImageElement or SVGImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)' 因为啥呀
官方的takePhoto也可以,将拍照的文件通过wx.getFileSystemManager转为base64上传
upng在ios上有问题