博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
利用canvas生成海报
阅读量:6936 次
发布时间:2019-06-27

本文共 5999 字,大约阅读时间需要 19 分钟。

准备

准备两张图片连接,最好是自己开发账号验证的https图片链接。

实现思路

其实就是canvas实现方式,首先要就是定义一个canvas容器,把容器放在中间,图片也要动态计算大小居中,显示下面的文字和二维码也是要根据容器动态去改变。

实现代码

  • 下载头像,将图片缓存到本地
async onLoad() {  let url1 = 'https://static-client-image.jrucker.cn/image/1547303314501.jpeg';  let url2 = 'https://static-client-image.jrucker.cn/image/1550757251583.jpeg';  this.getAsyncPic(url1, url2);},async getAsyncPic(url1, url2) {  let res = await this.getUrlPromise(url1, url2);  if (res.length && res.length === 2) {    let [bannerObj, wxcodePicObj] = res;    this.setData({      'canvas.banner': bannerObj.banner,      'canvas.wxcodePic': wxcodePicObj.wxcodePic    });  }},async getUrlPromise(url1, url2) {  // 生成海报的封面图缓存到本地  const promise1 = new Promise((resolve, reject) => {    wx.getImageInfo({   //  小程序获取图片信息API      src: url1,      success: function (res) {        resolve({          banner: res.path        })      },      fail(err) {        reject(err)      }    })  });  // 生成海报的小程序图缓存到本地  const promise2 = new Promise((resolve, reject) => {    wx.getImageInfo({   //  小程序获取图片信息API      src: url2,      success: function (res) {        resolve({          wxcodePic: res.path        })      },      fail(err) {        reject(err)      }    })  });  let res = await Promise.all([promise1, promise2]);  const promise = new Promise((resolve) => {    resolve(res ? res : [])  });  return promise;},复制代码
  • 绘制海报
async setPoster() {  if (this.data.posterImage) {    return this.setData({      visible: true,      posterImage: this.data.posterImage    })  }  wx.showLoading({
title: '海报生成中...'}); if (!this.data.canvas.banner || !this.data.canvas.wxcodePic) { let url1 = 'https://static-client-image.jrucker.cn/image/1547303314501.jpeg'; let url2 = 'https://static-client-image.jrucker.cn/image/1550757251583.jpeg'; await this.getAsyncPic(url1, url2); } const ctx = wx.createCanvasContext('canvas-box'); ctx.setFillStyle('#ffffff'); ctx.fillRect(0, 0, 270, 330); // 绘制顶部banner ctx.drawImage(this.data.canvas.banner, 0, 0, 270, 170); this.dealWords({ ctx: ctx, // 画布上下文 fontSize: 16, // 字体大小 word: this.data.canvas.title, // 需要处理的文字 maxWidth: 255, // 一行文字最大宽度 fillStyle: '#333333', x: 8, // 文字在x轴要显示的位置 y: 177, // 文字在y轴要显示的位置 maxLine: 1 // 文字最多显示的行数 }); this.dealWords({ ctx: ctx, fontSize: 14, word: this.data.canvas.desc, maxWidth: 260, fillStyle: '#999999', x: 8, y: 201, maxLine: 2 }); ctx.moveTo(0, 252); ctx.lineTo(270, 252); ctx.setLineWidth(0.5); ctx.setStrokeStyle('#f2f2f2'); ctx.stroke(); // 绘制小程序码 ctx.drawImage(this.data.canvas.wxcodePic, 9, 261, 60, 60); ctx.setFontSize(13); ctx.setFillStyle('#999999'); ctx.fillText('长按扫码查看详情', 80, 296); ctx.draw(); setTimeout(() => { wx.canvasToTempFilePath({ quality: 1, canvasId: 'canvas-box', success: (res) => { let tempFilePath = res.tempFilePath; wx.hideLoading(); this.setData({ visible: true, posterImage: tempFilePath }) }, fail: (res) => { console.log(res); } }); }, 1000)}复制代码
  • 绘制多行文本
dealWords(options) {  options.ctx.setFontSize(options.fontSize);//设置字体大小  let allRow = Math.ceil(options.ctx.measureText(options.word).width / options.maxWidth);//实际总共能分多少行  let count = allRow >= options.maxLine ? options.maxLine : allRow;//实际能分多少行与设置的最大显示行数比,谁小就用谁做循环次数  let endPos = 0;//当前字符串的截断点  for (let j = 0; j < count; j++) {    let nowStr = options.word.slice(endPos);//当前剩余的字符串    let rowWid = 0;//每一行当前宽度    options.ctx.setFillStyle(options.fillStyle);    if (options.ctx.measureText(nowStr).width > options.maxWidth) {
//如果当前的字符串宽度大于最大宽度,然后开始截取 for (let m = 0; m < nowStr.length; m++) { rowWid += options.ctx.measureText(nowStr[m]).width;//当前字符串总宽度 if (rowWid > options.maxWidth) { if (j === options.maxLine - 1) { //如果是最后一行 options.ctx.fillText(nowStr.slice(0, m - 1) + '...', options.x, options.y + (j + 1) * 18); //(j+1)*18这是每一行的高度 } else { options.ctx.fillText(nowStr.slice(0, m), options.x, options.y + (j + 1) * 18); } endPos += m;//下次截断点 break; } } } else {
//如果当前的字符串宽度小于最大宽度就直接输出 options.ctx.fillText(nowStr.slice(0), options.x, options.y + (j + 1) * 18); } }}复制代码
  • 保存绘制图片至相册,需提前判断是否已授权,这一步就是最后把canvas生成图片了,大功告成。
savePoster() {  const canvasToTempFilePath = () => {    wx.showLoading({
title: '加载中'}); wx.canvasToTempFilePath({ quality: 1, canvasId: 'canvas-box', fileType: 'png', success: (res) => { wx.saveImageToPhotosAlbum({ filePath: res.tempFilePath, success: (res) => { wx.hideLoading(); wx.showToast({ title: '保存成功', }); this.setData({ visible: false }) }, fail() { wx.hideLoading() } }) } }) }; /*查看是否授权*/ wx.getSetting({ success: (res) => { if (!res.authSetting['scope.writePhotosAlbum']) { wx.authorize({ scope: 'scope.writePhotosAlbum', success() { //这里是用户同意授权后的回调 canvasToTempFilePath(); }, fail() { //这里是用户拒绝授权后的回调 wx.showModal({ title: '提示', content: '若不打开授权,则无法将图片保存在相册中!', showCancel: true, cancelText: '暂不授权', cancelColor: '#000000', confirmText: '去授权', confirmColor: '#3CC51F', success: function (res) { if (res.confirm) { wx.openSetting({ //调起客户端小程序设置界面,返回用户设置的操作结果。 }) } else { console.log('用户点击取消') } } }) } }) } else { canvasToTempFilePath() } } });}复制代码

注意

1、图片要提前下载

这里面还有一个问题就是,图片要提前下载完之后再绘图,不然图片显示不出来,可以把下载图片的方法单独拎出来,然后下载图片后回调绘图方法。

2、ctx.draw()

这个方法是在绘制完成之后在调用,不然容易其它被覆盖。

效果图

转载于:https://juejin.im/post/5c7556d06fb9a049b07e0360

你可能感兴趣的文章
android 自定义AlertDialog(一段)
查看>>
Git - 操作指南
查看>>
jstorm简介(转)
查看>>
Spark&Hadoop:scala编写spark任务jar包,运行无法识别main函数,怎么办?
查看>>
Kafka Java API操作topic
查看>>
Starting vsftpd for vsftpd: [FAILED]问题的解决
查看>>
tomcat 使用log4j进行日志切割
查看>>
Python之关于量化投资实现代码--根据策略提出的代码--还未完善
查看>>
动手解决困扰自己的事情——记屏蔽网页广告
查看>>
mvn -DskipTests和-Dmaven.test.skip=true区别
查看>>
代码保存、配色、公布-总体方案----一段代码的公布
查看>>
整理/总结/规划
查看>>
异步请求数据加载到表格后根据不同状态改变表格背景颜色【表格背景色】
查看>>
分享基于Qt5开发的一款故障波形模拟软件
查看>>
【intellij】intellij idea 建立与src级别的目录
查看>>
欢迎来到Hadoop
查看>>
洛谷P3038 [USACO11DEC]牧草种植Grass Planting
查看>>
微信小程序获取当前页面的路径的方式
查看>>
SQL获取当月天数的几种方法
查看>>
fileUpload(草稿)
查看>>