如何使用Javascript将FontAwesome呈现为SVG图像?

6

我想使用Javascript动态地将FontAwesome图标呈现为SVG,并将其作为图像源提供。我希望我的输出类似于这样:

output

PS - 我会自己画圆圈,只需要一种渲染图标的方法。

到目前为止,我尝试了以下方法:

function addSVG() {

  var ele = document.getElementById("svg");

  var svg = `<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">
        <text x="4" y="15" style="font-family: FontAwesome" fill="red">&#xf007;</text>
    </svg>`

  var output = 'data:image/svg+xml;base64,' + btoa(svg)

  ele.src = output;
}
addSVG()
<head>
  <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet">
</head>

<body>
What it should look like:
  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20">
    <text x="4" y="15" style="font-family: FontAwesome" fill="red">&#xf007;</text>
  </svg>
What it looks like:
  <img id="svg">
</body>

正如您所见,如果没有使用Javascript(只是在HTML中使用SVG),它可以正常工作。

Font Awesome的哪个版本(从CDN引用看起来像是4.4)?你已经查看过这个了吗?https://fontawesome.com/how-to-use/on-the-web/setup/getting-started?using=svg-with-js - Tieson T.
1
是的,Font Awesome 的哪个版本会对答案产生很大影响。Font Awesome 5 内置了渲染 SVG 图标的方法,因此 v5 的方法可能与仅限于 v4 的方法非常不同。我想知道是否有必要将其实现为 <img src= ... >,或者您的最终目标只是在背景圆上获得 svg 图标的结果。如果是后者,则在 v5 中有更直接的方法。 - mwilkerson
4个回答

4

为什么需要在img标签中使用它?SVG就是一种图片!你不需要把它放到其他地方。

也许我不知道你的某些想法,但我认为这只是你的一个坏主意。

我的建议:直接将SVG与font-awesome图标放入HTML中:

您从中受益的好处:所有现代浏览器都支持它,没有像img标签或背景图片那样的限制。

var divSvg = document.getElementById('svg'),
    pics =
    {
        user: {col: '00a', icon: 'f007'},
        home: {col: '08c', icon: 'f015'},
        folder: {col: '88f', icon: 'f07c'},
        gear: {col: '5a0', icon: 'f013'},
        flag: {col: '05a', icon: 'f024'},
        leaf: {col: '080', icon: 'f06c'}
    },
    svg =
'<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32">\
    <text x="4" y="24" fill="COLOR" style="font:24px FontAwesome;cursor:pointer">PIC</text>\
</svg>';

for(var title in pics)
{
    var newSVG = svg.replace('PIC', '&#x'+pics[title].icon+';');
    //we put it in "B" tag to have a title because IE
    //does not support title attribute and title tag in SVG
    divSvg.innerHTML += '<b title="' + title + '">' +
                    newSVG.replace('COLOR', '#'+pics[title].col) + '</b>';
}

