示例图:


文献参考:

参考文档:https://zhuanlan.zhihu.com/p/597629702
uni-app官网:uni.createSelectorQuery() | uni-app官网
微信小程序官网:canvas | 微信开放文档

海报内容准备:

1、背景图片
2、二维码
3、用户头像,用户名称
4、简短的描述文案

PS:

1、若使用<canvas type="2d" id="myCanvas"></canvas> 则报错canvasToTempFilePath:fail fail canvas is empty。
2、若canvas不设置canvas-id,则报错<canvas>: canvas-id attribute is undefined(env: Windows,mp,1.06.2308310; lib: 2.25.3)。
3、若只设置canvas-id,则节点信息为null。
const query = uni.createSelectorQuery().in(this); query.select('#canvas').boundingClientRect(data => { console.log("节点信息" + JSON.stringify(data)); // null }).exec();
4、canvas绘制的图片不支持网络图片,因此使用网络需使用uni.getImageInfo获取图片信息。

实现

HTML页面

// 触发按钮
<view data-event-opts="{{[['tap',[['handleClick']]]]}}" bindtap="__e">生成海报</view>
// 海报容器
<canvas canvas-id="canvass" id="canvas" style="width:100%; height: 1000rpx;" />
// 生成的海报图片
<image src="{{imgAddRess}}" style="width:100%; height: 1000rpx;"></image>

JS页面

// 单网图
data: {
    return {
        imgAddRess: "",
        shareBg: "https://img2.baidu.com/it/u=3334525604,928778682&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1703955600&t=c88ebba9f3d8aeee92c6afd219945f9a",
        memberCount: 100,
        userImage:"/static/img/code/kong-img.png",
        userName: "快乐星球",
        shareQrImageUrl: "/static/img/code/kong-img.png"
    }
}
// 生成海报
handleClick() {
    const _this = this;
    // 因shareBg图片为线上图片,需做转换uni.getImageInfo({ src: this.shareBg })
    // 单个图片处理
    uni.getImageInfo({ src: this.shareBg }).then(res => {
    this.shareBg = res[1].path; // 获取转换后的图片路径
    this.createdCanvas().then(()=>{
      // 绘制需要延迟,不然第一次加载为空白
      setTimeout(() => {
        // 将生成的canvas图片,转为真实图片-地址
        uni.canvasToTempFilePath({
        x: 0,
        y: 0,
        canvasId: "canvass",
        success: res => {
          _this.imgAddRess =  res.tempFilePath;
          console.log('真实图片>>>>>>', res);
        },
        fail: (err) => { console.log('error', err) }
        },this); 
      }, 500);
    });
  });
},
handleClick2() {
    const _this = this;
    // 多张图片处理
    const Images = [this.shareBg, this.shareQrImageUrl, this.userImage];
    Promise.all(Images.map(img => uni.getImageInfo({ src: img }))).then(
      imageInfos => {
      console.log('Images then>>>>>>', imageInfos);
      this.shareBg = imageInfos[0][1].path;
      this.shareQrImageUrl = imageInfos[1][1].path;
      this.userImage = imageInfos[2][1].path;

      //根据参数开始绘图
      this.createdCanvas().then(()=>{
         // 绘制需要延迟,不然第一次加载为空白
        setTimeout(() => {
        // 将生成的canvas图片,转为真实图片-地址
        uni.canvasToTempFilePath({
        x: 0,
        y: 0,
        canvasId: "canvass",
        success: res => {
          _this.imgAddRess =  res.tempFilePath;
          console.log('真实图片>>>>>>', res);
        },
        fail: (err) => { console.log('error', err) }
        },this); 
      }, 500);
      })
    }
  );
}
createdCanvas(){
    const _this = this;
    return new Promise((resolve, reject) => {
        //绘图上下文
        const ctx = uni.createCanvasContext('canvass', this);
        uni.createSelectorQuery()
            .in(this)
            .select('#canvas')
            .boundingClientRect(rect => {
                if(!rect) return
                var width = rect.width;
                var height = rect.height;
                // 背景图
                ctx.drawImage( _this.shareBg, 0, 0, width, height); 

                // 文案:百位超能大神带你飞
                ctx.font = "bold 31px 'DINAlternate-Bold, DINAlternate'"
                ctx.setFillStyle('#ff9900');
                ctx.setTextAlign('left');
                ctx.fillText(_this.memberCount, Math.ceil(width*0.32), Math.ceil(height*0.103*2)+6);

                ctx.setFillStyle('#ff9900');
                ctx.setTextAlign('left');
                ctx.font = "16px 'PingFangSC-Medium, PingFang SC'"
                ctx.fillText('位超能大神带你飞',  Math.ceil(width*0.32)+66, Math.ceil(height*0.103*2));

                // 二维码区背景背景
                ctx.beginPath();
                // r:8 ,
                // 起始点
                ctx.moveTo(12, height - 92 + 8);
                // 左上角
                ctx.arcTo(12, height - 92, 12 + 8, height - 92, 8);
                // 右上角
                ctx.arcTo(width - 12, height - 92, width - 12, height - 92 + 8, 8);
                // 右下角
                ctx.arcTo(width - 12, height - 12, width - 12 - 8,  height - 12, 8);
                // 左下角
                ctx.arcTo(12, height - 12, 12, height - 12 - 8, 8);
                ctx.fillStyle = '#ffffff';
                ctx.closePath();
                ctx.fill();

                //用户头像+用户名
                let avatarurl_width = 50; //绘制的头像宽度
                let avatarurl_heigth = 50; //绘制的头像高度
                let avatarurl_x = 22; //绘制的头像在画布上的位置
                let avatarurl_y = height - 77; //绘制的头像在画布上的位置
                ctx.save(); // 保存绘图上下文
                ctx.beginPath(); // 开始创建一个路径
                ctx.arc(
                  avatarurl_width / 2 + avatarurl_x,
                  avatarurl_heigth / 2 + avatarurl_y,
                  avatarurl_width / 2,
                  0,
                  Math.PI * 2,
                  false
                ); // 画一个圆形裁剪区域
                ctx.clip(); // 裁剪
                ctx.drawImage(
                  this.userImage,
                  avatarurl_x,
                  avatarurl_y,
                  avatarurl_width,
                  avatarurl_heigth
                ); // //分享人头像-绘制图片x,y轴
                ctx.restore(); // 恢复之前保存的绘图上下文

                // 分享userName
                ctx.setFillStyle('#141414');
                ctx.setTextAlign('left');
                ctx.font = "bold 16px 'PingFangSC-Medium, PingFang SC'"
                let title = _this.userName;
                if(title.length>14){
                  title =title.substr(0,14)+'...'
                }
                ctx.fillText(title, 80, height - 55)                ;

                // 分享描述
                ctx.setFillStyle('#666666');
                ctx.setTextAlign('center');
                ctx.font = "11px 'PingFangSC-Regular, PingFang SC'" 
                ctx.fillText('欢迎来到快乐星球根据地', 140, height - 33);ht - 33);

                // 二维码图片
                ctx.drawImage(_this.shareQrImageUrl, width - 84, height - 84, 64, 64 );
                ctx.draw();
              }).exec()
          //获取节点
          resolve()
     })
}

多网图

data: {
    return {
  imgAddRess: "",
  shareBg:"https://img0.baidu.com/it/u=2868999810,2001254139&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=714",
  shareQrImageUrl: "https://img1.baidu.com/it/u=206225810,1732683717&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
  avater: "https://img2.baidu.com/it/u=1979438230,3745650916&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500"
    }
}
// 生成海报
 handleSetImage() {
   const _this = this;
   const Images = [this.shareBg, this.shareQrImageUrl, this.avater];
   let aa = Images.map(img => uni.getImageInfo({ src: img }));

   Promise.all(Images.map(img => uni.getImageInfo({ src: img }))).then(
     imageInfos => {
       console.log('Images then>>>>>>', imageInfos);
       this.shareBg = imageInfos[0][1].path;
       this.shareQrImageUrl = imageInfos[1][1].path;
       this.avater = imageInfos[2][1].path;

       //根据参数开始绘图
       this.createdCanvas().then(()=>{
         // 绘制需要延迟,不然第一次加载为空白
         setTimeout(() => {
           wx.canvasToTempFilePath({
             x: 0,
             y: 0,
             canvasId: "mc",
             success: res => {
               _this.imgAddRess =  res.tempFilePath;
               console.log('真实图片>>>>>>', res);
             },
             fail:(error)=>{
               console.log('error',error)
               uni.showToast({
                 title: error.errMsg,
                 icon:'none',
                 duration:2000,
               });
             }
           },this);
         }, 500);
       })
     }
   );
 },
 // 海报绘图
 createdCanvas() {
   const _this = this;
   const query = wx.createSelectorQuery().in(this);
   query.select('#mc').boundingClientRect(data => {
     console.log("得到布局位置信息" + JSON.stringify(data));
   }).exec();

   return new Promise((resolve, reject) => {
   //绘图上下文
   const ctx = wx.createCanvasContext('mc', this);
   wx.createSelectorQuery()
   .in(this)
   .select('#mc')
   .boundingClientRect(rect => {
     console.log('rect111',rect)
     if(!rect) return
     var width = rect.width;
     var height = rect.height;
     let qrw = (width-200) / 2;
     let qrh = ((height - 200) / 2 + 80);
     // 背景图
     ctx.drawImage( _this.shareBg, 0, 0, width, height); 

     // 头像
     ctx.drawImage(_this.avater, (width - 80) / 2 , 50 , 80, 80 );

     // 文案
     ctx.setFillStyle('#ffffff');
     ctx.setTextAlign('center');
     ctx.font = "bold 26px 'PingFangSC-Medium, PingFang SC'"
     ctx.fillText('超能小飞侠',  180, 170, width);

     ctx.font = "bold 16px 'DINAlternate-Bold, DINAlternate'"
     ctx.setFillStyle('#000000');
     ctx.setTextAlign('center');
     ctx.fillText("诚邀您参与超能封神", 185, 205, width); // (文本,X坐标,Y坐标, 最大宽度)

     // 二维码:(图片,X坐标,Y坐标, 图宽,图高)
     ctx.drawImage(_this.shareQrImageUrl, qrw , qrh , 200, 200 );
     //二维码图片
     ctx.draw();
   }).exec()
   //获取节点
   resolve()
   })
 },
posted on 2024-01-14 20:03  羽丫头不乖  阅读(428)  评论(0编辑  收藏  举报