Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 055d8c1

Browse files
committed
Improvements to PDF mathtext: positioning and encoding
(encoding is probably not really right, but works better than old version) svn path=/trunk/matplotlib/; revision=2591
1 parent d555e37 commit 055d8c1

2 files changed

Lines changed: 82 additions & 37 deletions

File tree

lib/matplotlib/backends/backend_pdf.py

Lines changed: 71 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ class Reference:
149149
def __init__(self, id):
150150
self.id = id
151151

152+
def __repr__(self):
153+
return "<Reference %d>" % self.id
154+
152155
def pdfRepr(self):
153156
return "%d 0 R" % self.id
154157

@@ -167,6 +170,9 @@ def __init__(self, name):
167170
else:
168171
self.name = re.sub(r'[^!-~]', Name.hexify, name)
169172

173+
def __repr__(self):
174+
return "<Name %s>" % self.name
175+
170176
def hexify(match):
171177
return '#%02x' % ord(match.group())
172178
hexify = staticmethod(hexify)
@@ -412,7 +418,8 @@ def embedTTF(self, filename):
412418

413419
font = FT2Font(filename)
414420

415-
def convert(length, upe=font.units_per_EM, nearest=True):
421+
422+
def cvt(length, upe=font.units_per_EM, nearest=True):
416423
"Convert font coordinates to PDF glyph coordinates"
417424
value = length / upe * 1000
418425
if nearest: return round(value)
@@ -434,8 +441,7 @@ def convert(length, upe=font.units_per_EM, nearest=True):
434441
firstchar, lastchar = chars[0], chars[-1]
435442

436443
# Get widths
437-
widths = [ convert(font.load_char(i, flags=LOAD_NO_SCALE)
438-
.horiAdvance)
444+
widths = [ cvt(font.load_char(i, flags=LOAD_NO_SCALE).horiAdvance)
439445
for i in range(firstchar, lastchar+1) ]
440446
# Remove redundant widths from end and beginning; doing the
441447
# end first helps reduce LastChar, which apparently needs to
@@ -448,21 +454,24 @@ def convert(length, upe=font.units_per_EM, nearest=True):
448454
firstchar += 1
449455
widths.pop(0)
450456

457+
widthsObject = self.reserveObject('font widths')
458+
fontdescObject = self.reserveObject('font descriptor')
451459
fontdict = { 'Type': Name('Font'),
452460
'Subtype': Name('TrueType'),
461+
'Encoding': Name('WinAnsiEncoding'), # ???
453462
'BaseFont': ps_name,
454463
'FirstChar': firstchar,
455464
'LastChar': lastchar,
456-
'Widths': self.reserveObject('font widths'),
457-
'FontDescriptor':
458-
self.reserveObject('font descriptor') }
465+
'Widths': widthsObject,
466+
'FontDescriptor': fontdescObject }
459467
# TODO: Encoding?
460468

461469
flags = 0
470+
symbolic = False #ps_name.name in ('Cmsy10', 'Cmmi10', 'Cmex10')
462471
if ff & FIXED_WIDTH: flags |= 1 << 0
463472
if 0: flags |= 1 << 1 # TODO: serif
464-
if 0: flags |= 1 << 2 # TODO: symbolic
465-
else: flags |= 1 << 5 # TODO: nonsymbolic
473+
if symbolic: flags |= 1 << 2
474+
else: flags |= 1 << 5
466475
if sf & ITALIC: flags |= 1 << 6
467476
if 0: flags |= 1 << 16 # TODO: all caps
468477
if 0: flags |= 1 << 17 # TODO: small caps
@@ -472,11 +481,11 @@ def convert(length, upe=font.units_per_EM, nearest=True):
472481
'Type': Name('FontDescriptor'),
473482
'FontName': ps_name,
474483
'Flags': flags,
475-
'FontBBox': [ convert(x, nearest=False) for x in font.bbox ],
476-
'Ascent': convert(font.ascender, nearest=False),
477-
'Descent': convert(font.descender, nearest=False),
478-
'CapHeight': convert(pclt['capHeight'], nearest=False),
479-
'XHeight': convert(pclt['xHeight']),
484+
'FontBBox': [ cvt(x, nearest=False) for x in font.bbox ],
485+
'Ascent': cvt(font.ascender, nearest=False),
486+
'Descent': cvt(font.descender, nearest=False),
487+
'CapHeight': cvt(pclt['capHeight'], nearest=False),
488+
'XHeight': cvt(pclt['xHeight']),
480489
'ItalicAngle': post['italicAngle'][1], # ???
481490
'FontFile2': self.reserveObject('font file'),
482491
'MaxWidth': max(widths+[missingwidth]),
@@ -490,11 +499,34 @@ def convert(length, upe=font.units_per_EM, nearest=True):
490499
# /FontFile (stream for type 1 font)
491500
# /CharSet (used when subsetting type1 fonts)
492501

