Revision: 4126
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4126&view=rev
Author:   mdboom
Date:     2007-11-06 10:32:30 -0800 (Tue, 06 Nov 2007)

Log Message:
-----------
Prevent errors when using OpenType CFF fonts.  This means turning off
subsetting on backend_pdf, and raising an exception in backend_ps.

Modified Paths:
--------------
    trunk/matplotlib/examples/mathtext_examples.py
    trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
    trunk/matplotlib/lib/matplotlib/backends/backend_ps.py
    trunk/matplotlib/lib/matplotlib/font_manager.py
    trunk/matplotlib/lib/matplotlib/mathtext.py

Modified: trunk/matplotlib/examples/mathtext_examples.py
===================================================================
--- trunk/matplotlib/examples/mathtext_examples.py      2007-11-06 18:23:13 UTC 
(rev 4125)
+++ trunk/matplotlib/examples/mathtext_examples.py      2007-11-06 18:32:30 UTC 
(rev 4126)
@@ -49,7 +49,7 @@
     r'$\widehat{abc}\widetilde{def}$',
     r'$\Gamma \Delta \Theta \Lambda \Xi \Pi \Sigma \Upsilon \Phi \Psi \Omega$',
     r'$\alpha \beta \gamma \delta \epsilon \zeta \eta \theta \iota \lambda \mu 
\nu \xi \pi \kappa \rho \sigma \tau \upsilon \phi \chi \psi$',
-    ur'Generic symbol: $\u23ce \mathrm{\ue0f2}$'
+    ur'Generic symbol: $\u23ce \mathrm{\ue0f2 \U0001D538}$'
     ]
 
 from pylab import *

Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py     2007-11-06 
18:23:13 UTC (rev 4125)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py     2007-11-06 
18:32:30 UTC (rev 4126)
@@ -9,6 +9,7 @@
 import re
 import sys
 import time
+import warnings
 import zlib
 
 import numpy as npy
@@ -25,7 +26,7 @@
      FigureManagerBase, FigureCanvasBase
 from matplotlib.cbook import Bunch, enumerate, is_string_like, reverse_dict, 
get_realpath_and_stat
 from matplotlib.figure import Figure
-from matplotlib.font_manager import findfont
+from matplotlib.font_manager import findfont, is_opentype_cff_font
 from matplotlib.afm import AFM
 import matplotlib.type1font as type1font
 import matplotlib.dviread as dviread
@@ -786,7 +787,8 @@
                 glyph = font.load_char(ccode, flags=LOAD_NO_HINTING)
                 # Why divided by 3.0 ??? Wish I knew... MGD
                 widths.append((ccode, cvt(glyph.horiAdvance) / 3.0))
-                cid_to_gid_map[ccode] = unichr(gind)
+                if ccode < 65536:
+                    cid_to_gid_map[ccode] = unichr(gind)
                 max_ccode = max(ccode, max_ccode)
             widths.sort()
             cid_to_gid_map = cid_to_gid_map[:max_ccode + 1]
@@ -876,6 +878,15 @@
             'StemV'       : 0 # ???
             }
 
+        # The font subsetting to a Type 3 font does not work for
+        # OpenType (.otf) that embed a Postscript CFF font, so avoid that --
+        # save as a (non-subsetted) Type 42 font instead.
+        if is_opentype_cff_font(filename):
+            fonttype = 42
+            warnings.warn(("'%s' can not be subsetted into a Type 3 font. " +
+                           "The entire font will be embedded in the output.") %
+                           os.path.basename(filename))
+        
         if fonttype == 3:
             return embedTTFType3(font, characters, descriptor)
         elif fonttype == 42:
@@ -1134,10 +1145,6 @@
         self.truetype_font_cache = {}
         self.afm_font_cache = {}
         self.file.used_characters = self.used_characters = {}
-        if rcParams['pdf.fonttype'] == 3:
-            self.encode_string = self.encode_string_type3
-        else:
-            self.encode_string = self.encode_string_type42
         self.mathtext_parser = MathTextParser("Pdf")
         self.image_magnification = dpi/72.0
         self.tex_font_map = None
@@ -1344,7 +1351,7 @@
         # When using Type 3 fonts, we can't use character codes higher
         # than 255, so we use the "Do" command to render those
         # instead.
