Revision: 6730
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6730&view=rev
Author:   jouni
Date:     2009-01-01 22:23:57 +0000 (Thu, 01 Jan 2009)

Log Message:
-----------
Allow multipage pdf files

Modified Paths:
--------------
    trunk/matplotlib/CHANGELOG
    trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py

Added Paths:
-----------
    trunk/matplotlib/examples/pylab_examples/multipage_pdf.py

Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG  2008-12-31 20:19:16 UTC (rev 6729)
+++ trunk/matplotlib/CHANGELOG  2009-01-01 22:23:57 UTC (rev 6730)
@@ -1,3 +1,5 @@
+2009-01-02 Allow multipage pdf files. - JKS
+
 2008-12-31 Improve pdf usetex by adding support for font effects
            (slanting and extending). - JKS
 

Added: trunk/matplotlib/examples/pylab_examples/multipage_pdf.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/multipage_pdf.py                   
        (rev 0)
+++ trunk/matplotlib/examples/pylab_examples/multipage_pdf.py   2009-01-01 
22:23:57 UTC (rev 6730)
@@ -0,0 +1,29 @@
+import numpy as np
+import matplotlib
+from matplotlib.backends.backend_pdf import PdfFile
+from pylab import *
+
+pdf = PdfFile('multipage_pdf.pdf')
+
+figure(figsize=(3,3))
+plot(range(7), [3,1,4,1,5,9,2], 'r-o')
+title('Page One')
+savefig(pdf, format='pdf')
+close()
+
+rc('text', usetex=True)
+figure(figsize=(8,6))
+x = np.arange(0,5,0.1)
+plot(x, np.sin(x), 'b-')
+title('Page Two')
+savefig(pdf, format='pdf')
+close()
+
+rc('text', usetex=False)
+figure(figsize=(4,5))
+plot(x, x*x, 'ko')
+title('Page Three')
+savefig(pdf, format='pdf')
+close()
+
+pdf.close()

Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py     2008-12-31 
20:19:16 UTC (rev 6729)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py     2009-01-01 
22:23:57 UTC (rev 6730)
@@ -219,6 +219,9 @@
     def __repr__(self):
         return "<Name %s>" % self.name
 
+    def __str__(self):
+        return '/' + self.name
+
     @staticmethod
     def hexify(match):
         return '#%02x' % ord(match.group())
@@ -336,13 +339,7 @@
 class PdfFile(object):
     """PDF file with one page."""
 
-    def __init__(self, width, height, dpi, filename):
-        self.width, self.height = width, height
-        self.dpi = dpi
-        if rcParams['path.simplify']:
-            self.simplify = (width * dpi, height * dpi)
-        else:
-            self.simplify = None
+    def __init__(self, filename):
         self.nextObject = 1     # next free object id
         self.xrefTable = [ [0, 65535, 'the zero object'] ]
         self.passed_in_file_object = False
@@ -364,17 +361,16 @@
 
         self.rootObject = self.reserveObject('root')
         self.infoObject = self.reserveObject('info')
-        pagesObject = self.reserveObject('pages')
-        thePageObject = self.reserveObject('page 0')
-        contentObject = self.reserveObject('contents of page 0')
+        self.pagesObject = self.reserveObject('pages')
+        self.pageList = []
         self.fontObject = self.reserveObject('fonts')
         self.alphaStateObject = self.reserveObject('extended graphics states')
         self.hatchObject = self.reserveObject('tiling patterns')
         self.XObjectObject = self.reserveObject('external objects')
-        resourceObject = self.reserveObject('resources')
+        self.resourceObject = self.reserveObject('resources')
 
         root = { 'Type': Name('Catalog'),
-                 'Pages': pagesObject }
+                 'Pages': self.pagesObject }
         self.writeObject(self.rootObject, root)
 
         info = { 'Creator': 'matplotlib ' + __version__ \
@@ -385,23 +381,12 @@
         # Possible TODO: Title, Author, Subject, Keywords
         self.writeObject(self.infoObject, info)
 
-        pages = { 'Type': Name('Pages'),
-                  'Kids': [ thePageObject ],
-                  'Count': 1 }
-        self.writeObject(pagesObject, pages)
-
-        thePage = { 'Type': Name('Page'),
-                    'Parent': pagesObject,
-                    'Resources': resourceObject,
-                    'MediaBox': [ 0, 0, dpi*width, dpi*height ],
-                    'Contents': contentObject }
-        self.writeObject(thePageObject, thePage)
-
         self.fontNames = {}     # maps filenames to internal font names
         self.nextFont = 1       # next free internal font name
         self.dviFontInfo = {}   # information on dvi fonts
         self.type1Descriptors = {} # differently encoded Type-1 fonts may
                                    # share the same descriptor
+        self.used_characters = {}
 
         self.alphaStates = {}   # maps alpha values to graphics state objects
         self.nextAlphaState = 1
@@ -426,16 +411,32 @@
                       'ExtGState': self.alphaStateObject,
                       'Pattern': self.hatchObject,
                       'ProcSet': procsets }
