微信小程序canvas 证件照制作( 二 )

initImgData(bodyAns,bodySeg) {if (bodyAns.person_num > 1) {uni.showToast({title: '图片检测到多个人像,请重新上传',icon:'none',duration: 2000});return}if (bodyAns.person_num == 0) {uni.showToast({title: '图片未检测到人像,请重新上传',icon:'none',duration: 2000});return}let widthInfo = bodyAns.person_info[0]let location = this.imgwidthsum(widthInfo)this.location = locationlet foreground = bodySeg.foregroundthis.foreground = foregroundthis.previewImg('data:image/png;base64,' + foreground, location).then(filePath => {this.canvasImages = filePaththis.buildOver = true})},imgwidthsum(data) {let body_parts = data.body_partsreturn {top_head: body_parts.top_head,left_shoulder: body_parts.left_shoulder,right_shoulder: body_parts.right_shoulder}},

  1. 使用uni.getImageInfo 读取图片,需要先将上一步中base64d 图片转为本地图片
const fsm = wx.getFileSystemManager();const FILE_BASE_NAME = 'tmp_base64src';const base64src = function(base64data, pathName) {return new Promise((resolve, reject) => {const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64data) || [];if (!format) {reject(new Error('ERROR_BASE64SRC_PARSE'));}const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME+pathName}.${format}`;const buffer = wx.base64ToArrayBuffer(bodyData);fsm.writeFile({filePath,data: buffer,encoding: 'binary',success() {resolve(filePath);},fail() {reject(new Error('ERROR_BASE64SRC_WRITE'));},});});};export default base64src;
  1. 将图片按照要一定的比列绘制在canvas 中
let IMG_RATIOlet ratio = 295/413let initWidth = 295let initHeight = 413let scrollTop = 250let IMG_REAL_W,IMG_REAL_HIMG_REAL_H = initHeightIMG_REAL_W = IMG_REAL_H*IMG_RATIOlet canH = imgW * IMG_REAL_H / IMG_REAL_Wconst ctx = uni.createCanvasContext("myselfCanvas", _this);if (color) {ctx.setFillStyle(color)ctx.fillRect(0,0,IMG_REAL_W,IMG_REAL_H)}// 绘制的时候将选中的背景颜色填充到画布中ctx.drawImage(res.path, 0, 0, IMG_REAL_W, IMG_REAL_H);
  1. 根据原图中头像位置坐标 。换算出需要在原图上裁剪出来的区域
let x = location.right_shoulder.x //右肩位置的坐标 xlet y = location.top_head.y - scrollTop // 头部坐标位置 减去一定比列的坐标 ylet x1 = location.left_shoulder.x // 左肩位置坐标 xvar canvasW = ((x1 - x) / imgW) * IMG_REAL_W;// 左肩坐标 减去右肩坐标 和原图的宽度比列 计算出 在上一步绘制的图中裁剪的宽度var canvasH = canvasW/ratio // 根据证件照的比列 计算出 裁剪的高度var canvasL = (x / imgW) * IMG_REAL_W;var canvasT = (y / imgH) * IMG_REAL_H;// 计算裁剪的起始坐标位置
  1. 在canvas 绘制图后导出证件照需要的尺寸
ctx.draw(false,(ret)=>{uni.showToast({icon:'success',mask:true,title: '绘制完成',});uni.canvasToTempFilePath({ // 保存canvas为图片x: canvasL,y: canvasT,width: canvasW, //canvasH,height: canvasH, //canvasH,destWidth: initWidth,destHeight: initHeight,canvasId: 'myselfCanvas',quality: 1,fileType: color? 'jpg': 'png',complete: function(res) {resolve(res.tempFilePath)} ,})});导出证件照之前,还需要修改图片的dpi
  1. 修改图片dpi 是将图片转为base64 格式后修改 。本项目使用changedpi 插件
  2. npm install changedpi
import {changeDpiDataUrl} from 'changedpi'export const changeDpi = (url, dpi) => {return new Promise((resolve) => {if (dpi) {uni.getFileSystemManager().readFile({filePath: url, //选择图片返回的相对路径encoding: 'base64', //编码格式success: res => {// 成功的回调// 'data:image/jpeg;base64,'let base64 = res.data;let str = changeDpiDataUrl('data:image/jpeg;base64,' + base64, dpi)base64src(str).then(filePath => {resolve(filePath)})}});}else {resolve(url)}})}
  1. 在小程序中使用需要注意 插件中直接使用了btoa atob 两个函数 。但是在小程序是不支持直接调用的 。需要重写这两个方法

    经验总结扩展阅读