canvas drawImage() 渲染 Font Awesome 图标

问题描述 投票:0回答:2

我需要使用画布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;">

javascript canvas font-awesome drawimage
2个回答
0
投票

直接将

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>


0
投票

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;">

© www.soinside.com 2019 - 2024. All rights reserved.