7

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

 2 years ago
source link: https://www.iyouhun.com/post-218.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

微信小程序实现canvas按照原图等比例不失真绘制海报图,防止模糊

我这里的场景是收款二维码+收款背景图。

绘制二维码

我这里绘制二维码使用的 wxapp-qrcode ,也可以使用weapp-qrcode,基本都一样,详细代码不过多累赘,这里主要说下适配不同屏幕大小的canvas。

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方法动态的获取图片的高度和宽度,动态的设置图片的高度和宽度,是图片布局的高度和宽度和原始图片的高度和宽度相等。

图片等比例缩放工具

//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;

工具库使用

<image bindload="imageLoad"  src="../test.png"/>
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})
 } 
})

绘制背景图

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

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分别去绘制二维码和背景图。

// 收款码
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))
})

效果图


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK