爱上你好超模 發表於 2022-5-11 10:50:00

如何使用 Javascript 将图标字体渲染为图片

<h1 id="前言">前言</h1>
<p>在软件开发中肯定要用到图标,比如下图的 Groove 音乐中就用到了许多图标。一种获取这些图标的方法是把 Groove 音乐截个图,然后熟练地开启 Photoshop,开始抠图。这种方式很逊,效率也很低(<s>虽然我刚开始就是这么干的</s>)。</p>
<p><img src="https://img2022.cnblogs.com/blog/2065884/202205/2065884-20220511093922699-1821774870.png" alt="Groove" loading="lazy"></p>
<p>如果打开 C:/Program Files/WindowsApps(需要修改权限才能进入),可以发现几个名字里带 <code>ZuneMusic</code> 的文件夹,其中的某一个文件夹中会有字体文件 SegMVR2.ttf。这是一个图标字体文件,双击安装之后,打开 Windows 自带的字符映射表应用,将字体换为 Segoe MVR MDL2 Assets,可以看到里面的字符其实就是图标。其实可以用 Metro Studio 将这些字体导出为 png、svg 等格式的图片,但是 Metro Studio 导出的字符看起来很细,也无法分别控制上下和左右的内边距,所以这里改用 Javascript 操作 canvas 绘制图标,然后导出为 png。</p>
<p><img src="https://img2022.cnblogs.com/blog/2065884/202205/2065884-20220511100059545-1769593360.png" alt="字符映射表" loading="lazy"></p>
<h1 id="实现方式">实现方式</h1>
<p>在 CodePen 上已经有人给出了将 Microsoft 开源的 Fabric UI Icon 渲染为 png 图片的 demo,效果很不错。阅读源代码之后可以发现,他在 <code>getFontIconCharacter()</code> 先创建了一个临时的元素,根据想要的图标的名字设置元素的 className,获取<code>::before </code>伪元素的 content 中字符的 Unicode,接着在 <code>drawIcon()</code> 中使用 <code>context.fillText()</code> 方法绘制字符,最后 <code>canvas.toDataURL()</code> 就能将 canvas 的内容转换为 base64 格式的图片。</p>
<p>可以看到,对于自定义的的字体,我们只需知道字符的 Unicode,就能实现导出功能。</p>
<h2 id="html">html</h2>
<p>html 和 coepen 中的几乎完全一样,唯一不同的地方就是将 <code>font-class</code> 换成了 <code>font-unicode</code>,因为我们只有字符的 unicode。</p>
<pre><code class="language-html">&lt;html&gt;

