Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

declarativeContent and chrome.declarativeContent.SetIcon -- How Does it Work?

136 views
Skip to first unread message

John Gordon

unread,
Sep 25, 2024, 12:32:08 PM9/25/24
to Chromium Extensions
Has anyone had success changing the action button icon using declarativeContent?

The api call is pretty weird:

chrome.declarativeContent.SetIcon({imageData:{}})

I would expect to just provide a string via chrome.runtime.getUrl(path-to-my-image), but instead you have this:

interface ImageData {
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/ImageData/colorSpace) */
readonly colorSpace: PredefinedColorSpace;
/**
* Returns the one-dimensional array containing the data in RGBA order, as integers in the range 0 to 255.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ImageData/data)
*/
readonly data: Uint8ClampedArray;
/**
* Returns the actual dimensions of the data in the ImageData object, in pixels.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ImageData/height)
*/
readonly height: number;
/**
* Returns the actual dimensions of the data in the ImageData object, in pixels.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/ImageData/width)
*/
readonly width: number;

Any ideas how to make this simpler?

John Gordon

unread,
Sep 25, 2024, 12:57:53 PM9/25/24
to Chromium Extensions, John Gordon
So, using the powers of ChatGPT (uh, oh), I managed to get this working in my service worker. Is this the best way, or is there something to do to improve it? My coding sensibilities are telling me this is pretty  low-level api stuff that I would've expected to be abstracted into a more coder-friendly method call.

async function loadImageDataFromPath(imagePath: string): Promise<ImageData> {
// Fetch the image from the URL
const response = await fetch(imagePath);

if (!response.ok) {
throw new Error('Failed to load image');
}

// Convert the response into a blob (binary large object)
const blob = await response.blob();

// Create an image bitmap from the blob
const bitmap = await createImageBitmap(blob);

// Create an offscreen canvas to handle the image rendering
const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
const ctx = canvas.getContext('2d');

if (!ctx) {
throw new Error('Failed to get canvas context');
}

// Draw the image onto the offscreen canvas
ctx.drawImage(bitmap, 0, 0);

// Extract and return the ImageData from the offscreen canvas
return ctx.getImageData(0, 0, canvas.width, canvas.height);
}

and how to use it:

const rule1 = {
conditions: createAllowedSitesConditions(allowedSites),
actions: [new chrome.declarativeContent.ShowAction(),new chrome.declarativeContent.SetIcon({imageData})]

woxxom

unread,
Sep 25, 2024, 2:52:22 PM9/25/24
to Chromium Extensions, John Gordon
The declarativeContent API is unfairly abandoned, which is why there's no support for a simple path of the icon, so indeed this method is exactly how a raster image (like PNG/JPG) should be used here, but it won't work for SVG, because a service worker has no DOM to parse it. For SVG you'd need to use the offscreen document API with an "img" element to load the image and probably "canvas" element instead of OffscreenCanvas to paint it, then use navigator.serviceWorker messaging to pass the result back to the service worker as shown in https://stackoverflow.com/a/77427098.
Reply all
Reply to author
Forward
0 new messages