如何将文本转换为 SVG 路径?

发布于 2024-12-09 14:32:26 字数 158 浏览 1 评论 0原文

我在 ttf 文件中有一个字体,想要生成 SVG,并将文本转换为路径。我不需要图像(因此使用 imagettftext 或 Image Magick 字体渲染功能是不够的),我需要可以放大和缩小的形状,我想丢失有关所使用字体的信息,并且不想在中引用它SVG 文件(因此此处不能使用字体声明)。是否可以?

I have a font in ttf file and want to generate SVG with text turned into paths. I don't need image (so using imagettftext or Image Magick font rendering capabilities is not enough), I need shape, that can be scaled up and down and I want to lose information about font used and don't want to reference it in SVG file (so font-face declarations can't be used here). Is it possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

⊕婉儿 2024-12-16 14:32:27

运行 Inkscape。输入您的文字。单击菜单>路径>对象到路径。

单击另存为...并选择纯 SVG 格式。

Run Inkscape. Enter your text. Click Menu > Path > Object to Path.

Click Save As... and choose the plain SVG format.

你穿错了嫁妆 2024-12-16 14:32:27

在四四方方的 SVG 3.28 中
选择文本然后进入菜单:形状> 为路径形状

文本将转换

,每个字形现在都是给定字体/字体的可编辑矢量形状David Spector 的 Inkscape 答案是我最近使用的答案

in Boxy SVG 3.28
Select text then go into menu: Shape > Shape to Path

the text will convert and each glyph is now an editable vector shape from the given typeface/font

David Spector's Inkscape answer is the one I use more recently

蓝戈者 2024-12-16 14:32:27

如果您可以获得 svgfont,那么您就拥有了使用字形路径渲染它的所有信息(将所需的所有字形路径数据复制粘贴到任意数量的路径元素,然后应用翻转 y 变换并将其缩放到任何大小)您需要的尺寸)。 Batik 有一个名为 ttf2svg 的工具,它可以为您提供 svgfont 输出。还有其他的,例如 fontforge

不确定是否有任何纯命令行工具可以直接生成这样的 svg,但 Inkscape 解决方案应该完全符合您的要求。

If you can get an svgfont out then you have all the information there to render it using the glyph paths (copy-paste all the glyph path data you need to any number of path elements and apply a flip-y transform and scale it to whatever size you need). Batik has a tool called ttf2svg, which gives you svgfont output. There are others as well, fontforge for example.

Not sure if there are any pure command-line tools out there that can generate an svg like this directly, but the Inkscape solution should do exactly what you want.

抚你发端 2024-12-16 14:32:27

Javascript 和 php 方法

如果您为用户使用基于 Web 的 GUI,您也可以选择 JS/php 混合方法:

  • 字体解析是通过 opentype.js
  • 文件保存到服务器是通过 JS 获取请求将 SVG 标记发送到简单的 php 脚本

客户端/JS 部分

默认 opentype 来完成的。 js支持.woff.ttfotf
woff2 需要 wawoff2 库来进行 brotli 解压缩。

let fonturl = 'https://fonts.gstatic.com/s/firasans/v16/va9E4kDNxMZdWfMOD5Vvl4jL.woff2';
let text = 'Hamburgefonsle';
let ext = fonturl.split(".").splice(-1)[0];

//init
(async() => {
  let buffer = await (await fetch(fonturl)).arrayBuffer();

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

  // parse
  let font = opentype.parse(buffer);

  // get svg
  renderText(svg, font, text, 48);
})();