502+
# Make an Identity-H encoded CID font for CM fonts? (Doesn't quite work)
503+
if False:
504+
del fontdict['Widths'], fontdict['FontDescriptor'], \
505+
fontdict['LastChar'], fontdict['FirstChar']
506+
507+
fontdict['Subtype'] = Name('Type0')
508+
fontdict['Encoding'] = Name('Identity-H')
509+
fontdict2Object = self.reserveObject('descendant font')
510+
fontdict['DescendantFonts'] = [ fontdict2Object ]
511+
# TODO: fontdict['ToUnicode']
512+
fontdict2 = { 'Type': Name('Font'),
513+
'Subtype': Name('CIDFontType2'),
514+
'BaseFont': ps_name,
515+
'W': widthsObject,
516+
'DW': missingwidth,
517+
'CIDSystemInfo': { 'Registry': 'Adobe',
518+
'Ordering': 'Identity',
519+
'Supplement': 0 },
520+
'FontDescriptor': fontdescObject }
521+
self.writeObject(fontdict2Object, fontdict2)
522+
523+
widths = [ firstchar, widths ]
524+
493525
fontdictObject = self.reserveObject('font dictionary')
494526
length1Object = self.reserveObject('decoded length of a font')
495527
self.writeObject(fontdictObject, fontdict)
496-
self.writeObject(fontdict['Widths'], widths)
497-
self.writeObject(fontdict['FontDescriptor'], descriptor)
528+
self.writeObject(widthsObject, widths)
529+
self.writeObject(fontdescObject, descriptor)
498530
self.currentstream = \
499531
Stream(descriptor['FontFile2'].id,
500532
self.reserveObject('length of font stream'),
@@ -809,18 +841,27 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
809841
for ox, oy, fontname, fontsize, glyph in pswriter:
810842
#print ox, oy, glyph
811843
fontname = fontname.lower()
812-
self._setup_textpos(x+ox, y+oy, angle, oldx, oldy)
813-
oldx, oldy = x+ox, y+oy
844+
a = angle / 180.0 * pi
845+
newx = x + cos(a)*ox - sin(a)*oy
846+
newy = y + sin(a)*ox + cos(a)*oy
847+
self._setup_textpos(newx, newy, angle, oldx, oldy)
848+
oldx, oldy = newx, newy
814849
if (fontname, fontsize) != prev_font:
815850
self.file.output(self.file.fontName(fontname), fontsize,
816851
Op.selectfont)
817852
prev_font = fontname, fontsize
818-
self.file.output(chr(glyph), Op.show)
853+
854+
#if fontname.endswith('cmsy10.ttf') or \
855+
#fontname.endswith('cmmi10.ttf') or \
856+
#fontname.endswith('cmex10.ttf'):
857+
# string = '\0' + chr(glyph)
858+
859+
string = chr(glyph)
860+
self.file.output(string, Op.show)
819861
self.file.output(Op.end_text)
820862

821863
def draw_text(self, gc, x, y, s, prop, angle, ismath=False):
822864
# TODO: combine consecutive texts into one BT/ET delimited section
823-
# mathtext
824865
# unicode
825866
if ismath: return self.draw_mathtext(gc, x, y, s, prop, angle)
826867
self.check_gc(gc, gc._rgb)
@@ -838,13 +879,18 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False):
838879
self.file.output(s, Op.show, Op.end_text)
839880

