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

Skip to content

Commit 974b360

Browse files
committed
Expose the pdf information dictionary
svn path=/trunk/matplotlib/; revision=7964
1 parent b386a56 commit 974b360

4 files changed

Lines changed: 66 additions & 9 deletions

File tree

CHANGELOG

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2009-11-13 The pdf backend now allows changing the contents of
2+
a pdf file's information dictionary via PdfPages.infodict. - JKS
3+
14
2009-11-12 font_manager.py should no longer cause EINTR on Python 2.6
25
(but will on the 2.5 version of subprocess). Also the
36
fc-list command in that file was fixed so now it should

doc/api/api_changes.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ list may help describe what changes may be necessary in your code.
1010
Changes beyond 0.99.x
1111
=====================
1212

13-
* You can now print several figures to one pdf file. See the docstrings
13+
* You can now print several figures to one pdf file and modify the
14+
document information dictionary of a pdf file. See the docstrings
1415
of the class :class:`matplotlib.backends.backend_pdf.PdfPages` for
1516
more information.
1617

examples/pylab_examples/multipage_pdf.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# This is a demo of creating a pdf file with several pages.
22

3+
import datetime
34
import numpy as np
45
import matplotlib
56
from matplotlib.backends.backend_pdf import PdfPages
@@ -29,5 +30,14 @@
2930
pdf.savefig(fig) # or you can pass a Figure object to pdf.savefig
3031
close()
3132

33+
# We can also set the file's metadata via the PdfPages object:
34+
d = pdf.infodict()
35+
d['Title'] = 'Multipage PDF Example'
36+
d['Author'] = u'Jouni K. Sepp\xe4nen'
37+
d['Subject'] = 'How to create a multipage pdf file and set its metadata'
38+
d['Keywords'] = 'PdfPages multipage keywords author title subject'
39+
d['CreationDate'] = datetime.datetime(2009,11,13)
40+
d['ModDate'] = datetime.datetime.today()
41+
3242
# Remember to close the object - otherwise the file will not be usable
3343
pdf.close()

lib/matplotlib/backends/backend_pdf.py

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""
66
from __future__ import division
77

8+
import codecs
89
import os
910
import re
1011
import sys
@@ -149,6 +150,16 @@ def pdfRepr(obj):
149150
elif isinstance(obj, (int, long)):
150151
return "%d" % obj
151152

153+
# Unicode strings are encoded in UTF-16BE with byte-order mark.
154+
elif isinstance(obj, unicode):
155+
try:
156+
# But maybe it's really ASCII?
157+
s = obj.encode('ASCII')
158+
return pdfRepr(s)
159+
except UnicodeEncodeError:
160+
s = codecs.BOM_UTF16_BE + obj.encode('UTF-16BE')
161+
return pdfRepr(s)
162+
152163
# Strings are written in parentheses, with backslashes and parens
153164
# escaped. Actually balanced parens are allowed, but it is
154165
# simpler to escape them all. TODO: cut long strings into lines;
@@ -374,7 +385,6 @@ def __init__(self, filename):
374385
fh.write("%\254\334 \253\272\n")
375386

376387
self.rootObject = self.reserveObject('root')
377-
self.infoObject = self.reserveObject('info')
378388
self.pagesObject = self.reserveObject('pages')
379389
self.pageList = []
380390
self.fontObject = self.reserveObject('fonts')
@@ -388,13 +398,12 @@ def __init__(self, filename):
388398
'Pages': self.pagesObject }
389399
self.writeObject(self.rootObject, root)
390400

391-
info = { 'Creator': 'matplotlib ' + __version__ \
392-
+ ', http://matplotlib.sf.net',
393-
'Producer': 'matplotlib pdf backend',
394-
'CreationDate': datetime.today() }
395-
396-
# Possible TODO: Title, Author, Subject, Keywords
397-
self.writeObject(self.infoObject, info)
401+
revision = '$Rev$'.strip('$').split(':')[1].strip()
402+
self.infoDict = {
403+
'Creator': 'matplotlib %s, http://matplotlib.sf.net' % __version__,
404+
'Producer': 'matplotlib pdf backend r%s' % revision,
405+
'CreationDate': datetime.today()
406+
}
398407

399408
self.fontNames = {} # maps filenames to internal font names
400409
self.nextFont = 1 # next free internal font name
@@ -471,6 +480,7 @@ def close(self):
471480
{ 'Type': Name('Pages'),
472481
'Kids': self.pageList,
473482
'Count': len(self.pageList) })
483+
self.writeInfoDict()
474484

475485
# Finalize the file
476486
self.writeXref()
@@ -1280,6 +1290,31 @@ def writeXref(self):
12801290
if borken:
12811291
raise AssertionError, 'Indirect object does not exist'
12821292

1293+
def writeInfoDict(self):
1294+
"""Write out the info dictionary, checking it for good form"""
1295+
1296+
is_date = lambda x: isinstance(x, datetime)
1297+
check_trapped = lambda x: isinstance(x, Name) and x.name in \
1298+
('True', 'False', 'Unknown')
1299+
keywords = {'Title': is_string_like,
1300+
'Author': is_string_like,
1301+
'Subject': is_string_like,
1302+
'Keywords': is_string_like,
1303+
'Creator': is_string_like,
1304+
'Producer': is_string_like,
1305+
'CreationDate': is_date,
1306+
'ModDate': is_date,
1307+
'Trapped': check_trapped}
1308+
for k in self.infoDict.keys():
1309+
if k not in keywords:
1310+
warnings.warn('Unknown infodict keyword: %s' % k)
1311+
else:
1312+
if not keywords[k](self.infoDict[k]):
1313+
warnings.warn('Bad value for infodict keyword %s' % k)
1314+
1315+
self.infoObject = self.reserveObject('info')
1316+
self.writeObject(self.infoObject, self.infoDict)
1317+
12831318
def writeTrailer(self):
12841319
"""Write out the PDF trailer."""
12851320

@@ -2052,6 +2087,14 @@ def close(self):
20522087
self._file.close()
20532088
self._file = None
20542089

2090+
def infodict(self):
2091+
"""
2092+
Return a modifiable information dictionary object
2093+
(see PDF reference section 10.2.1 'Document Information
2094+
Dictionary').
2095+
"""
2096+
return self._file.infoDict
2097+
20552098
def savefig(self, figure=None, **kwargs):
20562099
"""
20572100
Save the Figure instance *figure* to this file as a new page.

0 commit comments

Comments
 (0)