2011-10-12 12 views
31

Mam czcionkę w pliku ttf i chcę wygenerować SVG z tekstem zamienionym w ścieżki. Nie potrzebuję obrazu (więc użycie funkcji imagettftext lub Image Magick do renderowania czcionek nie jest wystarczające), potrzebuję kształtu, który można skalować w górę iw dół, i chcę stracić informacje o używanej czcionce i nie chcę jej Plik SVG (w związku z tym nie można tu użyć deklaracji czcionek). Czy to możliwe?Jak przekonwertować tekst na ścieżki SVG?

Odpowiedz

31

Stworzyłem własną klasę, aby przetworzyć plik czcionek SVG i zamienić tekst na glify. Przykład zastosowania:

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

Przykładowy wynik:

<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> 

Kod dla mojej klasy:

<?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; 
    } 
} 
+0

Ktoś się przydał do przeniesienia na Ruby? :) – corysimmons

+0

@CorySimmons: Przykro mi. Użyłem tego tylko w PHP. – LukLed

+0

Czy uważasz, że może działać jako port JavaScript? Coś Cię uderza jako coś, co może być problemem? – corysimmons

14

Obejście polega na użyciu programu inkscape (wykonaj to przez exec lub mniej po zapisaniu dokumentu SVG pod numerem file.svg). W Inkscape 0.49+, you can prostu przekazać --export-to-svg i --export-text-to-path coś takiego:

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

< w Inkscape 0.49, można ręcznie skrypt Inkscape (zauważ, że wymaga tego serwera X):

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

Spróbuję sprawdzić to rozwiązanie, ale jest to zdecydowanie obejście problemu. Jakieś inne pomysły :)? – LukLed

+0

@LukLed Obecnie mam ten sam problem, więc niestety nie.Mam nadzieję, że jeden z 11 innych widzów ma jeden;) – phihag

+0

Dołączyłem klasę PHP do przetwarzania czcionek SVG. Tutaj możesz zobaczyć przykładowe wyjście: http://lukasz.logo.pdev.cksk.com/svgtext.php?text=Simple%20text+&font=arial&size=20 – LukLed

2

If możesz uzyskać svgfont, a następnie masz wszystkie informacje potrzebne do renderowania go za pomocą ścieżek glifów (skopiuj i wklej wszystkie potrzebne dane ścieżki glifów do dowolnej liczby elementów ścieżki i zastosuj transformację typu flip-y i skaluj ją do dowolnego rozmiaru potrzebujesz). Batik ma narzędzie o nazwie ttf2svg, które daje wyjście svgfont. Są też inne, na przykład.

Nie jestem pewien, czy istnieją jakieś czyste narzędzia z linii poleceń, które mogą bezpośrednio generować svg, ale rozwiązanie Inkscape powinno zrobić dokładnie to, co chcesz.

+0

Dzięki za odpowiedź. To wydaje się być drogą do zrobienia. Teraz muszę pomyśleć o sposobie zautomatyzowania go. – LukLed

+0

Czy ktoś zna polecenie, które FontForge oferuje do konwersji tekstu na ścieżki SVG? Składnia użycia byłaby również niesamowita. – corysimmons

7

Właśnie napisał biblioteki PHP w oparciu o twoje który manipuluje danymi Font (z pliku SVG) i robi jakąkolwiek transformację na tym. Możesz spróbować z GitHub: przykład

https://github.com/kartsims/easysvg

Zastosowanie:

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 przykładem manipulacji danymi:

$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) 
+0

Nie używam go więcej, ale dobrze, że ktoś umieścił to na GitHub. – LukLed

+0

Ja też, ale myślałem, że to może uratować czyjś czas ;-) Jeśli ktokolwiek jest zainteresowany, to jestem gotów to poprawić, po prostu powiedz mi, co potrzebujesz – kartsims

+0

Robię podobny projekt w Ruby, ale wypakowuję tekst z tagi. https://github.com/caesarsol/svg-text-to-path. Planuję zrobić funkcje manipulacyjne tak jak twoje, przyjrzę się twojemu kodowi! – caesarsol

2

Jeśli jesteś na Mac Okazało się, że otwarcie pliku SVG w iVinci Express za pomocą obiektu tekstowego automatycznie przekształci go w ścieżkę. Stworzyłem mój SVG w Inkscape, który okazał się Wielkim T-em w Times New Roman (standardowe narzędzie do wybierania tekstu). Android SVG lib nie mógł sobie z tym poradzić pokazując Roboto T zamiast tego, więc otworzyłem w iVinci Express, zapisałem stamtąd i automatycznie przekonwertowałem na ścieżkę. Usunąłem trochę dodatkowych śmieci, które dodałem, i ustawiłem widok (Android tego wymaga) i wszystko było dobrze namalowane.

iVinci Express jest bezpłatny w sklepie Mac.

Powiązane problemy