admin管理员组

文章数量:1291121

I want to render a FontAwesome icon as an SVG dynamically provide it as an image source using Javascript. I want my output to be something like this

PS - I will draw the circle myself. Just need a way to render the icon.

So far, I have tried this approach:

function addSVG() {

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

  var svg = `<svg xmlns="" 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=".4.0/css/font-awesome.min.css" rel="stylesheet">
</head>

<body>
What it should look like:
  <svg xmlns="" 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>

I want to render a FontAwesome icon as an SVG dynamically provide it as an image source using Javascript. I want my output to be something like this

PS - I will draw the circle myself. Just need a way to render the icon.

So far, I have tried this approach:

function addSVG() {

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

  var svg = `<svg xmlns="http://www.w3/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./font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet">
</head>

<body>
What it should look like:
  <svg xmlns="http://www.w3/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>

As you can see, without the Javascript (just using SVG in HTML) it works fine.

Share Improve this question edited Jul 5, 2018 at 19:19 Frame91 3,7998 gold badges47 silver badges95 bronze badges asked Jul 5, 2018 at 17:20 Janit MehtaJanit Mehta 1851 silver badge11 bronze badges 2
  • Which version of Font Awesome (looks like 4.4, from the CDN reference)? Have you reviewed this already? fontawesome./how-to-use/on-the-web/setup/… – Tieson T. Commented Jul 5, 2018 at 19:29
  • 1 Yes, the question of which version of Font Awesome would make a big difference on the answer. Font Awesome 5 has built in methods of rendering SVG icons, so the approach in v5 may be very different than if you were limited to v4. And I would wonder whether it's necessary to implement it as an <img src= ... > or if your ultimate goal is simply to get the oute of an svg icon over a background circle. If the latter, then there are much more straightforward approaches in v5. – mwilkerson Commented Jul 6, 2018 at 4:04
Add a ment  | 

4 Answers 4

Reset to default 4

Why do you need it in img tag? SVG is an image! You do not need it to put in something else.

May be I do not know something from you, but I think this is just a bad idea from you.

My suggestion: put SVG in HTML with font-awesome icons directly:

Your benefit from this: all modern browsers support it without any limits like in img tags or as background image.

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/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./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>

You can't use an <img> element when referencing an external CSS stylesheet from XML. You need to use an <object> element like this answer remends, and prepend an <?xml-stylesheet?> processing instruction in order for the SVG+XML blob to be able to find the FontAwesome glyph for the HTML entity &#xf007;.

function addSVG() {
  var ele = document.getElementById("svg");
  var svg = `
    <?xml-stylesheet type="text/css" href="https://maxcdn.bootstrapcdn./font-awesome/4.4.0/css/font-awesome.min.css"?>
    <svg xmlns="http://www.w3/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./font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet">
</head>

<body>
  What it should look like:
  <svg xmlns="http://www.w3/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>

You don't need to convert the data into base64. I think the SVG syntax doesn't have any "crazy" characters in it, so it's safe to use.

Set the encoding to UTF-8, and drop the <svg> in there:

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

As mented you should first try to find a svg repository (Also described her: "Extracting SVG from Font Awesome".

SVG won't embed any fonts automatically

However you could actually create a self contained svg including the used font.

  1. Find download URL e.g from a cdn like https://www.cdnpkg.
  2. Download the font
  3. Create a @font-face with a data URL font source via a tool like transfonter - you can also specify a subset to include only the needed glyphs/characters

Example1: svg with embedded font

  <h3>Stand alone SVG</h3>
  
  <svg xmlns="http://www.w3/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/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="">

The data URL can also be used as css background-image.

Convert icon font to svg <path>

You can also fetch a fontAwesome font file and convert it to a svg using opentype.js.

This way your new icon can also be edited in a graphic application like inkscape, Adobe Illustrator etc.

Example 2: convert icon font

// absolute URL to fontFile
let fontURL =
  "https://maxcdn.bootstrapcdn./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/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 ment
 * https://github./opentypejs/opentype.js/issues/183#issuement-1147228025
 * will depress 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 depression
    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./.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();
  }

  // depress woff2
  if (ext === "woff2") {
    buffer = Uint8Array.from(Module.depress(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./[email protected]/build/depress_binding.js"></script>
<script src='https://cdn.jsdelivr/npm/opentype.js@latest/dist/opentype.min.js'></script>

本文标签: htmlHow to render FontAwesome as SVG Image using JavascriptStack Overflow