Skip to content

Commit 61eda61

Browse files
committed
finished unicode support for ps
svn path=/trunk/matplotlib/; revision=1108
1 parent c904605 commit 61eda61

6 files changed

Lines changed: 120 additions & 48 deletions

File tree

CHANGELOG

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
New entries should be added at the top
22

3-
2005-03-29 Added alpha unicode support for Agg and PS in progress - JDH
3+
2005-03-29 Added alpha unicode support for Agg and PS - JDH
44

55
2005-03-28 Added Jarrod's svg patch for text - JDH
66

examples/unicode_demo.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#!/usr/bin/python
22
# -*- coding: utf-8 -*-
33

4-
54
from pylab import *
65
plot([1,2,4])
76
title( unicode('Développés et fabriqués', 'latin-1') )

lib/matplotlib/backends/backend_ps.py

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from matplotlib.figure import Figure
1717

1818
from matplotlib.font_manager import fontManager
19-
from matplotlib.ft2font import FT2Font
19+
from matplotlib.ft2font import FT2Font, KERNING_UNFITTED, KERNING_DEFAULT, KERNING_UNSCALED
2020
from matplotlib.mathtext import math_parse_s_ps, bakoma_fonts
2121
from matplotlib.text import Text
2222

@@ -142,6 +142,7 @@ def set_font(self, fontname, fontsize):
142142
out = ("/%s findfont\n"
143143
"%1.3f scalefont\n"
144144
"setfont\n" % (fontname,fontsize))
145+
145146
self._pswriter.write(out)
146147
self.fontname = fontname
147148
self.fontsize = fontsize
@@ -478,41 +479,44 @@ def draw_unicode(self, gc, x, y, s, prop, angle):
478479
"""draw a unicode string. ps doesn't have unicode support, so
479480
we have to do this the hard way
480481
"""
481-
thisx, thisy = x, y
482+
483+
482484
font = self._get_font_ttf(prop)
483-
self.set_font(font.get_sfnt()[(1,0,0,6)], prop.get_size_in_points())
484-
xys = font.set_text(s, 0);
485+
486+
self.set_color(*gc.get_rgb())
487+
self.set_font(font.get_sfnt()[(1,0,0,6)], prop.get_size_in_points())
485488

486489
cmap = font.get_charmap()
487490
glyphd = reverse_dict(cmap)
488-
lastcode = None
489-
490-
#print len(s), len(xys)
491-
manual = True
492-
for c, xy in zip(s, xys):
493-
# use the freetype positions
494-
penx, peny = xy
495-
#print '\t', c, penx, peny
496-
if not manual: # use freetype positions
497-
thisx = x + penx/64.
498-
491+
lastgind = None
492+
#print 'text', s
493+
lines = []
494+
thisx, thisy = 0,0
495+
for c in s:
499496
ccode = ord(c)
500497
gind = glyphd[ccode]
498+
glyph = font.load_char(ccode)
499+
501500
name = font.get_glyph_name(gind)
502-
self._pswriter.write('%f %f moveto /%s glyphshow\n'%(thisx, thisy, name))
503-
504-
if manual: #manually lay them out using glyph metrics and kern
505-
glyph = font.load_char(ccode)
506-
#print c, ccode, gind, name, xy[0]/64.
507-
if lastcode is not None:
508-
kern = font.get_kerning(lastcode, ccode)
509-
#print lastcode, ccode, kern
510-
else:
511-
kern = 0
512-
lastcode = ccode
513-
thisx += (glyph.horiAdvance+kern)/64.0
514-
501+
if lastgind is not None:
502+
kern = font.get_kerning(lastgind, gind, KERNING_UNFITTED)
503+
else:
504+
kern = 0
505+
lastgind = gind
506+
thisx += kern/64.0
515507

508+
lines.append('%f %f m /%s glyphshow'%(thisx, thisy, name))
509+
thisx += glyph.linearHoriAdvance/65536.0
510+
511+
512+
thetext = '\n'.join(lines)
513+
ps = """gsave
514+
%(x)f %(y)f translate
515+
%(angle)f rotate
516+
%(thetext)s
517+
grestore
518+
""" % locals()
519+
self._pswriter.write(ps)
516520