840881
def get_text_width_height(self, s, prop, ismath):
841-
# TODO: mathtext
842882

843-
font = self._get_font_ttf(prop)
844-
font.set_text(s, 0.0)
845-
w, h = font.get_width_height()
846-
factor = 1.0/(self.dpi_factor*64.0)
847-
return factor*w, factor*h
883+
if ismath:
884+
fontsize = prop.get_size_in_points()
885+
w, h, pswriter = math_parse_s_pdf(s, self.file.dpi, fontsize)
886+
else:
887+
font = self._get_font_ttf(prop)
888+
font.set_text(s, 0.0)
889+
w, h = font.get_width_height()
890+
factor = 1.0/(self.dpi_factor*64.0)
891+
w *= factor
892+
h *= factor
893+
return w, h
848894

849895
def _get_font_ttf(self, prop):
850896
font = self.fonts.get(prop)

lib/matplotlib/mathtext.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -813,19 +813,18 @@ def _get_filename_and_num (self, font, sym, fontsize, dpi):
813813
num = ord(sym)
814814
else:
815815
num = 0
816-
sym = '.notdef'
817-
raise ValueError('unrecognized symbol "%s, %d"' % (sym, num))
816+
raise ValueError('unrecognized symbol "%s"' % (sym,))
818817

819818
return os.path.join(self.basepath, basename) + '.ttf', num
820819

821820
def render(self, ox, oy, font, sym, fontsize, dpi):
822821
fontname, metrics, glyphname, offset = \
823822
self._get_info(font, sym, fontsize, dpi)
824-
filename, num = self._get_filename_and_num(font, sym, fontsize, dpi)
823+
filename, num = self._get_filename_and_num(font, sym, fontsize, dpi)
825824
if fontname.lower() == 'cmex10':
826825
oy += offset - 512/2048.*10.
827826

828-
self.pswriter.append((ox, oy, filename, fontsize, num))
827+
self.pswriter.append((ox, oy, filename, fontsize, num))
829828

830829

831830
class StandardPSFonts(Fonts):
@@ -1570,9 +1569,9 @@ def __call__(self, s, dpi, fontsize, angle=0):
15701569
self.font_object = BakomaPSFonts()
15711570
#self.font_object = MyUnicodeFonts(output='PS')
15721571
Element.fonts = self.font_object
1573-
elif self.output == 'PDF':
1574-
self.font_object = BakomaPDFFonts()
1575-
Element.fonts = self.font_object
1572+
elif self.output == 'PDF':
1573+
self.font_object = BakomaPDFFonts()
1574+
Element.fonts = self.font_object
15761575

15771576
handler.clear()
15781577
expression.parseString( s )
@@ -1594,14 +1593,14 @@ def __call__(self, s, dpi, fontsize, angle=0):
15941593

15951594
handler.expr.set_origin(0, h-ymax)
15961595

1597-
if self.output in ('SVG', 'BMP'):
1598-
Element.fonts.set_canvas_size(w,h)
1596+
if self.output in ('SVG', 'BMP'):
1597+
Element.fonts.set_canvas_size(w,h)
15991598
elif self.output == 'PS':
16001599
pswriter = StringIO()
16011600
Element.fonts.set_canvas_size(w, h, pswriter)
1602-
elif self.output == 'PDF':
1603-
pswriter = list()
1604-
Element.fonts.set_canvas_size(w, h, pswriter)
1601+
elif self.output == 'PDF':
1602+
pswriter = list()
1603+
Element.fonts.set_canvas_size(w, h, pswriter)
16051604

16061605
handler.expr.render()
16071606
handler.clear()

0 commit comments

Comments
 (0)