微信小程序中type=webgl的canvas导出成base64图片
<canvas id="webgl" canvas-id="webgl" type="webgl" disable-scroll="{{true}}" bindtouchstart="touchstart"></canvas>
<image src='{{photoUrl}}'></image>
function createImg(){
photoUrl = renderer.domElement._ctx.canvas.toDataURL('image/png');// jpg形式在真机上不支持透明背景
self.setData({
photoUrl
})
}
微信小程序base64图片和拍照的照片合成为一张图片
.webgl {
position: absolute;
z-index: 5;
height: 100%;
width: 100%;
}
.camera {
position: absolute;
z-index: 0;
height: 100%;
width: 100%;
}
<canvas id="webgl" canvas-id="webgl" type="webgl" disable-scroll="{{true}}" bindtouchstart="touchstart"></canvas>
<camera device-position="back" flash="off" frame-size="large" binderror="error" class="camera"></camera>
<canvas canvas-id="photo" style="width: {{photoSize.width}}rpx;height:{{photoSize.height}}rpx;left:-10000px;"></canvas>
<image class="photo" src='{{photoUrl}}' style="width: {{photoSize.width}}rpx;height:{{photoSize.height}}rpx;"></image>
<view class="takephoto-btn" bindtap="takePhoto">拍照分享</view>
takePhoto(){
let self = this;
this.data.cameraContext.takePhoto({
quality: "high",
success: (res) => {
self.webglToPhoto(res.tempImagePath);
},
});
},
webglToPhoto(photo) {
let self = this;
const webglBase64 = this.createImg();
const fs = wx.getFileSystemManager();
const times = new Date().getTime();
const codeimg = wx.env.USER_DATA_PATH + "/" + times + ".png";
fs.writeFile({
filePath: codeimg,
data: webglBase64.slice(22),
encoding: "base64",
success: () => {
const ctx = wx.createCanvasContext("photo");
const {width, height} = self.data.sysInfo
ctx.drawImage(photo, 0, 0, width, height);
// 绘制codeimg时旋转180度
// ctx.translate(width, height);
// ctx.rotate((180 * Math.PI) / 180);
// 绘制codeimg的水平镜像
// ctx.translate(width,0);
// ctx.scale(-1,1);
// 绘制codeimg的垂直镜像(webgl生成的base64图片在canvas中绘制时会垂直颠倒)
ctx.translate(0,height);
ctx.scale(1,-1);
ctx.drawImage(codeimg, 0, 0, width, height);
ctx.draw(true);// 已将照片和base64图片合成绘制到canvas中,但是canvas不支持缩放,故而显示成image,不显示canvas
self.canvasToImg(ctx, width, height);
},
});
},
canvasToImg(ctx, width, height) {
let self = this;
ctx.draw(
true,
setTimeout(() => {
wx.canvasToTempFilePath({
quality: 1,
x: 0,
y: 0,
width: width,
height: height,
destWidth: width * wx.getSystemInfoSync().pixelRatio,
destHeight: height * wx.getSystemInfoSync().pixelRatio,
canvasId: "photo",
fileType: "png",
success(res) {
console.log("photo绘制成功");
wx.hideLoading({
success: (res) => {},
});
self.setData({
photoUrl: res.tempFilePath,
});
},
fail(err) {
wx.hideLoading({
success: (res) => {},
});
},
complete() {
wx.hideLoading({
success: (res) => {},
});
}, // end complete
});
}, 500)
);
},
savePhoto() {
let self = this;
wx.saveImageToPhotosAlbum({
filePath: this.data.photoUrl,
success() {
wx.showToast({
title: "图片已为您保存到本地",
icon: "none",
});
},
});
},
以上方法在安卓中好用,在IOS中toDataUrl得到的结果是data:;
,故而不起作用。
IOS解决办法如下:
<canvas id="webgl" canvas-id="webgl" class="webgl" type="webgl" disable-scroll="{{true}}">
<canvas class="helper-canvas" type="2d" id="canvas"></canvas>
</canvas>
<view class="takephoto-btn" bindtap="takePhoto">拍照分享</view>
.helper-canvas {
opacity: 0;
display: block;
position: absolute;
top: 0;
left: -100vw;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
}
// 拍照相关
takePhoto() {
let self = this;
wx.showLoading({
title: "图片处理中...",
});
this.data.cameraContext.takePhoto({
quality: "high",
success: (res) => {
// self.webglToPhoto(res.tempImagePath);
self.webglToPhoto2(res.tempImagePath);
},
});
},
webglToPhoto2(photo){
let self = this;
const query = wx.createSelectorQuery();
query.select('#canvas').fields({node: true,size: true}).exec((res)=>{
self.clipWebgl(res[0].node, photo)
.then(webglImg => {
const ctx = wx.createCanvasContext("photo");
const {width, height} = self.data.sysInfo
ctx.drawImage(photo, 0, 0, width, height);
ctx.drawImage(webglImg.path, 0, 0, width, height);
ctx.draw(true);
self.canvasToImg(ctx, width, height);
.....
});
})
return;
},
// 处理IOS的新增部分
function clipWebgl(helperCanvas,photo){
return new Promise((resolve,reject) => {
const [data, w, h] = screenshot(renderer, scene, camera, THREE.WebGLRenderTarget);
const ctx = helperCanvas.getContext('2d')
const imgData = helperCanvas.createImageData(data, w, h);
helperCanvas.height = imgData.height;
helperCanvas.width = imgData.width;
// var data_len = w * h * 4;
// var srcPixels = imgData.data;
// for (var i = 0; i < data_len; i += 4) {
// if (srcPixels[i] > 0 || srcPixels[i + 1] > 0 || srcPixels[i + 2] > 0)
// srcPixels[i + 3] = 255;
// }
ctx.putImageData(imgData, 0, 0);
wx.canvasToTempFilePath({
canvas: helperCanvas,
success(res) {
resolve({path: res.tempFilePath, width: imgData.width, height: imgData.height})
},
fail(err){
reject(err);
}
})
})
}
function screenshot(renderer, scene, camera, WebGLRenderTarget) {
const { width, height } = renderer.domElement;
// const { x: width, y: height } = renderer.getDrawingBufferSize();
const renderTarget = new WebGLRenderTarget(width, height);
const buffer = new Uint8Array(width * height * 4);
renderTarget.texture.encoding = renderer.outputEncoding;
renderer.setRenderTarget(renderTarget);
renderer.render(scene, camera);
renderer.readRenderTargetPixels(renderTarget, 0, 0, width, height, buffer);
renderer.setRenderTarget(null);
renderTarget.dispose();
flip(buffer, width, height, 4);
return [buffer, width, height];
}
function flip(pixels, w, h, c) {
// handle Arrays
if (Array.isArray(pixels)) {
var result = flip(new Float64Array(pixels), w, h, c);
for (var i = 0; i < pixels.length; i++) {
pixels[i] = result[i];
}
return pixels;
}
if (!w || !h) throw Error('Bad dimensions');
if (!c) c = pixels.length / (w * h);
var h2 = h >> 1;
var row = w * c;
var Ctor = pixels.constructor;
// make a temp buffer to hold one row
var temp = new Ctor(w * c);
for (var y = 0; y < h2; ++y) {
var topOffset = y * row;
var bottomOffset = (h - y - 1) * row;
// make copy of a row on the top half
temp.set(pixels.subarray(topOffset, topOffset + row));
// copy a row from the bottom half to the top
pixels.copyWithin(topOffset, bottomOffset, bottomOffset + row);
// copy the copy of the top half row to the bottom half
pixels.set(temp, bottomOffset);
}
return pixels;
};
THREE.js场景导出成图片
function downloadImage(imgUrl){
var a = document.getElementById('img');
a.href = imgUrl;
a.click();
}
setTimeout(()=>{
var url = renderer.domElement.toDataURL('image/jpeg')
downloadImage(url)
},2000);
代码片段:
https://developers.weixin.qq.com/s/tkXh0Ams7FvD
这里有时候会出现一个问题:安卓端生成的图片是清晰的,IOS端生成的图片很模糊,像马赛克,在css里对helper-canvas设置width,height可以解决这个问题