You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firefox粘贴图片报‘String contains an invalid character’问题求助

问题分析

Firefox首次粘贴网页图片报错的核心原因是处理HTML类型剪贴板内容时,图片未加载完成就执行了Canvas绘制与数据转换操作:

  • 复制网页图片时,剪贴板携带text/html格式数据,其中<img>的src可能是远程URL或未完全解析内容,首次粘贴时图片资源未加载完毕。
  • 直接调用ctx.drawImage(img, ...)时,图片处于未就绪状态,导致Canvas绘制失败,后续canvas.toDataURL()抛出“String contains an invalid character”错误。
  • 重试粘贴时浏览器缓存了图片资源,图片能快速加载完成,因此操作正常。

另外,同时监听keydown(Ctrl+V)和paste事件,会导致Firefox下首次处理逻辑冲突,加重问题。

修复方案

1. 等待图片加载完成后再处理Canvas操作

修改handlePasteEvent中text/html类型的处理逻辑,添加图片加载监听:

async handlePasteEvent(e) {
    if (e?.clipboardData?.items) {
        const data = e.clipboardData.items;
        const clipboardContent = data[0]
        const type = clipboardContent?.type

        if (clipboardContent.kind === "file" && type.indexOf("image") !== -1) {
            this?.$refs['clipboard-modal']?.showModal()
            const blob = clipboardContent.getAsFile();
            const url = window.URL.createObjectURL(blob)
            this.getDataBlob(url)
        } else if (clipboardContent.kind === "string" && clipboardContent.type === "text/html") {
            const htmlData = e.clipboardData.getData('text/html');
            
            if (!htmlData.includes('<img')) return

            const div = document.createElement('div')
            document.body.appendChild(div)
            div.innerHTML = htmlData

            const img = div.firstElementChild
            if (!img || img.tagName !== 'IMG') {
                document.body.removeChild(div)
                return
            }

            // 等待图片加载完成
            await new Promise((resolve, reject) => {
                img.onload = resolve
                img.onerror = reject
                img.crossOrigin = "anonymous"
            })

            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d');
            
            canvas.width = img.naturalWidth || img.width;
            canvas.height = img.naturalHeight || img.height;
            
            ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
            
            try {
                const imageDataURL = canvas.toDataURL('image/png');
                let blob = this.dataURLToBlob(imageDataURL)

                this?.$refs['clipboard-modal']?.showModal()
                this.clipboard_img = imageDataURL
                this.clipboard_img_blob = await this.blobToFile(blob);
            } catch(e) {
                console.log(e?.message);
                this.$refs.show.showFlashError(e?.message || 'Something went wrong')
                this.$nextTick(() => this?.$refs['clipboard-modal']?.hideModal())
            } finally {
                // 清理DOM元素
                document.body.removeChild(div)
                document.body.removeChild(canvas)
            }
        }
    }
}

2. 移除重复的keydown监听,避免事件冲突

删除created中的keydown事件绑定,仅保留paste事件监听即可:

// 移除这段代码
// created() {
//     window.addEventListener('keydown', (e) => {
//         if ((e.ctrlKey || e.metaKey) && e.key == 'v') {
//             this.handlePasteFromClipboard(e)
//         }
//     });
// },

3. 优化剪贴板读取逻辑的兼容性

Firefox对navigator.clipboard.read的权限要求更严格,建议优先使用paste事件自带的clipboardData,调整mounted中的监听逻辑:

mounted() {
    window.addEventListener('paste', e => {
        this.handlePasteEvent(e)
    })
},
关键注意事项
  • 必须通过img.onload确保图片加载完成后再执行Canvas操作,这是解决报错的核心。
  • 处理HTML剪贴板内容时,直接用<img>判断即可,无需使用转义后的&lt;img。
  • 及时清理创建的DOM元素(div、canvas),避免内存泄漏。
  • Firefox下navigator.clipboard.read仅支持HTTPS页面,且必须在用户交互事件内调用。

内容的提问来源于stack exchange,提问作者Elvis Murseli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 13:04:52