function renderText(svg, font, text, fontSize = 48) {

  // get baseline position and line height respecting descenders
  let {
    ascender,
    descender,
    unitsPerEm
  } = font;
  let scale = fontSize / unitsPerEm;
  let baseline = fontSize * (ascender / unitsPerEm);
  let lineHeight = (ascender + Math.abs(descender)) * scale;

  // get first left sidebearing for a horizontally tight bounding box
  let firstGlyph = font.stringToGlyphs(text.substring(0, 1))[0];
  let leftSB = firstGlyph.leftSideBearing * scale;

  // 1. get path data
  let pathOT = font.getPath(text, -leftSB, baseline, fontSize);

  // get bounding box
  let bb = pathOT.getBoundingBox();
  let width = bb.x2 - bb.x1;

  // round to integers
  [width, lineHeight] = [width, lineHeight].map(val => {
    return Math.ceil(val)
  })

  // get svg path data and render
  let d = pathOT.toPathData(1);
  path.setAttribute("d", d);

  // adjust viewBox
  svg.setAttribute('viewBox', [0, 0, width, lineHeight].join(' '))
  svg.setAttribute('width', width + 'px');
  svg.setAttribute('height', lineHeight + 'px');

}
svg {
  outline: 1px solid #ccc;
}
<h3>Preview</h3>
<div id="preview">
  <svg id="svg" xmlns="http://www.w3.org/2000/svg">
    <path id="path" />
  </svg>
</div>

<!-- decompress woff2 -->
<script src="https://unpkg.com/[email protected]/build/decompress_binding.js"></script>

<!-- load opentype.js -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/opentype.min.js"></script>

opentype.js 中创建 SVG 路径数据的核心函数是 font.getPath()

let path = font.getPath(text, x, y, fontSize);

通过php保存到服务器

显然,我们不能只用JS将静态文件保存到服务器。由于 SVG 是基于 XML 文本的,我们可以将 JS 生成的 SVG 发送到接收 SVG 标记的相当简单的 php 脚本。确保包含更多安全措施以避免各种上传!

php/save_json.php

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {

    // Get the raw POST data
    $postData = file_get_contents("php://input");

    // Decode the JSON data
    $data = json_decode($postData, true);

    // Extract the SVG string and file name
    if (!isset($data['content']) && $data['filename']) {
        exit();
    }
    $content = $data['content'];
    $fileName = $data['filename'];

    /**
     * super duper basic "security"
     * don't allow extensions other than .svg
     * content must contain svg and path
     * must not contain script elements
     */
    $ext = pathinfo($fileName)['extension'];
    // wrong extension
    if ($ext !== 'svg') exit();

    // not SVG markup: no svg or path tag
    if (strpos($content, '<svg') === false || strpos($content, '</svg>') === false || strpos($content, '<path') === false ) exit();

    // has scripts
    if (strpos($content, '<script') !== false) exit();

    // save to server
    file_put_contents($fileName, $content);
} 

JS 获取函数

async function saveSvgToServer(phpUrl, content = '', filename = '') {
    let data = {
        filename: filename,
        content: content
    }

    // save to server  
    let res = await fetch(phpUrl, {
        method: 'POST',
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify(data)
    });

}

在上面的代码片段中,我们将输出渲染到 SVG 元素。
这样我们就可以调整viewBox以满足文本的实际边界。在将标记发送到 php 脚本之前,我们需要使用 XMLSerializer().serializeToString(svg) 序列化/字符串化修改后的 SVG。
保存到服务器功能看起来像这样:

JS 保存按钮

// save to server
btnSave.onclick = async () => {
    let phpUrl = 'php/save_json.php'
    let markup = new XMLSerializer().serializeToString(svg);
    let filename = `../svg/font2svg.svg`;
    await saveSvgToServer(phpUrl, markup, filename);
};

Javascript and php approach

In case you're using a web based GUI for users you may also opt for a JS/php hybrid approach:

  • the font parsing is done client based via opentype.js
  • file saving to the server is done by a JS fetch request sending the SVG markup to a simple php script

Client-side/JS part

By default opentype.js supports .woff, .ttf, otf.
woff2 requires the wawoff2 library for brotli decompression.

let fonturl = 'https://fonts.gstatic.com/s/firasans/v16/va9E4kDNxMZdWfMOD5Vvl4jL.woff2';
let text = 'Hamburgefonsle';
let ext = fonturl.split(".").splice(-1)[0];

//init
(async() => {
  let buffer = await (await fetch(fonturl)).arrayBuffer();

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

  // parse
  let font = opentype.parse(buffer);

  // get svg
  renderText(svg, font, text, 48);
})();



