最近搜索

小程序 使用canvas 创建海报 可以保存临时图片 可以保存服务器

浏览:24
管理员 2025-08-04 19:34



高建议使用 960


 import {
  baseURL
} from '../../utils/config.js'
Page({
  data: {
    baseURL: baseURL, //默认是域名
    imgUrl:"",
  },
  async create_haibao() {

    if(this.data.imgUrl.length>1){
      wx.showShareImageMenu({
        path: this.data.imgUrl
      });
      return;
    }

    let canvas = wx.createOffscreenCanvas({
      type: "2d",
      width: 1080,
      height: 1787,
    });
    let context = canvas.getContext("2d");
    // 绘制底色 - 渐变背景
    const gradient = context.createLinearGradient(0, 0, 1080, 1787);
    gradient.addColorStop(0, '#f5f7fa');
    gradient.addColorStop(1, '#c3cfe2');
    //渐变背景
    //context.fillStyle = gradient;
    context.fillStyle = '#ffffff'; // 纯白色
    context.fillRect(0, 0, 1080, 1787);
 


    // 设置文字样式
    context.font = "bold 55px Microsoft YaHei"; // 加粗40px微软雅黑
    context.fillStyle = "#000000"; // 黑色文字
    context.textAlign = "left"; // 文字水平居中
    context.textBaseline = "middle"; // 文字垂直居中
    // 绘制名称
    context.fillText("小米商城", 280, 80); // 在(300,100)位置绘制文字

    //绘制时间
    context.font = "35px Microsoft YaHei"; // 加粗40px微软雅黑
    context.fillText("2025-08-08 12:22", 280, 180);

    // 绘制标题  一行20个字, 2行16个字后面...
    var title = "根据你的需求,我可以帮你根据你的需求,我可以帮你:根据你的需求,我可以帮你:根据你的需求,我可以帮你::";
    // 分割成两行
    var firstLine = title.substring(0, 20);
    var secondLine = title.substring(20);
    secondLine = secondLine.length > 16 ? secondLine.substring(0, 16) + "..." : secondLine;
    console.log("第一行: " + firstLine);
    console.log("第二行: " + secondLine);
    context.font = "bold 45px Microsoft YaHei"; // 加粗40px微软雅黑
    context.textAlign = "left"; // 文字水平居中
    context.fillStyle = "#000000"; // 黑色文字
    var title_y = 1200;
    context.fillText(firstLine, 60, title_y);
    context.fillText(secondLine, 60, title_y + 80);

    //绘制摘要  一行25个字, 2行20个字后面...
    // var desc = "绘制摘要  一行25个字, 2行20个字后面...";
    // var firstLine = desc.substring(0, 25);
    // var secondLine = desc.substring(25);
    // secondLine = secondLine.length > 20 ? secondLine.substring(0, 20) + "..." : secondLine;
    // context.font = "21px Microsoft YaHei"; // 加粗40px微软雅黑
    // context.textAlign = "left"; // 文字水平居中
    // context.fillStyle = "#000000"; // 黑色文字
    // var desc_y = 790;
    // context.fillText(firstLine, 50, desc_y);
    // context.fillText(secondLine, 50, desc_y + 40);




    //绘制 价格  ¥9.9-100
    context.font = "bold 50px Microsoft YaHei"; // 加粗40px微软雅黑
    context.textAlign = "left"; // 文字水平居中
    context.fillStyle = "#FF5722"; // 橙色
    context.fillText("¥9.9-100", 60, 1400);

    // 绘制灰色长方形
    context.fillStyle = '#c5c5c5'; // 标准灰色
    context.fillRect(50, 1555, 450, 80); // 600*30的长方形

    //绘制 提示
    context.font = "45px Microsoft YaHei"; // 加粗40px微软雅黑
    context.textAlign = "left"; // 文字水平居中
    context.fillStyle = "#000000"; // 黑色
    context.fillText("长按识别小程序码", 80, 1600);
 

    // 图片加载部分修改为:
    const loadImage = (src) => {
      return new Promise((resolve, reject) => {
        const img = canvas.createImage();
        img.onload = () => resolve(img);
        img.onerror = (err) => {
          console.error('图片加载失败:', src, err);
          reject(err);
        };
        img.src = src.includes('http') ? src : `/static/${src}`;
      });
    };
    try {
      const [logo, img, qr] = await Promise.all([
        loadImage(this.data.baseURL + "/static/upload_image/blog_cover/20250624/20250624004044.jpg"),
        loadImage(this.data.baseURL + "/static/upload_image/blog_cover/20250624/20250624004044.jpg"),
        loadImage(this.data.baseURL + "/static/upload_image/blog_cover/20250624/20250624004044.jpg")
      ]);
      context.drawImage(logo, 40, 40, 200, 200);
      context.drawImage(img, 110, 300, 850, 850);
      context.drawImage(qr, 600, 1350, 400, 400);
      //toDataURL(string type, number encoderOptions)
      //String type  图片格式,默认为 image/png
      // number encoderOptions 在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。
      //如果超出取值范围,将会使用默认值 0.92。其他参数会被忽略。
      const imageUrl = canvas.toDataURL("image/jpeg", 1);
      this.setData({
        img: imageUrl
      });

      const fs = wx.getFileSystemManager();
      const timestamp = new Date().getTime();
      console.log(timestamp)
      const filePath = `${wx.env.USER_DATA_PATH}/share_${timestamp}.jpg`;
      const base64Data = imageUrl.replace(/^data:image\/\w+;base64,/, '');
      fs.writeFileSync(filePath, base64Data, 'base64');
      this.setData({
        imgUrl:filePath
      })
      wx.showShareImageMenu({
        path: filePath
      });

    } catch (e) {
      console.error('海报生成失败:', e);
      wx.showToast({
        title: '海报生成失败',
        icon: 'none'
      });
    }
  },
  onLoad(options) {},
  onReady() {},
  onShow() {},
  onHide() {
  },
  onUnload() {
  },
  onPullDownRefresh() {
  },
  onReachBottom() {
  },
  onShareAppMessage() {
  }
})




