uni-app canvasToTempFilePath:fail Failed to execute

发布于 1周前 作者 songsunli 来自 Uni-App

uni-app canvasToTempFilePath:fail Failed to execute

项目属性
产品分类 uniapp/小程序/微信
PC开发环境操作系统 Mac
PC开发环境操作系统版本号 12.6.2
HBuilderX类型 正式
HBuilderX版本号 4.07
第三方开发者工具版本号 Stable Build 1.06.2402040
基础库版本号 3.3.5
项目创建方式 HBuilderX

示例代码:

<template>  
  <view class="c-display-flex-V-center my-page-container" @click="downloadImg">  
    <canvas type="2d" id="myCanvas" class="my-page-canvas" />  
  </view>  
</template>  

<script>  
const ctxW = 280;  
const ctxH = 275;  
export default {  
  name: 'invitation',  
  components: {  
    myGridItem,  
  },  
  data() {  
    return {  
      canvasObject: undefined,  
    };  
  },  
  beforeCreate() {  
    console.log('beforeCreate enter');  
  },  
  created() {  
    console.log('created enter');  
  },  
  mounted() {  
    console.log('mounted enter');  
  },  
  onLoad(option) {  
    console.log('onLoad');  
  },  
  onReady() {  
    this.drawCanvas();  
  },  
  methods: {  
    drawCanvas() {  
      const query = uni.createSelectorQuery().in(this);  
      let _this = this;  

      query.select("#myCanvas")  
        .fields({  
          node: true,  
          size: true,  
        })  
        .exec(async (res) => {  
          _this.canvasObject = res[0].node.id;  
          const canvas = res[0].node;  
          const ctx = canvas.getContext('2d');  

          let offsetY = 15;  
          const dpr = wx.getSystemInfoSync().pixelRatio;  
          canvas.width = ctxW * dpr;  
          canvas.height = ctxH * dpr;  
          ctx.scale(dpr, dpr);  

          let _offsetY = offsetY;  
          const imageSrc = '../../static/images/invitation_head.png';  
          let image = canvas.createImage();  
          await new Promise(resolve => {  
            image.onload = resolve;  
            image.src = imageSrc;  
          });  
          ctx.drawImage(image, (ctxW - 250) / 2, _offsetY, 250, 35);  

          offsetY += (35 + 10);  
          ctx.fillStyle = '#f3f3f3';  
          ctx.fillRect((ctxW - 200) / 2, offsetY, 200, 200);  
        });  
    },  
    downloadImg() {  
      uni.showLoading({  
        title: '正在下载...',  
      });  
      uni.canvasToTempFilePath({  
        canvas: this.canvasObject,  
        x: 0,  
        y: 0,  
        width: ctxW,  
        height: ctxH,  
        destWidth: ctxW,  
        destHeight: ctxH,  
        quality: 1.0,  
        success: function(res) {  
          uni.saveImageToPhotosAlbum({  
            filePath: res.tempFilePath,  
            success: function(saveRes) {  
              uni.showToast({  
                title: '保存成功',  
              });  
            },  
            fail: function(saveErr) {  
              if (saveErr.errMsg === 'saveImageToPhotosAlbum:fail:auth denied' ||  
                saveErr.errMsg === 'saveImageToPhotosAlbum:fail auth deny' ||  
                saveErr.errMsg === 'saveImageToPhotosAlbum:fail authorize no response'  
              ) {  
                uni.showModal({  
                  title: '需要您授权保存相册',  
                  modalType: false,  
                  success: modalRes => {  
                    uni.openSetting({  
                      success(settingRes) {  
                        if (settingRes.authSetting['scope.writePhotosAlbum']) {  
                          wx.showModal({  
                            title: '温馨提醒',  
                            content: '获取权限成功,再次点击保存即可~',  
                            modalType: false,  
                          })  
                        } else {  
                          wx.showModal({  
                            title: '温馨提醒',  
                            content: '获取权限失败,将无法保存到相册哦~',  
                            modalType: false,  
                          })  
                        }  
                      },  
                      fail(settingError) {  
                        console.log('settingError', JSON.stringify(settingError));  
                      },  
                    });  
                  },  
                });  
              }  
            },  
          });  
        },  
        fail: function(err) {  
          uni.showToast({  
            title: '生成图片失败',  
          });  
        },  
      }, this);  
    },  
  },  
}  
</script>  

<style scoped>  
.my-page-container {  
  background-color: white;  
  height: 500px;  
}  

.my-page-canvas {  
  width: 280px;  
  height: 275px;  
}  

