【小程序】--------------处理canvas导出图片模糊问题-------------【劉】
一、业务需求:
使用canvas在前端生成海报,并在海报上添加上水印。最后导出图片并保存到本地。
二、业务逻辑实现:
(1)创建canvas画布======》(2)在canvas上绘制海报========》(3)绘制水印===========》(4)绘制完成,导出图片路径=========》(5)保存到本地,并可以分享,(长按保存图片)
三、代码实现:
(1)、创建画布并将图片和水印绘制到canvas上
const ctx = wx.createCanvasContext('myCanvas'); ctx.drawImage("https://img******.jpg", 0, 0, 300, 400);
ctx.draw();
网络图:
如果是用网络图,则在模拟器上正常显示。则在手机上无法显示创建。
因为canvas.drawImage 是不支持网络图片的,只支持本地图片。所以,任何网络图片都需要先缓存到本地,在通过 drawImage 调用储存的本地资源进行绘制,缓存通过 wx.getImageInfo实现。代码如下
let _that = this
wx.getImageInfo({
src: 'https://img******.jpg',
success: function (res) {
let width = res.width
let height = res.height
let type = res.type
let path = res.path
ctx.drawImage(path, 0, 0, 300, 400);
ctx.drawImage("../../images/tools/water.png", 20, 20, 30, 40);
ctx.draw()
}
})
通过success回调函数可以获取网络图片的宽高路径,和图片的格式png、jpg、svg。。。。。。
还有一点需要注意的是 draw 方法是异步的,如果图片还没加载成功,有可能画出来的是空的,所以 draw 方法后的回调导出图片
ctx.draw(true, (res) => {
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: 50,
height: 50,
destWidth: 100,
destHeight: 100,
canvasId: 'myCanvas',
success(res) {
console.log(res.tempFilePath)
}
})
});
保存图片到本地
通过wx.saveImageToPhotosAlbum将图片保存到本地
wx.saveImageToPhotosAlbum({ filePath: res.tempFilePath, success(res) { console.log("保存成功") _that.showSaveSuccess() }, fail() { wx.showModal({ title: '保存到相册失败', content: '请点击图片,长按图片保存', showCancel: false }) } })
图片模糊问题
然而,在导出图片时,那就是canvas生成的图片保存后很模糊。
(1)、使用两个canvas进行绘图,一个canvas用于绘图展示。用另一个canvas设置和图片大小一样。用于导出图片时的绘制。设置opacity为0.不能设置display:none。
问题:但实际上上这个方案有一点问题:其一,生成需要两个画布;其二,绘制过大画布在安卓上面会出现问题,官方文档里也提示了避免设置过大的宽高,在安卓下会有crash的问题。
(2)、使用scale缩放画布,设置canvas的画布于图片大小一样。则用scale缩放到需要展示的大小。则在导出时不会出现模糊问题。
问题:在模拟器上是没有问题的,但是在真机上调试是没有效果的。
(3)、本质上就是生成一个更大的图片,因为手机的屏幕设备的像素比现在一般都是超过2的。实际上我们只需要在使用wx.canvasToTempFilePath的时候,设置参数destWidth和destHeight(输出的宽度和高度)为width和height的2倍以上即可。
当然,这个具体数值也可以wx.getSystemInfo这个API来获取设备的像素比了(pixelRatio),这个像素比作为以上数值。
在onLode函数中通过wx.getSystemInfo获取像素比(pixelRatio)。则在导出图片时需要设置
destWidth:width * pixelRatio
destHeight:height * pixelRatio