From: <jo...@us...> - 2009-01-01 22:24:03
|
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. |