function renderText(svg, font, text, fontSize = 48) {

  // get baseline position and line height respecting descenders
  let {
    ascender,
    descender,
    unitsPerEm
  } = font;
  let scale = fontSize / unitsPerEm;
  let baseline = fontSize * (ascender / unitsPerEm);
  let lineHeight = (ascender + Math.abs(descender)) * scale;

  // get first left sidebearing for a horizontally tight bounding box
  let firstGlyph = font.stringToGlyphs(text.substring(0, 1))[0];
  let leftSB = firstGlyph.leftSideBearing * scale;

  // 1. get path data
  let pathOT = font.getPath(text, -leftSB, baseline, fontSize);

  // get bounding box
  let bb = pathOT.getBoundingBox();
  let width = bb.x2 - bb.x1;

  // round to integers
  [width, lineHeight] = [width, lineHeight].map(val => {
    return Math.ceil(val)
  })

  // get svg path data and render
  let d = pathOT.toPathData(1);
  path.setAttribute("d", d);

  // adjust viewBox
  svg.setAttribute('viewBox', [0, 0, width, lineHeight].join(' '))
  svg.setAttribute('width', width + 'px');
  svg.setAttribute('height', lineHeight + 'px');

}
svg {
  outline: 1px solid #ccc;
}
<h3>Preview</h3>
<div id="preview">
  <svg id="svg" xmlns="http://www.w3.org/2000/svg">
    <path id="path" />
  </svg>
</div>

<!-- decompress woff2 -->
<script src="https://unpkg.com/[email protected]/build/decompress_binding.js"></script>

<!-- load opentype.js -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/opentype.min.js"></script>

The core function to create SVG path data in opentype.js is font.getPath()

let path = font.getPath(text, x, y, fontSize);

Save to server via php

Obviously, we can't save static files to a server with JS only. Since SVG is XML text based we can send the JS generated SVG to a rather simple php script receiving the SVG markup. Make sure to include more security measures to avoid all kinds of uploads!

php/save_json.php

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {

    // Get the raw POST data
    $postData = file_get_contents("php://input");

    // Decode the JSON data
    $data = json_decode($postData, true);

    // Extract the SVG string and file name
    if (!isset($data['content']) && $data['filename']) {
        exit();
    }
    $content = $data['content'];
    $fileName = $data['filename'];

    /**
     * super duper basic "security"
     * don't allow extensions other than .svg
     * content must contain svg and path
     * must not contain script elements
     */
    $ext = pathinfo($fileName)['extension'];
    // wrong extension
    if ($ext !== 'svg') exit();

    // not SVG markup: no svg or path tag
    if (strpos($content, '<svg') === false || strpos($content, '</svg>') === false || strpos($content, '<path') === false ) exit();

    // has scripts
    if (strpos($content, '<script') !== false) exit();

    // save to server
    file_put_contents($fileName, $content);
} 

JS fetch function

async function saveSvgToServer(phpUrl, content = '', filename = '') {
    let data = {
        filename: filename,
        content: content
    }

    // save to server  
    let res = await fetch(phpUrl, {
        method: 'POST',
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify(data)
    });

}

In the above snippet we were rendering the output to a SVG element.
This way we can adjust the viewBox to meet the actual boundaries of the text. Before sending the markup to the php script we need to serialize/stringify the modified SVG with XMLSerializer().serializeToString(svg).
The save-to-server function would look something like this:

JS save button

// save to server
btnSave.onclick = async () => {
    let phpUrl = 'php/save_json.php'
    let markup = new XMLSerializer().serializeToString(svg);
    let filename = `../svg/font2svg.svg`;
    await saveSvgToServer(phpUrl, markup, filename);
};
长安忆 2024-12-16 14:32:26

我创建了自己的类来处理 SVG 字体文件并将文本转换为字形。使用示例:

include "SVGFont.php";
$svgFont = new SVGFont();
$svgFont->load("/path/to/font.svg");
$result = $svgFont->textToPaths("Simple text", 20);