-        fonttype = rcParams['pdf.fonttype']
+        global_fonttype = rcParams['pdf.fonttype']
 
         # Set up a global transformation matrix for the whole math expression
         a = angle / 180.0 * pi
@@ -1357,6 +1364,11 @@
         prev_font = None, None
         oldx, oldy = 0, 0
         for ox, oy, fontname, fontsize, num, symbol_name in glyphs:
+            if is_opentype_cff_font(fontname):
+                fonttype = 42
+            else:
+                fonttype = global_fonttype
+            
             if fonttype == 42 or num <= 255:
                 self._setup_textpos(ox, oy, 0, oldx, oldy)
                 oldx, oldy = ox, oy
@@ -1364,14 +1376,19 @@
                     self.file.output(self.file.fontName(fontname), fontsize,
                                      Op.selectfont)
                     prev_font = fontname, fontsize
-                self.file.output(self.encode_string(unichr(num)), Op.show)
+                self.file.output(self.encode_string(unichr(num), fonttype), 
Op.show)
         self.file.output(Op.end_text)
 
         # If using Type 3 fonts, render all of the two-byte characters
         # as XObjects using the 'Do' command.
-        if fonttype == 3:
+        if global_fonttype == 3:
             for ox, oy, fontname, fontsize, num, symbol_name in glyphs:
