// import mergeImages from "./mergeImages"; export default { data(){ return { system_info:{}, //system info canvas_width:0, //canvas width px canvas_height:0, //canvas height px ctx:null, //canvas object canvas_id:null, //canvas id hidden:false, //Whether to hide canvas scale:1, //canvas scale r_canvas_scale:1, if_ctx:true } }, methods:{ /** * Compatibility px * @param {Object} size */ compatibilitySize(size) { let canvasSize = (parseFloat(size) / 750) * this.system_info.windowWidth canvasSize = parseFloat(canvasSize * 2) return canvasSize }, /** * Restore compatibility px * @param {Object} size */ resetCompatibilitySize(size) { return (parseFloat(size / 2) / this.system_info.windowWidth) * 750 }, async init(config){ if(config.path){ // 存一下实际图片大小 用于缩放比 this.imagesConfig = await this.scaleImageInfo(config.path); } return new Promise(async (resolve,reject)=>{ if(!config.canvas_id){ reject("Canvas ID cannot be empty, please refer to the usage example") return; } this.hidden = config.hidden this.canvas_id = config.canvas_id let system_info = await uni.getSystemInfoSync() this.system_info = system_info this.scale = config.scale && parseFloat(config.scale)>0?parseInt(config.scale):1 this.canvas_width = (config.canvas_width ? this.compatibilitySize(config.canvas_width) : system_info.windowWidth) * this.scale this.canvas_height = (config.canvas_height ? this.compatibilitySize(config.canvas_height) : system_info.windowHeight) * this.scale, this.r_canvas_scale = 1/this.scale this.ctx = uni.createCanvasContext(this.canvas_id,this) resolve() }) }, draw(callback){ return new Promise((resolve,reject)=>{ let stop = setTimeout(()=>{ this.ctx.draw(false,setTimeout(()=>{ uni.canvasToTempFilePath({ canvasId: this.canvas_id, quality: 1, success: (res)=>{ // console.log("--draw--"+ this.canvas_id) resolve(res) callback && callback(res) }, fail:(err)=>{ reject(JSON.stringify(err)|| "Failed to generate poster:101") } },this) },300)) clearTimeout(stop) },300) }) }, clearCanvas(callback){ return new Promise(async (resolve,reject)=>{ if(!this.ctx){ reject("canvas is not initialized:101") return }else{ this.ctx.clearRect(0,0, parseFloat(this.canvas_width)*this.scale, parseFloat(this.canvas_height)*this.scale ) this.ctx.draw(false,callback) resolve() } }) }, readFile(url){ return new Promise((resolve, reject) => { plus.io.resolveLocalFileSystemURL(url,(obj)=>{ obj.file((file)=>{ let fileReader = new plus.io.FileReader() fileReader.onload = (res)=>{ resolve(res.target.result) } fileReader.onerror = (err)=>{ reject(err) } fileReader.readAsDataURL(file) }, (err)=>{ reject(err) }) },(err)=>{ reject(err) }) }) }, // 下载图片资源 downLoadNetworkFile(url){ // #ifdef APP-PLUS if(url.indexOf('http') > -1){ return new Promise((resolve,reject)=>{ uni.downloadFile({ url, success:(res)=>{ // console.log(res.tempFilePath) if(res.statusCode == 200){ resolve(res.tempFilePath) }else{ reject("Download Image Fail:102") } }, fail:(err)=>{ reject("Download Image Fail:101") } }) }) }else{ return this.readFile(url); } // #endif // #ifdef H5 return new Promise((resolve,reject)=>{ uni.downloadFile({ url, success:(res)=>{ // console.log(res.tempFilePath) if(res.statusCode == 200){ resolve(res.tempFilePath) }else{ reject("Download Image Fail:102") } }, fail:(err)=>{ reject("Download Image Fail:101") } }) }) // #endif }, urlToBase64(config){ return new Promise(async (resolve,reject)=>{ if (typeof window != 'undefined') { await this.downLoadNetworkFile(config.url).then(res=>{ // two function resolve(res) }).catch(err=>{ reject(err) }) }else if (typeof plus != 'undefined') { plus.io.resolveLocalFileSystemURL(config.url,(obj)=>{ obj.file((file)=>{ let fileReader = new plus.io.FileReader() fileReader.onload = (res)=>{ resolve(res.target.result) } fileReader.onerror = (err)=>{ reject(err) } fileReader.readAsDataURL(file) }, (err)=>{ reject(err) }) },(err)=>{ reject(err) }) }else if(typeof wx != 'undefined'){ wx.getFileSystemManager().readFile({ filePath: config.url, encoding: 'base64', success: function(res) { resolve('data:image/png;base64,' + res.data) }, fail: function(error) { reject(error) } }) } }) }, mergeImageByColor(image,color,borderWidth = 0){ let ctx = this.ctx; const dArr = [-1, -1, 0, -1, 1, -1, -1, 0, 1, 0, -1, 1, 0, 1, 1, 1]; // offset array // 平移图像 for (let i = 0; i < dArr.length; i += 2) ctx.drawImage(image, dArr[i] * borderWidth, dArr[i + 1] * borderWidth); // 填充描边色 ctx.globalCompositeOperation = "source-in"; ctx.fillStyle = color; ctx.globalAlpha = 1; ctx.fillRect(0, 0, this.canvas_width,this.canvas_height); // 添加原图 ctx.globalCompositeOperation = "source-atop"; ctx.drawImage(image, 0, 0); ctx.draw(); }, async mergeImageByImg(item,target){ let ctx = this.ctx; ctx.globalCompositeOperation = "source-over"; let fileList = [ await this.downLoadNetworkFile(item), await this.downLoadNetworkFile(target), ] let options = this.getScaleOptions(); return new Promise((resolve, reject) => { resolve( Promise.all(fileList) .then((images) =>{ const borderWidth = 0; const dArr = [-1, -1, 0, -1, 1, -1, -1, 0, 1, 0, -1, 1, 0, 1, 1, 1]; // offset array // 平移图像 for (let i = 0; i < dArr.length; i += 4) ctx.drawImage(images[0], dArr[i] * borderWidth, dArr[i + 1] * borderWidth,this.canvas_width, this.canvas_height); // 填充描边色 ctx.globalCompositeOperation = "source-in"; ctx.fillRect(0, 0, this.canvas_width, this.canvas_height); // // 添加原图 ctx.globalCompositeOperation = "source-atop"; ctx.drawImage(images[1], 0, 0,options.width, options.height); ctx.draw(); }) ) }) }, mergeImages(sources = []){ let options = this.getScaleOptions(); return new Promise((resolve,reject) =>{ // Load sources let fileList = sources.map((source) => { return this.downLoadNetworkFile(source); }); resolve( Promise.all(fileList) .then((images) =>{ // Draw images to canvas images.forEach((image) => { this.ctx.globalAlpha = image.opacity ? image.opacity : 1; return this.ctx.drawImage(image, 0, 0 ,options.width,options.height); // return this.ctx.drawImage(image, 0, 0 , this.canvas_width,this.canvas_height); }); this.ctx.draw(); }) ) }) }, scaleImageInfo(src){ return new Promise((resolve,reject) =>{ uni.getImageInfo({ src: src, success(res){ resolve(res); }, fail:(error) =>{ reject(JSON.stringify(error)) } }) }) }, getScaleOptions(){ let { width,height } = this.imagesConfig; if(width > height){ return { width: 375, height: Number(parseFloat(this.canvas_height * (this.canvas_width / width)).toFixed(2)) } }else{ return { width: Number(parseFloat(this.canvas_width * (this.canvas_height / height)).toFixed(2)), height: 375, } } }, drawImage(config){ return new Promise(async (resolve,reject)=>{ if(config.url){ let type = 0 // 1、network image 2、native image 3、base64 image let image_url let reg = /^https?/ig; if(reg.test(config.url)){ type = 1 }else{ if((config.url.indexOf("data:image/png;base64") != -1) || config.url.indexOf("data:image/jpeg;base64") != -1){ type = 3 }else{ type = 2 } } if(type == 1){ // network image await this.downLoadNetworkFile(config.url).then(res=>{ // two function image_url = res }).catch(err=>{ reject(err) return; }) }else if(type == 2){ // native image const imageInfoResult = await uni.getImageInfo({ src: config.url }); try{ if(imageInfoResult.length <= 1){ reject(imageInfoResult[0].errMsg + ':404') return } }catch(e){ reject(e+':500') return } let base64 = await this.urlToBase64({url:imageInfoResult[1].path}) // #ifdef MP-WEIXIN await this.base64ToNative({url:base64}).then(res=>{ image_url = res }).catch(err=>{ reject(JSON.stringify(err)+":501") return; }) // #endif // #ifndef MP-WEIXIN image_url = base64 // #endif }else if(type == 3){ // #ifdef MP-WEIXIN await this.base64ToNative({url:config.url}).then(res=>{ image_url = res }).catch(err=>{ reject(JSON.stringify(err)+":500") return; }) // #endif // #ifndef MP-WEIXIN image_url = config.url // #endif }else{ reject("Other Type Errors:101") return } if(config.border_width){ let border_radius = 0 if(config.border_radius){ let multiple = config.w / config.border_radius border_radius = (parseFloat(config.w) + parseFloat(config.border_width)) / multiple } // drawRect await this.drawRect({ x:parseFloat(config.x) - parseFloat(config.border_width)/2, y:parseFloat(config.y) - parseFloat(config.border_width)/2, w:parseFloat(config.w) + parseFloat(config.border_width), h:parseFloat(config.h) + parseFloat(config.border_width), color:config.border_color, border_radius:border_radius, border_width:config.border_width, is_radius:config.is_radius }) } if(config.border_radius){ this.setNativeBorderRadius(config) }else if(config.is_radius){ //已废弃 is_radius this.ctx.setStrokeStyle("rgba(0,0,0,0)") this.ctx.save() this.ctx.beginPath() this.ctx.arc(this.compatibilitySize(parseFloat(config.x)*this.scale+parseFloat(config.w)*this.scale/2), this.compatibilitySize(parseFloat(config.y)*this.scale+parseFloat(config.h)*this.scale/2), this.compatibilitySize(parseFloat(config.w)*this.scale/2), 0, 2 * Math.PI, false) this.ctx.stroke(); this.ctx.clip() } await this.ctx.drawImage(image_url,this.compatibilitySize(parseFloat(config.x)*this.scale),this.compatibilitySize(parseFloat(config.y)*this.scale),this.compatibilitySize(parseFloat(config.w)*this.scale),this.compatibilitySize(parseFloat(config.h)*this.scale)) this.ctx.restore() //Restore previously saved drawing context resolve() }else{ let err_msg = "Links cannot be empty:101" reject(err_msg) } }) }, exportImg(){ return new Promise((resolve,reject) => { setTimeout(() =>{ uni.canvasToTempFilePath({ canvasId: this.canvas_id, quality: 1, success: (res)=>{ // console.log('res',res.tempFilePath) resolve(res.tempFilePath) }, fail:(err)=>{ reject(JSON.stringify(err)|| "Failed to generate poster:101") } },this) },1200) }) } } }