结果示例:

<g transform="scale(0.009765625) translate(0, 0)"><path transform="translate(0,0) rotate(180) scale(-1, 1)" d="M92 471l183 16q13 -110 60.5 -180.5t147.5 -114t225 -43.5q111 0 196 33t126.5 90.5t41.5 125.5q0 69 -40 120.5t-132 86.5q-59 23 -261 71.5t-283 91.5q-105 55 -156.5 136.5t-51.5 182.5q0 111 63 207.5t184 146.5t269 50q163 0 287.5 -52.5t191.5 -154.5t72 -231 l-186 -14q-15 139 -101.5 210t-255.5 71q-176 0 -256.5 -64.5t-80.5 -155.5q0 -79 57 -130q56 -51 292.5 -104.5t324.5 -93.5q128 -59 189 -149.5t61 -208.5q0 -117 -67 -220.5t-192.5 -161t-282.5 -57.5q-199 0 -333.5 58t-211 174.5t-80.5 263.5z" /><path transform="translate(1366,0) rotate(180) scale(-1, 1)" d="M136 0v1062h180v-1062h-180zM136 1259v207h180v-207h-180z" /><path transform="translate(1821,0) rotate(180) scale(-1, 1)" d="M135 0v1062h161v-149q50 78 133 125.5t189 47.5q118 0 193.5 -49t106.5 -137q126 186 328 186q158 0 243 -87.5t85 -269.5v-729h-179v669q0 108 -17.5 155.5t-63.5 76.5t-108 29q-112 0 -186 -74.5t-74 -238.5v-617h-180v690q0 120 -44 180t-144 60q-76 0 -140.5 -40 t-93.5 -117t-29 -222v-551h-180z" /><path transform="translate(3527,0) rotate(180) scale(-1, 1)" d="M135 -407v1469h164v-138q58 81 131 121.5t177 40.5q136 0 240 -70t157 -197.5t53 -279.5q0 -163 -58.5 -293.5t-170 -200t-234.5 -69.5q-90 0 -161.5 38t-117.5 96v-517h-180zM298 525q0 -205 83 -303t201 -98q120 0 205.5 101.5t85.5 314.5q0 203 -83.5 304t-199.5 101 q-115 0 -203.5 -107.5t-88.5 -312.5z" /><path transform="translate(4666,0) rotate(180) scale(-1, 1)" d="M131 0v1466h180v-1466h-180z" /><path transform="translate(5121,0) rotate(180) scale(-1, 1)" d="M75 522q0 268 138 416t358 148q213 0 348 -145t135 -408q0 -16 -1 -48h-792q10 -175 99 -268t222 -93q99 0 169 52t111 166l186 -23q-44 -163 -163 -253t-304 -90q-233 0 -369.5 143.5t-136.5 402.5zM271 633h593q-12 134 -68 201q-86 104 -223 104q-124 0 -208.5 -83 t-93.5 -222z" /><path transform="translate(6260,0) rotate(180) scale(-1, 1)" d="" /><path transform="translate(6829,0) rotate(180) scale(-1, 1)" d="M36 922v140h132v263l179 108v-371h181v-140h-181v-621q0 -77 9.5 -99t31 -35t61.5 -13q30 0 79 7l26 -159q-76 -16 -136 -16q-98 0 -152 31t-76 81.5t-22 212.5v611h-132z" /><path transform="translate(7398,0) rotate(180) scale(-1, 1)" d="M75 522q0 268 138 416t358 148q213 0 348 -145t135 -408q0 -16 -1 -48h-792q10 -175 99 -268t222 -93q99 0 169 52t111 166l186 -23q-44 -163 -163 -253t-304 -90q-233 0 -369.5 143.5t-136.5 402.5zM271 633h593q-12 134 -68 201q-86 104 -223 104q-124 0 -208.5 -83 t-93.5 -222z" /><path transform="translate(8537,0) rotate(180) scale(-1, 1)" d="M15 0l388 552l-359 510h225l163 -249q46 -71 74 -119q44 66 81 117l179 251h215l-367 -500l395 -562h-221l-218 330l-58 89l-279 -419h-218z" /><path transform="translate(9561,0) rotate(180) scale(-1, 1)" d="M36 922v140h132v263l179 108v-371h181v-140h-181v-621q0 -77 9.5 -99t31 -35t61.5 -13q30 0 79 7l26 -159q-76 -16 -136 -16q-98 0 -152 31t-76 81.5t-22 212.5v611h-132z" /></g>

