// 默认配置参数 const defaultOptions = () => ({ avatarUrl: '', userName: '采美', subTitle: '强烈为你推荐该商城', coverUrl: '', bgImageUrl: 'https://static.caimei365.com/app/img/icon/bgImage.png', // userBg: 'https://static.caimei365.com/app/img/icon/bg-card.png', userBg: 'https://static.caimei365.com/app/img/bg/home_cumres_bg@2x.png', userTitleBg: 'https://static.caimei365.com/app/img/icon/logo-fanbai@2x.png', // userTitleBg: 'https://static.caimei365.com/app/img/icon/logo-fanbai.png', ewmUrl: '', textArray: [], scale: 0.5, duty: { text: '客户经理', bgColor: '#FFF1EB', color: '#fff' } }) // 绘制海报 export default class DrawPoster { constructor(ctx, options = {}) { this.ctx = ctx this.options = Object.assign(defaultOptions(), options) } // 开始绘制 draw() { return new Promise(async (resolve, reject) => { try { await this.drawBgImage() await this.drawUserCoverImage() await this.drawCenterInfo() } catch (e) { console.log(e) reject(e) } finally { this.ctx.draw(true, res => { resolve(true) }) } }) } // 绘制背景 async drawBgImage() { try { const { bgImageUrl, scale } = this.options const [error, result] = await uni.downloadFile({ url: bgImageUrl }) if (error) return this.ctx.drawImage(result.tempFilePath, 0, 0, 750 * scale, 1240 * scale) this.ctx.save() return Promise.resolve(true) } catch (e) { return Promise.reject(e) } } // 绘制圆角矩形 drawRoundRect(x, y, w, h, r, color) { this.ctx.save() this.ctx.beginPath() this.ctx.moveTo(x + r , y) this.ctx.arcTo(x + w, y, x + w, y + h, r) this.ctx.arcTo(x + w, y + h, x , y + h, r) this.ctx.arcTo(x, y + h, x, y, r) this.ctx.arcTo(x, y, x + w, y , r) this.ctx.setFillStyle(color) this.ctx.fill() // this.ctx.clip() } // 绘制中心区域 async drawCenterInfo() { try { const { scale, coverUrl, ewmUrl } = this.options this.ctx.beginPath() await this.drawRoundRect(28 * scale, 28 * scale, 694 * scale, 878 * scale, 8, '#FFFFFF') await this.drawFooterText() this.ctx.drawImage(coverUrl, 56 * scale, 56 * scale, 638 * scale, 658 * scale) this.ctx.drawImage(ewmUrl, 524 * scale, 730 * scale, 160 * scale, 160 * scale) return Promise.resolve(true) } catch (e) { return Promise.reject(e) } } // 绘制封面图片 async drawCoverImage() { try { this.ctx.beginPath() const { coverUrl, scale } = this.options this.ctx.drawImage(coverUrl, 56 * scale, 56 * scale, 638 * scale, 658 * scale) this.ctx.save() return Promise.resolve(true) } catch (e) { console.log(e) } } // 绘制名片封面 async drawUserCoverImage() { try { const { userBg, scale, image, qrCode, linkMan, contractMobile, duty } = this.options await this.drawBorderReduisImage(userBg, 28 * scale, 920 * scale, 694 * scale, 290 * scale, 8) await this.drawUserCardInner() // 绘制名片内容 await this.drawCircleImg(image, 120 * scale, 1090 * scale, 30) //头像 this.drawFontText(36 * scale, 200 * scale, 1070 * scale, '#333333', linkMan, 'bold', true) this.drawFontText(30 * scale, 200 * scale, 1130 * scale, '#333333', contractMobile, '400') await this.drawBorderReduisImage(qrCode, 556 * scale, 1010 * scale, 120 * scale, 120 * scale, 6) this.drawFontText(18 * scale, 550 * scale, 1160 * scale, '#333333', ['长按或扫二维码', '——联系我——'], '400') return Promise.resolve(true) } catch (e) { return Promise.reject(e) } } async drawUserCardInner() { try { const { userTitleBg, scale } = this.options const [error, result] = await uni.downloadFile({ url: userTitleBg }) if (error) return this.ctx.drawImage(result.tempFilePath, 56 * scale, 940 * scale, 200 * scale, 70 * scale) return Promise.resolve(true) } catch (e) { return Promise.reject(e) } } async drawCircleImg(img, x, y, r) { const [error, result] = await uni.downloadFile({ url: img }) if (error) return this.ctx.save() this.ctx.beginPath() let size = 2 * r this.ctx.arc(x, y, r, 0, 2 * Math.PI) this.ctx.clip() this.ctx.drawImage(result.tempFilePath, x - r, y - r, size, size) this.ctx.restore() } async drawBorderReduisImage(imgUrl, bg_x, bg_y, bg_w, bg_h, bg_r) { const [error, result] = await uni.downloadFile({ url: imgUrl }) if (error) return this.ctx.save() this.ctx.beginPath() this.ctx.arc(bg_x + bg_r, bg_y + bg_r, bg_r, Math.PI, Math.PI*1.5) this.ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_r, bg_r, Math.PI * 1.5, Math.PI * 2) this.ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_h - bg_r, bg_r, 0, Math.PI * 0.5) this.ctx.arc(bg_x + bg_r, bg_y + bg_h - bg_r, bg_r, Math.PI * 0.5, Math.PI) this.ctx.clip() this.ctx.drawImage(result.tempFilePath, bg_x, bg_y, bg_w, bg_h) this.ctx.restore() } // 绘制文字 async drawFontText(fontsize, x, y, color, text, bold, isDuty = false) { this.ctx.save() if (Array.isArray(text)) { this.ctx.beginPath() this.ctx.font = `${bold} ${fontsize}px sans-serif` this.ctx.setFillStyle(color) text.forEach((e, i) => { this.ctx.fillText(e, x, y + fontsize * i) }) } else { this.ctx.beginPath() this.ctx.font = `${bold} ${fontsize}px sans-serif` this.ctx.setFillStyle(color) this.ctx.fillText(text, x, y) if (isDuty) { await this.drawRoundRect(x + (text.length * fontsize) + 8 , y-fontsize, 66, fontsize + 4, 4, '#FFF1EB') // this.ctx.fillStyle = `${this.options.duty.bgColor}` // this.ctx.fillRect(x + (text.length * fontsize) + 10, y-fontsize, 66, fontsize + 4) this.ctx.font = `${400} ${fontsize-6}px sans-serif` this.ctx.setFillStyle('#666666') this.ctx.fillText(this.options.duty.text, x + (text.length * fontsize) + 16, y - 2) } } } // 绘制底部 drawFooterText(callback) { const { scale, textArray } = this.options this.ctx.beginPath() if (callback) { callback({ scale, ctx: this.ctx, textArray }) } else { textArray.forEach((txt, index) => { this.ctx.setFontSize(30 * scale) this.ctx.setFillStyle('#333') this.ctx.fillText(txt, 56 * scale, (710 + 56 * index) * scale) }) } this.ctx.save() } // 绘制底部二维码 async drawEwmImage() { try { const { ewmUrl, scale } = this.options // const [error, result] = await uni.downloadFile({ url: ewmUrl }) console.log(ewmUrl, this.options) // if (error) return this.ctx.drawImage(ewmUrl, 524 * scale, 730 * scale, 160 * scale, 160 * scale) return Promise.resolve(true) } catch (e) { return Promise.reject(e) } } }