# cairo mathtext

When looking through the backend_cairo.py code, I

> realized that it currently renders the mathtext as
> images. While this is currently fine, as cairo's export
> of PS is really just an image, it would be better in the
> future to actually have it draw the fonts as paths.

> My first approach was to hack 'draw_mathtext.py', and to
> go and draw the strokes for the glyph's paths. The
> commands that the glyphs allow are (according to
> ft2font.cpp) are: MOVETO=0, LINETO=1, CURVE3=2, CURVE4=3,
> ENDPOLY=4. It seemed fairly simple, as cairo has the
> commands: 'move_to(x, y)', 'line_to(x, y)', and
> 'close_path()'. I wasn't sure if move_to and line_to were
> the equivalents of this, or actually 'rel_move_to' and
> 'rel_line_to'. Also, I wasn't sure how to map CURVE3 onto
> these types of curves).

> If anyone has any suggestions on how to do this, it would
> be greatly appreciated. I also realized halfway through
> that perhaps it was a better idea to instead use cairo's
> truetype font ability, and if there weren't a simpler
> method to do this..

I don't know much about cairo, but I can fill in a little detail about
the font paths. From
http://freetype.sourceforge.net/freetype2/docs/glyphs/glyphs-6.html

An outline is described as a series of closed contours in the 2D
plane. Each contour is made of a series of line segments and B?zier
arcs. Depending on the file format, these can be second-order or
third-order polynomials. The former are also called quadratic or
conic arcs, and they are used in the TrueType format. The latter are
called cubic arcs and are mostly used in the Type 1 format.

The CURVE3 code is a conic arc and the tuple that represents that
curve in the glyph.path sequence is

CURVE3, xctl, yctl, xto, yto

and for cubic arcs is

CURVE4, xctl1, yctl1, xctl2, yctl2, xto, yto

The code to extra path from a glyph was lifted from agg, but I put the
data structures in a list rather than an agg path to decouple agg form
the freetype module. I'm still deliberating about whether this is a
good idea or not.

Like you, I am not sure how to best handle conic arcs in cairo, but
Steve may know. Note that if you go the route you are considering,
you will lose hinting information, so figuring out a way to use
cairo's native truetype support may be preferable.

So I can't really answer any of your questions .... but I'll post a
conversion function from the ft2font path to an agg path in case it's
of any use

import os
import matplotlib
from matplotlib.ft2font import FT2Font
import matplotlib.agg as agg

MOVETO, LINETO, CURVE3, CURVE4, ENDPOLY = range(5)

def glyph_to_agg_path(glyph):
path = agg.path_storage()
for tup in glyph.path:
print tup
code = tup[0]
if code == MOVETO:
x,y = tup[1:]
path.move_to(x,y)
elif code == LINETO:
x,y = tup[1:]
path.line_to(x,y)
elif code == CURVE3:
xctl, yctl, xto, yto= tup[1:]
path.curve3(xctl, yctl, xto, yto)

elif code == CURVE4:
xctl1, yctl1, xctl2, yctl2, xto, yto= tup[1:]
path.curve4(xctl1, yct1, xctl2, yctl2, xto, yto)
elif code == ENDPOLY:
path.end_poly()

return path

fname = os.path.join(matplotlib.get_data_path(), 'Vera.ttf')
font = FT2Font(fname)
path = glyph_to_agg_path(glyph)

Thanks for the references. I decided to go for the second approach (it seems maybe more sane, and it doesn't seem like their are any major benefits to using the glyphs made..) The SVG code outputs a tuple of:
basename, fontsize, unicode, ox, oy, metrics

I go through the list, and output that. I'm not sure if I'm doing everything correctly. For example, I have no clue what 'metrics' contains (e.g. what advance, width, etc. will do, and if I need it or not). I'm also not sure if things like hinting work using this method either (esp. since I render each character seperately -- I'm not sure I see any other method of doing it, however).

Any of this look sane?