我的班级代码:

<?php

/**
 * This class represents SVG pa
 * @author Łukasz Ledóchowski [email protected]
 * @version 0.1
 */
class SVGFont {

    protected $id = '';
    protected $horizAdvX = 0;
    protected $unitsPerEm = 0;
    protected $ascent = 0;
    protected $descent = 0;
    protected $glyphs = array();

    /**
     * Function takes UTF-8 encoded string and returns unicode number for every character.
     * Copied somewhere from internet, thanks.
     */
    function utf8ToUnicode( $str ) {
        $unicode = array();
        $values = array();
        $lookingFor = 1;

        for ($i = 0; $i < strlen( $str ); $i++ ) {
            $thisValue = ord( $str[ $i ] );
            if ( $thisValue < 128 ) $unicode[] = $thisValue;
            else {
                if ( count( $values ) == 0 ) $lookingFor = ( $thisValue < 224 ) ? 2 : 3;
                $values[] = $thisValue;
                if ( count( $values ) == $lookingFor ) {
                    $number = ( $lookingFor == 3 ) ?
                        ( ( $values[0] % 16 ) * 4096 ) + ( ( $values[1] % 64 ) * 64 ) + ( $values[2] % 64 ):
                        ( ( $values[0] % 32 ) * 64 ) + ( $values[1] % 64 );

                    $unicode[] = $number;
                    $values = array();
                    $lookingFor = 1;
                }
            }
        }

        return $unicode;
    }

    /**
     * Function takes path to SVG font (local path) and processes its xml
     * to get path representation of every character and additional
     * font parameters
     */
    public function load($filename) {
        $this->glyphs = array();
        $z = new XMLReader;
        $z->open($filename);

        // move to the first <product /> node
        while ($z->read()) {
            $name = $z->name;

            if ($z->nodeType == XMLReader::ELEMENT) {
                if ($name == 'font') {
                    $this->id = $z->getAttribute('id');
                    $this->horizAdvX = $z->getAttribute('horiz-adv-x');
                }

                if ($name == 'font-face') {
                    $this->unitsPerEm = $z->getAttribute('units-per-em');
                    $this->ascent = $z->getAttribute('ascent');
                    $this->descent = $z->getAttribute('descent');
                }

                if ($name == 'glyph') {
                    $unicode = $z->getAttribute('unicode');
                    $unicode = $this->utf8ToUnicode($unicode);
                    $unicode = $unicode[0];

                    $this->glyphs[$unicode] = new stdClass();
                    $this->glyphs[$unicode]->horizAdvX = $z->getAttribute('horiz-adv-x');
                    if (empty($this->glyphs[$unicode]->horizAdvX)) {
                        $this->glyphs[$unicode]->horizAdvX = $this->horizAdvX;
                    }
                    $this->glyphs[$unicode]->d = $z->getAttribute('d');
                }
            }
        }

    }

    /**
     * Function takes UTF-8 encoded string and size, returns xml for SVG paths representing this string.
     * @param string $text UTF-8 encoded text
     * @param int $asize size of requested text
     * @return string xml for text converted into SVG paths
     */
    public function textToPaths($text, $asize) {
        $lines = explode("\n", $text);
        $result = "";
        $horizAdvY = 0;
        foreach($lines as $text) {
            $text = $this->utf8ToUnicode($text);
            $size =  ((float)$asize) / $this->unitsPerEm;
            $result .= "<g transform=\"scale({$size}) translate(0, {$horizAdvY})\">";
            $horizAdvX = 0;
            for($i = 0; $i < count($text); $i++) {
                $letter = $text[$i];
                $result .= "<path transform=\"translate({$horizAdvX},{$horizAdvY}) rotate(180) scale(-1, 1)\" d=\"{$this->glyphs[$letter]->d}\" />";
                $horizAdvX += $this->glyphs[$letter]->horizAdvX;
            }
            $result .= "</g>";
            $horizAdvY += $this->ascent + $this->descent;
        }

        return $result;
    }
}