-        self.writeObject(resourceObject, resources)
+        self.writeObject(self.resourceObject, resources)
 
-        # Start the content stream of the page
+    def newPage(self, width, height):
+        self.endStream()
+
+        self.width, self.height = width, height
+        if rcParams['path.simplify']:
+            self.simplify = (width * 72, height * 72)
+        else:
+            self.simplify = None
+        contentObject = self.reserveObject('page contents')
+        thePage = { 'Type': Name('Page'),
+                    'Parent': self.pagesObject,
+                    'Resources': self.resourceObject,
+                    'MediaBox': [ 0, 0, 72*width, 72*height ],
+                    'Contents': contentObject }
+        pageObject = self.reserveObject('page')
+        self.writeObject(pageObject, thePage)
+        self.pageList.append(pageObject)
+
         self.beginStream(contentObject.id,
                          self.reserveObject('length of content stream'))
 
     def close(self):
-        # End the content stream and write out the various deferred
-        # objects
         self.endStream()
+        # Write out the various deferred objects
         self.writeFonts()
         self.writeObject(self.alphaStateObject,
                          dict([(val[0], val[1])
@@ -449,6 +450,12 @@
         self.writeObject(self.XObjectObject, xobjects)
         self.writeImages()
         self.writeMarkers()
+        self.writeObject(self.pagesObject,
+                         { 'Type': Name('Pages'),
+                           'Kids': self.pageList,
+                           'Count': len(self.pageList) })
+
+        # Finalize the file
         self.writeXref()
         self.writeTrailer()
         if self.passed_in_file_object:
@@ -471,8 +478,9 @@
         self.currentstream = Stream(id, len, self, extra)
 
     def endStream(self):
-        self.currentstream.end()
-        self.currentstream = None
+        if self.currentstream is not None:
+            self.currentstream.end()
+            self.currentstream = None
 
     def fontName(self, fontprop):
         """
@@ -493,20 +501,27 @@
             Fx = Name('F%d' % self.nextFont)
             self.fontNames[filename] = Fx
             self.nextFont += 1
+            matplotlib.verbose.report(
+                'Assigning font %s = %s' % (Fx, filename),
+                'debug')
 
         return Fx
 
     def writeFonts(self):
         fonts = {}
         for filename, Fx in self.fontNames.items():
+            matplotlib.verbose.report('Embedding font %s' % filename, 'debug')
             if filename.endswith('.afm'):
                 # from pdf.use14corefonts
+                matplotlib.verbose.report('Writing AFM font', 'debug')
                 fontdictObject = self._write_afm_font(filename)
             elif self.dviFontInfo.has_key(filename):
                 # a Type 1 font from a dvi file; the filename is really the 
TeX name
+                matplotlib.verbose.report('Writing Type-1 font', 'debug')
                 fontdictObject = self.embedType1(filename, 
self.dviFontInfo[filename])
             else:
                 # a normal TrueType font
+                matplotlib.verbose.report('Writing TrueType font', 'debug')
                 realpath, stat_key = get_realpath_and_stat(filename)
                 chars = self.used_characters.get(stat_key)
                 if chars is not None and len(chars[1]):
@@ -1143,8 +1158,7 @@
         return cmds
 
     def writePath(self, path, transform):
-        cmds = self.pathOperations(
-            path, transform, self.simplify)
+        cmds = self.pathOperations(path, transform, self.simplify)
         self.output(*cmds)
 
     def reserveObject(self, name=''):
@@ -1198,13 +1212,11 @@
     truetype_font_cache = maxdict(50)
     afm_font_cache = maxdict(50)
 
-    def __init__(self, file, dpi, image_dpi):
+    def __init__(self, file, image_dpi):
         RendererBase.__init__(self)
         self.file = file
         self.gc = self.new_gc()
-        self.file.used_characters = self.used_characters = {}
         self.mathtext_parser = MathTextParser("Pdf")
-        self.dpi = dpi
         self.image_dpi = image_dpi
         self.tex_font_map = None
 
@@ -1235,13 +1247,13 @@
         else:
             fname = font.fname
         realpath, stat_key = get_realpath_and_stat(fname)
-        used_characters = self.used_characters.setdefault(
+        used_characters = self.file.used_characters.setdefault(
             stat_key, (realpath, set()))
         used_characters[1].update([ord(x) for x in s])
 
     def merge_used_characters(self, other):
         for stat_key, (realpath, charset) in other.items():
-            used_characters = self.used_characters.setdefault(
+            used_characters = self.file.used_characters.setdefault(
                 stat_key, (realpath, set()))
             used_characters[1].update(charset)
 
@@ -1299,7 +1311,7 @@
     def draw_mathtext(self, gc, x, y, s, prop, angle):
         # TODO: fix positioning and encoding
         width, height, descent, glyphs, rects, used_characters = \
-            self.mathtext_parser.parse(s, self.dpi, prop)
+            self.mathtext_parser.parse(s, 72, prop)
         self.merge_used_characters(used_characters)
 
         # When using Type 3 fonts, we can't use character codes higher
@@ -1327,7 +1339,6 @@
                 self._setup_textpos(ox, oy, 0, 0, oldx, oldy)
                 oldx, oldy = ox, oy
                 if (fontname, fontsize) != prev_font:
-                    fontsize *= self.dpi/72.0
                     self.file.output(self.file.fontName(fontname), fontsize,
                                      Op.selectfont)
                     prev_font = fontname, fontsize
@@ -1338,7 +1349,6 @@
         # as XObjects using the 'Do' command.
         if global_fonttype == 3:
             for ox, oy, fontname, fontsize, num, symbol_name in glyphs:
-                fontsize *= self.dpi/72.0
                 if is_opentype_cff_font(fontname):
                     fonttype = 42
                 else:
@@ -1367,7 +1377,7 @@
         texmanager = self.get_texmanager()
         fontsize = prop.get_size_in_points()
         dvifile = texmanager.make_dvi(s, fontsize)
-        dvi = dviread.Dvi(dvifile, self.dpi)
+        dvi = dviread.Dvi(dvifile, 72)
         page = iter(dvi).next()
         dvi.close()
 
@@ -1463,7 +1473,7 @@
         self.check_gc(gc, gc._rgb)
         if ismath: return self.draw_mathtext(gc, x, y, s, prop, angle)
 
-        fontsize = prop.get_size_in_points() * self.dpi/72.0
+        fontsize = prop.get_size_in_points()
 
         if rcParams['pdf.use14corefonts']:
             font = self._get_font_afm(prop)
@@ -1593,14 +1603,14 @@
             texmanager = self.get_texmanager()
             fontsize = prop.get_size_in_points()
             dvifile = texmanager.make_dvi(s, fontsize)
-            dvi = dviread.Dvi(dvifile, self.dpi)
+            dvi = dviread.Dvi(dvifile, 72)
             page = iter(dvi).next()
             dvi.close()
             # A total height (including the descent) needs to be returned.
             return page.width, page.height+page.descent, page.descent
         if ismath:
             w, h, d, glyphs, rects, used_characters = \
-                self.mathtext_parser.parse(s, self.dpi, prop)
+                self.mathtext_parser.parse(s, 72, prop)
 
         elif rcParams['pdf.use14corefonts']:
             font = self._get_font_afm(prop)
@@ -1645,14 +1655,14 @@
                 self.truetype_font_cache[filename] = font
             self.truetype_font_cache[key] = font
         font.clear()
-        font.set_size(prop.get_size_in_points(), self.dpi)
+        font.set_size(prop.get_size_in_points(), 72)
         return font
 
     def flipy(self):
         return False
 
     def get_canvas_width_height(self):
-        return self.file.width / self.dpi, self.file.height / self.dpi
+        return self.file.width / 72.0, self.file.height / 72.0
 
     def new_gc(self):
         return GraphicsContextPdf(self.file)
@@ -1887,16 +1897,22 @@
         return 'pdf'
 
     def print_pdf(self, filename, **kwargs):
-        ppi = 72 # Postscript points in an inch
         image_dpi = kwargs.get('dpi', 72) # dpi to use for images
-        self.figure.set_dpi(ppi)
+        self.figure.set_dpi(72)           # there are 72 pdf points to an inch
         width, height = self.figure.get_size_inches()
-        file = PdfFile(width, height, ppi, filename)
+        if isinstance(filename, PdfFile):
+            file = filename
+        else:
+            file = PdfFile(filename)
+        file.newPage(width, height)
         renderer = MixedModeRenderer(
-            width, height, ppi, RendererPdf(file, ppi, image_dpi))
+            width, height, 72, RendererPdf(file, image_dpi))
         self.figure.draw(renderer)
         renderer.finalize()
-        file.close()
+        if file != filename:    # we opened the file
+            file.close()
+        else:                   # multipage file; just finish off the page
+            file.endStream()
 
 class FigureManagerPdf(FigureManagerBase):
     pass


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

------------------------------------------------------------------------------
_______________________________________________
Matplotlib-checkins mailing list
Matplotlib-checkins@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to