&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    &lt;link rel="stylesheet" type="text/css" href="index.css"&gt;
    &lt;title&gt;iconfont to png&lt;/title&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;div class="ms-Grid" dir="ltr"&gt;
      &lt;h1 class="ms-font-su"&gt;Render Office Fabric UI Icons into Canvas&lt;/h1&gt;
      &lt;p&gt;This is a simple tool to render an icon from the &lt;a class="ms-fontColor-blueLight"
                href="https://developer.microsoft.com/en-us/fabric#/styles/icons"&gt;Office Fabric UI icon font&lt;/a&gt; into an
            HTML &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; with a background color. Right-click and save the image to use it.&lt;/p&gt;
      &lt;div class="ms-Grid-row"&gt;
            &lt;div class="ms-Grid-col ms-sm12 ms-lg6"&gt;
                &lt;h2 class="ms-font-xxl"&gt;Icon/Canvas Specifications&lt;/h2&gt;
                &lt;form id="form"&gt;
                  &lt;div class="ms-Grid"&gt;
                        &lt;div class="ms-Grid-row"&gt;
                            &lt;div class="ms-Grid-col ms-md6"&gt;
                              &lt;label for="font-unicode"&gt;Icon unicode&lt;/label&gt;
                              &lt;input type="text" name="fontClass" id="font-unicode"
                                    placeholder="e.g. ms-Icon ms-Icon-Warning" value="E768"&gt;
                            &lt;/div&gt;
                            &lt;div class="ms-Grid-col ms-md6"&gt;
                              &lt;label for="font-size"&gt;Font size (px)&lt;/label&gt;
                              &lt;input type="number" step="1" min="1" name="fontSize" id="font-size"
                                    placeholder="e.g. 60" value="56"&gt;
                            &lt;/div&gt;
                        &lt;/div&gt;
                        &lt;div class="ms-Grid-row"&gt;
                            &lt;div class="ms-Grid-col ms-md6"&gt;
                              &lt;label for="image-width"&gt;Image width (px)&lt;/label&gt;
                              &lt;input type="number" step="1" min="0" name="imageWidth" id="image-width"
                                    placeholder="e.g. 80" value="92"&gt;
                            &lt;/div&gt;
                            &lt;div class="ms-Grid-col ms-md6"&gt;
                              &lt;label for="image-height"&gt;Image height (px)&lt;/label&gt;
                              &lt;input type="number" step="1" min="0" name="imageHeight" id="image-height"
                                    placeholder="e.g. 80" value="92"&gt;
                            &lt;/div&gt;
                        &lt;/div&gt;
                        &lt;div class="ms-Grid-row"&gt;
                            &lt;div class="ms-Grid-col ms-md6"&gt;
                              &lt;label for="left-offset"&gt;Left offset&lt;/label&gt;
                              &lt;input type="number" step="1" name="leftOffset" id="left-offset" placeholder="e.g. 40"
                                    value="46"&gt;
                            &lt;/div&gt;
                            &lt;div class="ms-Grid-col ms-md6"&gt;
                              &lt;label for="top-offset"&gt;Top offset&lt;/label&gt;
                              &lt;input type="number" step="1" name="topOffset" id="top-offset" placeholder="e.g. 40"
                                    value="46"&gt;
                            &lt;/div&gt;
                        &lt;/div&gt;
                        &lt;div class="ms-Grid-row"&gt;
                            &lt;div class="ms-Grid-col ms-md6"&gt;
                              &lt;label for="bg-color"&gt;Background color&lt;/label&gt;
                              &lt;input type="text" name="bgColor" id="bg-color" placeholder="e.g. #777777"
                                    value=#777777&gt;
                            &lt;/div&gt;
                            &lt;div class="ms-Grid-col ms-md6"&gt;
                              &lt;label for="icon-color"&gt;Icon color&lt;/label&gt;
                              &lt;input type="text" name="iconColor" id="icon-color" placeholder="e.g. #FFFFFF"
                                    value=#FFFFFF&gt;
                            &lt;/div&gt;
                        &lt;/div&gt;
                        &lt;div class="ms-Grid-row"&gt;
                            &lt;div class="ms-Grid-col ms-sm12"&gt;
                              &lt;label&gt;&lt;input type="checkbox" checked name="shape" id="shape"&gt; Use a circle as the
                                    background fill&lt;/label&gt;
                            &lt;/div&gt;
                        &lt;/div&gt;
                  &lt;/div&gt;

                  &lt;input type="submit"
                        class="ms-button ms-bgColor-themeDark ms-bgColor-themeDarker--hover ms-fontColor-white"
                        value="Render Font Icon"&gt;

                  &lt;p&gt;If the icon does not render immediately, wait a few seconds and press the &lt;b&gt;Render&lt;/b&gt; button
                        again; the webfont may still be loading.&lt;/p&gt;

                &lt;/form&gt;
            &lt;/div&gt;
            &lt;div class="ms-Grid-col ms-sm12 ms-lg6"&gt;
                &lt;h2 class="ms-font-xxl"&gt;Result&lt;/h2&gt;

                &lt;div class="canvas-container"&gt;
                  &lt;canvas id="canvas" width="92" height="92"&gt;&lt;/canvas&gt;
                &lt;/div&gt;

                &lt;p&gt;&lt;a id="download-link"
                        class="ms-button ms-bgColor-themeDark ms-bgColor-themeDarker--hover ms-fontColor-white"
                        target="_blank"&gt;&lt;i class="ms-Icon ms-Icon--Download"&gt;&lt;/i&gt; Download the image&lt;/a&gt;&lt;/p&gt;
                &lt;label for="dataURL"&gt;Data URL&lt;/label&gt;
                &lt;input id="dataURL" type="text"&gt;
            &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;script src="index.js"&gt;&lt;/script&gt;

&lt;/html&gt;
</code></pre>
<h2 id="css">css</h2>
<p>与 codepen 中的代码相比,这里只是多了一个 <code>@font-face</code> 声明要使用的字体。图标的下载地址在 蓝奏云,密码为 <code>abcr</code>。</p>
<pre><code class="language-css">@import url(https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/11.0.0/css/fabric.min.css);

@font-face {
    font-family: 'Segoe MVR MDL2 Assets';
    src: url('SegoeMVRMDL2Assets.ttf') format('truetype');
    font-weight: normal;
    font-style: normal;
}