I have created my own class to process SVG font file and to turn text into glyphs. Example of using:

include "SVGFont.php";
$svgFont = new SVGFont();
$svgFont->load("/path/to/font.svg");
$result = $svgFont->textToPaths("Simple text", 20);

Example result:

<g transform="scale(0.009765625) translate(0, 0)"><path transform="translate(0,0) rotate(180) scale(-1, 1)" d="M92 471l183 16q13 -110 60.5 -180.5t147.5 -114t225 -43.5q111 0 196 33t126.5 90.5t41.5 125.5q0 69 -40 120.5t-132 86.5q-59 23 -261 71.5t-283 91.5q-105 55 -156.5 136.5t-51.5 182.5q0 111 63 207.5t184 146.5t269 50q163 0 287.5 -52.5t191.5 -154.5t72 -231 l-186 -14q-15 139 -101.5 210t-255.5 71q-176 0 -256.5 -64.5t-80.5 -155.5q0 -79 57 -130q56 -51 292.5 -104.5t324.5 -93.5q128 -59 189 -149.5t61 -208.5q0 -117 -67 -220.5t-192.5 -161t-282.5 -57.5q-199 0 -333.5 58t-211 174.5t-80.5 263.5z" /><path transform="translate(1366,0) rotate(180) scale(-1, 1)" d="M136 0v1062h180v-1062h-180zM136 1259v207h180v-207h-180z" /><path transform="translate(1821,0) rotate(180) scale(-1, 1)" d="M135 0v1062h161v-149q50 78 133 125.5t189 47.5q118 0 193.5 -49t106.5 -137q126 186 328 186q158 0 243 -87.5t85 -269.5v-729h-179v669q0 108 -17.5 155.5t-63.5 76.5t-108 29q-112 0 -186 -74.5t-74 -238.5v-617h-180v690q0 120 -44 180t-144 60q-76 0 -140.5 -40 t-93.5 -117t-29 -222v-551h-180z" /><path transform="translate(3527,0) rotate(180) scale(-1, 1)" d="M135 -407v1469h164v-138q58 81 131 121.5t177 40.5q136 0 240 -70t157 -197.5t53 -279.5q0 -163 -58.5 -293.5t-170 -200t-234.5 -69.5q-90 0 -161.5 38t-117.5 96v-517h-180zM298 525q0 -205 83 -303t201 -98q120 0 205.5 101.5t85.5 314.5q0 203 -83.5 304t-199.5 101 q-115 0 -203.5 -107.5t-88.5 -312.5z" /><path transform="translate(4666,0) rotate(180) scale(-1, 1)" d="M131 0v1466h180v-1466h-180z" /><path transform="translate(5121,0) rotate(180) scale(-1, 1)" d="M75 522q0 268 138 416t358 148q213 0 348 -145t135 -408q0 -16 -1 -48h-792q10 -175 99 -268t222 -93q99 0 169 52t111 166l186 -23q-44 -163 -163 -253t-304 -90q-233 0 -369.5 143.5t-136.5 402.5zM271 633h593q-12 134 -68 201q-86 104 -223 104q-124 0 -208.5 -83 t-93.5 -222z" /><path transform="translate(6260,0) rotate(180) scale(-1, 1)" d="" /><path transform="translate(6829,0) rotate(180) scale(-1, 1)" d="M36 922v140h132v263l179 108v-371h181v-140h-181v-621q0 -77 9.5 -99t31 -35t61.5 -13q30 0 79 7l26 -159q-76 -16 -136 -16q-98 0 -152 31t-76 81.5t-22 212.5v611h-132z" /><path transform="translate(7398,0) rotate(180) scale(-1, 1)" d="M75 522q0 268 138 416t358 148q213 0 348 -145t135 -408q0 -16 -1 -48h-792q10 -175 99 -268t222 -93q99 0 169 52t111 166l186 -23q-44 -163 -163 -253t-304 -90q-233 0 -369.5 143.5t-136.5 402.5zM271 633h593q-12 134 -68 201q-86 104 -223 104q-124 0 -208.5 -83 t-93.5 -222z" /><path transform="translate(8537,0) rotate(180) scale(-1, 1)" d="M15 0l388 552l-359 510h225l163 -249q46 -71 74 -119q44 66 81 117l179 251h215l-367 -500l395 -562h-221l-218 330l-58 89l-279 -419h-218z" /><path transform="translate(9561,0) rotate(180) scale(-1, 1)" d="M36 922v140h132v263l179 108v-371h181v-140h-181v-621q0 -77 9.5 -99t31 -35t61.5 -13q30 0 79 7l26 -159q-76 -16 -136 -16q-98 0 -152 31t-76 81.5t-22 212.5v611h-132z" /></g>