517521

518522
def draw_mathtext(self, gc,

lib/matplotlib/mathtext.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ def _get_info (self, font, sym, fontsize, dpi):
308308
else:
309309
offset = 0.
310310
metrics = Bunch(
311-
advance = glyph.horiAdvance/64.0,
311+
advance = glyph.linearHoriAdvance/65536.0,
312312
height = glyph.height/64.0,
313313
width = glyph.width/64.0,
314314
xmin = xmin,
@@ -364,7 +364,7 @@ def get_kern(self, font, symleft, symright, fontsize, dpi):
364364
kernd = cmkern[basename]
365365
key = symleft, symright
366366
kern = kernd.get(key,0)
367-
print basename, symleft, symright, key, kern
367+
#print basename, symleft, symright, key, kern
368368
return kern
369369

370370
def _get_num(self, font, sym):
@@ -441,7 +441,7 @@ def _get_info (self, font, sym, fontsize, dpi):
441441
else:
442442
offset = 0.
443443
metrics = Bunch(
444-
advance = glyph.horiAdvance/64.0,
444+
advance = glyph.linearHoriAdvance/65536.0,
445445
height = glyph.height/64.0,
446446
width = glyph.width/64.0,
447447
xmin = xmin,
@@ -666,11 +666,11 @@ def set_size_info(self, fontsize, dpi):
666666
mmetrics = Element.fonts.get_metrics(
667667
self.font, 'm', self.fontsize, dpi)
668668
self.widthm = mmetrics.width
669-
print self.widthm
669+
#print self.widthm
670670

671671
def advance(self):
672672
'get the horiz advance'
673-
return self.metrics.advance + self.kern*self.widthm
673+
return self.metrics.advance # how to handle cm units?+ self.kern*self.widthm
674674

675675

676676
def height(self):
@@ -724,7 +724,7 @@ def set_font(self, font):
724724
element.set_font(font)
725725

726726

727-
print 'set fonts'
727+
#print 'set fonts'
728728
for i in range(len(self.elements)-1):
729729
if not isinstance(self.elements[i], SymbolElement): continue
730730
if not isinstance(self.elements[i+1], SymbolElement): continue
@@ -736,7 +736,7 @@ def set_font(self, font):
736736
def set_size_info(self, fontsize, dpi):
737737
self.elements[0].set_size_info(self._scale*fontsize, dpi)
738738
Element.set_size_info(self, fontsize, dpi)
739-
print 'set size'
739+
#print 'set size'
740740

741741

742742
def set_origin(self, ox, oy):

src/ft2font.cpp

Lines changed: 78 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,13 @@ Glyph::Glyph( const FT_Face& face, const FT_Glyph& glyph, size_t ind) :
2222
setattr("horiBearingX", Py::Int( face->glyph->metrics.horiBearingX) );
2323
setattr("horiBearingY", Py::Int( face->glyph->metrics.horiBearingY) );
2424
setattr("horiAdvance", Py::Int( face->glyph->metrics.horiAdvance) );
25+
setattr("linearHoriAdvance", Py::Int( face->glyph->linearHoriAdvance) );
2526
setattr("vertBearingX", Py::Int( face->glyph->metrics.vertBearingX) );
2627

2728
setattr("vertBearingY", Py::Int( face->glyph->metrics.vertBearingY) );
2829
setattr("vertAdvance", Py::Int( face->glyph->metrics.vertAdvance) );
30+
//setattr("bitmap_left", Py::Int( face->glyph->bitmap_left) );
31+
//setattr("bitmap_top", Py::Int( face->glyph->bitmap_top) );
2932

3033
Py::Tuple abbox(4);
3134

@@ -616,25 +619,33 @@ FT2Font::compute_string_bbox( ) {
616619

617620

618621
char FT2Font::get_kerning__doc__[] =
619-
"dx = get_kerning(left, right)\n"
622+
"dx = get_kerning(left, right, mode)\n"
620623
"\n"
621624
"Get the kerning between left char and right glyph indices\n"
625+
"mode is a kerning mode constant\n"
626+
" KERNING_DEFAULT - Return scaled and grid-fitted kerning distances\n"
627+
" KERNING_UNFITTED - Return scaled but un-grid-fitted kerning distances\n"
628+
" KERNING_UNSCALED - Return the kerning vector in original font units\n"
622629
;
623630
Py::Object
624631
FT2Font::get_kerning(const Py::Tuple & args) {
625632
_VERBOSE("FT2Font::get_kerning");
626-
args.verify_length(2);
633+
args.verify_length(3);
627634
int left = Py::Int(args[0]);
628635
int right = Py::Int(args[1]);
629-
636+
int mode = Py::Int(args[2]);
637+
630638

631639
if (!FT_HAS_KERNING( face )) return Py::Int(0);
632640
FT_Vector delta;
633641

634-
FT_Get_Kerning( face, left, right,
635-
FT_KERNING_DEFAULT, &delta );
642+
if (FT_Get_Kerning( face, left, right, mode, &delta )) {
643+
return Py::Int(0);
644+
}
645+
else {
646+
return Py::Int(delta.x);
636647

637-
return Py::Int(delta.x);
648+
}
638649
}
639650

640651

@@ -686,10 +697,6 @@ FT2Font::set_text(const Py::Tuple & args) {
686697
std::string thischar("?");
687698
FT_UInt glyph_index;
688699

689-
Py::Tuple xy(2);
690-
xy[0] = Py::Float(pen.x);
691-
xy[1] = Py::Float(pen.y);
692-
xys[n] = xy;
693700

694701
if (pcode==NULL) {
695702
// plain ol string
@@ -727,6 +734,10 @@ FT2Font::set_text(const Py::Tuple & args) {
727734
// ignore errors, jump to next glyph
728735

729736
FT_Glyph_Transform( thisGlyph, 0, &pen);
737+
Py::Tuple xy(2);
738+
xy[0] = Py::Float(pen.x);
739+
xy[1] = Py::Float(pen.y);
740+
xys[n] = xy;
730741
pen.x += face->glyph->advance.x;
731742

732743
previous = glyph_index;
@@ -797,6 +808,8 @@ FT2Font::load_char(const Py::Tuple & args) {
797808
long charcode = Py::Int(args[0]);
798809

799810
int error = FT_Load_Char( face, (unsigned long)charcode, FT_LOAD_DEFAULT);
811+
//int error = FT_Load_Char( face, (unsigned long)charcode, FT_LOAD_LINEAR_DESIGN);
812+
//int error = FT_Load_Char( face, (unsigned long)charcode, FT_LOAD_RENDER);
800813

801814
if (error)
802815
throw Py::RuntimeError(Printf("Could not load charcode %d", charcode).str());
@@ -868,7 +881,7 @@ FT2Font::draw_bitmap( FT_Bitmap* bitmap,
868881
{
869882
if ( i >= width || j >= height )
870883
continue;
871-
image.buffer[i + j*width] |= bitmap->buffer[q*bitmap->width + p];
884+
image.buffer[i + j*width] |= bitmap->buffer[p + q*bitmap->width];
872885

873886
}
874887
}
@@ -1022,6 +1035,54 @@ FT2Font::draw_glyphs_to_bitmap(const Py::Tuple & args) {
10221035
return Py::Object();
10231036
}
10241037

1038+
1039+
char FT2Font::get_xys__doc__[] =
1040+
"get_xys()\n"
1041+
"\n"
1042+
"Get the xy locations of the current glyphs\n"
1043+
;
1044+
Py::Object
1045+
FT2Font::get_xys(const Py::Tuple & args) {
1046+
1047+
_VERBOSE("FT2Font::get_xys");
1048+
args.verify_length(0);
1049+
1050+
FT_BBox string_bbox = compute_string_bbox();
1051+
Py::Tuple xys(glyphs.size());
1052+
1053+
for ( size_t n = 0; n < glyphs.size(); n++ )
1054+
{
1055+
1056+
FT_BBox bbox;
1057+
FT_Glyph_Get_CBox(glyphs[n], ft_glyph_bbox_pixels, &bbox);
1058+
1059+
error = FT_Glyph_To_Bitmap(&glyphs[n],
1060+
ft_render_mode_normal,
1061+
0,
1062+
//&pos[n],
1063+
1 //destroy image;
1064+
);
1065+
if (error)
1066+
throw Py::RuntimeError("Could not convert glyph to bitmap");
1067+
1068+
FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyphs[n];
1069+
1070+
1071+
//bitmap left and top in pixel, string bbox in subpixel
1072+
FT_Int x = (FT_Int)(bitmap->left-string_bbox.xMin/64.);
1073+
FT_Int y = (FT_Int)(string_bbox.yMax/64.-bitmap->top+1);
1074+
//make sure the index is non-neg
1075+
x = x<0?0:x;
1076+
y = y<0?0:y;
1077+
Py::Tuple xy(2);
1078+
xy[0] = Py::Float(x);
1079+
xy[1] = Py::Float(y);
1080+
xys[n] = xy;
1081+
}
1082+
1083+
return xys;
1084+
}
1085+
10251086
char FT2Font::draw_glyph_to_bitmap__doc__[] =
10261087
"draw_glyph_to_bitmap(x, y, glyph)\n"
10271088
"\n"
@@ -1494,6 +1555,9 @@ FT2Font::init_type() {
14941555
FT2Font::draw_glyph_to_bitmap__doc__);
14951556
add_varargs_method("draw_glyphs_to_bitmap", &FT2Font::draw_glyphs_to_bitmap,
14961557
FT2Font::draw_glyphs_to_bitmap__doc__);
1558+
add_varargs_method("get_xys", &FT2Font::get_xys,
1559+
FT2Font::get_xys__doc__);
1560+
14971561
add_varargs_method("get_glyph", &FT2Font::get_glyph,
14981562
FT2Font::get_glyph__doc__);
14991563
add_varargs_method("get_num_glyphs", &FT2Font::get_num_glyphs,
@@ -1612,6 +1676,9 @@ initft2font(void)
16121676
d["EXTERNAL_STREAM"] = Py::Int(FT_FACE_FLAG_EXTERNAL_STREAM);
16131677
d["ITALIC"] = Py::Int(FT_STYLE_FLAG_ITALIC);
16141678
d["BOLD"] = Py::Int(FT_STYLE_FLAG_BOLD);
1679+
d["KERNING_DEFAULT"] = Py::Int(FT_KERNING_DEFAULT);
1680+
d["KERNING_UNFITTED"] = Py::Int(FT_KERNING_UNFITTED);
1681+
d["KERNING_UNSCALED"] = Py::Int(FT_KERNING_UNSCALED);
16151682

16161683
//initialize library
16171684
int error = FT_Init_FreeType( &_ft2Library );

src/ft2font.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class FT2Font : public Py::PythonExtension<FT2Font> {
6565
Py::Object write_bitmap(const Py::Tuple & args);
6666
Py::Object draw_rect(const Py::Tuple & args);
6767
Py::Object image_as_str(const Py::Tuple & args);
68+
Py::Object get_xys(const Py::Tuple & args);
6869
Py::Object draw_glyphs_to_bitmap(const Py::Tuple & args);
6970
Py::Object draw_glyph_to_bitmap(const Py::Tuple & args);
7071
Py::Object get_glyph_name(const Py::Tuple & args);
@@ -110,6 +111,7 @@ class FT2Font : public Py::PythonExtension<FT2Font> {
110111
static char draw_rect__doc__ [];
111112
static char image_as_str__doc__ [];
112113
static char draw_glyphs_to_bitmap__doc__ [];
114+
static char get_xys__doc__ [];
113115
static char draw_glyph_to_bitmap__doc__ [];
114116
static char get_glyph_name__doc__[];
115117
static char get_charmap__doc__[];

0 commit comments

Comments
 (0)