ctx = cairo.Context()
file = open('test.ps', 'wb')
ctx.set_target_ps(file, 4.3, 4.3, 300, 300)

width, height, fonts = math_parse_s_ft2font_svg(r'$x^y * \pi$', 96, 50)

for f in fonts:
basename, fontsize, num, ox, oy, metrics = f
ctx.select_font(basename)
ctx.scale_font(fontsize)
ctx.move_to(ox, 100 - oy)
ctx.show_text(unichr(num).encode('utf8'))

ctx.stroke()

ctx.show_page()

John Hunter wrote:

···

"Abraham" == Abraham Schneider <abes@...137...> writes:

> When looking through the backend_cairo.py code, I
> realized that it currently renders the mathtext as
> images. While this is currently fine, as cairo's export
> of PS is really just an image, it would be better in the
> future to actually have it draw the fonts as paths.

> My first approach was to hack 'draw_mathtext.py', and to
> go and draw the strokes for the glyph's paths. The
> commands that the glyphs allow are (according to
> ft2font.cpp) are: MOVETO=0, LINETO=1, CURVE3=2, CURVE4=3,
> ENDPOLY=4. It seemed fairly simple, as cairo has the
> commands: 'move_to(x, y)', 'line_to(x, y)', and
> 'close_path()'. I wasn't sure if move_to and line_to were
> the equivalents of this, or actually 'rel_move_to' and
> 'rel_line_to'. Also, I wasn't sure how to map CURVE3 onto
> these types of curves).

> If anyone has any suggestions on how to do this, it would
> be greatly appreciated. I also realized halfway through
> that perhaps it was a better idea to instead use cairo's
> truetype font ability, and if there weren't a simpler
> method to do this..

I don't know much about cairo, but I can fill in a little detail about
the font paths. From
http://freetype.sourceforge.net/freetype2/docs/glyphs/glyphs-6.html

An outline is described as a series of closed contours in the 2D
plane. Each contour is made of a series of line segments and Bézier
arcs. Depending on the file format, these can be second-order or
third-order polynomials. The former are also called quadratic or
conic arcs, and they are used in the TrueType format. The latter are
called cubic arcs and are mostly used in the Type 1 format.

The CURVE3 code is a conic arc and the tuple that represents that
curve in the glyph.path sequence is

CURVE3, xctl, yctl, xto, yto

and for cubic arcs is

CURVE4, xctl1, yctl1, xctl2, yctl2, xto, yto

The code to extra path from a glyph was lifted from agg, but I put the
data structures in a list rather than an agg path to decouple agg form
the freetype module. I'm still deliberating about whether this is a
good idea or not.

Like you, I am not sure how to best handle conic arcs in cairo, but
Steve may know. Note that if you go the route you are considering,
you will lose hinting information, so figuring out a way to use
cairo's native truetype support may be preferable.

So I can't really answer any of your questions .... but I'll post a
conversion function from the ft2font path to an agg path in case it's
of any use

import os
import matplotlib
from matplotlib.ft2font import FT2Font
import matplotlib.agg as agg

MOVETO, LINETO, CURVE3, CURVE4, ENDPOLY = range(5)

def glyph_to_agg_path(glyph):
path = agg.path_storage()
for tup in glyph.path:
print tup
code = tup[0]
if code == MOVETO:
x,y = tup[1:]
path.move_to(x,y)
elif code == LINETO:
x,y = tup[1:]
path.line_to(x,y)
elif code == CURVE3:
xctl, yctl, xto, yto= tup[1:]
path.curve3(xctl, yctl, xto, yto)

elif code == CURVE4:
xctl1, yctl1, xctl2, yctl2, xto, yto= tup[1:]
path.curve4(xctl1, yct1, xctl2, yctl2, xto, yto)
elif code == ENDPOLY:
path.end_poly()

return path

fname = os.path.join(matplotlib.get_data_path(), 'Vera.ttf')
font = FT2Font(fname)