Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert text to SVG paths?

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?

like image 550
LukLed Avatar asked Oct 12 '11 15:10

LukLed


People also ask

How do I make SVG text?

To create text SVG's in Inkscape you need to turn your text into a path. To do this just select your text and then go to “path” in the top menu bar and then choose “object to path”. This will turn your text into a path. From here you can click into each individual letter of your text and edit however you'd like.

What does convert text to paths mean?

When you convert text to a path, the text becomes a graphic object that cannot be altered. Still, Inkscape lets you change the converted text's look by reshaping it. This type of conversion assists in making wordmarks or logos.


2 Answers

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;     } } 
like image 95
LukLed Avatar answered Sep 24 '22 06:09

LukLed


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 
like image 45
phihag Avatar answered Sep 23 '22 06:09

phihag