小程序canvas生成海报图片压缩和失真问题解决

2022-04-14 14:07:44 浏览数 (1)

微信小程序实现canvas按照原图等比例不失真绘制海报图,防止模糊 我这里的场景是收款二维码 收款背景图。

绘制二维码

我这里绘制二维码使用的 wxapp-qrcode ,也可以使用weapp-qrcode,基本是一样的,今天主要讲解适配不同屏幕尺寸的canvas。

代码语言:javascript复制
onLoad: function (options) {
  const size = this.setCanvasSize() // 动态设置画布尺寸
  this.createQrCode('www.iyouhun.com', "mycanvas", size.w, size.h)
},
// 适配不同屏幕尺寸的canvas
setCanvasSize: function () {
  const size = {}
  try {
    const res = wx.getSystemInfoSync()
    let scale = 750 / 686; // 不同屏幕下canvas的适配比例;设计稿是750宽,686是因为wxss样式文件中设置的canvas尺寸
    let width = res.windowWidth / scale
    let height = width; // canvas画布为正方形
    size.w = width
    size.h = height
  } catch (e) {
    console.log("获取设备信息失败"   e)
  }
  return size
},
复制代码

绘制背景图

动态设置图片的高度和宽度

在小程序布局中,如果图片不是固定高度和高度,但image设置的是固定的高度和宽度,这时候原始图片相对image设置的固定高度和宽度不是等比例大小,那么这张图片就会变形,变的不清晰。这时就可以使用下面的等比例缩放的方式缩放图片,让图片不变形。或者通过imagebindload方法动态的获取图片的高度和宽度,动态的设置图片的高度和宽度,是图片布局的高度和宽度和原始图片的高度和宽度相等。

图片等比例缩放工具

代码语言:javascript复制
//Util.js 
 
class Util{ 
  /*** 
   * 按照显示图片的宽等比例缩放得到显示图片的高 
   * @params originalWidth 原始图片的宽 
   * @params originalHeight 原始图片的高 
   * @params imageWidth   显示图片的宽,如果不传就使用屏幕的宽 
   * 返回图片的宽高对象 
  ***/ 
  static imageZoomHeightUtil(originalWidth,originalHeight,imageWidth){ 
    let imageSize = {}; 
    if(imageWidth){ 
      imageSize.imageWidth = imageWidth; 
      imageSize.imageHeight = (imageWidth * originalHeight) / originalWidth; 
    }else{//如果没有传imageWidth,使用屏幕的宽 
      wx.getSystemInfo({  
        success: function (res) {  
          imageWidth = res.windowWidth;  
          imageSize.imageWidth = imageWidth; 
          imageSize.imageHeight = (imageWidth * originalHeight) / originalWidth; 
        }  
      }); 
    } 
    return imageSize; 
  } 
 
  /*** 
   * 按照显示图片的高等比例缩放得到显示图片的宽 
   * @params originalWidth 原始图片的宽 
   * @params originalHeight 原始图片的高 
   * @params imageHeight  显示图片的高,如果不传就使用屏幕的高 
   * 返回图片的宽高对象 
  ***/ 
  static imageZoomWidthUtil(originalWidth,originalHeight,imageHeight){ 
    let imageSize = {}; 
    if(imageHeight){ 
      imageSize.imageWidth = (imageHeight *originalWidth) / originalHeight; 
      imageSize.imageHeight = imageHeight; 
    }else{//如果没有传imageHeight,使用屏幕的高 
      wx.getSystemInfo({  
        success: function (res) {  
          imageHeight = res.windowHeight; 
          imageSize.imageWidth = (imageHeight *originalWidth) / originalHeight; 
          imageSize.imageHeight = imageHeight; 
        }  
      }); 
    } 
    return imageSize; 
  } 
 
} 
 
export default Util;
复制代码

工具库使用

代码语言:javascript复制
<image bindload="imageLoad"  src="../test.png"/>
复制代码
代码语言:javascript复制
import Util from '../common/Util'
 
Page({ 
 data:{ 
    imageWidth:0, 
    imageHeight:0 
 }, 
 imageLoad: function (e) {  
    //获取图片的原始宽度和高度 
    let originalWidth = e.detail.width
    let originalHeight = e.detail.height
    let imageSize = Util.imageZoomWidthUtil(originalWidth,originalHeight,145)
    this.setData({imageWidth:imageSize.imageWidth,imageHeight:imageSize.imageHeight})
 } 
})
复制代码

绘制背景图

用上面的方法动态设置图片宽高,解决失真问题

代码语言:javascript复制
import Util from '../../libs/Util'
// 背景图
let bgImg = new Promise(function (resolve) {
  wx.getImageInfo({
    src: 'https://www.iyouhun.com/payment/payment_pic.jpg',
    success: function (res) {
      that.setData({
        imgInfo: res
      })
      // 根据屏幕宽度得到图片高
      const imageSize = Util.imageZoomHeightUtil(that.data.imgInfo.width, that.data.imgInfo.height) 
      that.setData({ canvasHeight: imageSize.imageHeight })
      resolve(res.path)
    },
    fail: function (err) {
      console.log(err)
      wx.showToast({
        title: '网络错误请重试',
        icon: 'loading'
      })
    }
  })
})
复制代码

合成海报/收款码

这里使用Promise分别去绘制二维码和背景图。

代码语言:javascript复制
// 收款码
let qrcodeImg = new Promise(function (resolve) {
  // ...
})
// 背景图
let bgImg = new Promise(function (resolve) {
  // ...
}
Promise.all([bgImg, qrcodeImg]).then(function(result) {
  wx.showLoading({title: '加载中'})
  // canvas绘制文字和图片,创建画图
  const ctx = wx.createCanvasContext('myCanvas')
  // 绘制背景图
  ctx.drawImage(result[0], 0, 0, that.data.imgInfo.width, that.data.imgInfo.height, 0, 0, that.data.canvasWidth, that.data.canvasHeight)
  ctx.setFillStyle('white')
  // 绘制二维码 二维码宽度300
  const qrX = (that.data.canvasWidth - 300) / 2 // canvas宽度 - 二维码宽度 / 2 (居中)
  ctx.drawImage(result[1], qrX, 120, 300, 300)
  // 绘制文本
  ctx.fillStyle = '#ffffff' // 背景
  ctx.fillRect(Math.floor(qrX),420,300,20)
  ctx.fillStyle = "#333333"
  ctx.font = 25   'px Arial' // 文本大小, 字体
  ctx.textAlign = 'center'
  ctx.fillText(
    'No.'  that.data.serialNum,
    that.data.canvasWidth / 2, // 左上角 X坐标
    430, // 左上角 Y坐标
    300
  )
  //canvasToTempFilePath必须要在draw的回调中执行,否则会生成失败,官方文档有说明
  ctx.draw(false, setTimeout(function () {
    wx.canvasToTempFilePath({
      canvasId: 'myCanvas',
      x: 0,
      y: 0,
      width: that.data.canvasWidth,
      height: that.data.canvasHeight,
      success: function (res) {
        wx.hideLoading()
        that.setData({
          qrcodeStatus: true,
          shareImgSrc: res.tempFilePath
        })
      },
      fail: function (res) {
        wx.hideLoading()
        wx.showToast({
          title: '生成失败',
          icon: "none"
        })
      }
    })
  }, 1000))
})

0 人点赞