Code for my class:

<?php

/**
 * This class represents SVG pa
 * @author Łukasz Ledóchowski [email protected]
 * @version 0.1
 */
class SVGFont {

    protected $id = '';
    protected $horizAdvX = 0;
    protected $unitsPerEm = 0;
    protected $ascent = 0;
    protected $descent = 0;
    protected $glyphs = array();

    /**
     * Function takes UTF-8 encoded string and returns unicode number for every character.
     * Copied somewhere from internet, thanks.
     */
    function utf8ToUnicode( $str ) {
        $unicode = array();
        $values = array();
        $lookingFor = 1;

        for ($i = 0; $i < strlen( $str ); $i++ ) {
            $thisValue = ord( $str[ $i ] );
            if ( $thisValue < 128 ) $unicode[] = $thisValue;
            else {
                if ( count( $values ) == 0 ) $lookingFor = ( $thisValue < 224 ) ? 2 : 3;
                $values[] = $thisValue;
                if ( count( $values ) == $lookingFor ) {
                    $number = ( $lookingFor == 3 ) ?
                        ( ( $values[0] % 16 ) * 4096 ) + ( ( $values[1] % 64 ) * 64 ) + ( $values[2] % 64 ):
                        ( ( $values[0] % 32 ) * 64 ) + ( $values[1] % 64 );

                    $unicode[] = $number;
                    $values = array();
                    $lookingFor = 1;
                }
            }
        }

        return $unicode;
    }

    /**
     * Function takes path to SVG font (local path) and processes its xml
     * to get path representation of every character and additional
     * font parameters
     */
    public function load($filename) {
        $this->glyphs = array();
        $z = new XMLReader;
        $z->open($filename);

        // move to the first <product /> node
        while ($z->read()) {
            $name = $z->name;

            if ($z->nodeType == XMLReader::ELEMENT) {
                if ($name == 'font') {
                    $this->id = $z->getAttribute('id');
                    $this->horizAdvX = $z->getAttribute('horiz-adv-x');
                }

                if ($name == 'font-face') {
                    $this->unitsPerEm = $z->getAttribute('units-per-em');
                    $this->ascent = $z->getAttribute('ascent');
                    $this->descent = $z->getAttribute('descent');
                }

                if ($name == 'glyph') {
                    $unicode = $z->getAttribute('unicode');
                    $unicode = $this->utf8ToUnicode($unicode);
                    $unicode = $unicode[0];

                    $this->glyphs[$unicode] = new stdClass();
                    $this->glyphs[$unicode]->horizAdvX = $z->getAttribute('horiz-adv-x');
                    if (empty($this->glyphs[$unicode]->horizAdvX)) {
                        $this->glyphs[$unicode]->horizAdvX = $this->horizAdvX;
                    }
                    $this->glyphs[$unicode]->d = $z->getAttribute('d');
                }
            }
        }

    }

