Version 0 of glyphs

Updated 2013-03-15 15:59:15 by ABU

UNDER CONSTRUCTION

Glyphs 0.9 (unstable API)

Glyphs is a pure-tcl library for digging into TrueType font-files.

Glyphs is able to extract the vectorial paths of each glyph - points, lines, curves.

Opening and closing

This is our first quick trip; just open a .ttf, look inside and close

> package require glyphs
> set fObj [glyphs open "arial.ttf"]
> set ng [$fObj get numGlyphs]
> puts "found $ng glyphs"
> $fObj close

Inspecting font file's properties

Reopen the .ttf file

> set fObj [glyphs open "arial.ttf"]

we already know how to get the number-of-glyphs

> set res1 [$fObj get numGlyphs]
1674

and we can also get the overall-bounding box, or where the descender-line is placed

> set res2 [$fObj get bbox]
-1361 -665 4096 2060
>set res3 [$fObj get Descender]
-434

but there're a lot of properties and the better way to know which properties are set is:

> set props [$fObj get]
fontPath numGlyphs bbox unitsPerEm fontRevision Ascender Descender .....

WARNING: many properties may be added/removed for "glyphs 1.0"

Locating the single glyph

The quickest way to locate a single glyph is through its glyph-index. You know that "arial.ttf" has 1674 glyphs, therefore you can get all glyphs from 0 to 1674.

now let' take the 144th glyph set g144 $fObj glyph 144 As with fObj's properties, we can get some specific glyph's property: $g144 get index ;# --> 144 $g144 get bbox ;# --> 1 0 1936 1466 Forget about the "instructions" property it' a binary string "glyphs" is not currently able to decode. (Probably it will removed in the next revision) The most important properties are "points" and "commandpaths" Let's take a glyph simpler than 144 set g103 $fObj glyph 103 set L $g103 get points

{99 714 1 99 1079 0 ...} {299 711 1 299 446 0 ...} {516 1556 1 516 1761 1 ...} {889 1556 1 ...} Result looks like a list of 4 lists (4 contours). Each contour is made of a sequence of triples x y flag. Flag "1" means that point (x,y) is on-curve, Flag "0" means point (x,y) is the control point of a Quadratic Bezier curve.

But, how to translate these "points" in a parametric curve ?

set L $g103 get commandpaths

{{MOVETO 99 714} {QUADTO 99 1079 295.0 1285.5} ...} {{MOVETO 299 711} {QUADTO 299 446 441.5 293.5} ... } {{MOVETO 516 1556} {LINETO 516 1761} ... } {{MOVETO 889 1556} {LINETO 889 1761} ...} Result is a list of (4) contours. Each contour is made of a sequence of simple abstract commands:

  MOVETO  x y   --   set (x,y) as the current point
  LINETO  x y   --   draw a line from current point to (x,y).  (x,y) then becomes the current point
  QUADTO  x1 y1 x2 xy -- draw a quadratic bezier from current point, to (x1,y1) (control point) and to (x2,y2) (end-point)
  (x,y) then becomes the current point

It's your app's responsability to translate these 'abstract commands' in real commands. A naive implementation for the canvas widget could be:

proc CommandPaths2Canvas { cvs paths } {

    foreach path $paths {
         # first command should be MOVETO
        foreach pCmd $path {
            set points [lassign $pCmd cmd]
            switch -- $cmd {
                MOVETO {
                    ;
                }
                LINETO {
                        $cvs create line $lastX $lastY {*}$points
                }
                QUADTO {
                    $cvs create line $lastX $lastY {*}$points -smooth true
                }
                default { error "unrecognized path command \"$cmd\"" }            
            }
            set lastX [lindex $points end-1]
            set lastY [lindex $points end]            
        }
    }

}

There's no much more to do with a single-glyph. Since it's a dynamic object, you can free space when it's no more useful

  $g133 close

but, you are not required to do it. In fact, when the 'font-file' is closed

  $fObj close #;  -- THIS frees space also for all the extracted glyphs

all space is freed.

* More on accessing glyphs *

We've seen the standard way to access a glyph by-index. The major part of TTF holds a table for converting "character" (unicode) to index.

$fObj unicode2glyphIndex "A" $fObj unicode2glyphIndex "ß" ; # unicode char \u03B2 (greek letter "Beta") $fObj unicode2glyphIndex \u03B2 ; # unicode char \u03B2 (greek letter "Beta") $fObj numcode2glyphIndex 946 ; # it's always the greek letter "Beta" !

For your convenience, you can access a glyph, with two new methods

$fObj glyphByUnicode "ß" ; # glyph by Unicode $fObj glyphByCharCode 946 ; # glyph by CharCode