I need to render font awesome image using canvas drawImage(). The drawImage accept image argument:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage#image An element to draw into the context. The specification permits any canvas image source, specifically, an HTMLImageElement, an SVGImageElement, an HTMLVideoElement, an HTMLCanvasElement, an ImageBitmap, an OffscreenCanvas, or a VideoFrame.
I found the svg file from Font Awesome repository. For example: https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/svgs/solid/calendar.svg
So here is my working code:
const context = document.getElementById("myCanvas").getContext('2d');
const image = new Image();
image.src = `https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/svgs/solid/calendar.svg`;
image.onload = function(){
context.drawImage(image, 0, 0, 100, 100);
};
<canvas id="myCanvas" width="200" height="100"
style="border:1px solid #000000;">
But the svg file has a black color with white background. I want to change the color and the background font awesome icon before rendering. How can I do that? Here is my current attempt. Currently it has this error: DOMException: The source image could not be decoded.
and I don't think my current approach will work anyway...
const context = document.getElementById("myCanvas").getContext('2d');
modifyAndDraw(
`https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/svgs/solid/calendar.svg`,
context
);
async function modifyAndDraw(iconUrl, ctx) {
try {
const svgText = await fetchData(iconUrl);
const modifiedSvgText = modifySvgContent(svgText, '#ff0000', '#00ff00');
const imageBitmap = await createImageBitmap(
new Blob([modifiedSvgText], { type: 'image/svg+xml;charset=utf-8' })
);
ctx.drawImage(imageBitmap, 0, 0, 100, 100);
} catch (error) {
console.error('Error:', error);
}
};
async function fetchData(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch data from ${url}`);
}
return response.text();
};
async function modifySvgContent(svgText, fillColor, backgroundColor) {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(svgText, 'image/svg+xml');
const svgElement = xmlDoc.documentElement;
// Change fill color
svgElement.querySelectorAll('[fill]').forEach((element) => {
element.setAttribute('fill', fillColor);
});
// Add background color
svgElement.setAttribute('style', `background-color: ${backgroundColor}`);
return new XMLSerializer().serializeToString(svgElement);
};
<canvas id="myCanvas" width="200" height="100"
style="border:1px solid #000000;">
Using createImageBitmap
directly with a Blob containing the modified SVG data should work, but looks like there is some issue with decoding the SVG data when using this method.
You can try using the Image
object with a data URL to decode and render the SVG data correctly.
const context = document.getElementById("myCanvas").getContext('2d');
modifyAndDraw(
`https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/svgs/solid/calendar.svg`,
context
);
async function modifyAndDraw(iconUrl, ctx) {
try {
const svgText = await fetchData(iconUrl);
const modifiedSvgText = modifySvgContent(svgText, '#ff0000', '#00ff00');
const image = new Image(); // <--- Notice here
image.src = `data:image/svg+xml;charset=utf-8, ${encodeURIComponent(modifiedSvgText)}`;
image.onload = function() {
ctx.drawImage(image, 0, 0, 100, 100);
};
} catch (error) {
console.error('Error:', error);
}
};
async function fetchData(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch data from ${url}`);
}
return response.text();
};
function modifySvgContent(svgText, fillColor, backgroundColor) {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(svgText, 'image/svg+xml');
const svgElement = xmlDoc.documentElement;
const styleElement = xmlDoc.createElementNS('http://www.w3.org/2000/svg', 'style');
styleElement.textContent = `path { fill: ${fillColor}; }`;
svgElement.insertBefore(styleElement, svgElement.firstChild);
// Add background color
svgElement.setAttribute('style', `background-color: ${backgroundColor}`);
return new XMLSerializer().serializeToString(svgElement);
};
<canvas id="myCanvas" width="200" height="100" style="border:1px solid #000000;">
</canvas>