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

如何在Service Worker的OffscreenCanvas中使用SVG生成动态Action图标?

在Chrome扩展Service Worker的OffscreenCanvas中使用SVG图片的解决方案

问题背景

使用PNG图片时动态生成Action图标的代码运行正常,但替换为SVG后,createImageBitmap()抛出错误:

DOMException: The source image could not be decoded

相关代码及配置如下:

原service_worker.js代码

const iconFile = `icon.png`;
const canvas = new OffscreenCanvas(24, 24),
      ctx = canvas.getContext("2d");

fetch(iconFile)
.then(r => r.blob())
.then(createImageBitmap)
.then(img => ctx.drawImage(img, 0, 0))
.then(() =>
{
  ctx.fillStyle = 'lightgreen';
  ctx.fillRect(0, canvas.height-9, canvas.width, 9);
  chrome.action.setIcon({imageData: ctx.getImageData(0, 0, 24, 24)});
});

manifest.json配置

{
  "manifest_version": 3,
  "name": "Test extension",
  "author": "test",
  "description": "Test",
  "version": "0.0.1",

  "permissions":[],
  "action": {},
  "background": {
    "service_worker": "service_worker.js"
  }
}

icon.svg内容

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#00864b" d="M8.1 18.8.7 11.4l2.1-2.2 5.3 5.3L21.4 1.2l2.2 2.1z"/></svg>

解决方案

Service Worker环境中createImageBitmap无法直接解码SVG Blob,可通过以下两种方法解决:

方法一:将SVG转为Data URL后用Image对象加载

先把SVG文本转为Data URL,通过Image对象完成渲染后再绘制到OffscreenCanvas:

const iconFile = `icon.svg`;
const canvas = new OffscreenCanvas(24, 24),
      ctx = canvas.getContext("2d");

fetch(iconFile)
.then(r => r.text())
.then(svgText => {
  const svgDataUrl = `data:image/svg+xml;base64,${btoa(svgText)}`;
  const img = new Image();
  return new Promise((resolve, reject) => {
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.src = svgDataUrl;
  });
})
.then(img => {
  ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
  ctx.fillStyle = 'lightgreen';
  ctx.fillRect(0, canvas.height-9, canvas.width, 9);
  return chrome.action.setIcon({imageData: ctx.getImageData(0, 0, 24, 24)});
})
.catch(err => console.error(err));

方法二:通过Blob URL中转后生成ImageBitmap

创建Blob URL让Image对象加载SVG,再基于加载完成的Image生成ImageBitmap:

const iconFile = `icon.svg`;
const canvas = new OffscreenCanvas(24, 24),
      ctx = canvas.getContext("2d");

fetch(iconFile)
.then(r => r.blob())
.then(blob => {
  const url = URL.createObjectURL(blob);
  const img = new Image();
  return new Promise((resolve, reject) => {
    img.onload = () => {
      URL.revokeObjectURL(url);
      createImageBitmap(img).then(resolve).catch(reject);
    };
    img.onerror = reject;
    img.src = url;
  });
})
.then(imgBitmap => {
  ctx.drawImage(imgBitmap, 0, 0);
  ctx.fillStyle = 'lightgreen';
  ctx.fillRect(0, canvas.height-9, canvas.width, 9);
  return chrome.action.setIcon({imageData: ctx.getImageData(0, 0, 24, 24)});
})
.catch(err => console.error(err));

原理说明

Service Worker中的createImageBitmap不支持直接解析SVG Blob,因为SVG需要先经过浏览器的渲染流程转为位图。通过Image对象加载SVG(Data URL或Blob URL形式),浏览器会完成SVG的解析渲染,生成可用于Canvas绘制的图像源,从而解决解码失败的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 09:15:37