divSvg.onclick = function(e)
{
    if(e.target.tagName == 'text')
    {
        document.getElementById('output').innerHTML = 'Was clicked on ' +
                                // we take title from "B" tag:
                                e.target.parentNode.parentNode.title;

        /* if you need you can use:
        switch(e.target.parentNode.parentNode.title)
        {
            case 'user': alert('Here some procedure with user');
            case ...     YOUR CODE
            and so on... YOUR CODE
        }*/
    }
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet">
<div id="svg"></div><br>
<div id="output">Please click on any icon.</div>


将SVG直接嵌入HTML的缺点是,为了兼容性,您必须将整个页面的内容作为XHTML提供,而XHTML的语义略有不同且更严格,这可能会破坏页面的其他部分,如果标签没有明确关闭等。 - Patrick Roberts
@Bharata 对我来说是一个有趣且有帮助的回答。 - Alexandr_TT

3
当在XML中引用外部CSS样式表时,无法使用<img>元素。您需要使用像这个答案建议的<object>元素,并添加一个<?xml-stylesheet?>处理指令,以便SVG + XML blob能够找到FontAwesome字形对应HTML实体&#xf007;

function addSVG() {
  var ele = document.getElementById("svg");
  var svg = `
    <?xml-stylesheet type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"?>
    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20">
        <text x="4" y="15" style="font-family: FontAwesome" fill="red">&#xf007;</text>
    </svg>`
  var output = `data:image/svg+xml;utf8,${svg}`

  ele.type = 'image/svg+xml';
  ele.data = output;
}
addSVG()
<head>
  <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet">
</head>

<body>
  What it should look like:
  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20">
    <text x="4" y="15" style="font-family: FontAwesome" fill="red">&#xf007;</text>
  </svg> What it looks like:
  <object id="svg"></object>
</body>


1

您不需要将数据转换为base64。我认为SVG语法中没有任何“疯狂”的字符,因此可以安全使用。

将编码设置为UTF-8,并将<svg>放入其中:

'data:image/svg+xml;utf8,<svg ... > ... </svg>'

0

如评论所述,您首先应该尝试找到一个 SVG 代码库(也可以在这里描述:"从 Font Awesome 提取 SVG")。

SVG 不会自动嵌入任何字体

但是,您实际上可以创建一个包含所使用字体的 自包含 SVG。

  1. 从类似于 https://www.cdnpkg.com 的 CDN 中找到下载 URL
  2. 下载字体
  3. 使用像 transfonter 这样的工具创建一个带有数据 URL 字体源的 @font-face - 您还可以指定要包含的仅为所需字形/字符的子集

Example1: 带有嵌入字体的 SVG

  <h3>Stand alone SVG</h3>
  
  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
    <style>
@font-face {
    font-family: 'FontAwesome';
    src: url('data:font/woff2;charset=utf-8;base64,d09GMgABAAAAAAM4AAwAAAAAB2gAAALqAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhYGYAA8EQgKgSSBPAsMAAE2AiQDFAQgBYhrBzEbnwYRFZyXyH4mZG5HaVZSDpHqn35J3i05r0RQv/bv95yFezfArIE9ADhgtnGpCJuKfy6EnwC3ImZ83+V4KEOEam9MHNuyfeD+rdGUZSQB4P///XqeNSAFvAH8vjMZWDZWidXLI3GaevlggiVGAQ/4AH4S/INug74YVWXlpRcTaANIQsiFrJwV1xXkl/M4CyabdhEXgbfZfmDnLgz4sVGqUQoIAAwQSMjQRSbQRW4ESrmQYjvqGqSz/qT9f9TnRF1LoACtkGMCFgNykAApzwc0l7Q91Gb/ofYHDh1/1arDxdfjxBuooPWl13SXFIIP8ffJV5dfP/XGlQ+2tSgGtDSK60o3lSx1av//4q8+IOz9DcuNXXYvNoSrdzM3Dp9SzRg1Pzg96uxpkmnGaoqVOTFn5sW8uSDu7IupH37IXRsI5FFuu798x5r2k39rtm6Ah/PugOfvzf6w/u7/r6qq7ISmBIIWXVqpv6vrqiL/m1Bkx22HtIhooTiOQJF6Gg4SQmA6gB4xTADGI0BobbwAScNEATLdzRAg19lSAQqdbBKgjIeGeY6gqY0nqLTyNlrr6tP17fTzVybyCquju47QLfYgaReXkBkXN5AbFndRGBLf5ZcwGm4laOqRbqPSJT1Ea6PSB13tTM6qmRIA2/IbdDiyos/KyhZezlkv/9WHnje0rD6Y6LLvgHF0pSwJqJdwvmfRUSjZyYExUKzGSV+2BCQcNsUVRvbDMORKxzpxr2HFn2xJVxKzqIvKsizj6iI7JqO4Wnavr6rBQadXur+uZ5th/JmqKC1t+Q06cJ/9yHPcUNGqbSmGRky3gMC8kan90NvVBzJ0OKN4tWxyHkaWFNawhMvxfItReuI7NFVIJwWKz3fqsOrYggXl5udOsoM4uAS1TrTgadPuzgcTXpeXkGy/NpyhY9MQW2uqxysFXk8m9xPScjxThMjUfUNlirXjUuu8CznOuFQ1hLLrtiRf0Av0HKMvjkUtkfLdDQA=') format('woff2');
    font-weight: normal;
    font-style: normal;
    font-display: swap;
}

    </style>
    <circle cx="50%" cy="50%" r="50%" fill="red"/>
    <text x="4" y="15" style="font-family: FontAwesome" fill="white">&#xf007;</text>
  </svg>


  <h3>Img with SVG data URL</h3>

<img src="data:image/svg+xml, %3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cstyle%3E%0A@font-face %7B font-family: 'FontAwesome'; src: url('data:font/woff2;charset=utf-8;base64,d09GMgABAAAAAAM4AAwAAAAAB2gAAALqAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhYGYAA8EQgKgSSBPAsMAAE2AiQDFAQgBYhrBzEbnwYRFZyXyH4mZG5HaVZSDpHqn35J3i05r0RQv/bv95yFezfArIE9ADhgtnGpCJuKfy6EnwC3ImZ83+V4KEOEam9MHNuyfeD+rdGUZSQB4P///XqeNSAFvAH8vjMZWDZWidXLI3GaevlggiVGAQ/4AH4S/INug74YVWXlpRcTaANIQsiFrJwV1xXkl/M4CyabdhEXgbfZfmDnLgz4sVGqUQoIAAwQSMjQRSbQRW4ESrmQYjvqGqSz/qT9f9TnRF1LoACtkGMCFgNykAApzwc0l7Q91Gb/ofYHDh1/1arDxdfjxBuooPWl13SXFIIP8ffJV5dfP/XGlQ+2tSgGtDSK60o3lSx1av//4q8+IOz9DcuNXXYvNoSrdzM3Dp9SzRg1Pzg96uxpkmnGaoqVOTFn5sW8uSDu7IupH37IXRsI5FFuu798x5r2k39rtm6Ah/PugOfvzf6w/u7/r6qq7ISmBIIWXVqpv6vrqiL/m1Bkx22HtIhooTiOQJF6Gg4SQmA6gB4xTADGI0BobbwAScNEATLdzRAg19lSAQqdbBKgjIeGeY6gqY0nqLTyNlrr6tP17fTzVybyCquju47QLfYgaReXkBkXN5AbFndRGBLf5ZcwGm4laOqRbqPSJT1Ea6PSB13tTM6qmRIA2/IbdDiyos/KyhZezlkv/9WHnje0rD6Y6LLvgHF0pSwJqJdwvmfRUSjZyYExUKzGSV+2BCQcNsUVRvbDMORKxzpxr2HFn2xJVxKzqIvKsizj6iI7JqO4Wnavr6rBQadXur+uZ5th/JmqKC1t+Q06cJ/9yHPcUNGqbSmGRky3gMC8kan90NvVBzJ0OKN4tWxyHkaWFNawhMvxfItReuI7NFVIJwWKz3fqsOrYggXl5udOsoM4uAS1TrTgadPuzgcTXpeXkGy/NpyhY9MQW2uqxysFXk8m9xPScjxThMjUfUNlirXjUuu8CznOuFQ1hLLrtiRf0Av0HKMvjkUtkfLdDQA=') format('woff2'); font-weight: normal; font-style: normal; font-display: swap;%0A%7D %3C/style%3E%3Ccircle cx='50%25' cy='50%25' r='50%25' fill='red'/%3E%3Ctext x='4' y='15' style='font-family: FontAwesome' fill='white'%3E&%23xf007;%3C/text%3E%3C/svg%3E" alt="">

数据 URL 也可以用作 css 背景图像。

将图标字体转换为 svg <path>

您还可以获取一个 fontAwesome 字体文件,并使用 opentype.js 将其转换为 svg。

这样,您的新图标也可以在图形应用程序中进行编辑,例如 inkscape、Adobe Illustrator 等。

示例 2:转换图标字体

// absolute URL to fontFile
let fontURL =
  "https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/fonts/fontawesome-webfont.woff2";

// font awesome character as entity
let text = decodeHtmlEntity("&#xf007;");

// define size and padding
let fontSize = 100;
let padding = 15;
let iconColor = '#fff';
let bgColor = 'red';

/**
* load font
* convert to svg pathdata
*/
(async () => {
  let font = await loadFont(fontURL);
  
  // get font metrics for positioning and scaling
  let unitsPerEm = font.unitsPerEm;
  let ratio = fontSize / unitsPerEm;
  let ascender = font.ascender;
  let glyph = font.stringToGlyphs(text)[0];
  let bb = glyph.getBoundingBox();
  let xOff = (fontSize - bb.x2 * ratio) / 2;

  // get pathdata
  let width = fontSize + padding;
  let height = fontSize + padding;
  let pathD = font
    .getPath(text, xOff + padding / 2, ascender * ratio + padding / 2, fontSize)
    .toPathData();

  let ns = "http://www.w3.org/2000/svg";
  let svg = document.createElementNS(ns, "svg");
  let circle = document.createElementNS(ns, "circle");
  let path = document.createElementNS(ns, "path");
  //svg.setAttribute('viewBox', `0 0 ${+width.toFixed(3)} ${fontSize}` );
  svg.setAttribute(
    "viewBox",
    `0 0 ${width} ${height}`
  );
  svg.setAttribute("width", width);
  svg.setAttribute("height", height);
  circle.setAttribute("cx", "50%");
  circle.setAttribute("cy", "50%");
  circle.setAttribute("r", "50%");
  circle.setAttribute("fill", bgColor);
  path.setAttribute("d", pathD);
  path.setAttribute("fill", iconColor);
  svg.append(circle);
  svg.append(path);
  preview.append(svg);

  // create dataURL
  let dataURl =
    "data:image/svg+xml, " +
    new XMLSerializer()
      .serializeToString(svg)
      .replaceAll('"', "'")
      .replaceAll("#", "%23");
  imgData.src = dataURl;
})();

/**
 * opentype.js helper
 * Based on @yne's comment
 * https://github.com/opentypejs/opentype.js/issues/183#issuecomment-1147228025
 * will decompress woff2 files
 */
async function loadFont(src, options = {}) {
  let buffer = {};
  let font = {};
  let ext = "woff2";
  let url;

  // 1. is file
  if (src instanceof Object) {
    // get file extension to skip woff2 decompression
    let filename = src.name.split(".");
    ext = filename[filename.length - 1];
    buffer = await src.arrayBuffer();
  }

  // 2. is base64 data URI
  else if (/^data/.test(src)) {
    // is base64
    let data = src.split(";");
    ext = data[0].split("/")[1];

    // create buffer from blob
    let srcBlob = await (await fetch(src)).blob();
    buffer = await srcBlob.arrayBuffer();
  }

  // 3. is url
  else {
    // if google font css - retrieve font src
    if (/googleapis.com/.test(src)) {
      ext = "woff2";
      src = await getGoogleFontUrl(src, options);
    }

    // might be subset - no extension
    let hasExt =
      src.includes(".woff2") ||
      src.includes(".woff") ||
      src.includes(".ttf") ||
      src.includes(".otf")
        ? true
        : false;
    url = src.split(".");
    ext = hasExt ? url[url.length - 1] : "woff2";

    let fetchedSrc = await fetch(src);
    buffer = await fetchedSrc.arrayBuffer();
  }

  // decompress woff2
  if (ext === "woff2") {
    buffer = Uint8Array.from(Module.decompress(buffer)).buffer;
  }

  // parse font
  font = opentype.parse(buffer);
  return font;
}

function decodeHtmlEntity(str) {
  let txt = document.createElement("p");
  txt.innerHTML = str;
  str = txt.textContent;
  txt.remove();
  return str;
}
svg{
  border: 1px solid #ccc;
  width:20em;
  height:auto;
}

img{
  border: 1px solid #ccc;
  width:20em;
}
<h3>SVG</h3>
<div id="preview"></div>
<h3>Img</h3>
<img id="imgData" src="">


<script src="https://unpkg.com/wawoff2@2.0.1/build/decompress_binding.js"></script>
<script src='https://cdn.jsdelivr.net/npm/opentype.js@latest/dist/opentype.min.js'></script>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接