uniapp 编译支付宝小程序canvas 合成图片实例,支付宝小程序 canvas 渲染图片 可以换成自己的图片即可

文章目录

  • 前言
  • [一、在页面中使用 Canvas](#一、在页面中使用 Canvas)
  • [二、在页面的 JS 文件中绘制图片](#二、在页面的 JS 文件中绘制图片)
  • 总结

前言

uniapp 编译支付宝小程序canvas 合成图片实例,支付宝小程序 canvas 渲染图片 可以换成自己的图片即可


一、在页面中使用 Canvas

html 复制代码
<template>
  <view>
    <!-- Canvas 画布 -->
    <canvas 
      type="2d" 
	  :id="alipayCanvasId"
      :style="canvasStyle"
      :width="canvasWidth" :height="canvasHeight"
      @ready="onCanvasReady" 
    />
    
    <!-- 生成的海报预览 -->
    <image 
      v-if="finalPosterUrl" 
      :src="finalPosterUrl" 
      mode="widthFix" 
      style="width: 100%; margin-top: 20rpx"
      show-menu-by-longpress="true"
    />
  </view>
</template>

二、在页面的 JS 文件中绘制图片

你可以使用 myCanvas 这个 canvas-id 来获取 canvas 上下文,并绘制图片。

javascript 复制代码
<script>
export default {
  data() {
    return {
      finalPosterUrl: '', // 生成的海报临时路径
	  alipayCanvasId:"alipayPosterCanvas",
      alipayCanvas: null,  // Canvas 实例
      alipayCtx: null,     // 2D 上下文
      dpr: 1,        // 设备像素比
      // Canvas 基础配置
      canvasWidth: 0, // 动态计算的canvas宽度
      canvasHeight: 0, // 动态计算的canvas高度
      canvasStyle: "", // canvas样式
    };
  },
  
  methods: {
    /**
     * Canvas 就绪回调
     */
    onCanvasReady() {
      // 图片资源
      const mainImgUrl = 'xxxxxx/haibao_image.png';
      const qrImgUrl = 'xxxxxx/0379ec3faccad8485f136bd94b1486e1e367ac8c.jpeg';

      // 查询 Canvas 节点
      uni.createSelectorQuery()
 // 绑定当前组件上下文(关键)
        .select(`#${this.alipayCanvasId}`)
        .node()
        .exec(async (res) => {
          if (!res || !res[0] || !res[0].node) {
            console.error('未找到 Canvas 节点');
            return;
          }

          // 初始化 Canvas 环境
          this.initCanvasEnv(res[0].node);

          try {
            // 分步加载并绘制图片(使用封装的方法)
            const mainImg = await this.loadImage(mainImgUrl);
            this.drawMainImage(mainImg);
            
            const qrImg = await this.loadImage(qrImgUrl);
            this.drawQrCode(qrImg);

            // 转换为临时图片
            this.convertToTempImage();
          } catch (err) {
            console.error('海报生成失败:', err);
            uni.showToast({ title: '生成失败', icon: 'none' });
          }
        });
    },

    /**
     * 初始化 Canvas 环境(尺寸、上下文等)
     */
    initCanvasEnv(canvasNode) {
      this.alipayCanvas = canvasNode;
      this.alipayCtx = canvasNode.getContext('2d');
      
      // 获取设备信息
      const sysInfo = uni.getSystemInfoSync();
      this.dpr = sysInfo.pixelRatio || 1;
      
      // 计算逻辑宽高(750rpx = 屏幕宽度)
      this.canvasWidth = sysInfo.screenWidth;
      this.canvasHeight = (1200 / 750) * sysInfo.screenWidth;
      
      // 设置实际像素尺寸(解决模糊问题)
      this.alipayCanvas.width = this.canvasWidth * this.dpr;
      this.alipayCanvas.height = this.canvasHeight * this.dpr;
      
      // 缩放上下文
      this.alipayCtx.scale(this.dpr, this.dpr);
    },

    /**
     * 封装:加载图片(支持网络图片下载 + Canvas 图片对象转换)
     * @param {String} url - 图片URL
     * @returns {Promise} - 加载完成的图片对象
     */
    loadImage(url) {
      return new Promise(async (resolve, reject) => {
        try {
          // 1. 下载网络图片(支付宝需要先下载为本地临时路径)
          const tempPath = await this.downloadImage(url);
          
          // 2. 将临时路径转换为 Canvas 可绘制的图片对象
          const img = this.alipayCanvas.createImage();
          img.onload = () => resolve(img);
          img.onerror = () => reject(new Error(`图片加载失败: ${url}`));
          img.src = tempPath; // 使用下载后的临时路径
        } catch (err) {
          reject(err);
        }
      });
    },

    /**
     * 封装:下载网络图片为本地临时路径
     * @param {String} url - 图片URL
     * @returns {Promise} - 本地临时路径
     */
    downloadImage(url) {
      return new Promise((resolve, reject) => {
        // 校验URL有效性
        if (!url || typeof url !== 'string') {
          reject(new Error(`无效的图片URL: ${url}`));
          return;
        }

        uni.downloadFile({
          url,
          success: (res) => {
            if (res.statusCode === 200) {
              resolve(res.tempFilePath); // 返回临时路径
            } else {
              reject(new Error(`下载失败,状态码: ${res.statusCode}`));
            }
          },
          fail: (err) => {
            reject(new Error(`下载错误: ${err.errMsg}`));
          }
        });
      });
    },

    /**
     * 绘制主图
     * @param {Object} img - 主图图片对象
     */
    drawMainImage(img) {
      // 铺满整个画布
      this.alipayCtx.drawImage(img, 0, 0, this.canvasWidth, this.canvasHeight);
    },

    /**
     * 绘制二维码
     * @param {Object} img - 二维码图片对象
     */
    drawQrCode(img) {
      // 二维码尺寸(画布宽度的30%)
      const qrSize = this.canvasWidth * 0.3;
      // 二维码位置(底部居中,距离底部20rpx)
      const qrX = (this.canvasWidth - qrSize) / 2;
      const qrY = this.canvasHeight - qrSize - (20 / 750) * this.canvasWidth;

      // 绘制白色背景(增强对比度)
      this.alipayCtx.fillStyle = '#ffffff';
      this.alipayCtx.fillRect(qrX - 10, qrY - 10, qrSize + 20, qrSize + 20);
      
      // 绘制二维码
      this.alipayCtx.drawImage(img, qrX, qrY, qrSize, qrSize);
    },

    /**
     * 转换 Canvas 为临时图片
     */
    convertToTempImage() {
      uni.canvasToTempFilePath({
        canvasId: this.alipayCanvasId,
        width: this.canvasWidth,
        height: this.canvasHeight,
        destWidth: this.canvasWidth * this.dpr, // 输出高清图
        destHeight: this.canvasHeight * this.dpr,
        success: (res) => {
          this.finalPosterUrl = res.tempFilePath;
          console.log('海报生成成功:', res.tempFilePath);
        },
        fail: (err) => {
          console.error('转换图片失败:', err);
          uni.showToast({ title: '转换失败', icon: 'none' });
        }
      }, this);
    }
  }
};
</script>

总结

注意事项

‌跨域问题‌:如果图片 URL 是外部链接,确保服务器支持跨域请求,或者在支付宝小程序管理后台添加图片的域名到"业务域名"白名单中。

‌图片加载‌:由于网络请求和图片加载可能需要时间,建议在 onReady 或在图片加载成功后调用 drawImage 方法。

‌动态图片‌:如果图片是动态生成的或者来自用户上传,确保在调用 drawImage 前图片已经加载完成。可以使用 my.getImageInfo 方法获取图片信息,例如尺寸等,然后再进行绘制。

相关推荐
万岳科技系统开发6 小时前
校园跑腿外卖搭建助力高校周边商家拓展线上业务
大数据·人工智能·小程序
微三云 - 廖会灵 (私域系统开发)13 小时前
消费返物业费平台搭建:美家时代商业模式拆解与系统开发选型指南
小程序·系统架构
Norris Huang14 小时前
Icevue:为 Apache Iceberg REST Catalog 打造一个轻量、只读的可视化入口
apache
greenbbLV15 小时前
中小公司积分商城选型:SaaS与私有化方案对比解析
大数据·前端·小程序
ajassi20001 天前
AI语音智能体开发日记(三)解决小程序配网中的蓝牙命名与MAC地址获取问题
ai·apache·ai编程
结网的兔子2 天前
【前端开发】Web端迁移至 uni-app 及鸿蒙扩展方案对比
前端·uni-app·harmonyos
2501_915909062 天前
iOS 应用反调试技详解术 检测调试器的原理与防护实践
android·ios·小程序·https·uni-app·iphone·webview
SelectDB技术团队2 天前
当 PostgreSQL 面临性能瓶颈:80TB 电商业务迁移至 Apache Doris 的实践思考
数据库·postgresql·apache
sbjdhjd2 天前
安全初级 | Upload 文件上传漏洞实操
android·经验分享·安全·网络安全·开源·php·apache
AI多Agent协作实战派2 天前
AI多Agent协作系统实战(二十八):顶栏统一战争——从1个页面异常到31个页面全量对齐
数据库·人工智能·uni-app