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

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 兩個函數 。但是在小程序是不支持直接調用的 。需要重寫這兩個方法
  2. 重寫的方法
(function(f) {'use strict';/* istanbul ignore else */if (typeof exports === 'object' && exports != null &&typeof exports.nodeType !== 'number') {module.exports = f ();} else if (typeof define === 'function' && define.amd != null) {define ([], f);} else {var base64 = f ();var global = typeof self !== 'undefined' ? self : $.global;if (typeof global.btoa !== 'function') global.btoa = base64.btoa;if (typeof global.atob !== 'function') global.atob = base64.atob;}} (function() {'use strict';var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';function InvalidCharacterError(message) {this.message = message;}InvalidCharacterError.prototype = new Error ();InvalidCharacterError.prototype.name = 'InvalidCharacterError';// encoder// [https://gist.github.com/999166] by [https://github.com/nignag]function btoa(input) {var str = String (input);for (// initialize result and countervar block, charCode, idx = 0, map = chars, output = '';// if the next str index does not exist://change the mapping table to "="http://check if d has no fractional digitsstr.charAt (idx | 0) || (map = '=', idx % 1);// "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8output += map.charAt (63 & block >> 8 - idx % 1 * 8)) {charCode = str.charCodeAt (idx += 3 / 4);if (charCode > 0xFF) {throw new InvalidCharacterError ("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");}block = block << 8 | charCode;}return output;}// decoder// [https://gist.github.com/1020396] by [https://github.com/atk]function atob(input) {var str = (String (input)).replace (/[=]+$/, ''); // #31: ExtendScript bad parse of /=// if (str.length % 4 === 1) {//throw new InvalidCharacterError ("'atob' failed: The string to be decoded is not correctly encoded.");// }for (// initialize result and countersvar bc = 0, bs, buffer, idx = 0, output = '';// get next characterbuffer = str.charAt (idx++); // eslint-disable-line no-cond-assign// character found in table? initialize bit storage and add its ascii value;~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,// and if not first of each 4 characters,// convert the first 8 bits to one ascii characterbc++ % 4) ? output += String.fromCharCode (255 & bs >> (-2 * bc & 6)) : 0) {// try to find character in table (0-63, not found => -1)buffer = chars.indexOf (buffer);}return output;}return {btoa: btoa, atob: atob};}));

推薦閱讀