    /**
     * Function takes UTF-8 encoded string and size, returns xml for SVG paths representing this string.
     * @param string $text UTF-8 encoded text
     * @param int $asize size of requested text
     * @return string xml for text converted into SVG paths
     */
    public function textToPaths($text, $asize) {
        $lines = explode("\n", $text);
        $result = "";
        $horizAdvY = 0;
        foreach($lines as $text) {
            $text = $this->utf8ToUnicode($text);
            $size =  ((float)$asize) / $this->unitsPerEm;
            $result .= "<g transform=\"scale({$size}) translate(0, {$horizAdvY})\">";
            $horizAdvX = 0;
            for($i = 0; $i < count($text); $i++) {
                $letter = $text[$i];
                $result .= "<path transform=\"translate({$horizAdvX},{$horizAdvY}) rotate(180) scale(-1, 1)\" d=\"{$this->glyphs[$letter]->d}\" />";
                $horizAdvX += $this->glyphs[$letter]->horizAdvX;
            }
            $result .= "</g>";
            $horizAdvY += $this->ascent + $this->descent;
        }

        return $result;
    }
}
¢蛋碎的人ぎ生 2024-12-16 14:32:26

解决方法是使用 inkscape(在将 SVG 文档保存到 file.txt 后通过 exec 执行它)。 svg)。在 inkscape 0.49+ 中,您可以只需传递 --export-to-svg--export-text-to-path,如下所示:

$ inkscape file_text.svg --export-text-to-path --export-plain-svg file_shapes.svg

在 inkscape 中0.49,您可以手动编写 inkscape 脚本(请注意,这需要 X 服务器):

$ inkscape --with-gui --verb EditSelectAll --verb ObjectToPath --verb FileSave \
           --verb FileQuit file.svg

A workaround is using inkscape (execute it via exec or so after saving the SVG document to file.svg). In inkscape 0.49+, you can simply pass --export-to-svg and --export-text-to-path, like this:

$ inkscape file_text.svg --export-text-to-path --export-plain-svg file_shapes.svg

In inkscape < 0.49, you can manually script inkscape (note that this requires an X server):

$ inkscape --with-gui --verb EditSelectAll --verb ObjectToPath --verb FileSave \
           --verb FileQuit file.svg
陪你到最终 2024-12-16 14:32:26

我刚刚根据你的库编写了一个 PHP 库,它可以操作字体数据(来自 SVG 文件)并对其进行任何类型的转换。您可以从 GitHub 尝试一下:

https://github.com/kartsims/easysvg

使用示例:

require 'easySVG.php';
$svg = new EasySVG();
$svg->setFont("paris-bold-webfont.svg", 100, "#000000");
$svg->addText("Simple text display");
$svg->addAttribute("width", "800px");
$svg->addAttribute("height", "100px");
echo $svg->asXML();

SVG 数据操作示例:

$def = 'YOUR SVG DEFINITION HERE';
$easySVG = new EasySVG();
// rotate by 40°
$rotated_def = $easySVG->defRotate($def, 40)
// rotate by 40° with center at (200,100)
$rotated_def2 = $easySVG->defRotate($def, 40, 200, 100)
// scale transform : width*4
$scaled_def = $easySVG->defScale($def, 4)

I just wrote a PHP library based on yours that manipulates font data (from SVG file) and does any sort of transformation on it. You may give it a try from the GitHub :

https://github.com/kartsims/easysvg

Usage example :

require 'easySVG.php';
$svg = new EasySVG();
$svg->setFont("paris-bold-webfont.svg", 100, "#000000");
$svg->addText("Simple text display");
$svg->addAttribute("width", "800px");
$svg->addAttribute("height", "100px");
echo $svg->asXML();

SVG data manipulation example :

$def = 'YOUR SVG DEFINITION HERE';
$easySVG = new EasySVG();
// rotate by 40°
$rotated_def = $easySVG->defRotate($def, 40)
// rotate by 40° with center at (200,100)
$rotated_def2 = $easySVG->defRotate($def, 40, 200, 100)
// scale transform : width*4
$scaled_def = $easySVG->defScale($def, 4)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文