<?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, 08 Jan 2012 12:45:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Reportlab Tables &#8211; Creating Tables in PDFs with Python</title>
		<link>http://www.blog.pythonlibrary.org/2010/09/21/reportlab-tables-creating-tables-in-pdfs-with-python/</link>
		<comments>http://www.blog.pythonlibrary.org/2010/09/21/reportlab-tables-creating-tables-in-pdfs-with-python/#comments</comments>
		<pubDate>Wed, 22 Sep 2010 02:16:12 +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=1218</guid>
		<description><![CDATA[Back in March of this year, I wrote a simple tutorial on Reportlab, a handy 3rd party Python package that allows the developer to create PDFs programmatically. Recently, I received a request to cover how to do tables in Reportlab. Since my Reportlab article is so popular, I figured it was probably worth the trouble [...]]]></description>
			<content:encoded><![CDATA[<div class="socialize-in-content" style="float:left;"><div class="socialize-in-button socialize-in-button-left"><a href="http://twitter.com/share" class="twitter-share-button" data-counturl="http://www.blog.pythonlibrary.org/2010/09/21/reportlab-tables-creating-tables-in-pdfs-with-python/" data-url="http://bit.ly/sf2cnJ" data-text="Reportlab Tables &#8211; Creating Tables in PDFs with Python" data-count="vertical" data-via="socializeWP" ><!--Tweetter--></a></div><div class="socialize-in-button socialize-in-button-left"><iframe src="http://www.facebook.com/plugins/like.php?href=http://www.blog.pythonlibrary.org/2010/09/21/reportlab-tables-creating-tables-in-pdfs-with-python/&amp;layout=button_count&amp;show_faces=true&amp;width=100&amp;action=like&amp;font=arial&amp;colorscheme=light&amp;height=65" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:100px !important; height:65px;" allowTransparency="true"></iframe></div><div class="socialize-in-button socialize-in-button-left"><script type="text/javascript">
			<!-- 
			reddit_url = "http://www.blog.pythonlibrary.org/2010/09/21/reportlab-tables-creating-tables-in-pdfs-with-python/";
			reddit_title = "Reportlab Tables &#8211; Creating Tables in PDFs with Python";	//-->
		</script><script type="text/javascript" src="http://www.reddit.com/static/button/button2.js"></script></div><div class="socialize-in-button socialize-in-button-left"><g:plusone size="small" href="http://www.blog.pythonlibrary.org/2010/09/21/reportlab-tables-creating-tables-in-pdfs-with-python/"></g:plusone></div></div><p>Back in March of this year, I wrote a <a href="http://www.blog.pythonlibrary.org/2010/03/08/a-simple-step-by-step-reportlab-tutorial/">simple tutorial</a> on Reportlab, a handy 3rd party Python package that allows the developer to create PDFs programmatically. Recently, I received a request to cover how to do tables in Reportlab. Since my Reportlab article is so popular, I figured it was probably worth the trouble to figure out tables. In this article, I will attempt to show you the basics of inserting tables into Reportlab generated PDFs.<span id="more-1218"></span></p>
<p>One of the few issues I have with Reportlab is their user guide. It shows some good examples, but they&#8217;re almost always incomplete. Go download the user guide <a href="http://www.reportlab.com/software/opensource/rl-toolkit/guide/">here</a> and start reading chapter seven (the chapter on tables) and you&#8217;ll quickly see the following code snippet:</p>
<pre class="python">LIST_STYLE = TableStyle<span style="color: black;">&#40;</span>
    <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'LINEABOVE'</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">-1</span>,<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>, <span style="color: #ff4500;">2</span>, colors.<span style="color: black;">green</span><span style="color: black;">&#41;</span>,
    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'LINEABOVE'</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">-1</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>, <span style="color: #ff4500;">0.25</span>, colors.<span style="color: black;">black</span><span style="color: black;">&#41;</span>,
    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'LINEBELOW'</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">-1</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>, <span style="color: #ff4500;">2</span>, colors.<span style="color: black;">green</span><span style="color: black;">&#41;</span>,
    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'ALIGN'</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">-1</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>, <span style="color: #483d8b;">'RIGHT'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
<span style="color: black;">&#41;</span></pre>
<p>Of course, this snippet is completely un-runnable and the text around it is pretty useless for figuring out how to import <strong>TableStyle</strong> and <strong>colors</strong>. It sounds like you can get all the Table stuff from the Flowable class (pg 76 &#8211; first page of chapter 7). Unfortunately, there is no &#8220;reportlab.Flowable&#8221;. You have to know that all the flowables come from something called <strong>platypus</strong>. Let&#8217;s stop here and talk about what a &#8220;flowable&#8221; is. Here what the user guide says:</p>
<p><em><br />
Flowables are things which can be drawn and which have wrap, draw and perhaps split methods. Flowable is an abstract base class for things to be drawn and an instance knows its size and draws in its own coordinate system (this requires the base API to provide an absolute coordinate system when the Flowable.draw method is called). To get an instance use f=Flowable().</em> (pg 62, section 5.3). Note that nowhere on that page does it show how to get the Flowable class. I only found out how by doing a text search of their source. Here&#8217;s the syntax:  <em>from reportlab.platypus import Flowable</em></p>
<p>It&#8217;s this sort of thing that made me almost give up on using Reportlab at all several years ago. Fortunately, my boss made me figure it out and had some real examples for me to follow. Alright, enough ranting. On with the tables tutorial!</p>
<h2>Getting Started with Reportlab Tables</h2>
<p>We&#8217;re actually going to take some of the table examples from the Reportlab User Guide and make them runnable. I&#8217;ll try to explain what&#8217;s going on in the code, but you may want to refer to the guide as well. Let&#8217;s start with the example on pg 78 entitled <em>TableStyle Cell Formatting Commands</em>. This first real example shows how to create a table with multiple colors, but no visible grid. Let&#8217;s make it runnable!</p>
<pre class="python"><span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">lib</span> <span style="color: #ff7700;font-weight:bold;">import</span> colors
<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, Table, TableStyle
&nbsp;
doc = SimpleDocTemplate<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;simple_table.pdf&quot;</span>, pagesize=letter<span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># container for the 'Flowable' objects</span>
elements = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
data= <span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'00'</span>, <span style="color: #483d8b;">'01'</span>, <span style="color: #483d8b;">'02'</span>, <span style="color: #483d8b;">'03'</span>, <span style="color: #483d8b;">'04'</span><span style="color: black;">&#93;</span>,
       <span style="color: black;">&#91;</span><span style="color: #483d8b;">'10'</span>, <span style="color: #483d8b;">'11'</span>, <span style="color: #483d8b;">'12'</span>, <span style="color: #483d8b;">'13'</span>, <span style="color: #483d8b;">'14'</span><span style="color: black;">&#93;</span>,
       <span style="color: black;">&#91;</span><span style="color: #483d8b;">'20'</span>, <span style="color: #483d8b;">'21'</span>, <span style="color: #483d8b;">'22'</span>, <span style="color: #483d8b;">'23'</span>, <span style="color: #483d8b;">'24'</span><span style="color: black;">&#93;</span>,
       <span style="color: black;">&#91;</span><span style="color: #483d8b;">'30'</span>, <span style="color: #483d8b;">'31'</span>, <span style="color: #483d8b;">'32'</span>, <span style="color: #483d8b;">'33'</span>, <span style="color: #483d8b;">'34'</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span>
t=Table<span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>
t.<span style="color: black;">setStyle</span><span style="color: black;">&#40;</span>TableStyle<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'BACKGROUND'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">-2</span>,<span style="color: #ff4500;">-2</span><span style="color: black;">&#41;</span>,colors.<span style="color: black;">green</span><span style="color: black;">&#41;</span>,
                       <span style="color: black;">&#40;</span><span style="color: #483d8b;">'TEXTCOLOR'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>,colors.<span style="color: black;">red</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
elements.<span style="color: black;">append</span><span style="color: black;">&#40;</span>t<span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># write the document to disk</span>
doc.<span style="color: black;">build</span><span style="color: black;">&#40;</span>elements<span style="color: black;">&#41;</span></pre>
<p>If you run this code, you should see something like this centered along the top of your PDF:</p>
<p><a href="http://www.blog.pythonlibrary.org/wp-content/uploads/2010/09/table_with_no_grid.png"><img src="http://www.blog.pythonlibrary.org/wp-content/uploads/2010/09/table_with_no_grid.png" alt="table_with_no_grid.png" title="table_with_no_grid.png" width="220" height="141" class="aligncenter size-full wp-image-1219" /></a></p>
<p>If you look at the code, you&#8217;ll notice that we have a series of imports. We import <strong>colors </strong>from &#8220;reportlab.lib&#8221;, <strong>letter</strong> from &#8220;reportlab.lib.pagesizes&#8221; and <strong>SimpleDocTemplate</strong>, <strong>Table</strong>, and <strong>TableStyle</strong> from &#8220;reportlab.platypus&#8221;.  The imports are pretty self-explanatory, but they also help us familiarize ourselves with the way that Reportlab&#8217;s code is laid out. If we need other Flowables, like Paragraph, we can probably assume that it would come from &#8220;reportlab.platypus&#8221; since Table is a Flowable. If you try it, you&#8217;ll see that this assumption is correct.</p>
<p>Next we create a document template using the <strong>SimpleDocTemplate</strong> class. The first argument is the path to the PDF that we want to create and the second argument is the page size. In this example, we just put in the name of the document. This will cause the script to put the PDF in the same folder that it&#8217;s run from. For reasons that I&#8217;ve never seen explained, you use a list to hold the flowables. In this code, we call our list &#8220;elements&#8221;. In the user guide, they call it &#8220;story&#8221;. </p>
<p>The <strong>data</strong> list holds the data that will go in our table. The list is a list of lists. The table will 5 columns wide (the length of the nested lists) and 4 rows tall (the number of nested lists). We pass this list into our <strong>Table</strong> class to create the Table in memory and then call our Table instance&#8217;s setStyle method to change the style. To do this, we pass it a <strong>TableStyle</strong> class, which contains the styles we want to apply. In this case, we want to apply a green background color from the cells in column 2, row 2 to column 3, row 2. Note that the columns and rows are zero-based so 0 = 1, 1 = 2, etc. Also notice that the example uses (-2, -2) rather than the much easier to understand (3, 2). This illustrates that you can also specify settings from the lower right corner instead of just doing everything from the top left. Unfortunately, the coordinate system starting on the lower right starts at (-1,-1) and that makes it a little harder to get one&#8217;s mind around.</p>
<p>Then we set the text color to red in the first two columns. I admit that I&#8217;m not quite sure how this works as the ending coordinates just don&#8217;t seem to fit with the ones for the background color. I&#8217;ll leave that to my readers to explain.</p>
<p>Finally, we append the table to our elements list and then call our document instance&#8217;s <strong>build</strong> method with the elements list as its only argument. This causes the document to be build and the PDF created. Now you have a PDF table!</p>
<h2>Adding a Grid to the Table</h2>
<p><a href="http://www.blog.pythonlibrary.org/wp-content/uploads/2010/09/table_with_grid.png"><img src="http://www.blog.pythonlibrary.org/wp-content/uploads/2010/09/table_with_grid.png" alt="table_with_grid.png" title="table_with_grid.png" width="251" height="198" class="aligncenter size-full wp-image-1226" /></a></p>
<p>Let&#8217;s take the next example from the Reportlab documentation and see if we can get it to run too. This next example shows how to add a visible grid to the table as well as how to position the text within the cells.</p>
<pre class="python"><span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">lib</span> <span style="color: #ff7700;font-weight:bold;">import</span> colors
<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, inch
<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, Table, TableStyle
&nbsp;
doc = SimpleDocTemplate<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;simple_table_grid.pdf&quot;</span>, pagesize=letter<span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># container for the 'Flowable' objects</span>
elements = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
data= <span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'00'</span>, <span style="color: #483d8b;">'01'</span>, <span style="color: #483d8b;">'02'</span>, <span style="color: #483d8b;">'03'</span>, <span style="color: #483d8b;">'04'</span><span style="color: black;">&#93;</span>,
       <span style="color: black;">&#91;</span><span style="color: #483d8b;">'10'</span>, <span style="color: #483d8b;">'11'</span>, <span style="color: #483d8b;">'12'</span>, <span style="color: #483d8b;">'13'</span>, <span style="color: #483d8b;">'14'</span><span style="color: black;">&#93;</span>,
       <span style="color: black;">&#91;</span><span style="color: #483d8b;">'20'</span>, <span style="color: #483d8b;">'21'</span>, <span style="color: #483d8b;">'22'</span>, <span style="color: #483d8b;">'23'</span>, <span style="color: #483d8b;">'24'</span><span style="color: black;">&#93;</span>,
       <span style="color: black;">&#91;</span><span style="color: #483d8b;">'30'</span>, <span style="color: #483d8b;">'31'</span>, <span style="color: #483d8b;">'32'</span>, <span style="color: #483d8b;">'33'</span>, <span style="color: #483d8b;">'34'</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span>
t=Table<span style="color: black;">&#40;</span>data,<span style="color: #ff4500;">5</span><span style="color: #66cc66;">*</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0.4</span><span style="color: #66cc66;">*</span>inch<span style="color: black;">&#93;</span>, <span style="color: #ff4500;">4</span><span style="color: #66cc66;">*</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0.4</span><span style="color: #66cc66;">*</span>inch<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
t.<span style="color: black;">setStyle</span><span style="color: black;">&#40;</span>TableStyle<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'ALIGN'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">-2</span>,<span style="color: #ff4500;">-2</span><span style="color: black;">&#41;</span>,<span style="color: #483d8b;">'RIGHT'</span><span style="color: black;">&#41;</span>,
                       <span style="color: black;">&#40;</span><span style="color: #483d8b;">'TEXTCOLOR'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">-2</span>,<span style="color: #ff4500;">-2</span><span style="color: black;">&#41;</span>,colors.<span style="color: black;">red</span><span style="color: black;">&#41;</span>,
                       <span style="color: black;">&#40;</span><span style="color: #483d8b;">'VALIGN'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>,<span style="color: #483d8b;">'TOP'</span><span style="color: black;">&#41;</span>,
                       <span style="color: black;">&#40;</span><span style="color: #483d8b;">'TEXTCOLOR'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>,colors.<span style="color: black;">blue</span><span style="color: black;">&#41;</span>,
                       <span style="color: black;">&#40;</span><span style="color: #483d8b;">'ALIGN'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">-1</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>,<span style="color: #483d8b;">'CENTER'</span><span style="color: black;">&#41;</span>,
                       <span style="color: black;">&#40;</span><span style="color: #483d8b;">'VALIGN'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">-1</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>,<span style="color: #483d8b;">'MIDDLE'</span><span style="color: black;">&#41;</span>,
                       <span style="color: black;">&#40;</span><span style="color: #483d8b;">'TEXTCOLOR'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">-1</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>,colors.<span style="color: black;">green</span><span style="color: black;">&#41;</span>,
                       <span style="color: black;">&#40;</span><span style="color: #483d8b;">'INNERGRID'</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">-1</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>, <span style="color: #ff4500;">0.25</span>, colors.<span style="color: black;">black</span><span style="color: black;">&#41;</span>,
                       <span style="color: black;">&#40;</span><span style="color: #483d8b;">'BOX'</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">-1</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>, <span style="color: #ff4500;">0.25</span>, colors.<span style="color: black;">black</span><span style="color: black;">&#41;</span>,
                       <span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
elements.<span style="color: black;">append</span><span style="color: black;">&#40;</span>t<span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># write the document to disk</span>
doc.<span style="color: black;">build</span><span style="color: black;">&#40;</span>elements<span style="color: black;">&#41;</span></pre>
<p>We have one new import here from the <strong>pagesizes</strong> library: <strong>inch</strong>. The &#8220;inch&#8221; just gives us a simple way to set sizes or margins in our PDF. In this case, we use it to set the table&#8217;s column widths and row heights. The next change is in <em>setStyle </em>section of the code and this is really the key to getting tables to look the way you want. The <em>TableStyle</em> class controls the look of the table completely. For example, the first two lines align the middle six cells to the right and color them red. The next two lines set the four cells in the first column to the color blue and to the text to the top of the cell. You can figure out the three lines on your own.</p>
<p>The last two lines of code draw the inner grid and the box around the grid. Then we append the table to our elements list and finally, build the document.</p>
<h2>Creating Complex Cell Values</h2>
<p>The last major example we&#8217;re going to look at is the Complex Cell Values example from the Reportlab user guide.  This one shows you to insert other Reportlab Flowables in the cells themselves. Let&#8217;s take a quick look!</p>
<pre class="python"><span style="color: #ff7700;font-weight:bold;">from</span> reportlab.<span style="color: black;">lib</span> <span style="color: #ff7700;font-weight:bold;">import</span> colors
<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, inch
<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> Image, Paragraph, SimpleDocTemplate, Table
<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
&nbsp;
doc = SimpleDocTemplate<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;complex_cell_values.pdf&quot;</span>, pagesize=letter<span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># container for the 'Flowable' objects</span>
elements = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
styleSheet = getSampleStyleSheet<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
I = Image<span style="color: black;">&#40;</span><span style="color: #483d8b;">'replogo.gif'</span><span style="color: black;">&#41;</span>
I.<span style="color: black;">drawHeight</span> = <span style="color: #ff4500;">1.25</span><span style="color: #66cc66;">*</span>inch<span style="color: #66cc66;">*</span>I.<span style="color: black;">drawHeight</span> / I.<span style="color: black;">drawWidth</span>
I.<span style="color: black;">drawWidth</span> = <span style="color: #ff4500;">1.25</span><span style="color: #66cc66;">*</span>inch
P0 = Paragraph<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
               &lt;b&gt;A pa&lt;font color=red&gt;r&lt;/font&gt;a&lt;i&gt;graph&lt;/i&gt;&lt;/b&gt;
               &lt;super&gt;&lt;font color=yellow&gt;1&lt;/font&gt;&lt;/super&gt;'</span><span style="color: #483d8b;">''</span>,
               styleSheet<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;BodyText&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
P = Paragraph<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span><span style="color: #483d8b;">'
    &lt;para align=center spaceb=3&gt;The &lt;b&gt;ReportLab Left
    &lt;font color=red&gt;Logo&lt;/font&gt;&lt;/b&gt;
    Image&lt;/para&gt;'</span><span style="color: #483d8b;">''</span>,
    styleSheet<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;BodyText&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
data= <span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'A'</span>, <span style="color: #483d8b;">'B'</span>, <span style="color: #483d8b;">'C'</span>, P0, <span style="color: #483d8b;">'D'</span><span style="color: black;">&#93;</span>,
       <span style="color: black;">&#91;</span><span style="color: #483d8b;">'00'</span>, <span style="color: #483d8b;">'01'</span>, <span style="color: #483d8b;">'02'</span>, <span style="color: black;">&#91;</span>I,P<span style="color: black;">&#93;</span>, <span style="color: #483d8b;">'04'</span><span style="color: black;">&#93;</span>,
       <span style="color: black;">&#91;</span><span style="color: #483d8b;">'10'</span>, <span style="color: #483d8b;">'11'</span>, <span style="color: #483d8b;">'12'</span>, <span style="color: black;">&#91;</span>P,I<span style="color: black;">&#93;</span>, <span style="color: #483d8b;">'14'</span><span style="color: black;">&#93;</span>,
       <span style="color: black;">&#91;</span><span style="color: #483d8b;">'20'</span>, <span style="color: #483d8b;">'21'</span>, <span style="color: #483d8b;">'22'</span>, <span style="color: #483d8b;">'23'</span>, <span style="color: #483d8b;">'24'</span><span style="color: black;">&#93;</span>,
       <span style="color: black;">&#91;</span><span style="color: #483d8b;">'30'</span>, <span style="color: #483d8b;">'31'</span>, <span style="color: #483d8b;">'32'</span>, <span style="color: #483d8b;">'33'</span>, <span style="color: #483d8b;">'34'</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span>
&nbsp;
t=Table<span style="color: black;">&#40;</span>data,style=<span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'GRID'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">-2</span>,<span style="color: #ff4500;">-2</span><span style="color: black;">&#41;</span>,<span style="color: #ff4500;">1</span>,colors.<span style="color: black;">green</span><span style="color: black;">&#41;</span>,
                    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'BOX'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>,<span style="color: #ff4500;">2</span>,colors.<span style="color: black;">red</span><span style="color: black;">&#41;</span>,
                    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'LINEABOVE'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>,<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">-2</span>,<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>,<span style="color: #ff4500;">1</span>,colors.<span style="color: black;">blue</span><span style="color: black;">&#41;</span>,
                    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'LINEBEFORE'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span>,<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span>,<span style="color: #ff4500;">-2</span><span style="color: black;">&#41;</span>,<span style="color: #ff4500;">1</span>,colors.<span style="color: black;">pink</span><span style="color: black;">&#41;</span>,
                    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'BACKGROUND'</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>, colors.<span style="color: black;">pink</span><span style="color: black;">&#41;</span>,
                    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'BACKGROUND'</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>, colors.<span style="color: black;">lavender</span><span style="color: black;">&#41;</span>,
                    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'BACKGROUND'</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span>, <span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>, colors.<span style="color: black;">orange</span><span style="color: black;">&#41;</span>,
                    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'BOX'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">-1</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>,<span style="color: #ff4500;">2</span>,colors.<span style="color: black;">black</span><span style="color: black;">&#41;</span>,
                    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'GRID'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>,<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">-1</span>,<span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>,<span style="color: #ff4500;">0.5</span>,colors.<span style="color: black;">black</span><span style="color: black;">&#41;</span>,
                    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'VALIGN'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>,<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>,<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>,<span style="color: #483d8b;">'BOTTOM'</span><span style="color: black;">&#41;</span>,
                    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'BACKGROUND'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>,<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>,<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>,colors.<span style="color: black;">limegreen</span><span style="color: black;">&#41;</span>,
                    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'BACKGROUND'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>,<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>,<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>,colors.<span style="color: black;">khaki</span><span style="color: black;">&#41;</span>,
                    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'ALIGN'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>,<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>,<span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>,<span style="color: #483d8b;">'CENTER'</span><span style="color: black;">&#41;</span>,
                    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'BACKGROUND'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>,<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>,<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>,colors.<span style="color: black;">beige</span><span style="color: black;">&#41;</span>,
                    <span style="color: black;">&#40;</span><span style="color: #483d8b;">'ALIGN'</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>,<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>,<span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span>,<span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>,<span style="color: #483d8b;">'LEFT'</span><span style="color: black;">&#41;</span>,
<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
t._argW<span style="color: black;">&#91;</span><span style="color: #ff4500;">3</span><span style="color: black;">&#93;</span>=<span style="color: #ff4500;">1.5</span><span style="color: #66cc66;">*</span>inch
&nbsp;
elements.<span style="color: black;">append</span><span style="color: black;">&#40;</span>t<span style="color: black;">&#41;</span>
<span style="color: #808080; font-style: italic;"># write the document to disk</span>
doc.<span style="color: black;">build</span><span style="color: black;">&#40;</span>elements<span style="color: black;">&#41;</span></pre>
<p>This snippet has a couple new imports. First off, we need access to <strong>Image </strong>and <strong>Paragraph</strong>, which are part of the <strong>platypus </strong>lib. We also need to be able to use <strong>getSampleStyleSheet</strong>, so we import that from the <strong>styles </strong>lib. Paragraphs are flowables that allow us to use HTML-like syntax to style our text and insert images, although we don&#8217;t do the image insertion in this manner in this particular example. </p>
<p>Anyway, once again, the style is where the action is. In this example, we take a shortcut and pass the style directly into the Table object using its <strong>style</strong> parameter instead of using the Table&#8217;s &#8220;setStyle&#8221; method in combination with the TableStyle class. The result would have been the same if we had done it that way though. You should be able to parse the style yourself at this point. The only real difference was where we added the Paragraph and Image instances to the data list.</p>
<h2>Other Odds and Ends</h2>
<p>There are just a few other things to mention about Tables that didn&#8217;t really fit with the previous examples. Reportlab provides the ability to split tables when there are too many rows to fit on the page. This is enabled by default. According to the documentation, there is no way to split by column currently, so don&#8217;t bother trying to insert an extra-wide column.</p>
<p>The Table also has <strong>repeatRows</strong> and <strong>repeatCols</strong> parameters. The repeatRows parameter controls how many rows to repeat on a split. The repeatCols parameter is not currently implemented. To be honest, I&#8217;m not even sure why this parameter is even included. It&#8217;s been there for quite a while and it still does nothing.</p>
<h2>Wrapping Up</h2>
<p>Now you should have a good foundation for PDF table creation using the Reportlab toolkit. This article just scratches the surface of what Reportlab can do, so be sure to read the documentation, the tests and the various other examples on their website to truly understand the power within this handy toolkit.</p>
<h2>Further Reading</h2>
<ul>
<li>Reportlab <a href="http://www.reportlab.com/software/opensource/">Open Source</a></li>
<li>A Reportlab <a href=""http://www.blog.pythonlibrary.org/2010/03/08/a-simple-step-by-step-reportlab-tutorial/">Tutorial</a></li>
</ul>
<h2>Downloads</h2>
<ul>
<li><a href='http://www.blog.pythonlibrary.org/wp-content/uploads/2010/09/reportlab_tables.zip'>reportlab_tables.zip</a></li>
<li><a href='http://www.blog.pythonlibrary.org/wp-content/uploads/2010/09/reportlab_tables.tar'>reportlab_tables.tar</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.blog.pythonlibrary.org/2010/09/21/reportlab-tables-creating-tables-in-pdfs-with-python/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<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[<div class="socialize-in-content" style="float:left;"><div class="socialize-in-button socialize-in-button-left"><a href="http://twitter.com/share" class="twitter-share-button" data-counturl="http://www.blog.pythonlibrary.org/2010/05/15/manipulating-pdfs-with-python-and-pypdf/" data-url="http://bit.ly/uBTiMw" data-text="Manipulating PDFs with Python and pyPdf" data-count="vertical" data-via="socializeWP" ><!--Tweetter--></a></div><div class="socialize-in-button socialize-in-button-left"><iframe src="http://www.facebook.com/plugins/like.php?href=http://www.blog.pythonlibrary.org/2010/05/15/manipulating-pdfs-with-python-and-pypdf/&amp;layout=button_count&amp;show_faces=true&amp;width=100&amp;action=like&amp;font=arial&amp;colorscheme=light&amp;height=65" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:100px !important; height:65px;" allowTransparency="true"></iframe></div><div class="socialize-in-button socialize-in-button-left"><script type="text/javascript">
			<!-- 
			reddit_url = "http://www.blog.pythonlibrary.org/2010/05/15/manipulating-pdfs-with-python-and-pypdf/";
			reddit_title = "Manipulating PDFs with Python and pyPdf";	//-->
		</script><script type="text/javascript" src="http://www.reddit.com/static/button/button2.js"></script></div><div class="socialize-in-button socialize-in-button-left"><g:plusone size="small" href="http://www.blog.pythonlibrary.org/2010/05/15/manipulating-pdfs-with-python-and-pypdf/"></g:plusone></div></div><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[<div class="socialize-in-content" style="float:left;"><div class="socialize-in-button socialize-in-button-left"><a href="http://twitter.com/share" class="twitter-share-button" data-counturl="http://www.blog.pythonlibrary.org/2010/03/08/a-simple-step-by-step-reportlab-tutorial/" data-url="http://bit.ly/sA7SS3" data-text="A Simple Step-by-Step Reportlab Tutorial" data-count="vertical" data-via="socializeWP" ><!--Tweetter--></a></div><div class="socialize-in-button socialize-in-button-left"><iframe src="http://www.facebook.com/plugins/like.php?href=http://www.blog.pythonlibrary.org/2010/03/08/a-simple-step-by-step-reportlab-tutorial/&amp;layout=button_count&amp;show_faces=true&amp;width=100&amp;action=like&amp;font=arial&amp;colorscheme=light&amp;height=65" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:100px !important; height:65px;" allowTransparency="true"></iframe></div><div class="socialize-in-button socialize-in-button-left"><script type="text/javascript">
			<!-- 
			reddit_url = "http://www.blog.pythonlibrary.org/2010/03/08/a-simple-step-by-step-reportlab-tutorial/";
			reddit_title = "A Simple Step-by-Step Reportlab Tutorial";	//-->
		</script><script type="text/javascript" src="http://www.reddit.com/static/button/button2.js"></script></div><div class="socialize-in-button socialize-in-button-left"><g:plusone size="small" href="http://www.blog.pythonlibrary.org/2010/03/08/a-simple-step-by-step-reportlab-tutorial/"></g:plusone></div></div><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 2.855 seconds -->

