I'm trying make my action icon dynamic by manipulating it with offscreenCanvas()
:
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)});
});
This works fine, however when I attempt use a SVG
image instead of PNG
, the createImageBitmap()
returns error:
DOMException: The source image could not be decoded
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>
Any suggestions how to use SVG
image in offscreenCanvas
in service workers?
If your the SVG images in your Blobs have absolute
width
andheight
, they should be supported bycreateImageBitmap
natively. However, currently no browser supports this feature, and while I made a polyfill for the main thread, it won't work in a Worker where implementers are very reluctant to add an SVG parser.So one could have hoped that injecting some scripts into the current tab would have made it.
But Chrome extensions still use JSON serialization for their various messaging APIs (BUG 248548) and there is thus no way (that I found) of transferring the ImageBitmap from one context to the other in MV3.
So you will have to parse the SVG image yourself and convert it to Canvas2D commands.
For this task, a library like canvg may come handy. They're in the area for a long time, seem to do a pretty good job, and do work in Workers... after some tweaks.
They only provide an UMD version of their library, so you'd have to build it to ESM yourself, and also bring a
DOMParser
implementation (canvg uses xmldom, you can make your build export it too).Then, you have to declare your background script as a module and you can import it all in there:
But if you don't want to do all these builds, and add the 300KB of lib necessary for all this, AND if you have only icons as simple as the one in your example, which consist of only
<path>
elements, you can certainly come up with your own parser, or even avoid the SVG format entirely and instead store the data as JSON. ThePath2D
constructor can take an SVG path declaration string as input, which allows us to generate simple assets in JSON format: