我需要使用画布drawImage()渲染字体很棒的图像。 drawImage 接受图像参数:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage#image 要绘制到上下文中的元素。该规范允许任何画布图像源,特别是 HTMLImageElement、SVGImageElement、HTMLVideoElement、HTMLCanvasElement、ImageBitmap、OffscreenCanvas 或 VideoFrame。
我从 Font Awesome 存储库找到了 svg 文件。例如: https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/svgs/solid/calendar.svg
这是我的工作代码:
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;">
但是 svg 文件是黑色白色背景的。我想在渲染之前更改颜色和背景字体很棒的图标。我怎样才能做到这一点?这是我目前的尝试。目前它有这个错误:
DOMException: The source image could not be decoded.
而且我认为我当前的方法无论如何都不会起作用......
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;">
直接将
createImageBitmap
与包含修改后的 SVG 数据的 Blob 一起使用应该可行,但看起来使用此方法时解码 SVG 数据存在一些问题。
您可以尝试使用带有数据 URL 的
Image
对象来正确解码和渲染 SVG 数据。
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>
Font Awesome SVG 没有指定任何
fill
,因此尝试更改它们是行不通的。
对于具有单个
<path>
的 SVG,您只需将所需的填充颜色注入文本即可。
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) {
const svgText = await fetchData(iconUrl);
const modifiedSvgText = svgText.replace('<path ', '<path fill="purple" ');
const blob = new Blob([modifiedSvgText], {
type: 'image/svg+xml;charset=utf-8'
});
const image = await loadImage(URL.createObjectURL(blob));
ctx.fillStyle = "orange";
ctx.fillRect(0, 0, 100, 100);
ctx.drawImage(image, 0, 0, 100, 100);
};
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 loadImage(url) {
return new Promise((resolve) => {
const img = new Image();
img.src = url;
img.onload = () => resolve(img);
});
}
<canvas id="myCanvas" width="200" height="200" style="border:1px solid #000000;">