利用 canvas 实现背景图片和其他图片以及文字的组合生成新图片

124 阅读2分钟
<image class="poster" :src="poster" mode="widthFix"></image>
<div class="qrcode" ref="qrCodeUrl" v-if="!poster"></div>
<view class="btns flex-align">
    <view class="btn" @click="savePoster">
        <image src="xxx.png" mode="widthFix"></image>
        <view class="title">
            保存图片
        </view>
    </view>
    <view class="btn" @click="copy">
        <image src="xxx.png" mode="widthFix"></image>
        <view class="title">
            复制链接
        </view>
    </view>
</view>

import QRCode from 'qrcodejs2'
import html2canvas from 'html2canvas'
import urlConstants from 'constants/urlConstants.js'
import { saveAs } from 'file-saver'; 

 data() {
     return {
         poster: '',
         headImg: 'xxx.png',
         shareUrl: 'xxxx',
         qrcode: '',
     }
 }
 
this.creatQrCode(this.shareUrl)

 // 生成二维码
 creatQrCode(url) {
     if (this.qrcode) return
     var qrcode = new QRCode(this.$refs.qrCodeUrl, {
         text: url,
         width: 65,
         height: 65,
         colorDark: '#000000',
         colorLight: '#ffffff',
         correctLevel: QRCode.CorrectLevel.H
     })
     this.toImage()
 },
 // 二维码转图片
 toImage() {
     html2canvas(this.$refs.qrCodeUrl).then(canvas => {
         this.qrcode = canvas.toDataURL('image/png')
         this.canvasDraw()
     })
 },
 // 结合背景图片+文字+二维码
 canvasDraw(info) {
     const that = this
     // 动态创建canvas标签
     var canvas = document.createElement("canvas");
     // 设置canvas画布宽度和高度
     canvas.width = 565;
     canvas.height = 800;
     // 创建context对象
     var context = canvas.getContext("2d");
     // 用context.rect方法绘制矩形
     context.rect(0, 0, canvas.width, canvas.height);
     // 设置字体颜色
     // 渲染
     context.fill();
     // 背景图
     var myImage = new Image();
     myImage.src =
         'xxx.png'; //背景图片,本地或在线皆可
     // 跨域,必须
     myImage.crossOrigin = 'Anonymous';
     // 使用img的onload事件
     myImage.onload = function() {
         // 背景
         context.drawImage(myImage, 0, 0, 565, 800);
         // 图片跨域,必须
         context.fillStyle = "#333";
         context.font = "22px Microsoft Yahei";
         context.fillText("邀请人", 140, 115);

         context.fillStyle = "#333";
         context.font = "bold 26px Microsoft Yahei";
         context.fillText('xxx', 140, 155);

         context.fillStyle = "#333";
         context.font = "22px Microsoft Yahei";
         // 分享文案
         const sharetext='我是文案我是文案我是文案我是文案我是文案我是文案我是文案我是文案我是文案我是文案我是文案我是文案我是文案我是文案我是文案我是文案我是'
         let result = that.text(sharetext)
         for (let i = 0; i <= result.rows; i++) {
             context.fillText(sharetext.slice(result.rowFontNum * (i - 1), result.rowFontNum * i), 40,
                 470 + i * 32)
         }

        // 矩形+边框
        context.fillStyle = 'white'
        that.drawRect(context, 160, 260, 240, 220, 30)
        context.fillRect(160, 260, 240, 220)
        context.lineWidth = 5;
        context.strokeStyle = '#0a0c14'
        context.stroke()
        context.restore()
        
         // 二维码
         var myImage2 = new Image();
         myImage2.src = that.qrcode;
         // 图片跨域,必须
         myImage2.crossOrigin = 'Anonymous';
         myImage2.onload = function() {
             context.drawImage(myImage2, 415, 640, 120, 120);

             // 头像
             var myImage1 = new Image();
             myImage1.src = that.headImg;
             myImage1.crossOrigin = 'Anonymous';
             myImage1.onload = function() {
                 that.drawRound(context, 40, 45, 90, myImage1)

                 // canvas生成img图片
                 // 如果是生成png格式,那么就"image/png" 
                 // 如果是要生成jpg格式,那么就改为"image/jpeg"
                 var base64 = canvas.toDataURL("image/png");
                 that.poster = base64

                 // base64转为png
                 uni.uploadFile({
                     url:'xxx',
                     filePath: base64,
                     success: res => {
                         let data = JSON.parse(res.data);
                         that.poster = data.data.fuul_path
                     }
                 });
             }
         }
     }
 },
 // 文字换行
 text(str) {
     // 每行所需字数 = 画布总宽度 / 单个字体大小
     let rowFontNum = Math.floor(500 / 22)
     // 字符串总长度
     let strLength = str.length
     // 所需行数 = 字符总长度 / 每行所需字数
     let rows = Math.ceil(strLength / rowFontNum)
     return {
         rowFontNum,
         rows
     }
 },
 // 圆角头像
 drawRound(context, r, x, y, img) {
     let radius = r;
     // 创建圆形路径
     context.beginPath();
     context.arc(x + r, y + r, r, 0, Math.PI * 2);
     context.closePath();
     // 裁剪
     context.clip();
     // 将图片绘制到 canvas 上
     context.drawImage(img, x, y, radius * 2, radius * 2);
 },
 // 复制
 copy() {
     uni.setClipboardData({
         data: this.shareUrl
     })
 },
 // 保存
 savePoster() {
     if (!this.poster) {
         uni.$showMsg('图片生成中,请稍后')
         return
     }
     saveAs(this.poster, '分享海报')
 },
 // 圆角矩形+边框
drawRect(context, x, y, w, h, r) {
    // 创建圆形路径
    context.beginPath();
    context.moveTo(x + r, y)
    context.arcTo(x + w, y, x + w, y + h, r) //右上角,设置r为0则变为直角
    context.arcTo(x + w, y + h, x, y + h, r) //右下角
    context.arcTo(x, y + h, x, y, r) //左下角
    context.arcTo(x, y, x + w, y, r) //左上角
    context.closePath();
    // 裁剪
    context.clip();
},

效果图:

image.png

image.png

参考链接:blog.csdn.net/weixin_3675…

文字换行:blog.csdn.net/qq_37054093…

头像圆角:www.kancloud.cn/xuwenyang/p…

生成二维码+图片:juejin.cn/post/721959…

圆角矩形+边框:blog.csdn.net/weixin_4495…