Chr*_*s M 5 javascript svg fabricjs opentype-svg-font
我使用 FabricJS 允许用户在浏览器中设计 SVG。当我想要保存时,我尝试使用 OpenType JS 将文本框 (Fabric) 转换为使用 OpenType 的 SVG 路径。
我看到的问题是我的文本框的位置没有转换为添加到画布的新路径。
和
当我将新路径添加到画布,然后调用 toSVG() 时,它会在我保存的结果 SVG 中消失。
代码:
async function convertTextToPaths() {
ungroup();
var _all = canvas.getObjects();
for(i=0;i<_all.length;i++) {
var activeObject = _all[i];
if(activeObject.type=="textbox") {
const font = await opentype.load('fonts/'+activeObject.fontFamily+'.ttf');
debugger;
console.log(activeObject.type, activeObject.left, activeObject.top+activeObject.height, activeObject.fontSize);
const path = font.getPath(activeObject.text, activeObject.left, activeObject.top+activeObject.height, activeObject.fontSize);
const outlinetextpath = new fabric.Path(path.toPathData(3));
activeObject.dirty=true;
canvas.remove(activeObject);
canvas.insertAt(outlinetextpath,2);
canvas.renderAll();
}
}
}
Run Code Online (Sandbox Code Playgroud)
有任何意义或者有人可以分享一些想法吗?
谢谢
您需要根据字体的指标计算一些缩放因子/比率,以实现适当的垂直对齐。
\n调用font.getPath(string, x, y, fontSize)将“绘制”一条从下到上的路径:
示例:在 x=500, y=250
\n 处绘制文本元素(画布大小:1000\xc3\x97500px;字体系列:Fira Sans;字体大小:100px;)
Fabric.js
\nlet activeObject = new fabric.Textbox(\'Hamburg\', {\n left: 500,\n top: 250,\n fontFamily: \'Fira Sans\',\n fontSize: 100\n});\nRun Code Online (Sandbox Code Playgroud)\nopentype.js
\nfont.getPath(\'Hamburg\', 500, 250, 100)\nRun Code Online (Sandbox Code Playgroud)\n\n红色:opentype.js 路径;黑色:织物生成的文本框
\n左:top: 250
\n右:object.top+object.height
opentype.js 生成的元素使用字体的基线作为参考点垂直对齐到 250 像素。
\n而fabric.jstextBox根据元素的顶部(边界框)y 坐标来对齐元素。
(由于内容安全策略,下载功能将无法在 SO 上运行)
\nlet activeObject = new fabric.Textbox(\'Hamburg\', {\n left: 500,\n top: 250,\n fontFamily: \'Fira Sans\',\n fontSize: 100\n});\nRun Code Online (Sandbox Code Playgroud)\r\nfont.getPath(\'Hamburg\', 500, 250, 100)\nRun Code Online (Sandbox Code Playgroud)\r\nconst canvas = new fabric.Canvas("canvas");\nconst fontFileUrl = \'https://fonts.gstatic.com/s/firasans/v16/va9E4kDNxMZdWfMOD5Vvl4jO.ttf\';\nconst [textBoxX, textBoxY] = [500, 250];\nconst fontName = "Fira Sans";\nconst fontWeight = 400;\nconst fontSizeCanvas = 100;\nconst textboxString = "Hamburg";\nconst btnDownload = document.querySelector(\'.btn-download\')\n\n\nconvertTextToPaths();\nasync function convertTextToPaths() {\n //parse font file with opentype.js\n const font = await opentype.load(fontFileUrl);\n\n //draw textbox on canvas\n let activeObject = new fabric.Textbox(textboxString, {\n left: textBoxX,\n top: textBoxY,\n fontFamily: fontName,\n fontWeight: fontWeight,\n fontSize: fontSizeCanvas\n });\n canvas.add(activeObject);\n\n // get properties of fabric.js object\n let [type, string, fontSize] = [activeObject.type, activeObject.text, activeObject.fontSize];\n let [left, top, height, width] = [activeObject.left, activeObject.top, activeObject.height, activeObject\n .width\n ];\n\n /**\n * Get metrics and ratios from font\n * to calculate absolute offset values according to font size \n */\n let unitsPerEm = font.unitsPerEm;\n let ratio = fontSize / unitsPerEm;\n // font.descender is a negative value - hence Math.abs()\n let [ascender, descender] = [font.ascender, Math.abs(font.descender)];\n let ascenderAbs = Math.ceil(ascender * ratio);\n let descenderAbs = Math.ceil(descender * ratio);\n let lineHeight = (ascender + descender) * ratio;\n\n /**\n * calculate difference between font path bounding box and \n * canvas bbox (including line height)\n */\n let font2CanvasRatio = 1 / lineHeight * height\n let baselineY = top + ascenderAbs * font2CanvasRatio;\n\n // Create path object from font\n path = font.getPath(string, left, baselineY, fontSize);\n //path = font.getPath(string, left, top, fontSize);\n let pathData = path.toPathData();\n // render on canvas\n const outlinetextpath = new fabric.Path(pathData, {\n fill: \'red\'\n });\n canvas.add(outlinetextpath);\n\n\n //optional: just for illustration: render center and baseline\n canvas.add(new fabric.Line([0, 250, 1000, 250], {\n stroke: \'red\'\n }));\n canvas.add(new fabric.Line([0, baselineY, 1000, baselineY], {\n stroke: \'purple\'\n }));\n\n\n // Download/export svg\n upDateSVGExport(canvas);\n canvas.on(\'object:modified\', function(e) {\n //console.log(\'changed\')\n upDateSVGExport(canvas);\n });\n\n}\n\nfunction upDateSVGExport(canvas) {\n let svgOut = canvas.toSVG();\n let svgbase64 = \'data:image/svg+xml;base64,\' + btoa(svgOut);\n btnDownload.href = svgbase64;\n}Run Code Online (Sandbox Code Playgroud)\r\n本质上,我们需要将 Fabrics.js 对象渲染的高度testBox与基于字体规格的理想渲染边界进行比较。
\n首先我们需要获得一些比率来将字体单位转换为像素。
\n最重要的是,我们需要计算一个比率/因子,将相对字体度量值转换为绝对字体大小相关像素值:
1. 字体规格:字体大小与字体单位的比率
\nletunitsPerEm = font.unitsPerEm;\nletratio = fontSize /unitsPerEm;
大多数网络字体的 value 为 1000unitsPerEm。
\n但是,传统的 truetype 字体(因此没有特别针对 Web 使用进行优化)通常每个 em 使用 2048 个单位。
2. 字体规格:上升和下降
\n// font.descender is a negative value - hence Math.abs()\nlet [ascender, descender] = [font.ascender, Math.abs(font.descender)];\nlet ascenderAbs = Math.ceil(ascender * ratio);\nlet descenderAbs = Math.ceil(descender * ratio);\nlet lineHeight = (ascender + descender) * ratio;\nRun Code Online (Sandbox Code Playgroud)\n关于字体的指标,理想的 bBox 的高度为
\n(ascender + descender) * FontSize2unitsPerEmRatio。
3. 字体规格到画布坐标
\nFabric.js bBox 稍大 \xe2\x80\x93 因此我们需要比较它们的高度以获得完美的缩放因子。
\nlet font2CanvasRatio = 1 / lineHeight * height \nRun Code Online (Sandbox Code Playgroud)\n现在我们在使用时得到正确的 y 偏移getPath()
let baselineY = top + ascenderAbs * font2CanvasRatio;\npath = font.getPath(string, left, baselineY, fontSize);\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
1201 次 |
| 最近记录: |