wxml

<view style="padding: 35rpx; background-color: #d0d0d0;">
  <image mode="widthFix" style="width: 100%; border: 1rpx solid black;"   src="{{img}}"></image>

</view>

<button bind:tap="create_haibao">创建海报</button>


修改后的海报    分辨率高了    高清了很多


image.png



image.png



生成海报会报一个错误


海报生成失败: Error: writeFileSync:fail the maximum size of the file storage limit is exceeded    at Ub (WAServiceMainContext.js?t=wechat&v=3.8.12:1)    at Object.<anonymous> (WAServiceMainContext.js?t=wechat&v=3.8.12:1)    at I (WAServiceMainContext.js?t=wechat&v=3.8.12:1)    at Object.p (WAServiceMainContext.js?t=wechat&v=3.8.12:1)    at _callee$ (index.js? [sm]:172)    at s (<anonymous>:1:1588)    at Generator.<anonymous> (<anonymous>:1:2925)    at Generator.next (<anonymous>:1:1951)    at asyncGeneratorStep (<anonymous>:1:906)    at c (<anonymous>:1:1125)(env: Windows,mp,1.06.2504010; lib: 3.8.12)

这个错误表明微信小程序的本地文件存储空间已超过限制,导致海报生成失败。以下是解决方案和优化建议:

  1. 清理已存储的临时文件

  1. 检查文件存储限制

  • 微信小程序本地文件存储总大小限制为10MB3

  • 单个文件不得超过4MB限制

  1. 长期解决方案

  • 定期清理生成的临时文件

  • 将大文件存储到云开发或服务器

  • 压缩图片资源后再处理

// 新版写法
const fs = wx.getFileSystemManager()
fs.getSavedFileList({
  success(res) {
    console.log(res.fileList) 
    
     res.fileList.forEach((file) => {
      wx.removeSavedFile({ filePath: file.filePath })
    })
  }
})


建议配合fs.removeSavedFile定期清理缓存文件
wx.removeSavedFile({ filePath: file.filePath })



联系站长

站长微信:xiaomao0055

站长QQ:14496453