html {
    box-sizing: border-box;
}

*,
*:before,
*:after {
    box-sizing: inherit;
}

body {
    font-family: "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif;
    background-color: #0078d4;
    color: white;
}

.ms-Grid {
    margin: 0 auto;
    padding: 0 16px;
    max-width: 1280px;
}

.ms-Grid-row {
    margin-left: -16px;
    margin-right: -16px;
}

.ms-Grid-col {
    padding: 0 16px;
}

label {
    display: block;
    margin-bottom: 0.5em;
}

input {
    border: none;
    display: block;
    margin-bottom: 2em;
    padding: 5px;
    width: 100%;
    font-size: 16px;
}

input {
    display: inline-block;
    padding: 0;
    width: auto;
}

input,
input,
.ms-button {
    cursor: pointer;
    display: inline-block;
    padding: 0.75em 2em;
    text-decoration: none;
    width: auto;

}

.ms-button .ms-Icon {
    transform: translateY(2px);
}

.canvas-container {
    background-color: white;
    display: inline-block;
    margin-bottom: 1em;
    padding: 10px;
    width: auto;
}

#canvas {
    color: black;
    font-family: FabricMDL2Icons;
}
</code></pre>
<h2 id="js">js</h2>
<p>这里我们主要修改了 <code>getFontIconCharacter()</code> 函数,直接根据输入框的内容返回字符的 Unicode。</p>
<pre><code class="language-js">const form = document.getElementById("form");
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
const download = document.getElementById("download-link");
const dataURL = document.getElementById("dataURL");
const fontFamily = "Segoe MVR MDL2 Assets";

function getFontIconCharacter(unicode) {
    return String.fromCharCode(parseInt(unicode, 16));
}

function drawCircle() {
    var centerX = canvas.width / 2;
    var centerY = canvas.height / 2;
    var radius = canvas.width / 2;
    context.beginPath();
    context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
    context.fillStyle = document.getElementById("bg-color").value || "#777777";
    context.fill();
}

function drawRect() {
    context.fillStyle = document.getElementById("bg-color").value || "#777777";
    context.fillRect(0, 0, canvas.width, canvas.height);
}

function drawIcon() {
    canvas.width = parseInt(document.getElementById("image-width").value, 10) || 92;
    canvas.height = parseInt(document.getElementById("image-height").value, 10) || 92;
    context.clearRect(0, 0, canvas.width, canvas.height);
    if (document.getElementById("shape").checked) {
      drawCircle();
    } else {
      drawRect();
    }
    context.fillStyle = document.getElementById("icon-color").value || "#FFFFFF";
    let fontUnicode = document.getElementById("font-unicode").value,
      fontSize = document.getElementById("font-size").value || 280,
      topOffset = document.getElementById("top-offset").value || 210,
      leftOffset = document.getElementById("left-offset").value || 210;
    context.font = `${fontSize}px ${fontFamily}`;
    context.textAlign = "center";
    context.textBaseline = "middle";
    context.fillText(getFontIconCharacter(fontUnicode), parseInt(leftOffset, 10), parseInt(topOffset, 10));
    dataURL.value = canvas.toDataURL();

}

window.addEventListener('load', function () {
    drawIcon();
});

document.addEventListener('DOMContentLoaded', function () {
    context.font = "10px " + fontFamily;
    context.fillText("...", 0, 0);
});

form.addEventListener("submit", function (event) {
    event.preventDefault();
    drawIcon();
});

download.addEventListener("click", function (event) {
    if (typeof this.download !== "undefined") {
      this.href = canvas.toDataURL();
      this.download = `${document.getElementById("font-unicode").value}.png`;
    } else {
      event.preventDefault();
      alert("Your browser does not support downloading a canvas image. Please right-click on the image to save it.");
    }
});

dataURL.addEventListener("focus", function (event) {
    dataURL.select();
});
</code></pre>
<h2 id="效果">效果</h2>
<p>打开 html 之后如下图所示,只需修改 <code>Icon unicode</code>,再点击 <code>Render Font Icon</code> 按钮,就能在右侧的画布中看到图标,点击 <code>Download the image</code> 按钮就能下载图标了。</p>
<p><img src="https://img2022.cnblogs.com/blog/2065884/202205/2065884-20220511103616681-532630548.png" alt="效果" loading="lazy"></p><br><br>
来源:https://www.cnblogs.com/zhiyiYo/p/16257021.html
頁: [1]
查看完整版本: 如何使用 Javascript 将图标字体渲染为图片