.my-page-canvas-core {  
  box-sizing: border-box;  
  width: 280px;  
  height: 275px;  
  padding: 15px;  
  display: flex;  
  flex-direction: column;  
  align-items: center;  
}  

.core-head-image {  
  width: 250px;  
  height: 35px;  
}  

.core-content-image {  
  margin-top: 10px;  
  width: 200px;  
  height: 200px;  
  background-color: #f3f3f3;  
}  
</style>

操作步骤:

  • 点击图片区域,即可触发下载任务。

预期结果:

  • 能够生成图片并保存到相册中。

实际结果:

  • 生成图片失败。

bug描述:

  • Canvas绘制并生成图片失败,报错信息如下:
    {"errMsg":"canvasToTempFilePath:fail Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or SVGImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas or VideoFrame)'"}

4 回复

小程序把 type="2d"去掉就好了


把 type="2d"去掉,使用createCanvasContext绘制画面的图片很模糊。

已解决。canvas在下载的时候再先使用createSelectorQuery查找到,而不是使用之前查找的对象。参考链接 https://developers.weixin.qq.com/community/develop/article/doc/000242073903a04e082ab595b52013

在 uni-app 中,canvasToTempFilePath 是一个用于将 canvas 内容导出为图片路径的 API。如果你遇到 canvasToTempFilePath:fail Failed to execute 的错误,可能是由于以下原因之一:

1. Canvas 未正确渲染

  • 原因: 在调用 canvasToTempFilePath 时,Canvas 可能还没有完成渲染,导致导出失败。
  • 解决方案: 确保在 Canvas 渲染完成后再调用 canvasToTempFilePath。可以使用 setTimeout 延迟调用,或者在 Canvas 的 draw 方法完成后再执行导出。
setTimeout(() => {
    uni.canvasToTempFilePath({
        canvasId: 'myCanvas',
        success: (res) => {
            console.log(res.tempFilePath);
        },
        fail: (err) => {
            console.error(err);
        }
    });
}, 500); // 延迟 500ms 确保 Canvas 渲染完成

2. Canvas ID 错误

  • 原因: canvasId 参数传递错误,无法找到对应的 Canvas 元素。
  • 解决方案: 确保 canvasId 与 Canvas 元素的 canvas-id 属性一致。
<canvas canvas-id="myCanvas" style="width: 300px; height: 300px;"></canvas>
uni.canvasToTempFilePath({
    canvasId: 'myCanvas', // 确保与 canvas-id 一致
    success: (res) => {
        console.log(res.tempFilePath);
    },
    fail: (err) => {
        console.error(err);
    }
});

3. Canvas 尺寸问题

  • 原因: Canvas 的宽度或高度为 0,导致无法导出图片。
  • 解决方案: 确保 Canvas 的宽度和高度设置正确,并且不为 0。
<canvas canvas-id="myCanvas" style="width: 300px; height: 300px;"></canvas>

4. 未在 draw 方法中绘制内容

  • 原因: 如果没有在 Canvas 上绘制任何内容,导出时会失败。
  • 解决方案: 确保在调用 canvasToTempFilePath 之前,已经在 Canvas 上绘制了内容。
const ctx = uni.createCanvasContext('myCanvas');
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, 100, 100);
ctx.draw();

setTimeout(() => {
    uni.canvasToTempFilePath({
        canvasId: 'myCanvas',
        success: (res) => {
            console.log(res.tempFilePath);
        },
        fail: (err) => {
            console.error(err);
        }
    });
}, 500);

5. 平台兼容性问题

  • 原因: 在某些平台(如小程序)上,canvasToTempFilePath 的实现可能有所不同,导致导出失败。
  • 解决方案: 确保在目标平台上测试代码,并根据平台文档调整代码。

6. 权限问题

  • 原因: 在某些平台上,导出 Canvas 内容可能需要特定的权限或配置。
  • 解决方案: 检查目标平台的文档,确保已正确配置权限。

7. Canvas 上下文未完成绘制

  • 原因: 如果在 ctx.draw() 之后立即调用 canvasToTempFilePath,可能会导致 Canvas 内容尚未完全绘制。
  • 解决方案: 使用 ctx.drawcallback 参数,确保在绘制完成后再调用 canvasToTempFilePath
const ctx = uni.createCanvasContext('myCanvas');
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, 100, 100);
ctx.draw(true, () => {
    uni.canvasToTempFilePath({
        canvasId: 'myCanvas',
        success: (res) => {
            console.log(res.tempFilePath);
        },
        fail: (err) => {
            console.error(err);
        }
    });
});
回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!