我将此 SVG 文件与 此字体的 TTF 文件放在同一目录中。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="150"
height="100"
viewBox="0 0 150 100"
>
<style type="text/css">
@font-face {
font-family: "easyPrint";
src: url('./easy-print.regular.ttf');
}
</style>
<text
x="10"
y="30"
class="word"
font-family="easyPrint"
font-size="25"
>
TEST
</text>
<text
x="10"
y="80"
font-size="25"
>
TEST
</text>
</svg>
当我这样做时,我得到两种不同的字体。应该是我的自定义字体的字体与您在字体系列中给它乱码时看到的字体相同。这与默认值不同。
我也尝试过使用 OTF 文件。具体字体并不重要。我只是想生成一堆具有特定字体的文本 SVG 图像。
如果您需要独立的 svg 文件,
您应该考虑将字体文件嵌入为 base64 资源(使用像 transfonter 这样的工具):
只要您的应用程序支持 CSS,此 svg 就会显示自定义字体(内联 svg,在 img 元素中引用,直接在浏览器中打开)。
<p>(Letter "a" is not contained in the reduced character subset)</p>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 100">
<style>
@font-face {
font-family: 'easyPrint';
src: url('data:font/woff2;charset=utf-8;base64,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') format('woff2');
font-weight: normal;
}
</style>
<text
x="10"
y="30"
class="word"
font-family="easyPrint"
font-size="25"
>
TESTa
</text>
</svg>
您可以通过对字体进行子集化来显着减小文件大小:
仅选定的角色可用。
如果您正在部署 google 字体,您也可以尝试 vecta 的 nano 优化器,它具有非常需要的公开可用的 google 字体的自动嵌入功能。
此方法需要将字体内联为 dataURL。
否则 png 输出将呈现默认字体,如 Times。
function svg2Png(selector) {
const svgEl = document.querySelector(selector);
let svgVB = svgEl.getAttribute('viewBox');
let svgVBArr = svgVB ? svgVB.split(' ') : '';
let svgVBW = svgVBArr ? svgVBArr[2] : '';
let svgVBH = svgVBArr ? svgVBArr[3] : '';
let svgClientBB = svgEl.getBoundingClientRect();
let svgClientW = svgClientBB.width;
let svgClientH = svgClientBB.height;
let svgBB = svgEl.getBBox();
let svgW = svgVBW? svgVBW : svgBB.width;
svgW = svgClientW > svgW ? svgClientW : svgW;
let svgH = svgVBH? svgVBH : svgBB.height;
svgH = svgClientH > svgH ? svgClientH : svgH;
let blob = new Blob([svgEl.outerHTML], {type: 'image/svg+xml'});
let URL = window.URL;
let blobURL = URL.createObjectURL(blob);
let tmpImg = new Image();
tmpImg.src = blobURL;
tmpImg.width = svgClientW > svgW ? svgClientW : svgW;
tmpImg.height = svgClientH > svgH ? svgClientH : svgH;
tmpImg.onload = () => {
let canvas = document.createElement("canvas");
canvas.width = svgW;
canvas.height = svgH;
let context = canvas.getContext("2d");
// draw blob img to canvas with some delay
setTimeout(function () {
context.drawImage(tmpImg, 0, 0, svgW, svgH);
let pngDataUrl = canvas.toDataURL();
let svgImg = document.createElement("img");
svgImg.width = svgW;
svgImg.height = svgH;
svgImg.class = "svgImg";
svgImg.src = pngDataUrl;
// just additional wrapping for example usage
let imgWrp = document.createElement("div");
imgWrp.setAttribute("class", "img-wrp");
imgWrp.appendChild(svgImg);
document.body.appendChild(imgWrp);
}, 300);
};
}
svg,
img{
border:1px solid #ccc
}
.svg-wrp{
position:relative;
overflow:auto;
resize:both;
width:50%;
}
<div class="btn-wrp">
<button type="button" onclick="svg2Png('svg')">svg2Png</button>
</div>
<div class="svg-wrp">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 100">
<style>
@font-face {
font-family: 'easyPrint';
src: url('data:font/woff2;charset=utf-8;base64,d09GMgABAAAAAAYUAA4AAAAAC0wAAAXAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhYGYABECAQRCAqKIIgGCxIAATYCJAMgBCAFhwcHNQwHGygJyJ4HmZuXZhUqTbxanGnLj376P+3PzAUjVjd+SqMCXLtQtvBXumS8oL8eJSLhdr9lQUSRFVpAgWWWaJbkWViR/9cssN//fq3u4nXb0nQaGhqHtKVTypv7bd6KeEI0qoSKh0jIolG7JVon5MxhngW9XAo/R/8YIAAiAAAADEEYCJl7aAdQAO/4LgBs0e5HN/iCATCqQfNFPlS51E6DMpIZLf2fZ14r4MXNUfzJcwAkW5qVBAAtAqI9JK9myQAGzFab8Q9d06/sespbamysvLmgALVg3K0EQAF0AaAXFCJntmm0v4KggVz1fq9AychZAsXP3/y6sPmYLgIhbZjfZA9v0obhldQwhHQRV2yzLiJc00U2uOx552vHNzKkykf10WiBPuN1Q+yINRq9PjuGJvTR15QaFTbjcJH/8TBkalFeQdabGDkas4lmq4dmhhIeixDzy0ORnqKWBLMcIBQ3hsMIJmLVftN+tFZcf7wvdsD7T/cDOjcrafblgKVdtDFAbawj+4LaPgg50hiGV9gci6lqZWdnT6Sjd+n3S1LPT0RPt2O2pWy/c2Sy30dTQJQUdNljx10nxp/VRY5ZirtGdwpCN3n+uDmJjglhZBK3FhvDAKA7NmONEpuPIS9NCJsjEDqXm0rMfgtN6HKUiTujg1blZpvKViLzbkczN3YiVsCGtWCjjm56hN8UNu71w+JA70m8mhba6zUdAqi+CqG4pAwsa1Mf1SeH/Q+t329JcsnPpcfnPA5H6zS1tNk5Y16OaDyqrFhu9Ikaxzzo3gwPOipjOl+rb5r74rHVsRly7QNh0jeZGrH5In2BET01tWomou8wxKgd1SPHfVDeQXnlgXErXqeZv2mfQ6P2dtC+qaPenZQ94eS166w24xxBTqMpiF3r3XlkdapJsmXMI6ZSmKIVmGAx1wjDD+4kUM2szbbaubVWx9zH1XUOCIR4//mlU62B97yVaoad8qtaRVIPeFc/9TYmGZpsb+NZjZ2aTvhNlOwCJ689Isr/LCY45brFOvVWkRvkxOBNiBtT9/7R+MQpeEJOORph6jwlLZ3xv2CdHZhJJrbNvOPIPXwZq0mq9c5N/B1BfeY9PNlUXKg3CcaXNjG+T/btfe7Qi2L2k4E3Z6lG7wY26kW7nLD9882ja9SiZYBhn32Po9dI1vKiVGte8Mmf+9+p+AKGyo3XWQrsOxk8l8QHtfkB1TF4dQVZ77uoIdXKPp0nr5/FjCSSVa1K+cMfi3gH+YE+ZelFlaGgLOvnCp+onqG8bm0zs4qqtxX0WmUOJ2vIUGkQQ3CY09RnUDSUjWo1xblWFMi1Tj6R6soetJxczeAp6MPbqSsIJkfNycRsAAAABAAB/XfxmcWKol9ZgfgCAODdp24d9e+3/J7aSygAgIVrRImppNu8ek5gwzGAGDez6QZLfgFoBfChjz7BmxfAn18TEOBDBiAAAGAACAJQhh5kTgkgJTuICeHZCWNkEsEtm0hqy4iiMEg0ldXEkgsTh3WYeCanD8n69AVlq+ouAho4AKjzMEmINgJh8mQQYV7cRLJnPVHSc4Zo1jxJrNR8TRxlMcTzl+GwjByvbFHhcVXjWMh+Mn/TKVB+5kDLrQHjyVjrq3t4Tjbc8RuPS/1SgVQVklguWOLPd/t87uPDHSjr/Lzm9foybagG0+6+ZkZ7S2X/ypFg/cDj1zdMz5Sqh5cGB8qD//nHcbj1qCOOPD4ZavRr0ULSaqV+kila9BuwUtBS3SRLBa0gqeR1jwmqtFwHp2fCPC2q8wPG6iqKuZcEDZqmRZsh3ZbqVwllXnfkdT9X6NXe18kFpJpHJd4G/eV++dx8fNz8vPx8VGjWjAIdvJZqub2hTN+qvZmbyD12hnYtKvXrEXK63oBm2HSL6TLHHxhepcKA8tZnZ+rVq6Lloy1jK7VYsd5IJTBj0v9Xg18Xq4rgQJ4n3CdHblVOu4n+X3uR3AoAAAA=') format('woff2');
font-weight: normal;
}
</style>
<text
x="10"
y="30"
class="word"
font-family="easyPrint"
font-size="25"
>
TEST
</text>
</svg>
</div>
此示例部署 opentype.js 库。
Opentype.js 有一个方便的功能
font.getPath()
允许您根据之前加载的字体文件将字符串渲染为 svg <path>
元素。
let svgcontainer = document.querySelector('#svgcontainer');
let inputText = document.querySelector('#inputText');
// opentype.js accepts only ttf and otf
let fontFile = 'https://fonts.gstatic.com/s/firasans/v15/va9E4kDNxMZdWfMOD5Vvl4jO.ttf';
inputText.addEventListener('change', function(e) {
let testString = e.currentTarget.value;
let params = {
string: testString,
font: fontFile,
fontSize: 100,
x: 0,
y: 0,
decimals: 3
}
text2Path(params)
})
//default
let params = {
string: inputText.value,
font: fontFile,
fontSize: 100,
x: 0,
y: 0,
decimals: 3
}
text2Path(params)
function text2Path(params) {
opentype.load(params.font, function(err, font) {
if (!err) {
let options = params.options;
let path = font.getPath(params.string, params.x, params.fontSize, params.fontSize, options);
let textPath = path.toSVG(params.decimals);
let newSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
newSvg.classList.add('svgText');
newSvg.setAttribute('xmlns', "http://www.w3.org/2000/svg");
newSvg.insertAdjacentHTML('beforeend', textPath);
svgcontainer.appendChild(newSvg);
// adjust bbox
let bb = newSvg.getBBox();
newSvg.setAttribute('viewBox', '0 0 ' + (bb.width + bb.x) + ' ' + (params.fontSize * 1.5));
//add downloadbtn
let btnDownload = document.createElement("a");
btnDownload.setAttribute('download', 'font-' + params.string + '.svg');
btnDownload.textContent = 'Download';
let dataURl = getDataUrl(newSvg.outerHTML, 'image/svg+xml');
btnDownload.href = dataURl;
svgcontainer.appendChild(btnDownload)
} else {
console.log('Font could not be loaded: ' + err);
}
});
}
function getDataUrl(str, mime) {
let dataUrl = 'data:' + mime + ';base64,' + btoa(unescape(encodeURIComponent(str)))
return dataUrl;
}
.svgText {
height: 10em;
display: inline-block;
border: 1px solid #ccc;
}
a {
display: block
}
<script src="https://cdn.jsdelivr.net/npm/opentype.js@latest/dist/opentype.min.js"></script>
<div class="layout">
<div class="frm-wrp">
<input id="inputText" type="text" value="Test">
</div>
<div class="svgcontainer" id="svgcontainer"></div>
</div>
这可能是最方便的解决方案。
<text>
元素并将它们转换为路径:SVG 不会自动包含/嵌入所有使用的字体!
如前所述:应用程序是否可以处理嵌入字体很大程度上取决于其CSS 支持。
大多数图像查看器都会失败。
通常,即使您使用 inkscape 等高级编辑器,这也根本不起作用。通常桌面应用程序依赖于基于系统的字体管理,因此它们无法以可编辑模式访问嵌入的字体子集。
您也可以尝试在浏览器中将 svg 转换为 pdf,并在打开时将所有字体转换为路径轮廓。
Inkskape(免费且开源)有一个“绘制所有文本”的选项。 (另请参阅这篇文章)。