解决uniapp微信小程序canvas不能引入字体的问题
在使用前要先把调试基础库调整为2.25.1,我调到这个版本就好其他的版本我也没试 下面是我画布导出的大概效果姓名这里使用了字体,白色的轮廓是字体轮廓填充
首先要了解一个api名称: 这里source里面只能是网络链接,因为我没有服务器,也不想装搭本地服务,所以我使用的是vscode中Live server然后访问字体链接先把效果搞出来,之后再是上服务器配置安全域名 scopes这个属性,native表示可以在canvas2d中使用这个字体 下面是部分必要代码片段 大致逻辑就是等字体加载成功之后获取画布对象然后把文字绘制到画布上面然后导出base64的图片 至于750和176是我代码的逻辑,按照自己的代码逻辑动态修改或者写死都可以
<template> <canvas type="2d" id="canvasName" :style="{width:750 + px,height:176 + px}" /> </template> <script> let canvas = null let ctx = null let dpr = null uni.loadFontFace({ global: true, family: "DINMedium", source: url("http://192.168.108.240:5500/files/iconfont2.ttf"), success: () => { this.draw() }, scopes: ["webview", "native"], }) methods:{ draw() { const self = this; let fm = DINMedium; const query = wx.createSelectorQuery() query.select(#canvasName) .fields({ node: true, size: true }) .exec((res) => { console.log(res) canvas = res[0].node ctx = canvas.getContext(2d) dpr = wx.getSystemInfoSync().pixelRatio canvas.width = res[0].width * dpr canvas.height = res[0].height * dpr ctx.scale(dpr, dpr) let x = 20 let y = 20 let fontSize = 20 this.drawText(ctx, "姓名", 88, "#01A5AE", 750 / 2, 88, 400, true, center, true,fm) ctx.lineWidth = 2 ctx.strokeStyle = #ffffff // ctx.font = "bold " + fontSize + px + fm; ctx.strokeText("姓名", 750 / 2, 88) ctx.restore() this.name = canvas.toDataURL() }) }, drawText(ctx, text, fontSize, color, x, y, maxWidth, bold, align, shadow,fontFamily) { if (bold) { ctx.font = `bold ${ fontSize}px ${ fontFamily ? fontFamily : normal}`; } else { ctx.font = `normal ${ fontSize}px ${ fontFamily ? fontFamily : normal}`; } if (align) { ctx.textAlign = align } else { ctx.textAlign = left } ctx.fillStyle = color if (ctx.measureText(text).width > maxWidth) { var count = 1; while (ctx.measureText(text.slice(0, text.length - count)).width > 693) { count++ } if (shadow) { ctx.shadowOffsetX = 3; //用来设定阴影在 X轴的延伸距 ctx.shadowOffsetX = 3; //用来设定阴影在 Y轴的延伸距 ctx.shadowBlur = 4; //设定阴影的模糊程度 默认0 ctx.shadowColor = "rgba(0, 0, 0, 0.5)"; } ctx.fillText(text.slice(0, text.length - (count + 1)) + "...", x, y) } else { ctx.fillText(text, x, y) } }, } </script>
APP和H5字体是正常的不管是用uni.loadFontFace还是用@font-face都可以直接用,就小程序事情多
base64ToTemp(base64){ return new Promise((r) => { let qrcode = base64.replace(/. +/g, ).replace(/[ ]/g, ) const fs = wx.getFileSystemManager(); //随机定义路径名称 var times = new Date().getTime(); var codeimg = wx.env.USER_DATA_PATH + / + times + .png; //将base64图片写入 var that = this; fs.writeFile({ filePath: codeimg, data: qrcode.split(data:image/png;base64,)[1], encoding: base64, complete(res) { console.log(res) }, success: () => { r(codeimg) } }) }) }, // 为了兼容小程序和APP所以这里分开处理了 使用逻辑(){ // #ifdef MP var temp = await this.base64ToTemp(this.name) console.log(temp) this.temp = temp this.ctx.drawImage(temp, 0, 554 * (this .canvasWidth / 750) - 230, this.canvasWidth, 176) // #endif // #ifndef MP this.drawText(this.ctx, "姓名", 88, "#01A5AE", this.canvasWidth / 2, 554 * (this .canvasWidth / 750) - 140, 400, true, center, true) this.ctx.lineWidth = 2 this.ctx.setStrokeStyle(#ffffff) this.ctx.strokeText("姓名", this.canvasWidth / 2, 554 * (this.canvasWidth / 750) - 140) this.ctx.restore() // #endif }
下面是我绘制九宫格已经底板的所有逻辑 设计到的一些封装方法可以参考我 部分方法有点改动不过大逻辑都一样
squaredDraw() { var colCount = 3; var gap = 5; var imageWidth = (750 - ((colCount - 1) * gap)) / colCount var TextB = 60 this.canvasWidth = 750 var bottomTitle = 72; var bottomQrCode = 200; var QrCodeWidth = 160; this.canvasHeight = TextB + bottomQrCode + bottomTitle + (imageWidth + 5) * Math.ceil(this.drawImageList .length / colCount) this.$nextTick(async () => { uni.showLoading({ title: "加载中...", mask: true }) this.ctx = uni.createCanvasContext(myCanvas) this.drawText(this.ctx, "篮球比赛篮球比赛篮球比赛", 32, "#222222", 375, 46, 200, true, center) for (let i = 0; i < this.drawImageList.length; i++) { uni.hideLoading() uni.showLoading({ title: `(${ i + 1}/${ this.drawImageList.length})`, mask: true }) await this.drawImageWidthFix1(this.ctx, this.drawImageList[i] + ?type=1&size=300, ( i % colCount == 0 ? 0 : (imageWidth + 5) * (i % colCount)), (bottomTitle + (imageWidth + gap) * parseInt(i / colCount)), imageWidth, imageWidth) } uni.hideLoading() uni.showLoading({ title: `生成中...`, mask: true }) this.ctx.drawImage(../../static/3.png, (750 - 120) / 2, bottomTitle + ( imageWidth + 5) * Math.ceil(this.drawImageList.length / colCount) + ( bottomQrCode - QrCodeWidth) / 2, QrCodeWidth, QrCodeWidth) this.drawText(this.ctx, "篮球比赛的文字描述篮球比赛的文字描述篮球比赛的文字描述", 32, "#222222", 375, bottomTitle + ( imageWidth + 5) * Math.ceil(this.drawImageList.length / colCount) + bottomQrCode + 20, 400, true, center) this.ctx.drawImage(../../static/top.png, 0, 0, this.canvasWidth, 554 * (this .canvasWidth / 750)) // #ifdef MP var temp = await this.base64ToTemp(this.name) console.log(temp) this.temp = temp this.ctx.drawImage(temp, 0, 554 * (this .canvasWidth / 750) - 230, this.canvasWidth, 176) // #endif // #ifndef MP this.drawText(this.ctx, "姓名", 88, "#01A5AE", this.canvasWidth / 2, 554 * (this .canvasWidth / 750) - 140, 400, true, center, true) this.ctx.lineWidth = 2 this.ctx.setStrokeStyle(#ffffff) this.ctx.strokeText("姓名", this.canvasWidth / 2, 554 * (this.canvasWidth / 750) - 140) this.ctx.restore() // #endif var bottomImageHeight = 404 * (this.canvasWidth / 750) var bottomImageTop = this.canvasHeight - bottomImageHeight this.ctx.drawImage(../../static/bottom.png, 0, bottomImageTop, this.canvasWidth, bottomImageHeight) this.drawText(this.ctx, "内蒙古包头赛区", 42, "#ffffff", 53, bottomImageTop + 274, 400, true, left, true) this.ctx.restore() this.drawText(this.ctx, "2020.04.05", 58, "#ffffff", 132, bottomImageTop + 346, 400, true, left, true) this.ctx.restore() this.ctx.draw() setTimeout(() => { uni.canvasToTempFilePath({ x: 0, y: 0, width: this.canvasWidth, height: this.canvasHeight, destWidth: this.canvasWidth * 2, destHeight: this.canvasHeight * 2, // quality: 0.5, canvasId: myCanvas, complete: () => { uni.hideLoading() }, success: (res) => { this.imageSrc = res .tempFilePath } }) }, 1200) }) },
上一篇:
微信支付全部详细流程