-                if num > 255:
+                if is_opentype_cff_font(fontname):
+                    fonttype = 42
+                else:
+                    fonttype = global_fonttype
+                
+                if fonttype == 3 and num > 255:
                     self.file.output(Op.gsave,
                                      0.001 * fontsize, 0,
                                      0, 0.001 * fontsize,
@@ -1471,10 +1488,9 @@
             self.draw_polygon(boxgc, gc._rgb,
                               ((x1,y1), (x2,y2), (x3,y3), (x4,y4)))
 
-    def encode_string_type3(self, s):
-        return s.encode('cp1252', 'replace')
-
-    def encode_string_type42(self, s):
+    def encode_string(self, s, fonttype):
+        if fonttype == 3:
+            return s.encode('cp1252', 'replace')
         return s.encode('utf-16be', 'replace')
 
     def draw_text(self, gc, x, y, s, prop, angle, ismath=False):
@@ -1500,20 +1516,29 @@
             font = self._get_font_afm(prop)
             l, b, w, h = font.get_str_bbox(s)
             y -= b * fontsize / 1000
+            fonttype = 42
         else:
             font = self._get_font_ttf(prop)
             self.track_characters(font, s)
             font.set_text(s, 0.0, flags=LOAD_NO_HINTING)
             y += font.get_descent() / 64.0
 
+            fonttype = rcParams['pdf.fonttype']
+                
+            # We can't subset all OpenType fonts, so switch to Type 42
+            # in that case.
+            if is_opentype_cff_font(font.fname):
+                fonttype = 42
+            
         def check_simple_method(s):
             """Determine if we should use the simple or woven method
-            to output this text, and chunks the string into 1-bit and
-            2-bit sections if necessary."""
+            to output this text, and chunks the string into 1-byte and
+            2-byte sections if necessary."""
             use_simple_method = True
             chunks = []
-            if rcParams['pdf.fonttype'] == 3:
-                if not isinstance(s, str) and len(s) != 0:
+
+            if not rcParams['pdf.use14corefonts']:
+                if fonttype == 3 and not isinstance(s, str) and len(s) != 0:
                     # Break the string into chunks where each chunk is either
                     # a string of chars <= 255, or a single character > 255.
                     s = unicode(s)
@@ -1537,7 +1562,7 @@
                              prop.get_size_in_points(),
                              Op.selectfont)
             self._setup_textpos(x, y, angle)
-            self.file.output(self.encode_string(s), Op.show, Op.end_text)
+            self.file.output(self.encode_string(s, fonttype), Op.show, 
Op.end_text)
 
         def draw_text_woven(chunks):
             """Outputs text using the woven method, alternating
@@ -1567,7 +1592,7 @@
                 for chunk_type, chunk in chunks:
                     if mode == 1 and chunk_type == 1:
                         self._setup_textpos(newx, 0, 0, oldx, 0, 0)
-                        self.file.output(self.encode_string(chunk), Op.show)
+                        self.file.output(self.encode_string(chunk, fonttype), 
Op.show)
                         oldx = newx
 
                     lastgind = None

Modified: trunk/matplotlib/lib/matplotlib/backends/backend_ps.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_ps.py      2007-11-06 
18:23:13 UTC (rev 4125)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_ps.py      2007-11-06 
18:32:30 UTC (rev 4126)
@@ -18,7 +18,7 @@
 from matplotlib.cbook import is_string_like, izip, get_realpath_and_stat
 from matplotlib.figure import Figure
 
-from matplotlib.font_manager import findfont
+from matplotlib.font_manager import findfont, is_opentype_cff_font
 from matplotlib.ft2font import FT2Font, KERNING_DEFAULT, LOAD_NO_HINTING
 from matplotlib.ttconv import convert_ttf_to_ps
 from matplotlib.mathtext import MathTextParser
@@ -1030,7 +1030,7 @@
         else:
             self._print_figure(outfile, format, dpi, facecolor, edgecolor,
                                orientation, isLandscape, papertype)
-        
+            
     def _print_figure(self, outfile, format, dpi=72, facecolor='w', 
edgecolor='w',
                       orientation='portrait', isLandscape=False, 
papertype=None):
         """
@@ -1134,7 +1134,15 @@
                     for c in chars:
                         gind = cmap.get(ord(c)) or 0
                         glyph_ids.append(gind)
-                    convert_ttf_to_ps(font_filename, fh, 
rcParams['ps.fonttype'], glyph_ids)
+                    # The ttf to ps (subsetting) support doesn't work for
+                    # OpenType fonts that are Postscript inside (like the
+                    # STIX fonts).  This will simply turn that off to avoid
+                    # errors.
+                    if is_opentype_cff_font(font_filename):
+                        raise RuntimeError("OpenType CFF fonts can not be 
saved using the internal Postscript backend at this time.\nConsider using the 
Cairo backend.")
+                    else:
+                        fonttype = rcParams['ps.fonttype']
+                        convert_ttf_to_ps(font_filename, fh, 
rcParams['ps.fonttype'], glyph_ids)
         print >>fh, "end"
         print >>fh, "%%EndProlog"
 

Modified: trunk/matplotlib/lib/matplotlib/font_manager.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/font_manager.py     2007-11-06 18:23:13 UTC 
(rev 4125)
+++ trunk/matplotlib/lib/matplotlib/font_manager.py     2007-11-06 18:32:30 UTC 
(rev 4126)
@@ -1059,6 +1059,25 @@
             return self.defaultFont
         return fname
 
+
+_is_opentype_cff_font_cache = {}
+def is_opentype_cff_font(filename):
+    """
+    Returns True if the given font is a Postscript Compact Font Format
+    Font embedded in an OpenType wrapper.
+    """
+    if os.path.splitext(filename)[1].lower() == '.otf':
+        result = _is_opentype_cff_font_cache.get(filename)
+        if result is None:
+            fd = open(filename, 'rb')
+            tag = fd.read(4)
+            fd.close()
+            result = (tag == 'OTTO')
+            _is_opentype_cff_font_cache[filename] = result
+        return result
+    return False
+        
+    
 if USE_FONTCONFIG and sys.platform != 'win32':
     import re
 

Modified: trunk/matplotlib/lib/matplotlib/mathtext.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/mathtext.py 2007-11-06 18:23:13 UTC (rev 
4125)
+++ trunk/matplotlib/lib/matplotlib/mathtext.py 2007-11-06 18:32:30 UTC (rev 
4126)
@@ -1945,7 +1945,8 @@
                        ) | Error(r"Expected \hspace{n}"))
                      ).setParseAction(self.customspace).setName('customspace')
 
-        symbol       =(Regex(ur"([a-zA-Z0-9 
+\-*/<>=:,.;!'@()\u0080-\uffff])|(\\[%${}\[\]])")
+        unicode_range = u"\U00000080-\U0001ffff"
+        symbol       =(Regex(UR"([a-zA-Z0-9 
+\-*/<>=:,.;!'@()%s])|(\\[%%${}\[\]])" % unicode_range)
                      | Combine(
                          bslash
                        + oneOf(tex2uni.keys())


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Matplotlib-checkins mailing list
Matplotlib-checkins@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to