Answers to many common questions about ReportLab open source can be found on the reportlab-users Google Group. Please send queries, suggested FAQs or requests to the users list by subscribing or (if you are not subscribed) to firstname.lastname@example.org.
1.1 What is ReportLab?
1.2 How do I get it?
1.3.1 Licensing for contributions
1.4 System requirements
1.5 Platforms (Unices, Windows, MacOS)
1.7 Is there a mailing list?
1.8 How stable is it?
1.9 Where is the documentation? How do I learn my way around it?
1.10 Does ReportLab toolkit work on Java platform?
2.1.1 I've never programmed in Python before. Is there a Python tutorial?
2.1.2 How do I make "Hello World!" PDF file?
2.1.3 Can I use any images
2.1.4 What colors can I use and how?
2.1.5 Does reportlab support reading PDFs?
2.1.6 Can I use vector graphics within my PDFs?
ReportLab Inc. is a software company developing open-source and commercial products for generating dynamic documents and graphics. The ReportLab toolkit is our main open-source library; it is a collection of open source Python language modules organised and supported by ReportLab. The modules are primarily concerned with automating methods for generating Portable Document Format (PDF) files, but there is also a cross-platform vector graphics library able to generate bitmap and vector charts and drawings.
If you have not already done so, you will need to install the Python language from www.python.org. If you want to include bitmap images, you should also install the Python Imaging Library. Thereafter, you need the latest stable version of the ReportLab package from our downloads page.
The open-source version of the ReportLab toolkit and our other open-source tools are available under the BSD license. This means that you can basically do anything you want with it, including using it in a commercial package. (We used to use the Python license, but the Python license became historically complicated. We chose the BSD license because it was the shortest and most readable Open Source license).
pyRXP, our XML parser, is under the GNU General Public License. This is because the RXP parser within it is under such a license. If you want to use pyRXP in a closed source project you will have to negotiate with us. rlextra, our commercial software package that contains pyRXPis also licensed. Pricing details can be found here.
How does copyright/licensing work with regards to items contributed to ReportLab? If something eventually makes its way into the core ReportLab libraries, does one need to assign copyright over to ReportLab Inc, or simply release it under the same style of license as ReportLab?
The open-source toolkit is under a BSD compatible license. Anything contributed presumably would be better under that. We're fairly sure that other open-source licenses would be acceptable provided they don't effect the toolkit itself.
A full source Python installation requires about 50Mb of disk space, and a Python process needs about 4Mb of memory. Compact distributions as small as 1-2Mb are possible. On top of this, ReportLab toolkit and all dependent libraries could use between 2 and 10 Mb (assuming you build all the manuals and run all the tests).
The ReportLab toolkit runs everywhere Python runs, which means everywhere with an ANSI C compiler.
There are a number of routes to install ReportLab. We recommend using pip as it automatically pulls down all needed dependancies. Use the following links for guides on how to install ReportLab PLUS and ReportLab open-source.
The group mailing list is at http://two.pairlist.net/mailman/listinfo/reportlab-users.
The library has been in production use for over 10 years with some of the world's largest financial institutions, delivering real-time documents and charts; and has been widely deployed by members of our user group in a wide variety of environments.
New features are sometimes introduced on an experimental basis and might contain bugs or undergo changes in the first few release cycles. For an impartial opinion on stability, feel free to join our user group and ask them directly.
The best place to start is by looking at the output of the test scripts, testpdfgen.pdf and testplatypus.pdf, which are also available on this site. These work as 'mini-tutorials' as well as tests, and by looking at the source code you can quickly learn how to create any effects you need
At the moment, the only way to work with ReportLab toolkit using Java is to use Java implementation of python called Jython (www.jython.org). Currently we are in the testing phase and it seems that most of ReportLab toolkit features do work under Jython. However, things that need OS specific features, like os.chdir() will not work, because they're not supported by Java. This is especially true for the set of test suites.
ReportLab toolkit has been tested under Sun's J2SDK 1.3.1. It is known that under J2SDK 1.4.0_01 test_pdfbase_ttfonts.py fails horribly with an outOfMemory exception, probably caused by a JVM bug. For information on how to install ReportLab toolkit to work with Jython, see the user guide.
Take a look at some of the resources here https://wiki.python.org/moin/BeginnersGuide/Programmers.
The pdfgen package is the lowest level interface for generating PDF documents and the best place to start learning. A pdfgen program is essentially a sequence of instructions for "painting" a document onto a sequence of pages. The interface object which provides the painting operations is the pdfgen canvas.
The canvas should be thought of as a sheet of white paper with points on the sheet identified using Cartesian (X,Y) coordinates which by default have the (0,0) origin point at the lower left corner of the page. Furthermore the first coordinate x goes to the right and the second coordinate y goes up, by default.
A simple example program that uses a canvas follows:
from reportlab.pdfgen import canvas from reportlab.lib.units import cm c = canvas.Canvas("hello.pdf") c.drawString(9*cm, 22*cm, "Hello World!") c.showPage() c.save()
This example outputs 'hello.pdf' file in the current directory.
To use images other than JPEGs, you need to have the Python Imaging Library installed. And to compress pages (which is not done by default), you need zlib. zlib is included on Windows, but is an optional extension on Unix and Mac; you need to rebuild Python with it included.
It is possible that some scripts which need images may error if PIL is not present; we aim to tighten this up so that it degrades gracefully when these extensions are not available.
There are five ways to specify colors in pdfgen:
- by name (using the color module)
- by red/green/blue (additive, RGB) value
- by cyan/magenta/yellow/darkness (subtractive, CMYK)
- by gray level.
- by using class PCMYKColorfrom reportlab.lib.colors module. It is similar to CMYKColor, but instead of being 0-1 based, the values are range from 0 to 100.
The colors function below exercises the first four methods.
def colors(canvas): from reportlab.lib import colors from reportlab.lib.units import inch black = colors.black y = x = 0; dy=inch*3/4.0; dx=inch*5.5/5; w=h=dy/2 rdx=(dx-w)/2; rdy=h/5.0; texty=h+2*rdy canvas.setFont("Helvetica",10) for [namedcolor, name] in ( [colors.lavenderblush, "lavenderblush"], [colors.lawngreen, "lawngreen"], [colors.lemonchiffon, "lemonchiffon"], [colors.lightblue, "lightblue"], [colors.lightcoral, "lightcoral"]): canvas.setFillColor(namedcolor) canvas.rect(x+rdx, y+rdy, w, h, fill=1) canvas.setFillColor(black) canvas.drawCentredString(x+dx/2, y+texty, name) x = x+dx y = y + dy; x = 0 for rgb in [(1,0,0), (0,1,0), (0,0,1),(0.5,0.3,0.1), (0.4,0.5,0.3)]: r,g,b = rgb canvas.setFillColorRGB(r,g,b) canvas.rect(x+rdx, y+rdy, w, h, fill=1) canvas.setFillColor(black) canvas.drawCentredString(x+dx/2, y+texty,"r%s g%s b%s"%rgb) x = x+dx y = y + dy; x = 0 for cmyk in [(1,0,0,0), (0,1,0,0), (0,0,1,0), (0,0,0,1), (0,0,0,0)]: c,m,y1,k = cmyk canvas.setFillColorCMYK(c,m,y1,k) canvas.rect(x+rdx, y+rdy, w, h, fill=1) canvas.setFillColor(black) canvas.drawCentredString(x+dx/2, y+texty,"c%s m%s y%s k%s"%cmyk) x = x+dx y = y + dy; x = 0 for gray in (0.0, 0.25, 0.50, 0.75, 1.0): canvas.setFillGray(gray) canvas.rect(x+rdx, y+rdy, w, h, fill=1) if __name__ == "__main__": from reportlab.pdfgen import canvas from reportlab.lib.units import cm c = canvas.Canvas("colors.pdf") colors(c) c.showPage() c.save()
The RGB or additive color specification follows the way a computer screen adds different levels of the red, green, or blue light to make any color, where white is formed by turning all three lights on full (1,1,1).
The CMYK or subtractive method follows the way a printer mixes three pigments (cyan, magenta, and yellow) to form colors. Because mixing chemicals is more difficult than combining light there is a fourth parameter for darkness. For example a chemical combination of the CMY pigments generally never makes a perfect black -- instead producing a muddy color -- so to get black, printers don't use the CMY pigments but use a direct black ink. Because CMYK maps more directly to the way printer hardware works it may be the case that colors specified in CMYK will provide better fidelity and better control when printed.
In addition to all the above, CMYKColors have three extra constructor possibilities:
- spotName (default None)
This is a printer friendly name that may be used under certain circumstances to select an ink etc. This is normally only useful when we're doing EPS graphics to allow separation of colour plates.
- density (default 1 or 100 PCMYKColor)
The CMYK model allows us to put more or less ink on the paper without changing the color. 0 means no ink, 1 (or 100) means slap it on maximally. This feature allows a three plate print say black and two named spot colors to have many variants of the individual colors without changing the definition of the colors.
CMYKColor(0.5,0.25,0.25,0,density=1) is not treated the same by the printer as CMYKColor(1.0,0.5,0.5,0,density=0.5) as there are no spot names. Since densities have to lie below 1 to get the required effect, you need something like CMYKColor(1.0,0.5,0.5,0,spotName='dingo_ink',density=0.5)
- knockout(default None)
In printing it's important to realize that the second colour goes on top of the first without erasing what's underneath. Since we may need to have this erasing mode (especially for colour separation EPS) we have the knockout parameter.
A (P)CMYKColor with knockout set will attempt to erase what's underneath it when drawn (irrespective of the ink order). This may in fact cause registration problems when black knockout lines are drawn onto other colors effectively we create a white line first and when the black line doesn't quite hit the right place (because of mis-positioning) we see the white line partially covered by the black.
Yes and no. The open-source package doesn't do this.
PageCatcher, a component of our commercial ReportLab PLUS package, does. The PageCatcher API allows you to extract text, graphics and even entire pages to use in your ReportLab projects. Its main goal is to accelerate development new projects by letting you reuse content developed in other tools. Expensive graphic design work can be directly integrated into ReportLab's automation tools.
PageCatcher is shipped as part of our commercial toolkit. More details here.
Yes and no. The open-source package doesn't do this. PageCatcher (see the previous answer) allows you to easily incorporate any vector image by saving it as a PDF and then using it exactly as you would an image file, and Report Markup Language accepts PDF files along with JPG, GIF and PNG.
The pdfgen package is the lowest level interface for generating PDF documents. A pdfgen program is essentially a sequence of instructions for "painting" a document onto a sequence of pages. The interface object which provides the painting operations is the pdfgen.Canvas.
Platypus stands for "Page Layout and Typography Using Scripts". It is a high level page layout library which lets you programmatically create complex documents with a minimum of effort.
The design of Platypus seeks to separate "high level" layout decisions from the document content as much as possible. Thus, for example, paragraphs are constructed using paragraph styles and pages are constructed using page templates with the intention that hundreds of documents with thousands of pages can be reformatted to different style specifications with the modifications of a few lines in a single shared file which contains the paragraph styles and page layout specifications.
The overall design of Platypus can be thought of has having several layers.
Top down, these are:
- DocTemplates - the outermost container for the document.
- PageTemplates - specifications for layouts of pages of various kinds
- Frames - specifications of regions in pages that can contain flowing text or graphics.
- Flowables - text or graphic elements that should be "flowed into the document (i.e. things like images, paragraphs and tables, but not things like page footers or fixed page graphics).
- pdfgen.Canvas - the lowest level which ultimately receives the painting of the document from the other layers.
Consider the following code sequence which provides a very simple "hello world" example for Platypus.
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer from reportlab.lib.styles import getSampleStyleSheet from reportlab.rl_config import defaultPageSize from reportlab.lib.units import inch PAGE_HEIGHT=defaultPageSize PAGE_WIDTH=defaultPageSize styles = getSampleStyleSheet()
First we import some constructors, some paragraph styles and other conveniences from other modules.
Title = "Hello world" pageinfo = "platypus example" def myFirstPage(canvas, doc): canvas.saveState() canvas.setFont('Times-Bold',16) canvas.drawCentredString(PAGE_WIDTH/2.0, PAGE_HEIGHT-108, Title) canvas.setFont('Times-Roman',9) canvas.drawString(inch, 0.75 * inch,"First Page / %s" % pageinfo) canvas.restoreState()
We define the fixed features of the first page of the document with the function above.
def myLaterPages(canvas, doc): canvas.saveState() canvas.setFont('Times-Roman', 9) canvas.drawString(inch, 0.75 * inch,"Page %d %s" % (doc.page, pageinfo)) canvas.restoreState()
Since we want pages after the first to look different from the first we define an alternate layout for the fixed features of the other pages. Note that the two functions above use the pdfgen level canvas operations to paint the annotations for the pages.
def go(): doc = SimpleDocTemplate("phello.pdf") Story = [Spacer(1,2*inch)] style = styles["Normal"] for i in range(100): bogustext = ("Paragraph number %s. " % i) \*20 p = Paragraph(bogustext, style) Story.append(p) Story.append(Spacer(1,0.2*inch)) doc.build(Story, onFirstPage=myFirstPage, onLaterPages=myLaterPages) if __name__ == "__main__": go()
Finally, we create a story and build the document. Note that we are using a "canned" document template here, which comes pre-built with page templates. We are also using a pre-built paragraph style. We are only using two types of flowables here -- Spacers and Paragraphs. The first Spacer ensures that the Paragraphs skip past the title string.
The complete script is here. It will generate the Platypus output phello.pdf.
ReportLab Graphics is one of the sub-packages to the ReportLab library. It is a integrated part of the ReportLab toolkit that allows you to use its powerful charting and graphics features to improve your PDF forms and reports.
PythonPoint is a library for creating presentation slides. PythonPoint lets you create attractive and consistent presentation slides on any platform. It is built on top of the PDFgen PDF library and the PLATYPUS Page Layout library. Essentially, it converts slides in an XML format to PDF.
It's included in the standard distribution of the ReportLab library -- look in the reportlab/tools/pythonpoint directory.
Every copy of Acrobat Reader comes with 14 standard fonts built in. Therefore, the ReportLab PDF Library only needs to refer to these by name. If you want to use other fonts, they must be embedded in the PDF document. You also need to make sure your strings are in the same encoding as the font you have selected.
You can use the mechanism described below to include arbitrary fonts in your documents.
You can embed fonts in TTF and Type 1 format. Type 1 embedding relies on font description files in the Adobe AFM ('Adobe Font Metrics') and PFB ('Printer Font Binary') format. The former is an ASCII file and contains information about the characters ('glyphs') in the font such as height, width, bounding box info and other 'metrics', while the latter is a binary file that describes the shapes of the font.
The following sample uses the Type 1 font 'Dark Garden ' and the TTF font Vera, which come bundled with the ReportLab distribution in the directory reportlab/fonts.
In the following example, we locate the folder containing the test fonts and register them for future use with the pdfmetrics module, after which we can use them like any other standard font.
import os import reportlab from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont from reportlab.pdfgen.canvas import Canvas folder = os.path.dirname(reportlab.__file__) + os.sep + 'fonts' afmFile = os.path.join(folder, 'DarkGardenMK.afm') pfbFile = os.path.join(folder, 'DarkGardenMK.pfb') ttfFile = os.path.join(folder, 'Vera.ttf') justFace = pdfmetrics.EmbeddedType1Face(afmFile, pfbFile) faceName = 'DarkGardenMK' # pulled from AFM file pdfmetrics.registerTypeFace(justFace) justFont = pdfmetrics.Font('DarkGardenMK', faceName, 'WinAnsiEncoding') pdfmetrics.registerFont(justFont) pdfmetrics.registerFont(TTFont("Vera", ttfFile)) canvas = Canvas('TestFonts.pdf') canvas.setFont('DarkGardenMK', 32) canvas.drawString(10, 150, 'This should be drawn in') canvas.drawString(10, 100, 'the font DarkGardenMK') canvas.setFont('Vera', 32) canvas.drawString(10, 250, 'This should be drawn in') canvas.drawString(10, 200, 'the font Vera') canvas.showPage() canvas.save()
This example outputs 'TestFonts.pdf' file in the current directory.
There is more information about font embedding in the User Guide, and in the files test_pdfbase_ttfonts.py and test_pdfbase_fontembed.py in the reportlab/tests/ directory.
If you have a BitBucket account, bug reports can be filed in the BitBucket issue tracker. Either way, please also notify the mailing list (email@example.com), as other users may often be able to help. Please give enough detail to adequately describe the bug - and a code snippet which illustrates it (if possible).