<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The Mouse Vs. The Python &#187; Python PDF Series</title>
	<atom:link href="http://www.blog.pythonlibrary.org/tag/python-pdf-series/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.blog.pythonlibrary.org</link>
	<description>Python Programming from the Frontlines</description>
	<lastBuildDate>Sun, 05 Sep 2010 16:58:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Manipulating PDFs with Python and pyPdf</title>
		<link>http://www.blog.pythonlibrary.org/2010/05/15/manipulating-pdfs-with-python-and-pypdf/</link>
		<comments>http://www.blog.pythonlibrary.org/2010/05/15/manipulating-pdfs-with-python-and-pypdf/#comments</comments>
		<pubDate>Sat, 15 May 2010 19:50:11 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[wxPython]]></category>
		<category><![CDATA[Python PDF Series]]></category>

		<guid isPermaLink="false">http://www.blog.pythonlibrary.org/?p=868</guid>
		<description><![CDATA[There&#8217;s a handy 3rd party module called pyPdf out there that you can use to merge PDFs documents together, rotate pages, split and crop pages, and decrypt/encrypt PDF documents. In this article, we&#8217;ll take a look at a few of these functions and then create a simple GUI with wxPython that will allow us to [...]]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s a handy 3rd party module called <a href="http://pybrary.net/pyPdf/">pyPdf</a> out there that you can use to merge PDFs documents together, rotate pages, split and crop pages, and decrypt/encrypt PDF documents. In this article, we&#8217;ll take a look at a few of these functions and then create a simple GUI with <a href="http://www.wxpython.org">wxPython</a> that will allow us to merge a couple of PDFs.<span id="more-868"></span></p>
<h2>A pyPdf Tour</h2>
<p>To get the most out of pyPdf, you need to learn its two major functions: PdfFileReader and PdfFileWriter. They are the ones that I use the most. Let&#8217;s take a look at what they can do:</p>
<pre class="python"><span style="color: #808080; font-style: italic;"># Merge two PDFs</span>
<span style="color: #ff7700;font-weight:bold;">from</span> pyPdf <span style="color: #ff7700;font-weight:bold;">import</span> PdfFileReader, PdfFileWriter
&nbsp;
output = PdfFileWriter<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
pdfOne = PdfFileReader<span style="color: black;">&#40;</span><span style="color: #008000;">file</span><span style="color: black;">&#40;</span> <span style="color: #483d8b;">&quot;some<span style="color: #000099; font-weight: bold;">\p</span>ath<span style="color: #000099; font-weight: bold;">\t</span>o<span style="color: #000099; font-weight: bold;">\a</span><span style="color: #000099; font-weight: bold;">\P</span>Df&quot;</span>, <span style="color: #483d8b;">&quot;rb&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
pdfTwo = PdfFileReader<span style="color: black;">&#40;</span><span style="color: #008000;">file</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;some<span style="color: #000099; font-weight: bold;">\o</span>ther<span style="color: #000099; font-weight: bold;">\p</span>ath<span style="color: #000099; font-weight: bold;">\t</span>o<span style="color: #000099; font-weight: bold;">\a</span><span style="color: #000099; font-weight: bold;">\P</span>Df&quot;</span>, <span style="color: #483d8b;">&quot;rb&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
output.<span style="color: black;">addPage</span><span style="color: black;">&#40;</span>pdfOne.<span style="color: black;">getPage</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
output.<span style="color: black;">addPage</span><span style="color: black;">&#40;</span>pdfTwo.<span style="color: black;">getPage</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
outputStream = <span style="color: #008000;">file</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">&quot;output.pdf&quot;</span>, <span style="color: #483d8b;">&quot;wb&quot;</span><span style="color: black;">&#41;</span>
output.<span style="color: black;">write</span><span style="color: black;">&#40;</span>outputStream<span style="color: black;">&#41;</span>
outputStream.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre>
<p>The code above will open two PDFs, take the first page from each and create a third PDF by joining those two pages. Note that the pages are zero-based, so zero is page one, one is page two, etc. I use this sort of script to extract one or more pages from a PDF or to join a series of PDFs together. For example, sometimes my users will receive a bunch of scanned documents where each page of the document ends up in a separate PDF. They need all the single pages joined into one PDF and pyPdf allows me to do this very simply.</p>
<p>There aren&#8217;t many applications for the rotating functions that pyPdf gives me in my day-to-day experience, but maybe you have lots of users that scan documents in landscape rather than portrait and you end up needing to do a lot of turning. Fortunately, this is pretty painless:</p>
<pre class="python"><span style="color: #ff7700;font-weight:bold;">from</span> pyPdf <span style="color: #ff7700;font-weight:bold;">import</span> PdfFileWriter, PdfFileReader
&nbsp;
output = PdfFileWriter<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
input1 = PdfFileReader<span style="color: black;">&#40;</span><span style="color: #008000;">file</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;document1.pdf&quot;</span>, <span style="color: #483d8b;">&quot;rb&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
output.<span style="color: black;">addPage</span><span style="color: black;">&#40;</span>input1.<span style="color: black;">getPage</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>.<span style="color: black;">rotateClockwise</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">90</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># output.addPage(input1.getPage(2).rotateCounterClockwise(90))</span>
&nbsp;
outputStream = <span style="color: #008000;">file</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;output.pdf&quot;</span>, <span style="color: #483d8b;">&quot;wb&quot;</span><span style="color: black;">&#41;</span>
output.<span style="color: black;">write</span><span style="color: black;">&#40;</span>outputStream<span style="color: black;">&#41;</span>
outputStream.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre>
<p>The code above is just taken from the pyPdf documentation and shortened for this example. As you can see, the method to call is <em>rotateClockwise</em> or <em>rotateCounterClockwise</em>. Make sure you pass the method the number of degrees to turn the page as well.</p>
<p>Now let&#8217;s see what information we can pull from the PDF about itself:</p>
<pre class="python"><span style="color: #66cc66;">&gt;&gt;&gt;</span> <span style="color: #ff7700;font-weight:bold;">from</span> pyPdf <span style="color: #ff7700;font-weight:bold;">import</span> PdfFileReader
<span style="color: #66cc66;">&gt;&gt;&gt;</span> p = r<span style="color: #483d8b;">'E:<span style="color: #000099; font-weight: bold;">\M</span>y Documents<span style="color: #000099; font-weight: bold;">\M</span>y Dropbox<span style="color: #000099; font-weight: bold;">\e</span>books<span style="color: #000099; font-weight: bold;">\h</span>elloWorld book.pdf'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> pdf = PdfFileReader<span style="color: black;">&#40;</span><span style="color: #008000;">file</span><span style="color: black;">&#40;</span>p, <span style="color: #483d8b;">'rb'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> pdf.<span style="color: black;">documentInfo</span>
<span style="color: black;">&#123;</span><span style="color: #483d8b;">'/CreationDate'</span>: u<span style="color: #483d8b;">'D:20090323080712Z'</span>, <span style="color: #483d8b;">'/Author'</span>: u<span style="color: #483d8b;">'Warren Sande'</span>, <span style="color: #483d8b;">'/Producer'</span>: u<span style="color: #483d8b;">'Acrobat Distiller 8.0.0 (Windows)'</span>, <span style="color: #483d8b;">'/Creator'</span>: u<span style="color: #483d8b;">'FrameMaker 8.0'</span>, <span style="color: #483d8b;">'/ModDate'</span>: u<span style="color: #483d8b;">&quot;D:20090401124817-04'00'&quot;</span>, <span style="color: #483d8b;">'/Title'</span>: u<span style="color: #483d8b;">'Hello World!'</span><span style="color: black;">&#125;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> pdf.<span style="color: black;">getNumPages</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #ff4500;">432</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> info = pdf.<span style="color: black;">getDocumentInfo</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> info.<span style="color: black;">author</span>
u<span style="color: #483d8b;">'Warren Sande'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> info.<span style="color: black;">creator</span>
u<span style="color: #483d8b;">'FrameMaker 8.0'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> info.<span style="color: black;">producer</span>
u<span style="color: #483d8b;">'Acrobat Distiller 8.0.0 (Windows)'</span>
<span style="color: #66cc66;">&gt;&gt;&gt;</span> info.<span style="color: black;">title</span>
u<span style="color: #483d8b;">'Hello World!'</span></pre>
<p>As you can see, we can gather quite a bit of useful data using pyPdf. Now let&#8217;s create a simple GUI to make merging two PDFs easier!</p>
<h2>Creating a wxPython PDF Merger Application</h2>
<p><a href="http://www.blog.pythonlibrary.org/wp-content/uploads/2010/05/pdf_joiner.png"><img src="http://www.blog.pythonlibrary.org/wp-content/uploads/2010/05/pdf_joiner.png" alt="PDF Joiner" title="PDF Joiner" width="416" height="200" class="aligncenter size-full wp-image-875" /></a></p>
<p>I came up with this script yesterday. It uses Tim Golden&#8217;s <a href="http://timgolden.me.uk/python/winshell.html">winshell </a>module to give me easy access to the user&#8217;s desktop on Windows. If you&#8217;re on Linux or Mac, then you&#8217;ll want to change this part of the code for your platform. I wanted to use wxPython&#8217;s StandardPaths module, but it didn&#8217;t have a function for getting the desktop that I could see. Anyway, enough talk. Let&#8217;s look at some code!</p>
<pre class="python"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
<span style="color: #ff7700;font-weight:bold;">import</span> pyPdf
<span style="color: #ff7700;font-weight:bold;">import</span> winshell
<span style="color: #ff7700;font-weight:bold;">import</span> wx
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> MyFileDropTarget<span style="color: black;">&#40;</span>wx.<span style="color: black;">FileDropTarget</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, window<span style="color: black;">&#41;</span>:
        wx.<span style="color: black;">FileDropTarget</span>.<span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">window</span> = window
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> OnDropFiles<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, x, y, filenames<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">window</span>.<span style="color: black;">SetInsertionPointEnd</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">for</span> <span style="color: #008000;">file</span> <span style="color: #ff7700;font-weight:bold;">in</span> filenames:
            <span style="color: #008000;">self</span>.<span style="color: black;">window</span>.<span style="color: black;">WriteText</span><span style="color: black;">&#40;</span><span style="color: #008000;">file</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">########################################################################</span>
<span style="color: #ff7700;font-weight:bold;">class</span> JoinerPanel<span style="color: black;">&#40;</span>wx.<span style="color: black;">Panel</span><span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;</span><span style="color: #483d8b;">&quot;&quot;</span><span style="color: #483d8b;">&quot;&quot;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#----------------------------------------------------------------------</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, parent<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;</span><span style="color: #483d8b;">&quot;Constructor&quot;</span><span style="color: #483d8b;">&quot;&quot;</span>
        wx.<span style="color: black;">Panel</span>.<span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, parent=parent<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #008000;">self</span>.<span style="color: black;">currentPath</span> = winshell.<span style="color: black;">desktop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
        lblSize = <span style="color: black;">&#40;</span><span style="color: #ff4500;">70</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>
        pdfLblOne = wx.<span style="color: black;">StaticText</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, label=<span style="color: #483d8b;">&quot;PDF One:&quot;</span>, size=lblSize<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pdfOne</span> = wx.<span style="color: black;">TextCtrl</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        dt = MyFileDropTarget<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">pdfOne</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pdfOne</span>.<span style="color: black;">SetDropTarget</span><span style="color: black;">&#40;</span>dt<span style="color: black;">&#41;</span>
        pdfOneBtn = wx.<span style="color: black;">Button</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, label=<span style="color: #483d8b;">&quot;Browse&quot;</span>, name=<span style="color: #483d8b;">&quot;pdfOneBtn&quot;</span><span style="color: black;">&#41;</span>
        pdfOneBtn.<span style="color: black;">Bind</span><span style="color: black;">&#40;</span>wx.<span style="color: black;">EVT_BUTTON</span>, <span style="color: #008000;">self</span>.<span style="color: black;">onBrowse</span><span style="color: black;">&#41;</span>
&nbsp;
        pdfLblTwo = wx.<span style="color: black;">StaticText</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, label=<span style="color: #483d8b;">&quot;PDF Two:&quot;</span>, size=lblSize<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pdfTwo</span> = wx.<span style="color: black;">TextCtrl</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        dt = MyFileDropTarget<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">pdfTwo</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pdfTwo</span>.<span style="color: black;">SetDropTarget</span><span style="color: black;">&#40;</span>dt<span style="color: black;">&#41;</span>
        pdfTwoBtn = wx.<span style="color: black;">Button</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, label=<span style="color: #483d8b;">&quot;Browse&quot;</span>, name=<span style="color: #483d8b;">&quot;pdfTwoBtn&quot;</span><span style="color: black;">&#41;</span>
        pdfTwoBtn.<span style="color: black;">Bind</span><span style="color: black;">&#40;</span>wx.<span style="color: black;">EVT_BUTTON</span>, <span style="color: #008000;">self</span>.<span style="color: black;">onBrowse</span><span style="color: black;">&#41;</span>
&nbsp;
        outputLbl = wx.<span style="color: black;">StaticText</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, label=<span style="color: #483d8b;">&quot;Output name:&quot;</span>, size=lblSize<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">outputPdf</span> = wx.<span style="color: black;">TextCtrl</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
        widgets = <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span>pdfLblOne, <span style="color: #008000;">self</span>.<span style="color: black;">pdfOne</span>, pdfOneBtn<span style="color: black;">&#41;</span>,
                   <span style="color: black;">&#40;</span>pdfLblTwo, <span style="color: #008000;">self</span>.<span style="color: black;">pdfTwo</span>, pdfTwoBtn<span style="color: black;">&#41;</span>,
                   <span style="color: black;">&#40;</span>outputLbl, <span style="color: #008000;">self</span>.<span style="color: black;">outputPdf</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
&nbsp;
        joinBtn = wx.<span style="color: black;">Button</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, label=<span style="color: #483d8b;">&quot;Join PDFs&quot;</span><span style="color: black;">&#41;</span>
        joinBtn.<span style="color: black;">Bind</span><span style="color: black;">&#40;</span>wx.<span style="color: black;">EVT_BUTTON</span>, <span style="color: #008000;">self</span>.<span style="color: black;">onJoinPdfs</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #008000;">self</span>.<span style="color: black;">mainSizer</span> = wx.<span style="color: black;">BoxSizer</span><span style="color: black;">&#40;</span>wx.<span style="color: black;">VERTICAL</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> widget <span style="color: #ff7700;font-weight:bold;">in</span> widgets:
            <span style="color: #008000;">self</span>.<span style="color: black;">buildRows</span><span style="color: black;">&#40;</span>widget<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">mainSizer</span>.<span style="color: black;">Add</span><span style="color: black;">&#40;</span>joinBtn, <span style="color: #ff4500;">0</span>, wx.<span style="color: black;">ALL</span>|wx.<span style="color: black;">CENTER</span>, <span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">SetSizer</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">mainSizer</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#----------------------------------------------------------------------</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> buildRows<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, widgets<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;</span><span style="color: #483d8b;">&quot;&quot;</span><span style="color: #483d8b;">&quot;&quot;</span>
        sizer = wx.<span style="color: black;">BoxSizer</span><span style="color: black;">&#40;</span>wx.<span style="color: black;">HORIZONTAL</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> widget <span style="color: #ff7700;font-weight:bold;">in</span> widgets:
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span>widget, wx.<span style="color: black;">StaticText</span><span style="color: black;">&#41;</span>:
                sizer.<span style="color: black;">Add</span><span style="color: black;">&#40;</span>widget, <span style="color: #ff4500;">0</span>, wx.<span style="color: black;">ALL</span>|wx.<span style="color: black;">CENTER</span>, <span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">elif</span> <span style="color: #008000;">isinstance</span><span style="color: black;">&#40;</span>widget, wx.<span style="color: black;">TextCtrl</span><span style="color: black;">&#41;</span>:
                sizer.<span style="color: black;">Add</span><span style="color: black;">&#40;</span>widget, <span style="color: #ff4500;">1</span>, wx.<span style="color: black;">ALL</span>|wx.<span style="color: black;">EXPAND</span>, <span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                sizer.<span style="color: black;">Add</span><span style="color: black;">&#40;</span>widget, <span style="color: #ff4500;">0</span>, wx.<span style="color: black;">ALL</span>, <span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">mainSizer</span>.<span style="color: black;">Add</span><span style="color: black;">&#40;</span>sizer, <span style="color: #ff4500;">0</span>, wx.<span style="color: black;">EXPAND</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#----------------------------------------------------------------------</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> onBrowse<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, event<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;</span><span style="color: #483d8b;">&quot;
        Browse for PDFs
        &quot;</span><span style="color: #483d8b;">&quot;&quot;</span>
        widget = event.<span style="color: black;">GetEventObject</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        name = widget.<span style="color: black;">GetName</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
        wildcard = <span style="color: #483d8b;">&quot;PDF (*.pdf)|*.pdf&quot;</span>
        dlg = wx.<span style="color: black;">FileDialog</span><span style="color: black;">&#40;</span>
            <span style="color: #008000;">self</span>, message=<span style="color: #483d8b;">&quot;Choose a file&quot;</span>,
            defaultDir=<span style="color: #008000;">self</span>.<span style="color: black;">currentPath</span>,
            defaultFile=<span style="color: #483d8b;">&quot;&quot;</span>,
            wildcard=wildcard,
            style=wx.<span style="color: black;">OPEN</span> | wx.<span style="color: black;">CHANGE_DIR</span>
            <span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> dlg.<span style="color: black;">ShowModal</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span> == wx.<span style="color: black;">ID_OK</span>:
            path = dlg.<span style="color: black;">GetPath</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> name == <span style="color: #483d8b;">&quot;pdfOneBtn&quot;</span>:
                <span style="color: #008000;">self</span>.<span style="color: black;">pdfOne</span>.<span style="color: black;">SetValue</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                <span style="color: #008000;">self</span>.<span style="color: black;">pdfTwo</span>.<span style="color: black;">SetValue</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span>
            <span style="color: #008000;">self</span>.<span style="color: black;">currentPath</span> = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span>
        dlg.<span style="color: black;">Destroy</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;">#----------------------------------------------------------------------</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> onJoinPdfs<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, event<span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;</span><span style="color: #483d8b;">&quot;
        Join the two PDFs together and save the result to the desktop
        &quot;</span><span style="color: #483d8b;">&quot;&quot;</span>
        pdfOne = <span style="color: #008000;">self</span>.<span style="color: black;">pdfOne</span>.<span style="color: black;">GetValue</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        pdfTwo = <span style="color: #008000;">self</span>.<span style="color: black;">pdfTwo</span>.<span style="color: black;">GetValue</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">exists</span><span style="color: black;">&#40;</span>pdfOne<span style="color: black;">&#41;</span>:
            msg = <span style="color: #483d8b;">&quot;The PDF at %s does not exist!&quot;</span> <span style="color: #66cc66;">%</span> pdfOne
            dlg = wx.<span style="color: black;">MessageDialog</span><span style="color: black;">&#40;</span><span style="color: #008000;">None</span>, msg, <span style="color: #483d8b;">'Error'</span>, wx.<span style="color: black;">OK</span>|wx.<span style="color: black;">ICON_EXCLAMATION</span><span style="color: black;">&#41;</span>
            dlg.<span style="color: black;">ShowModal</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            dlg.<span style="color: black;">Destroy</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">exists</span><span style="color: black;">&#40;</span>pdfTwo<span style="color: black;">&#41;</span>:
            msg = <span style="color: #483d8b;">&quot;The PDF at %s does not exist!&quot;</span> <span style="color: #66cc66;">%</span> pdfTwo
            dlg = wx.<span style="color: black;">MessageDialog</span><span style="color: black;">&#40;</span><span style="color: #008000;">None</span>, msg, <span style="color: #483d8b;">'Error'</span>, wx.<span style="color: black;">OK</span>|wx.<span style="color: black;">ICON_EXCLAMATION</span><span style="color: black;">&#41;</span>
            dlg.<span style="color: black;">ShowModal</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            dlg.<span style="color: black;">Destroy</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">return</span>
&nbsp;
        outputPath = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>winshell.<span style="color: black;">desktop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, <span style="color: #008000;">self</span>.<span style="color: black;">outputPdf</span>.<span style="color: black;">GetValue</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> + <span style="color: #483d8b;">&quot;.pdf&quot;</span>
        output = pyPdf.<span style="color: black;">PdfFileWriter</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
        pdfOne = pyPdf.<span style="color: black;">PdfFileReader</span><span style="color: black;">&#40;</span><span style="color: #008000;">file</span><span style="color: black;">&#40;</span>pdfOne, <span style="color: #483d8b;">&quot;rb&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> page <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>pdfOne.<span style="color: black;">getNumPages</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
            output.<span style="color: black;">addPage</span><span style="color: black;">&#40;</span>pdfOne.<span style="color: black;">getPage</span><span style="color: black;">&#40;</span>page<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        pdfTwo = pyPdf.<span style="color: black;">PdfFileReader</span><span style="color: black;">&#40;</span><span style="color: #008000;">file</span><span style="color: black;">&#40;</span>pdfTwo, <span style="color: #483d8b;">&quot;rb&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> page <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>pdfTwo.<span style="color: black;">getNumPages</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
            output.<span style="color: black;">addPage</span><span style="color: black;">&#40;</span>pdfTwo.<span style="color: black;">getPage</span><span style="color: black;">&#40;</span>page<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
        outputStream = <span style="color: #008000;">file</span><span style="color: black;">&#40;</span>outputPath, <span style="color: #483d8b;">&quot;wb&quot;</span><span style="color: black;">&#41;</span>
        output.<span style="color: black;">write</span><span style="color: black;">&#40;</span>outputStream<span style="color: black;">&#41;</span>
        outputStream.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
        msg = <span style="color: #483d8b;">&quot;PDF was save to &quot;</span> + outputPath
        dlg = wx.<span style="color: black;">MessageDialog</span><span style="color: black;">&#40;</span><span style="color: #008000;">None</span>, msg, <span style="color: #483d8b;">'PDF Created'</span>, wx.<span style="color: black;">OK</span>|wx.<span style="color: black;">ICON_INFORMATION</span><span style="color: black;">&#41;</span>
        dlg.<span style="color: black;">ShowModal</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        dlg.<span style="color: black;">Destroy</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #008000;">self</span>.<span style="color: black;">pdfOne</span>.<span style="color: black;">SetValue</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">pdfTwo</span>.<span style="color: black;">SetValue</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">outputPdf</span>.<span style="color: black;">SetValue</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">########################################################################</span>
<span style="color: #ff7700;font-weight:bold;">class</span> JoinerFrame<span style="color: black;">&#40;</span>wx.<span style="color: black;">Frame</span><span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #808080; font-style: italic;">#----------------------------------------------------------------------</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        wx.<span style="color: black;">Frame</span>.<span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #008000;">None</span>, wx.<span style="color: black;">ID_ANY</span>,
                          <span style="color: #483d8b;">&quot;PDF Joiner&quot;</span>, size=<span style="color: black;">&#40;</span><span style="color: #ff4500;">550</span>, <span style="color: #ff4500;">200</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        panel = JoinerPanel<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">#----------------------------------------------------------------------</span>
<span style="color: #808080; font-style: italic;"># Run the program</span>
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">&quot;__main__&quot;</span>:
    app = wx.<span style="color: black;">App</span><span style="color: black;">&#40;</span><span style="color: #008000;">False</span><span style="color: black;">&#41;</span>
    frame = JoinerFrame<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    frame.<span style="color: black;">Show</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    app.<span style="color: black;">MainLoop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre>
<p>You&#8217;ll notice that the frame and panel have dopey names. Feel free to change them. This is Python after all! The <em>MyFileDropTarget</em> class is used to enable drag-and-drop functionality on the first two text controls. If the user wants, they may drag a PDF onto one of those text controls and the path will magically get inserted. Otherwise, they can use the Browse button(s) to find the PDF(s) of their choice. Once they have their PDFs chosen, they need to enter the name of the output PDF, which goes in the third text control. You don&#8217;t even need to append the &#8220;.pdf&#8221; extension since this application will do it for you. </p>
<p>The last step is to press the &#8220;Join PDFs&#8221; button. This will add the second PDF to the end of the first, then display a dialog if it was created successfully. For this to function correctly, we need to loop over all the pages of each PDF and add them to the output in order. </p>
<p>It would be fun to enhance this application with some kind of drag-and-drop interface where the user could see the PDF pages and rearrange them by dragging them around. Or just being able to specify a few pages from each PDF to add rather than joining them in their entirety. I&#8217;ll leave those as exercises for the reader though.</p>
<p>I hope you found this article interesting and that it will spark your creative juices. If you write something cool with these ideas, be sure to post a comment so I can see it! </p>
]]></content:encoded>
			<wfw:commentRss>http://www.blog.pythonlibrary.org/2010/05/15/manipulating-pdfs-with-python-and-pypdf/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>A Simple Step-by-Step Reportlab Tutorial</title>
		<link>http://www.blog.pythonlibrary.org/2010/03/08/a-simple-step-by-step-reportlab-tutorial/</link>
		<comments>http://www.blog.pythonlibrary.org/2010/03/08/a-simple-step-by-step-reportlab-tutorial/#comments</comments>
		<pubDate>Tue, 09 Mar 2010 01:03:23 +0000</pubDate>
		<dc:creator>Mike</dc:creator>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Python PDF Series]]></category>
		<category><![CDATA[Reportlab]]></category>

		<guid isPermaLink="false">http://www.blog.pythonlibrary.org/?p=668</guid>
		<description><![CDATA[The subtitle for this article could easily be &#8220;How To Create PDFs with Python&#8221;, but WordPress doesn&#8217;t support that. Anyway, the premier PDF library in Python is Reportlab. It is not distributed with that standard library, so you&#8217;ll need to download it if you want to run the examples in this tutorial. There will also [...]]]></description>
			<content:encoded><![CDATA[<p>The subtitle for this article could easily be &#8220;How To Create PDFs with Python&#8221;, but WordPress doesn&#8217;t support that. Anyway, the premier PDF library in Python is <a href="http://www.reportlab.com/software/opensource/rl-toolkit/download/">Reportlab</a>. It is not distributed with that standard library, so you&#8217;ll need to download it if you want to run the examples in this tutorial. There will also be at least one example of how to put an image into a PDF, which means you&#8217;ll also need the <a href="http://www.pythonware.com/products/pil/">Python Imaging Library</a> (PIL). As I understand it, Reportlab is compatible with Python 2.x, <a href="http://ironpython.net/">IronPython</a> and <a href="http://www.jython.org/">Jython</a>. They are currently working on a port for Python 3.x (or will be soon).<span id="more-668"></span></p>
<h2>Installation</h2>
<p>Reportlab supports most of the normal Python installation methods. You have the option of downloading the source and running &#8220;python setup.py install&#8221; or running a binary installer (on Windows). There was a recent thread on their mailing list that seemed to indicate that they may also support <a href="http://pypi.python.org/pypi/pip">pip</a> soon. The threads I&#8217;ve read about Reportlab&#8217;s support of easy_install are confusing, so I&#8217;m not sure if they already support that method or not.</p>
<h2>Creating a Simple PDF</h2>
<p>Reportlab has decent documentation. What I mean by that is that the documentation gives you just enough to get started, but when you find something slightly complex to do, you get to figure it out on your own. Just recently, they added a <a href="http://www.reportlab.com/snippets/">Code Snippets</a> section to their website that will hopefully become a recipe book of cool tips and tricks and also help ameliorate this issue. But enough about that. Let&#8217;s see how to actually create something!</p>
<p>In Reportlab, the lowest-level component that&#8217;s used regularly is the <em>canvas</em> object from the <em>pdfgen</em> package. The functions in this package allow you to &#8220;paint&#8221; a document with your text, images, lines or whatever. I&#8217;ve heard some people describe this as writing in PostScript. I doubt it&#8217;s really that bad. In my experience, it&#8217;s actually a lot like using a GUI toolkit to layout widgets in specific locations. Let&#8217;s see how the canvas object works:</p>
<pre class="python"><span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">pdfgen</span> <span style="color: #ff7700;font-weight:bold;">import</span> canvas
&nbsp;
c = canvas.<span style="color: black;">Canvas</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;hello.pdf&quot;</span><span style="color: black;">&#41;</span>
c.<span style="color: black;">drawString</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">100</span>,<span style="color: #ff4500;">750</span>,<span style="color: #483d8b;">&quot;Welcome to Reportlab!&quot;</span><span style="color: black;">&#41;</span>
c.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre>
<p>You should end up with a PDF that looks something like this:</p>
<p><a href="http://www.blog.pythonlibrary.org/wp-content/uploads/2010/03/hello-pdf-screenshot.png"><img src="http://www.blog.pythonlibrary.org/wp-content/uploads/2010/03/hello-pdf-screenshot-300x184.png" alt="" title="hello-pdf-screenshot" width="300" height="184" class="aligncenter size-medium wp-image-672" /></a></p>
<p>The first thing to notice about this code is that if we want to save the PDF, we need to supply a file name to the Canvas object. This can be an absolute path or a relative path. In this example, it should create the PDF in the same location that you run the script from. The next piece of the puzzle is the <em>drawString</em> method. This will draw text wherever you tell it to. When using the canvas object, it starts at the bottom left of the page, so for this example, we told it to draw the string 100 points from the left margin and 750 points from the bottom of the page (1 point = 1/72 inch). You can change this default in the Canvas constructor by passing a zero to the <em>bottomup </em>keyword argument. However, I&#8217;m not exactly sure what will happen if you do that as the Reportlab user guide isn&#8217;t clear on this topic. I think it will change the start point to the top left though. The final piece in the code above is to save your PDF.</p>
<p>That was easy! You&#8217;ve just created a really simple PDF! Note that the default Canvas size is A4, so if you happen to be American, you&#8217;ll probably want to change that to letter size. This is easy to do in Reportlab. All you need to do is the following:</p>
<pre class="python"><span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">lib</span>.<span style="color: black;">pagesizes</span> <span style="color: #ff7700;font-weight:bold;">import</span> letter
<span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">pdfgen</span> <span style="color: #ff7700;font-weight:bold;">import</span> canvas
&nbsp;
canvas = canvas.<span style="color: black;">Canvas</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'myfile.pdf'</span>, pagesize=letter<span style="color: black;">&#41;</span>
width, height = letter</pre>
<p>The main reason to grab the width and height is that you can use them for calculations to decide when to add a page break or help define margins. Let&#8217;s take a quick look at the constructor for the Canvas object to see what other options we have:</p>
<pre class="python"><span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>,filename,
    pagesize=letter,
    bottomup = <span style="color: #ff4500;">1</span>,
    pageCompression=<span style="color: #ff4500;">0</span>,
    encoding=rl_config.<span style="color: black;">defaultEncoding</span>,
    verbosity=<span style="color: #ff4500;">0</span>
    encrypt=<span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:</pre>
<p>The above was pulled directly from the <a href="http://www.reportlab.com/docs/reportlab-userguide.pdf">Reportlab User Guide</a>, page 11. You can read about the other options in their guide if you want the full details. </p>
<p>Now let&#8217;s do something a little more complicated and useful.</p>
<h2>A Little Form, Little Function</h2>
<p><a href="http://www.blog.pythonlibrary.org/wp-content/uploads/2010/03/pdf-partial-form.png"><img src="http://www.blog.pythonlibrary.org/wp-content/uploads/2010/03/pdf-partial-form-300x88.png" alt="" title="pdf-partial-form" width="300" height="88" class="aligncenter size-medium wp-image-677" /></a></p>
<p>In this example, we&#8217;ll create a partial printable form. As far as I can tell, Reportlab doesn&#8217;t support the fillable forms that were added to Adobe products a few years ago. Anyway, let&#8217;s take a look at some code!</p>
<pre class="python"><span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">lib</span>.<span style="color: black;">pagesizes</span> <span style="color: #ff7700;font-weight:bold;">import</span> letter
<span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">pdfgen</span> <span style="color: #ff7700;font-weight:bold;">import</span> canvas
&nbsp;
canvas = canvas.<span style="color: black;">Canvas</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;form.pdf&quot;</span>, pagesize=letter<span style="color: black;">&#41;</span>
canvas.<span style="color: black;">setLineWidth</span><span style="color: black;">&#40;</span>.<span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>
canvas.<span style="color: black;">setFont</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Helvetica'</span>, <span style="color: #ff4500;">12</span><span style="color: black;">&#41;</span>
&nbsp;
canvas.<span style="color: black;">drawString</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">30</span>,<span style="color: #ff4500;">750</span>,<span style="color: #483d8b;">'OFFICIAL COMMUNIQUE'</span><span style="color: black;">&#41;</span>
canvas.<span style="color: black;">drawString</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">30</span>,<span style="color: #ff4500;">735</span>,<span style="color: #483d8b;">'OF ACME INDUSTRIES'</span><span style="color: black;">&#41;</span>
canvas.<span style="color: black;">drawString</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">500</span>,<span style="color: #ff4500;">750</span>,<span style="color: #483d8b;">&quot;12/12/2010&quot;</span><span style="color: black;">&#41;</span>
canvas.<span style="color: black;">line</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">480</span>,<span style="color: #ff4500;">747</span>,<span style="color: #ff4500;">580</span>,<span style="color: #ff4500;">747</span><span style="color: black;">&#41;</span>
&nbsp;
canvas.<span style="color: black;">drawString</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">275</span>,<span style="color: #ff4500;">725</span>,<span style="color: #483d8b;">'AMOUNT OWED:'</span><span style="color: black;">&#41;</span>
canvas.<span style="color: black;">drawString</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">500</span>,<span style="color: #ff4500;">725</span>,<span style="color: #483d8b;">&quot;$1,000.00&quot;</span><span style="color: black;">&#41;</span>
canvas.<span style="color: black;">line</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">378</span>,<span style="color: #ff4500;">723</span>,<span style="color: #ff4500;">580</span>,<span style="color: #ff4500;">723</span><span style="color: black;">&#41;</span>
&nbsp;
canvas.<span style="color: black;">drawString</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">30</span>,<span style="color: #ff4500;">703</span>,<span style="color: #483d8b;">'RECEIVED BY:'</span><span style="color: black;">&#41;</span>
canvas.<span style="color: black;">line</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">120</span>,<span style="color: #ff4500;">700</span>,<span style="color: #ff4500;">580</span>,<span style="color: #ff4500;">700</span><span style="color: black;">&#41;</span>
canvas.<span style="color: black;">drawString</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">120</span>,<span style="color: #ff4500;">703</span>,<span style="color: #483d8b;">&quot;JOHN DOE&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
canvas.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre>
<p>This is based on an actual receipt I created at work. The main difference between this one and the previous example is the <em>canvas.line</em> code. You can use it to draw lines on your documents by passing two X/Y pairs. I&#8217;ve used this functionality to create grids, although it&#8217;s pretty tedious. Other points of interest in this code include the setLineWidth(.3) command, which tells Reportlab how thick or thin the line should be; and the setFont(&#8216;Helvetica&#8217;, 12) command, which allows us to specify a specific font and point size. </p>
<p>Our next example will build on what we&#8217;ve learned so far, but also introduce us to the concept of &#8220;flowables&#8221;.</p>
<h2>Going with the Flow</h2>
<p><a href="http://www.blog.pythonlibrary.org/wp-content/uploads/2010/03/pdf-form-letter.png"><img src="http://www.blog.pythonlibrary.org/wp-content/uploads/2010/03/pdf-form-letter-300x246.png" alt="" title="pdf-form-letter" width="300" height="246" class="aligncenter size-medium wp-image-678" /></a></p>
<p>If you&#8217;re in advertising or do any kind of work with form letters, then Reportlab makes for an excellent addition to your arsenal. We use it to create form letters for people who have overdue parking tickets. The following example is based on some code I wrote for that application, although the letter is quite a bit different. (Note that the code below will not run without the Python Imaging Library)</p>
<pre class="python"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">time</span>
<span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">lib</span>.<span style="color: black;">enums</span> <span style="color: #ff7700;font-weight:bold;">import</span> TA_JUSTIFY
<span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">lib</span>.<span style="color: black;">pagesizes</span> <span style="color: #ff7700;font-weight:bold;">import</span> letter
<span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">platypus</span> <span style="color: #ff7700;font-weight:bold;">import</span> SimpleDocTemplate, Paragraph, Spacer, Image
<span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">lib</span>.<span style="color: black;">styles</span> <span style="color: #ff7700;font-weight:bold;">import</span> getSampleStyleSheet, ParagraphStyle
<span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">lib</span>.<span style="color: black;">units</span> <span style="color: #ff7700;font-weight:bold;">import</span> inch
&nbsp;
doc = SimpleDocTemplate<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;form_letter.pdf&quot;</span>,pagesize=letter,
                        rightMargin=<span style="color: #ff4500;">72</span>,leftMargin=<span style="color: #ff4500;">72</span>,
                        topMargin=<span style="color: #ff4500;">72</span>,bottomMargin=<span style="color: #ff4500;">18</span><span style="color: black;">&#41;</span>
Story=<span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
logo = <span style="color: #483d8b;">&quot;python_logo.png&quot;</span>
magName = <span style="color: #483d8b;">&quot;Pythonista&quot;</span>
issueNum = <span style="color: #ff4500;">12</span>
subPrice = <span style="color: #483d8b;">&quot;99.00&quot;</span>
limitedDate = <span style="color: #483d8b;">&quot;03/05/2010&quot;</span>
freeGift = <span style="color: #483d8b;">&quot;tin foil hat&quot;</span>
&nbsp;
formatted_time = <span style="color: #dc143c;">time</span>.<span style="color: black;">ctime</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
full_name = <span style="color: #483d8b;">&quot;Mike Driscoll&quot;</span>
address_parts = <span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;411 State St.&quot;</span>, <span style="color: #483d8b;">&quot;Marshalltown, IA 50158&quot;</span><span style="color: black;">&#93;</span>
&nbsp;
im = Image<span style="color: black;">&#40;</span>logo, <span style="color: #ff4500;">2</span><span style="color: #66cc66;">*</span>inch, <span style="color: #ff4500;">2</span><span style="color: #66cc66;">*</span>inch<span style="color: black;">&#41;</span>
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>im<span style="color: black;">&#41;</span>
&nbsp;
styles=getSampleStyleSheet<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
styles.<span style="color: black;">add</span><span style="color: black;">&#40;</span>ParagraphStyle<span style="color: black;">&#40;</span>name=<span style="color: #483d8b;">'Justify'</span>, alignment=TA_JUSTIFY<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
ptext = <span style="color: #483d8b;">'&lt;font size=12&gt;%s&lt;/font&gt;'</span> <span style="color: #66cc66;">%</span> formatted_time
&nbsp;
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Paragraph<span style="color: black;">&#40;</span>ptext, styles<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Normal&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Spacer<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">12</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Create return address</span>
ptext = <span style="color: #483d8b;">'&lt;font size=12&gt;%s&lt;/font&gt;'</span> <span style="color: #66cc66;">%</span> full_name
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Paragraph<span style="color: black;">&#40;</span>ptext, styles<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Normal&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> part <span style="color: #ff7700;font-weight:bold;">in</span> address_parts:
    ptext = <span style="color: #483d8b;">'&lt;font size=12&gt;%s&lt;/font&gt;'</span> <span style="color: #66cc66;">%</span> part.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Paragraph<span style="color: black;">&#40;</span>ptext, styles<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Normal&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Spacer<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">12</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
ptext = <span style="color: #483d8b;">'&lt;font size=12&gt;Dear %s:&lt;/font&gt;'</span> <span style="color: #66cc66;">%</span> full_name.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Paragraph<span style="color: black;">&#40;</span>ptext, styles<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Normal&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Spacer<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">12</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
ptext = <span style="color: #483d8b;">'&lt;font size=12&gt;We would like to welcome you to our subscriber base for %s Magazine! <span style="color: #000099; font-weight: bold;">\</span>
        You will receive %s issues at the excellent introductory price of $%s. Please respond by<span style="color: #000099; font-weight: bold;">\</span>
        %s to start receiving your subscription and get the following free gift: %s.&lt;/font&gt;'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>magName,
                                                                                                issueNum,
                                                                                                subPrice,
                                                                                                limitedDate,
                                                                                                freeGift<span style="color: black;">&#41;</span>
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Paragraph<span style="color: black;">&#40;</span>ptext, styles<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Justify&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Spacer<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">12</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
ptext = <span style="color: #483d8b;">'&lt;font size=12&gt;Thank you very much and we look forward to serving you.&lt;/font&gt;'</span>
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Paragraph<span style="color: black;">&#40;</span>ptext, styles<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Justify&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Spacer<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">12</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
ptext = <span style="color: #483d8b;">'&lt;font size=12&gt;Sincerely,&lt;/font&gt;'</span>
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Paragraph<span style="color: black;">&#40;</span>ptext, styles<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Normal&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Spacer<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">48</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
ptext = <span style="color: #483d8b;">'&lt;font size=12&gt;Ima Sucker&lt;/font&gt;'</span>
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Paragraph<span style="color: black;">&#40;</span>ptext, styles<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Normal&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Spacer<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">12</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
doc.<span style="color: black;">build</span><span style="color: black;">&#40;</span>Story<span style="color: black;">&#41;</span></pre>
<p>Well, that&#8217;s a lot more code than our previous examples contained. We&#8217;ll need to look over it slowly to understand everything that&#8217;s going on. When you&#8217;re ready, just continue reading.</p>
<p>The first part that we need to look at are the new imports:</p>
<pre class="python"><span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">lib</span>.<span style="color: black;">enums</span> <span style="color: #ff7700;font-weight:bold;">import</span> TA_JUSTIFY
<span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">platypus</span> <span style="color: #ff7700;font-weight:bold;">import</span> SimpleDocTemplate, Paragraph, Spacer, Image
<span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">lib</span>.<span style="color: black;">styles</span> <span style="color: #ff7700;font-weight:bold;">import</span> getSampleStyleSheet, ParagraphStyle
<span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">lib</span>.<span style="color: black;">units</span> <span style="color: #ff7700;font-weight:bold;">import</span> inch</pre>
<p>From enums, we import &#8220;TA_JUSTIFY&#8221;, which allows our strings to have the <em>justified </em>format. There are a number of other constants we could import that would allow us to right or left justify our text and do other fun things. Next is the platypus (which stands for Page Layout and Typography Using Scripts) module. It contains lots of modules, but probably the most important of them are the flowables, such as Paragraph. A flowable typically has the following abilities: <em>wrap</em>, <em>draw</em> and sometimes <em>split</em>. They are used to make writing paragraphs, tables and other constructs over multiple pages easier to do.</p>
<p>The SimpleDocTemplate class allows us to set up margins, page size, filename and a bunch of other settings for our document all in one place. A Spacer is good for adding a line of blank space, like a paragraph break. The Image class utilizes the Python Image Library to allow easy insertion and manipulation of images in your PDF. </p>
<p>The getSampleStyleSheet gets a set of default styles that we can use in our PDF. ParagraphStyle is used to set our paragraph&#8217;s text alignment in this example, but it can do much more than that (see page 67 of the user guide). Finally, the <em>inch</em> is a unit of measurement to help in positioning items on your PDF. You can see this in action where we position the logo: Image(logo, 2*inch, 2*inch). This means that the logo will be two inches from the top and two inches from the left.</p>
<p>I don&#8217;t recall the reason why Reportlab&#8217;s examples use a Story list, but that&#8217;s how we&#8217;ll do it here as well. Basically you create a line of text, a table, and image or whatever and append it to the Story list. You&#8217;ll see that throughout the entire example. The first time we use it is when we add the image. Before we look at the next instance, we&#8217;ll need to look at how we add a style to our styles object:</p>
<pre class="python">styles.<span style="color: black;">add</span><span style="color: black;">&#40;</span>ParagraphStyle<span style="color: black;">&#40;</span>name=<span style="color: #483d8b;">'Justify'</span>, alignment=TA_JUSTIFY<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre>
<p>The reason this is important is because you can use the style list to apply various paragraph alignment settings (and more) to text in your document. In the code above, we create a ParagraphStyle called &#8220;Justify&#8221;. All it does is justify our text. You&#8217;ll see an example of this later in the text. For now, let&#8217;s look at a quick example:</p>
<pre class="python">ptext = <span style="color: #483d8b;">'&lt;font size=12&gt;%s&lt;/font&gt;'</span> <span style="color: #66cc66;">%</span> formatted_time
Story.<span style="color: black;">append</span><span style="color: black;">&#40;</span>Paragraph<span style="color: black;">&#40;</span>ptext, styles<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Normal&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre>
<p>For our first line of text, we use the Paragraph class. As you can see, the Paragraph class accepts some HTML-like tags. In this instance, we set the font&#8217;s point size to 12 and use the normal style (which is left aligned, among other things). The rest of the example is pretty much the same, just with Spacers thrown in here and there. At the end, we call <em>doc.build</em> to create the document.</p>
<h2>Wrapping Up</h2>
<p>Now you know the basics for creating PDFs in Python using Reportlab. We didn&#8217;t even scratch the surface of what all you can do with Reportlab though. Some examples include tables, graphs, paginating, color overprinting, hyperlinks, graphics and much more. I highly recommend that you download the module along with its user guide and give it a try!</p>
<p><b>Further Reading</b></p>
<ul>
<li><a href="http://www.reportlab.com/software/opensource/">Reportlab Home Page</a></li>
<li><a href="http://www.protocolostomy.com/2008/10/22/generating-reports-with-charts-using-python-reportlab/">Generating Reports with Charts</a></li>
<li><a href="http://stochasticgeometry.wordpress.com/2009/01/06/reportlab/">A series on Reportlab</a></li>
</ul>
<li><a href="http://www.magitech.org/2006/05/05/getting-started-with-reportlab/">Getting Started with Reportlab</a></li>
]]></content:encoded>
			<wfw:commentRss>http://www.blog.pythonlibrary.org/2010/03/08/a-simple-step-by-step-reportlab-tutorial/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 7.574 seconds -->
