bzr revid: pinky-6e2b8c053bc91a80362d7d3867ff412eb65b09c7
This commit is contained in:
pinky 2007-01-07 23:37:01 +00:00
parent 131e3f481e
commit 43eda8f14e
36 changed files with 15417 additions and 0 deletions

View File

@ -0,0 +1,6 @@
global-include *.dtd *.txt *.xml *.yml
global-include *.c *.h *.in *.mashed
global-include *.gif *.png *.jpg .a85
global-include *.AFM *.PFB *.ttf
global-include README
include changes

35
bin/reportlab/README Normal file
View File

@ -0,0 +1,35 @@
#copyright ReportLab Inc. 2000-2001
#see license.txt for license details
#history http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/reportlab/README?cvsroot=reportlab
#$Header: /tmp/reportlab/reportlab/README,v 1.9 2002/03/05 17:21:44 rgbecker Exp $
This is the ReportLab PDF library.
Licensing
=========
BSD license. See license.txt for details
Installation
============
Either unpack reportlab.zip or reportlab.tgz to some directory say
d:\ReportLab. If you can, ensure that the line terminator style is
correct for your OS (man zip programs have a text mode option eg -a).
Create a .pth file, say reportlab.pth in your Python
home directory. It should have one line:
d:/ReportLab.
Alternatively unpack the archive into a directory which is already on your
python path.
Documentation
=============
Full documentation is included in PDF format in the docs directory.
If you are working with a CVS version, run the script genAll.py
in that directory to generate the documentation.
Acknowledgements and Thanks
===========================
lib/normalDate.py originally by Jeff Bauer
(please let us know of other acknowledgements - we just
started this section - 13/2/2002)

7788
bin/reportlab/changes Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
Thid directory holds documentation. For end users,
it should contain a number of PDF manuals. For
people working with the source, this directory will
be the destination for any manuals built.
If you don't see the pdf manual you expected or you wich to
ensure an up to date copy run the script tools/genAll.py!

View File

@ -0,0 +1,37 @@
#!/bin/env python
import os, sys
def _genAll(d=None,verbose=1):
if not d: d = '.'
if not os.path.isabs(d):
d = os.path.normpath(os.path.join(os.getcwd(),d))
L = ['reference/genreference.py',
'userguide/genuserguide.py',
'graphguide/gengraphguide.py',
'../tools/docco/graphdocpy.py',
]
if os.path.isdir('../rl_addons'):
L = L + ['../rl_addons/pyRXP/docs/PyRXP_Documentation.rml']
elif os.path.isdir('../../rl_addons'):
L = L + ['../../rl_addons/pyRXP/docs/PyRXP_Documentation.rml']
for p in L:
os.chdir(d)
os.chdir(os.path.dirname(p))
if p[-4:]=='.rml':
try:
from rlextra.rml2pdf.rml2pdf import main
main(exe=0,fn=[os.path.basename(p)], quiet=not verbose, outDir=d)
except:
pass
else:
cmd = '%s %s %s' % (sys.executable,os.path.basename(p), not verbose and '-s' or '')
if verbose: print cmd
os.system(cmd)
"""Runs the manual-building scripts"""
if __name__=='__main__':
#need a quiet mode for the test suite
if '-s' in sys.argv: # 'silent
verbose = 0
else:
verbose = 1
_genAll(os.path.dirname(sys.argv[0]),verbose)

View File

@ -0,0 +1,105 @@
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/graphguide/ch1_intro.py
from reportlab.tools.docco.rl_doc_utils import *
import reportlab
title("Graphics Guide")
centred('ReportLab Version ' + reportlab.Version)
nextTemplate("Normal")
########################################################################
#
# Chapter 1
#
########################################################################
heading1("Introduction")
heading2("About this document")
disc("""
This document is intended to be a helpful and reasonably full
introduction to the use of the ReportLab Graphics sub-package.
Starting with simple drawings and shapes, we will take you through the
slightly more complex reusable widgets all the way through to our
powerful and flexible chart library. You will see examples of using
reportlab/graphics to make bar charts, line charts, line plots, pie
charts... and a smiley face.
""")
disc("""
We presume that you have already installed both the Python programming
language and the core ReportLab library. If you have not done either
of these, look in the ReportLab User Guide where chapter one
talks you through all the required steps.
""")
disc("""
We recommend that you read some or all of the User Guide and have at
least a basic understanding of how the ReportLab library works before
you start getting to grips with ReportLab Graphics.
""")
disc("")
todo("""
Be warned! This document is in a <em>very</em> preliminary form. We need
your help to make sure it is complete and helpful. Please send any
feedback to our user mailing list, reportlab-users@reportlab.com.
""")
heading2("What is ReportLab?")
disc("""ReportLab is a software library that lets you directly
create documents in Adobe's Portable Document Format (PDF) using
the Python programming language. """)
disc("""The ReportLab library directly creates PDF based on
your graphics commands. There are no intervening steps. Your applications
can generate reports extremely fast - sometimes orders
of magnitude faster than traditional report-writing
tools.""")
heading2("What is ReportLab Graphics?")
disc("""
ReportLab Graphics is one of the sub-packages to the ReportLab
library. It started off as a stand-alone set of programs, but is now a
fully integrated part of the ReportLab toolkit that allows you to use
its powerful charting and graphics features to improve your PDF forms
and reports.
""")
heading2("Getting Involved")
disc("""ReportLab is an Open Source project. Although we are
a commercial company we provide the core PDF generation
sources freely, even for commercial purposes, and we make no income directly
from these modules. We also welcome help from the community
as much as any other Open Source project. There are many
ways in which you can help:""")
bullet("""General feedback on the core API. Does it work for you?
Are there any rough edges? Does anything feel clunky and awkward?""")
bullet("""New objects to put in reports, or useful utilities for the library.
We have an open standard for report objects, so if you have written a nice
chart or table class, why not contribute it?""")
bullet("""Demonstrations and Case Studies: If you have produced some nice
output, send it to us (with or without scripts). If ReportLab solved a
problem for you at work, write a little 'case study' and send it in.
And if your web site uses our tools to make reports, let us link to it.
We will be happy to display your work (and credit it with your name
and company) on our site!""")
bullet("""Working on the core code: we have a long list of things
to refine or to implement. If you are missing some features or
just want to help out, let us know!""")
disc("""The first step for anyone wanting to learn more or
get involved is to join the mailing list. To Subscribe visit
$http://two.pairlist.net/mailman/listinfo/reportlab-users$.
From there you can also browse through the group's archives
and contributions. The mailing list is
the place to report bugs and get support. """)

View File

@ -0,0 +1,376 @@
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/graphguide/ch2_concepts.py
from reportlab.tools.docco.rl_doc_utils import *
heading1("General Concepts")
disc("""
In this chapter we will present some of the more fundamental principles of
the graphics library, which will show-up later in various places.
""")
heading2("Drawings and Renderers")
disc("""
A <i>Drawing</i> is a platform-independent description of a collection of
shapes.
It is not directly associated with PDF, Postscript or any other output
format.
Fortunately, most vector graphics systems have followed the Postscript
model and it is possible to describe shapes unambiguously.
""")
disc("""
A drawing contains a number of primitive <i>Shapes</i>.
Normal shapes are those widely known as rectangles, circles, lines,
etc.
One special (logic) shape is a <i>Group</i>, which can hold other
shapes and apply a transformation to them.
Groups represent composites of shapes and allow to treat the
composite as if it were a single shape.
Just about anything can be built up from a small number of basic
shapes.
""")
disc("""
The package provides several <i>Renderers</i> which know how to draw a
drawing into different formats.
These include PDF (of course), Postscript, and bitmap output.
The bitmap renderer uses Raph Levien's <i>libart</i> rasterizer
and Fredrik Lundh's <i>Python Imaging Library</i> (PIL).
Very recently, an experimental SVG renderer was also added.
It makes use of Python's standard library XML modules, so you don't
need to install the XML-SIG's additional package named PyXML.
If you have the right extensions installed, you can generate drawings
in bitmap form for the web as well as vector form for PDF documents,
and get "identical output".
""")
disc("""
The PDF renderer has special "privileges" - a Drawing object is also
a <i>Flowable</i> and, hence, can be placed directly in the story
of any Platypus document, or drawn directly on a <i>Canvas</i> with
one line of code.
In addition, the PDF renderer has a utility function to make
a one-page PDF document quickly.
""")
disc("""
The SVG renderer is special as it is still pretty experimental.
The SVG code it generates is not really optimised in any way and
maps only the features available in ReportLab Graphics (RLG) to
SVG. This means there is no support for SVG animation, interactivity,
scripting or more sophisticated clipping, masking or graduation
shapes.
So, be careful, and please report any bugs you find!
""")
disc("""
We expect to add both input and output filters for many vector
graphics formats in future.
SVG was the most prominent first one to start with for which there
is now an output filter in the graphics package.
An SVG input filter will probably become available in Summer 2002
as an additional module.
GUIs will be able to obtain screen images from the bitmap output
filter working with PIL, so a chart could appear in a Tkinter
GUI window.
""")
heading2("Coordinate System")
disc("""
The Y-direction in our X-Y coordinate system points from the
bottom <i>up</i>.
This is consistent with PDF, Postscript and mathematical notation.
It also appears to be more natural for people, especially when
working with charts.
Note that in other graphics models (such as SVG) the Y-coordinate
points <i>down</i>.
For the SVG renderer this is actually no problem as it will take
your drawings and flip things as needed, so your SVG output looks
just as expected.
""")
disc("""
The X-coordinate points, as usual, from left to right.
So far there doesn't seem to be any model advocating the opposite
direction - at least not yet (with interesting exceptions, as it
seems, for Arabs looking at time series charts...).
""")
heading2("Getting Started")
disc("""
Let's create a simple drawing containing the string "Hello World",
displayed on top of a coloured rectangle.
After creating it we will save the drawing to a standalone PDF file.
""")
eg("""
from reportlab.lib import colors
from reportlab.graphics.shapes import *
d = Drawing(400, 200)
d.add(Rect(50, 50, 300, 100, fillColor=colors.yellow))
d.add(String(150,100, 'Hello World',
fontSize=18, fillColor=colors.red))
from reportlab.graphics import renderPDF
renderPDF.drawToFile(d, 'example1.pdf', 'My First Drawing')
""")
disc("This will produce a PDF file containing the following graphic:")
from reportlab.graphics.shapes import *
from reportlab.graphics import testshapes
t = testshapes.getDrawing01()
draw(t, "'Hello World'")
disc("""
Each renderer is allowed to do whatever is appropriate for its format,
and may have whatever API is needed.
If it refers to a file format, it usually has a $drawToFile$ function,
and that's all you need to know about the renderer.
Let's save the same drawing in Encapsulated Postscript format:
""")
##eg("""
## from reportlab.graphics import renderPS
## renderPS.drawToFile(D, 'example1.eps', 'My First Drawing')
##""")
eg("""
from reportlab.graphics import renderPS
renderPS.drawToFile(d, 'example1.eps')
""")
disc("""
This will produce an EPS file with the identical drawing, which
may be imported into publishing tools such as Quark Express.
If we wanted to generate the same drawing as a bitmap file for
a website, say, all we need to do is write code like this:
""")
eg("""
from reportlab.graphics import renderPM
renderPM.saveToFile(d, 'example1.png', 'PNG')
""")
disc("""
Many other bitmap formats, like GIF, JPG, TIFF, BMP and PPN are
genuinely available, making it unlikely you'll need to add external
postprocessing steps to convert to the final format you need.
""")
disc("""
To produce an SVG file containing the identical drawing, which
may be imported into graphical editing tools such as Illustrator
all we need to do is write code like this:
""")
eg("""
from reportlab.graphics import renderSVG
renderSVG.drawToFile(d, 'example1.svg')
""")
heading2("Attribute Verification")
disc("""
Python is very dynamic and lets us execute statements at run time that
can easily be the source for unexpected behaviour.
One subtle 'error' is when assigning to an attribute that the framework
doesn't know about because the used attribute's name contains a typo.
Python lets you get away with it (adding a new attribute to an object,
say), but the graphics framework will not detect this 'typo' without
taking special counter-measures.
""")
disc("""
There are two verification techniques to avoid this situation.
The default is for every object to check every assignment at run
time, such that you can only assign to 'legal' attributes.
This is what happens by default.
As this imposes a small performance penalty, this behaviour can
be turned off when you need it to be.
""")
eg("""
>>> r = Rect(10,10,200,100, fillColor=colors.red)
>>>
>>> r.fullColor = colors.green # note the typo
>>> r.x = 'not a number' # illegal argument type
>>> del r.width # that should confuse it
""")
disc("""
These statements would be caught by the compiler in a statically
typed language, but Python lets you get away with it.
The first error could leave you staring at the picture trying to
figure out why the colors were wrong.
The second error would probably become clear only later, when
some back-end tries to draw the rectangle.
The third, though less likely, results in an invalid object that
would not know how to draw itself.
""")
eg("""
>>> r = shapes.Rect(10,10,200,80)
>>> r.fullColor = colors.green
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
File "C:\code\users\andy\graphics\shapes.py", line 254, in __setattr__
validateSetattr(self,attr,value) #from reportlab.lib.attrmap
File "C:\code\users\andy\lib\attrmap.py", line 74, in validateSetattr
raise AttributeError, "Illegal attribute '%s' in class %s" % (name, obj.__class__.__name__)
AttributeError: Illegal attribute 'fullColor' in class Rect
>>>
""")
disc("""
This imposes a performance penalty, so this behaviour can be turned
off when you need it to be.
To do this, you should use the following lines of code before you
first import reportlab.graphics.shapes:
""")
eg("""
>>> import reportlab.rl_config
>>> reportlab.rl_config.shapeChecking = 0
>>> from reportlab.graphics import shapes
>>>
""")
disc("""
Once you turn off $shapeChecking$, the classes are actually built
without the verification hook; code should get faster, then.
Currently the penalty seems to be about 25% on batches of charts,
so it is hardly worth disabling.
However, if we move the renderers to C in future (which is eminently
possible), the remaining 75% would shrink to almost nothing and
the saving from verification would be significant.
""")
disc("""
Each object, including the drawing itself, has a $verify()$ method.
This either succeeds, or raises an exception.
If you turn off automatic verification, then you should explicitly
call $verify()$ in testing when developing the code, or perhaps
once in a batch process.
""")
heading2("Property Editing")
disc("""
A cornerstone of the reportlab/graphics which we will cover below is
that you can automatically document widgets.
This means getting hold of all of their editable properties,
including those of their subcomponents.
""")
disc("""
Another goal is to be able to create GUIs and config files for
drawings.
A generic GUI can be built to show all editable properties
of a drawing, and let you modify them and see the results.
The Visual Basic or Delphi development environment are good
examples of this kind of thing.
In a batch charting application, a file could list all the
properties of all the components in a chart, and be merged
with a database query to make a batch of charts.
""")
disc("""
To support these applications we have two interfaces, $getProperties$
and $setProperties$, as well as a convenience method $dumpProperties$.
The first returns a dictionary of the editable properties of an
object; the second sets them en masse.
If an object has publicly exposed 'children' then one can recursively
set and get their properties too.
This will make much more sense when we look at <i>Widgets</i> later on,
but we need to put the support into the base of the framework.
""")
eg("""
>>> r = shapes.Rect(0,0,200,100)
>>> import pprint
>>> pprint.pprint(r.getProperties())
{'fillColor': Color(0.00,0.00,0.00),
'height': 100,
'rx': 0,
'ry': 0,
'strokeColor': Color(0.00,0.00,0.00),
'strokeDashArray': None,
'strokeLineCap': 0,
'strokeLineJoin': 0,
'strokeMiterLimit': 0,
'strokeWidth': 1,
'width': 200,
'x': 0,
'y': 0}
>>> r.setProperties({'x':20, 'y':30, 'strokeColor': colors.red})
>>> r.dumpProperties()
fillColor = Color(0.00,0.00,0.00)
height = 100
rx = 0
ry = 0
strokeColor = Color(1.00,0.00,0.00)
strokeDashArray = None
strokeLineCap = 0
strokeLineJoin = 0
strokeMiterLimit = 0
strokeWidth = 1
width = 200
x = 20
y = 30
>>> """)
disc("""
<i>Note: $pprint$ is the standard Python library module that allows
you to 'pretty print' output over multiple lines rather than having
one very long line.</i>
""")
disc("""
These three methods don't seem to do much here, but as we will see
they make our widgets framework much more powerful when dealing with
non-primitive objects.
""")
heading2("Naming Children")
disc("""
You can add objects to the $Drawing$ and $Group$ objects.
These normally go into a list of contents.
However, you may also give objects a name when adding them.
This allows you to refer to and possibly change any element
of a drawing after constructing it.
""")
eg("""
>>> d = shapes.Drawing(400, 200)
>>> s = shapes.String(10, 10, 'Hello World')
>>> d.add(s, 'caption')
>>> s.caption.text
'Hello World'
>>>
""")
disc("""
Note that you can use the same shape instance in several contexts
in a drawing; if you choose to use the same $Circle$ object in many
locations (e.g. a scatter plot) and use different names to access
it, it will still be a shared object and the changes will be
global.
""")
disc("""
This provides one paradigm for creating and modifying interactive
drawings.
""")

View File

@ -0,0 +1,416 @@
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/graphguide/ch3_shapes.py
from reportlab.tools.docco.rl_doc_utils import *
from reportlab.graphics.shapes import *
heading1("Shapes")
disc("""
This chapter describes the concept of shapes and their importance
as building blocks for all output generated by the graphics library.
Some properties of existing shapes and their relationship to
diagrams are presented and the notion of having different renderers
for different output formats is briefly introduced.
""")
heading2("Available Shapes")
disc("""
Drawings are made up of Shapes.
Absolutely anything can be built up by combining the same set of
primitive shapes.
The module $shapes.py$ supplies a number of primitive shapes and
constructs which can be added to a drawing.
They are:
""")
bullet("Rect")
bullet("Circle")
bullet("Ellipse")
bullet("Wedge (a pie slice)")
bullet("Polygon")
bullet("Line")
bullet("PolyLine")
bullet("String")
bullet("Group")
bullet("Path (<i>not implemented yet, but will be added in the future</i>)")
disc("""
The following drawing, taken from our test suite, shows most of the
basic shapes (except for groups).
Those with a filled green surface are also called <i>solid shapes</i>
(these are $Rect$, $Circle$, $Ellipse$, $Wedge$ and $Polygon$).
""")
from reportlab.graphics import testshapes
t = testshapes.getDrawing06()
draw(t, "Basic shapes")
heading2("Shape Properties")
disc("""
Shapes have two kinds of properties - some to define their geometry
and some to define their style.
Let's create a red rectangle with 3-point thick green borders:
""")
eg("""
>>> from reportlab.graphics.shapes import Rect
>>> from reportlab.lib.colors import red, green
>>> r = Rect(5, 5, 200, 100)
>>> r.fillColor = red
>>> r.strokeColor = green
>>> r.strokeWidth = 3
>>>
""")
from reportlab.graphics.shapes import Rect
from reportlab.lib.colors import red, green
d = Drawing(220, 120)
r = Rect(5, 5, 200, 100)
r.fillColor = red
r.strokeColor = green
r.strokeWidth = 3
d.add(r)
draw(d, "red rectangle with green border")
disc("""
<i>Note: In future examples we will omit the import statements.</i>
""")
disc("""
All shapes have a number of properties which can be set.
At an interactive prompt, we can use their <i>dumpProperties()</i>
method to list these.
Here's what you can use to configure a Rect:
""")
eg("""
>>> r.dumpProperties()
fillColor = Color(1.00,0.00,0.00)
height = 100
rx = 0
ry = 0
strokeColor = Color(0.00,0.50,0.00)
strokeDashArray = None
strokeLineCap = 0
strokeLineJoin = 0
strokeMiterLimit = 0
strokeWidth = 3
width = 200
x = 5
y = 5
>>>
""")
disc("""
Shapes generally have <i>style properties</i> and <i>geometry
properties</i>.
$x$, $y$, $width$ and $height$ are part of the geometry and must
be provided when creating the rectangle, since it does not make
much sense without those properties.
The others are optional and come with sensible defaults.
""")
disc("""
You may set other properties on subsequent lines, or by passing them
as optional arguments to the constructor.
We could also have created our rectangle this way:
""")
eg("""
>>> r = Rect(5, 5, 200, 100,
fillColor=red,
strokeColor=green,
strokeWidth=3)
""")
disc("""
Let's run through the style properties. $fillColor$ is obvious.
$stroke$ is publishing terminology for the edge of a shape;
the stroke has a color, width, possibly a dash pattern, and
some (rarely used) features for what happens when a line turns
a corner.
$rx$ and $ry$ are optional geometric properties and are used to
define the corner radius for a rounded rectangle.
""")
disc("All the other solid shapes share the same style properties.")
heading2("Lines")
disc("""
We provide single straight lines, PolyLines and curves.
Lines have all the $stroke*$ properties, but no $fillColor$.
Here are a few Line and PolyLine examples and the corresponding
graphics output:
""")
eg("""
Line(50,50, 300,100,
strokeColor=colors.blue, strokeWidth=5)
Line(50,100, 300,50,
strokeColor=colors.red,
strokeWidth=10,
strokeDashArray=[10, 20])
PolyLine([120,110, 130,150, 140,110, 150,150, 160,110,
170,150, 180,110, 190,150, 200,110],
strokeWidth=2,
strokeColor=colors.purple)
""")
d = Drawing(400, 200)
d.add(Line(50,50, 300,100,strokeColor=colors.blue, strokeWidth=5))
d.add(Line(50,100, 300,50,
strokeColor=colors.red,
strokeWidth=10,
strokeDashArray=[10, 20]))
d.add(PolyLine([120,110, 130,150, 140,110, 150,150, 160,110,
170,150, 180,110, 190,150, 200,110],
strokeWidth=2,
strokeColor=colors.purple))
draw(d, "Line and PolyLine examples")
heading2("Strings")
disc("""
The ReportLab Graphics package is not designed for fancy text
layout, but it can place strings at desired locations and with
left/right/center alignment.
Let's specify a $String$ object and look at its properties:
""")
eg("""
>>> s = String(10, 50, 'Hello World')
>>> s.dumpProperties()
fillColor = Color(0.00,0.00,0.00)
fontName = Times-Roman
fontSize = 10
text = Hello World
textAnchor = start
x = 10
y = 50
>>>
""")
disc("""
Strings have a textAnchor property, which may have one of the
values 'start', 'middle', 'end'.
If this is set to 'start', x and y relate to the start of the
string, and so on.
This provides an easy way to align text.
""")
disc("""
Strings use a common font standard: the Type 1 Postscript fonts
present in Acrobat Reader.
We can thus use the basic 14 fonts in ReportLab and get accurate
metrics for them.
We have recently also added support for extra Type 1 fonts
and the renderers all know how to render Type 1 fonts.
""")
##Until now we have worked with bitmap renderers which have to use
##TrueType fonts and which make some substitutions; this could lead
##to differences in text wrapping or even the number of labels on
##a chart between renderers.
disc("""
Here is a more fancy example using the code snippet below.
Please consult the ReportLab User Guide to see how non-standard
like 'LettErrorRobot-Chrome' fonts are being registered!
""")
eg("""
d = Drawing(400, 200)
for size in range(12, 36, 4):
d.add(String(10+size*2, 10+size*2, 'Hello World',
fontName='Times-Roman',
fontSize=size))
d.add(String(130, 120, 'Hello World',
fontName='Courier',
fontSize=36))
d.add(String(150, 160, 'Hello World',
fontName='LettErrorRobot-Chrome',
fontSize=36))
""")
from reportlab.pdfbase import pdfmetrics
from reportlab import rl_config
rl_config.warnOnMissingFontGlyphs = 0
afmFile, pfbFile = getJustFontPaths()
T1face = pdfmetrics.EmbeddedType1Face(afmFile, pfbFile)
T1faceName = 'LettErrorRobot-Chrome'
pdfmetrics.registerTypeFace(T1face)
T1font = pdfmetrics.Font(T1faceName, T1faceName, 'WinAnsiEncoding')
pdfmetrics.registerFont(T1font)
d = Drawing(400, 200)
for size in range(12, 36, 4):
d.add(String(10+size*2, 10+size*2, 'Hello World',
fontName='Times-Roman',
fontSize=size))
d.add(String(130, 120, 'Hello World',
fontName='Courier',
fontSize=36))
d.add(String(150, 160, 'Hello World',
fontName='LettErrorRobot-Chrome',
fontSize=36))
draw(d, 'fancy font example')
heading2("""Paths""")
disc("""
Postscript paths are a widely understood concept in graphics.
They are not implemented in $reportlab/graphics$ as yet, but they
will be, soon.
""")
# NB This commented out section is for 'future compatibility' - paths haven't
# been implemented yet, but when they are we can uncomment this back in.
##disc("""Postscript paths are a widely understood concept in graphics. A Path
## is a way of defining a region in space. You put an imaginary pen down,
## draw straight and curved segments, and even pick the pen up and move
## it. At the end of this you have described a region, which may consist
## of several distinct close shapes or unclosed lines. At the end, this
## 'path' is 'stroked and filled' according to its properties. A Path has
## the same style properties as a solid shape. It can be used to create
## any irregular shape.""")
##
##disc("""In Postscript-based imaging models such as PDF, Postscript and SVG,
## everything is done with paths. All the specific shapes covered above
## are instances of paths; even text strings (which are shapes in which
## each character is an outline to be filled). Here we begin creating a
## path with a straight line and a bezier curve:""")
##
##eg("""
##>>> P = Path(0,0, strokeWidth=3, strokeColor=red)
##>>> P.lineTo(0, 50)
##>>> P.curveTo(10,50,80,80,100,30)
##>>>
##""")
##disc("""As well as being the only way to draw complex shapes, paths offer some
## performance advantages in renderers which support them. If you want to
## create a scatter plot with 5000 blue circles of different sizes, you
## can create 5000 circles, or one path object. With the latter, you only
## need to set the color and line width once. PINGO just remembers the
## drawing sequence, and writes it out into the file. In renderers which
## do not support paths, the renderer will still have to decompose it
## into 5000 circles so you won't save anything.""")
##
##disc("""<b>Note that our current path implementation is an approximation; it
## should be finished off accurately for PDF and PS.</b>""")
heading2("Groups")
disc("""
Finally, we have Group objects.
A group has a list of contents, which are other nodes.
It can also apply a transformation - its contents can be rotated,
scaled or shifted.
If you know the math, you can set the transform directly.
Otherwise it provides methods to rotate, scale and so on.
Here we make a group which is rotated and translated:
""")
eg("""
>>> g =Group(shape1, shape2, shape3)
>>> g.rotate(30)
>>> g.translate(50, 200)
""")
disc("""
Groups provide a tool for reuse.
You can make a bunch of shapes to represent some component - say,
a coordinate system - and put them in one group called "Axis".
You can then put that group into other groups, each with a different
translation and rotation, and you get a bunch of axis.
It is still the same group, being drawn in different places.
""")
disc("""Let's do this with some only slightly more code:""")
eg("""
d = Drawing(400, 200)
Axis = Group(
Line(0,0,100,0), # x axis
Line(0,0,0,50), # y axis
Line(0,10,10,10), # ticks on y axis
Line(0,20,10,20),
Line(0,30,10,30),
Line(0,40,10,40),
Line(10,0,10,10), # ticks on x axis
Line(20,0,20,10),
Line(30,0,30,10),
Line(40,0,40,10),
Line(50,0,50,10),
Line(60,0,60,10),
Line(70,0,70,10),
Line(80,0,80,10),
Line(90,0,90,10),
String(20, 35, 'Axes', fill=colors.black)
)
firstAxisGroup = Group(Axis)
firstAxisGroup.translate(10,10)
d.add(firstAxisGroup)
secondAxisGroup = Group(Axis)
secondAxisGroup.translate(150,10)
secondAxisGroup.rotate(15)
d.add(secondAxisGroup)
thirdAxisGroup = Group(Axis,
transform=mmult(translate(300,10),
rotate(30)))
d.add(thirdAxisGroup)
""")
d = Drawing(400, 200)
Axis = Group(
Line(0,0,100,0), # x axis
Line(0,0,0,50), # y axis
Line(0,10,10,10), # ticks on y axis
Line(0,20,10,20),
Line(0,30,10,30),
Line(0,40,10,40),
Line(10,0,10,10), # ticks on x axis
Line(20,0,20,10),
Line(30,0,30,10),
Line(40,0,40,10),
Line(50,0,50,10),
Line(60,0,60,10),
Line(70,0,70,10),
Line(80,0,80,10),
Line(90,0,90,10),
String(20, 35, 'Axes', fill=colors.black)
)
firstAxisGroup = Group(Axis)
firstAxisGroup.translate(10,10)
d.add(firstAxisGroup)
secondAxisGroup = Group(Axis)
secondAxisGroup.translate(150,10)
secondAxisGroup.rotate(15)
d.add(secondAxisGroup)
thirdAxisGroup = Group(Axis,
transform=mmult(translate(300,10),
rotate(30)))
d.add(thirdAxisGroup)
draw(d, "Groups examples")

View File

@ -0,0 +1,422 @@
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/graphguide/ch4_widgets.py
from reportlab.tools.docco.rl_doc_utils import *
from reportlab.graphics.shapes import *
from reportlab.graphics.widgets import signsandsymbols
heading1("Widgets")
disc("""
We now describe widgets and how they relate to shapes.
Using many examples it is shown how widgets make reusable
graphics components.
""")
heading2("Shapes vs. Widgets")
disc("""Up until now, Drawings have been 'pure data'. There is no code in them
to actually do anything, except assist the programmer in checking and
inspecting the drawing. In fact, that's the cornerstone of the whole
concept and is what lets us achieve portability - a renderer only
needs to implement the primitive shapes.""")
disc("""We want to build reusable graphic objects, including a powerful chart
library. To do this we need to reuse more tangible things than
rectangles and circles. We should be able to write objects for other
to reuse - arrows, gears, text boxes, UML diagram nodes, even fully
fledged charts.""")
disc("""
The Widget standard is a standard built on top of the shapes module.
Anyone can write new widgets, and we can build up libraries of them.
Widgets support the $getProperties()$ and $setProperties()$ methods,
so you can inspect and modify as well as document them in a uniform
way.
""")
bullet("A widget is a reusable shape ")
bullet("""it can be initialized with no arguments
when its $draw()$ method is called it creates a primitive Shape or a
Group to represent itself""")
bullet("""It can have any parameters you want, and they can drive the way it is
drawn""")
bullet("""it has a $demo()$ method which should return an attractively drawn
example of itself in a 200x100 rectangle. This is the cornerstone of
the automatic documentation tools. The $demo()$ method should also have
a well written docstring, since that is printed too!""")
disc("""Widgets run contrary to the idea that a drawing is just a bundle of
shapes; surely they have their own code? The way they work is that a
widget can convert itself to a group of primitive shapes. If some of
its components are themselves widgets, they will get converted too.
This happens automatically during rendering; the renderer will not see
your chart widget, but just a collection of rectangles, lines and
strings. You can also explicitly 'flatten out' a drawing, causing all
widgets to be converted to primitives.""")
heading2("Using a Widget")
disc("""
Let's imagine a simple new widget.
We will use a widget to draw a face, then show how it was implemented.""")
eg("""
>>> from reportlab.lib import colors
>>> from reportlab.graphics import shapes
>>> from reportlab.graphics import widgetbase
>>> from reportlab.graphics import renderPDF
>>> d = shapes.Drawing(200, 100)
>>> f = widgetbase.Face()
>>> f.skinColor = colors.yellow
>>> f.mood = "sad"
>>> d.add(f)
>>> renderPDF.drawToFile(d, 'face.pdf', 'A Face')
""")
from reportlab.graphics import widgetbase
d = Drawing(200, 120)
f = widgetbase.Face()
f.x = 50
f.y = 10
f.skinColor = colors.yellow
f.mood = "sad"
d.add(f)
draw(d, 'A sample widget')
disc("""
Let's see what properties it has available, using the $setProperties()$
method we have seen earlier:
""")
eg("""
>>> f.dumpProperties()
eyeColor = Color(0.00,0.00,1.00)
mood = sad
size = 80
skinColor = Color(1.00,1.00,0.00)
x = 10
y = 10
>>>
""")
disc("""
One thing which seems strange about the above code is that we did not
set the size or position when we made the face.
This is a necessary trade-off to allow a uniform interface for
constructing widgets and documenting them - they cannot require
arguments in their $__init__()$ method.
Instead, they are generally designed to fit in a 200 x 100
window, and you move or resize them by setting properties such as
x, y, width and so on after creation.
""")
disc("""
In addition, a widget always provides a $demo()$ method.
Simple ones like this always do something sensible before setting
properties, but more complex ones like a chart would not have any
data to plot.
The documentation tool calls $demo()$ so that your fancy new chart
class can create a drawing showing what it can do.
""")
disc("""
Here are a handful of simple widgets available in the module
<i>signsandsymbols.py</i>:
""")
from reportlab.graphics.shapes import Drawing
from reportlab.graphics.widgets import signsandsymbols
d = Drawing(230, 230)
ne = signsandsymbols.NoEntry()
ds = signsandsymbols.DangerSign()
fd = signsandsymbols.FloppyDisk()
ns = signsandsymbols.NoSmoking()
ne.x, ne.y = 10, 10
ds.x, ds.y = 120, 10
fd.x, fd.y = 10, 120
ns.x, ns.y = 120, 120
d.add(ne)
d.add(ds)
d.add(fd)
d.add(ns)
draw(d, 'A few samples from signsandsymbols.py')
disc("""
And this is the code needed to generate them as seen in the drawing above:
""")
eg("""
from reportlab.graphics.shapes import Drawing
from reportlab.graphics.widgets import signsandsymbols
d = Drawing(230, 230)
ne = signsandsymbols.NoEntry()
ds = signsandsymbols.DangerSign()
fd = signsandsymbols.FloppyDisk()
ns = signsandsymbols.NoSmoking()
ne.x, ne.y = 10, 10
ds.x, ds.y = 120, 10
fd.x, fd.y = 10, 120
ns.x, ns.y = 120, 120
d.add(ne)
d.add(ds)
d.add(fd)
d.add(ns)
""")
heading2("Compound Widgets")
disc("""Let's imagine a compound widget which draws two faces side by side.
This is easy to build when you have the Face widget.""")
eg("""
>>> tf = widgetbase.TwoFaces()
>>> tf.faceOne.mood
'happy'
>>> tf.faceTwo.mood
'sad'
>>> tf.dumpProperties()
faceOne.eyeColor = Color(0.00,0.00,1.00)
faceOne.mood = happy
faceOne.size = 80
faceOne.skinColor = None
faceOne.x = 10
faceOne.y = 10
faceTwo.eyeColor = Color(0.00,0.00,1.00)
faceTwo.mood = sad
faceTwo.size = 80
faceTwo.skinColor = None
faceTwo.x = 100
faceTwo.y = 10
>>>
""")
disc("""The attributes 'faceOne' and 'faceTwo' are deliberately exposed so you
can get at them directly. There could also be top-level attributes,
but there aren't in this case.""")
heading2("Verifying Widgets")
disc("""The widget designer decides the policy on verification, but by default
they work like shapes - checking every assignment - if the designer
has provided the checking information.""")
heading2("Implementing Widgets")
disc("""We tried to make it as easy to implement widgets as possible. Here's
the code for a Face widget which does not do any type checking:""")
eg("""
class Face(Widget):
\"\"\"This draws a face with two eyes, mouth and nose.\"\"\"
def __init__(self):
self.x = 10
self.y = 10
self.size = 80
self.skinColor = None
self.eyeColor = colors.blue
self.mood = 'happy'
def draw(self):
s = self.size # abbreviate as we will use this a lot
g = shapes.Group()
g.transform = [1,0,0,1,self.x, self.y]
# background
g.add(shapes.Circle(s * 0.5, s * 0.5, s * 0.5,
fillColor=self.skinColor))
# CODE OMITTED TO MAKE MORE SHAPES
return g
""")
disc("""We left out all the code to draw the shapes in this document, but you
can find it in the distribution in $widgetbase.py$.""")
disc("""By default, any attribute without a leading underscore is returned by
setProperties. This is a deliberate policy to encourage consistent
coding conventions.""")
disc("""Once your widget works, you probably want to add support for
verification. This involves adding a dictionary to the class called
$_verifyMap$, which map from attribute names to 'checking functions'.
The $widgetbase.py$ module defines a bunch of checking functions with names
like $isNumber$, $isListOfShapes$ and so on. You can also simply use $None$,
which means that the attribute must be present but can have any type.
And you can and should write your own checking functions. We want to
restrict the "mood" custom attribute to the values "happy", "sad" or
"ok". So we do this:""")
eg("""
class Face(Widget):
\"\"\"This draws a face with two eyes. It exposes a
couple of properties to configure itself and hides
all other details\"\"\"
def checkMood(moodName):
return (moodName in ('happy','sad','ok'))
_verifyMap = {
'x': shapes.isNumber,
'y': shapes.isNumber,
'size': shapes.isNumber,
'skinColor':shapes.isColorOrNone,
'eyeColor': shapes.isColorOrNone,
'mood': checkMood
}
""")
disc("""This checking will be performed on every attribute assignment; or, if
$config.shapeChecking$ is off, whenever you call $myFace.verify()$.""")
heading2("Documenting Widgets")
disc("""
We are working on a generic tool to document any Python package or
module; this is already checked into ReportLab and will be used to
generate a reference for the ReportLab package.
When it encounters widgets, it adds extra sections to the
manual including:""")
bullet("the doc string for your widget class ")
bullet("the code snippet from your <i>demo()</i> method, so people can see how to use it")
bullet("the drawing produced by the <i>demo()</i> method ")
bullet("the property dump for the widget in the drawing. ")
disc("""
This tool will mean that we can have guaranteed up-to-date
documentation on our widgets and charts, both on the web site
and in print; and that you can do the same for your own widgets,
too!
""")
heading2("Widget Design Strategies")
disc("""We could not come up with a consistent architecture for designing
widgets, so we are leaving that problem to the authors! If you do not
like the default verification strategy, or the way
$setProperties/getProperties$ works, you can override them yourself.""")
disc("""For simple widgets it is recommended that you do what we did above:
select non-overlapping properties, initialize every property on
$__init__$ and construct everything when $draw()$ is called. You can
instead have $__setattr__$ hooks and have things updated when certain
attributes are set. Consider a pie chart. If you want to expose the
individual wedges, you might write code like this:""")
eg("""
from reportlab.graphics.charts import piecharts
pc = piecharts.Pie()
pc.defaultColors = [navy, blue, skyblue] #used in rotation
pc.data = [10,30,50,25]
pc.slices[7].strokeWidth = 5
""")
#removed 'pc.backColor = yellow' from above code example
disc("""The last line is problematic as we have only created four wedges - in
fact we might not have created them yet. Does $pc.wedges[7]$ raise an
error? Is it a prescription for what should happen if a seventh wedge
is defined, used to override the default settings? We dump this
problem squarely on the widget author for now, and recommend that you
get a simple one working before exposing 'child objects' whose
existence depends on other properties' values :-)""")
disc("""We also discussed rules by which parent widgets could pass properties
to their children. There seems to be a general desire for a global way
to say that 'all wedges get their lineWidth from the lineWidth of
their parent' without a lot of repetitive coding. We do not have a
universal solution, so again leave that to widget authors. We hope
people will experiment with push-down, pull-down and pattern-matching
approaches and come up with something nice. In the meantime, we
certainly can write monolithic chart widgets which work like the ones
in, say, Visual Basic and Delphi.""")
disc("""For now have a look at the following sample code using an early
version of a pie chart widget and the output it generates:""")
eg("""
from reportlab.lib.colors import *
from reportlab.graphics import shapes,renderPDF
from reportlab.graphics.charts.piecharts import Pie
d = Drawing(400,200)
d.add(String(100,175,"Without labels", textAnchor="middle"))
d.add(String(300,175,"With labels", textAnchor="middle"))
pc = Pie()
pc.x = 25
pc.y = 50
pc.data = [10,20,30,40,50,60]
pc.slices[0].popout = 5
d.add(pc, 'pie1')
pc2 = Pie()
pc2.x = 150
pc2.y = 50
pc2.data = [10,20,30,40,50,60]
pc2.labels = ['a','b','c','d','e','f']
d.add(pc2, 'pie2')
pc3 = Pie()
pc3.x = 275
pc3.y = 50
pc3.data = [10,20,30,40,50,60]
pc3.labels = ['a','b','c','d','e','f']
pc3.wedges.labelRadius = 0.65
pc3.wedges.fontName = "Helvetica-Bold"
pc3.wedges.fontSize = 16
pc3.wedges.fontColor = colors.yellow
d.add(pc3, 'pie3')
""")
# Hack to force a new paragraph before the todo() :-(
disc("")
from reportlab.lib.colors import *
from reportlab.graphics import shapes,renderPDF
from reportlab.graphics.charts.piecharts import Pie
d = Drawing(400,200)
d.add(String(100,175,"Without labels", textAnchor="middle"))
d.add(String(300,175,"With labels", textAnchor="middle"))
pc = Pie()
pc.x = 25
pc.y = 50
pc.data = [10,20,30,40,50,60]
pc.slices[0].popout = 5
d.add(pc, 'pie1')
pc2 = Pie()
pc2.x = 150
pc2.y = 50
pc2.data = [10,20,30,40,50,60]
pc2.labels = ['a','b','c','d','e','f']
d.add(pc2, 'pie2')
pc3 = Pie()
pc3.x = 275
pc3.y = 50
pc3.data = [10,20,30,40,50,60]
pc3.labels = ['a','b','c','d','e','f']
pc3.slices.labelRadius = 0.65
pc3.slices.fontName = "Helvetica-Bold"
pc3.slices.fontSize = 16
pc3.slices.fontColor = colors.yellow
d.add(pc3, 'pie3')
draw(d, 'Some sample Pies')

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,59 @@
#!/bin/env python
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/graphguide/gengraphguide.py
__version__=''' $Id: gengraphguide.py 2385 2004-06-17 15:26:05Z rgbecker $ '''
__doc__ = """
This module contains the script for building the graphics guide.
"""
def run(pagesize=None, verbose=1, outDir=None):
import os
from reportlab.tools.docco.rl_doc_utils import setStory, getStory, RLDocTemplate, defaultPageSize
from reportlab.tools.docco import rl_doc_utils
from reportlab.lib.utils import open_and_read, _RL_DIR
if not outDir: outDir = os.path.join(_RL_DIR,'docs')
destfn = os.path.join(outDir,'graphguide.pdf')
doc = RLDocTemplate(destfn,pagesize = pagesize or defaultPageSize)
#this builds the story
setStory()
G = {}
exec 'from reportlab.tools.docco.rl_doc_utils import *' in G, G
doc = RLDocTemplate(destfn,pagesize = pagesize or defaultPageSize)
for f in (
'ch1_intro',
'ch2_concepts',
'ch3_shapes',
'ch4_widgets',
'ch5_charts',
):
exec open_and_read(f+'.py',mode='t') in G, G
del G
story = getStory()
if verbose: print 'Built story contains %d flowables...' % len(story)
doc.build(story)
if verbose: print 'Saved "%s"' % destfn
def makeSuite():
"standard test harness support - run self as separate process"
from reportlab.test.utils import ScriptThatMakesFileTest
return ScriptThatMakesFileTest('../docs/graphguide', 'gengraphguide.py', 'graphguide.pdf')
def main():
import sys
verbose = '-s' not in sys.argv
if not verbose: sys.argv.remove('-s')
if len(sys.argv) > 1:
try:
pagesize = eval(sys.argv[1])
except:
print 'Expected page size in argument 1', sys.argv[1]
raise
print 'set page size to',sys.argv[1]
else:
pagesize = None
run(pagesize,verbose)
if __name__=="__main__":
main()

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,439 @@
BI
/W 283 /H 181 /BPC 8 /CS /RGB /F [/A85 /Fl]
ID
Gb"/lGEc'<R`9K?ST/gccciOJc<4e(<bO6Z:4`rg,Y/Cp6(efX#nfXW*Hb1H
&OfM-Pamra&k""R8@/E>,,kl8"&2NBd%Kaogum165&NYZBITmkcQDo:\lEnA
GJETphXmY&(BXdG&0O5g!!*-(#S8+DJ,fTO":,P]5_&h8!X&eu$f\(VI^5_q
jm)jbosgIBN01+GE&G/,0E`$J,.ogcq?_*e\?bYbO$E4*_M&A1cC@I!9Dd\'
+4<JpceXMW:S/-3%Sg@m:0f)>?4QDr'3BbF=2qLTa,V3(b)tC;HhK!DHiEs=
#e!]_gC"9\WeUZ]%d_rZDm+pZHhMjerV*pJn(tTrkH8+&G'_fGA&n<1gUDI\
)T%dl>;gEVr7uSSD=[2`\)2)Y\8d.Vp$:55>ISM;g9k_IXBE5_odUJ&4fhbj
+t4u*CCeUS/R,f.kn4Mb(GB+%B[KmgIC4%Q_Cr\%1,1M'_1Dj^kKfbZDr.!E
F(WairP]R[bk1DXB:hnj5(2_GWLnY9BgP/'PUTNpnM"tB`!I)(N#O]nba:,[
7un]KC=L=e,=d\00l5LHTgOSF))>aLTKrYb%NI015l^i^qt9:L_$;(Sl-nh/
pYP5l]D"DU][No_Y;b?do<#LYHN!Ng-V^$t+XoX`J[UDW6NstgiU^:#aXJYf
@T/-h#kbk9#UMApV<$^um2e#j'7`g:&J1#=2rAubQ**M!it6f3,*@pVZY%I6
6o/H!J4.k`9lkR_-;U4ln3a&Bj2[3$3u/IFT]*eDlR2scpu.!iLu\C$^CPtn
H@SNS^AI?QDnk,W"$D00h*&FIlDn4&G3't(Uo5[]m!,=p/AQ+U,=dd\o,oLh
`[7$Kifm(afHdLC\5iol9&c'@AXlrl+e2TcVCt*"D43P1/tBd4IK''*Z:Y1g
&tsE#;eD`AXDo:8;HP?kPAJ]<++5EP`)3&A0_Gc=bj+0GNAo^=jcrnRI.>2-
?@.[$o*RI.f9aJ`&3E/CRVaf0!I//;.6.N@dhWJ":#_Dm4P7SLk/f_K3$fY"
@lB&<Ha6I;-o4cM4MW0dOj"KZ#pDR1Yo[/:choqG8q9ig4MWML'j_uP_D&eT
fr<8f4$thGNQ*)+Mfaj\\>>=ZT!#RpKMq"Z6@j)ODfZ2)o?9+0oW[2)q0V"P
i5SJT2Aq@18&2N,MORue((.$!o41l.*at,LGSoZG'&i)k+<?5^(d*$sCsl0%
TKio3:;J7p.=$?[:u/^*Hhlcis6p!eY>_>o\;RS\8iUnSbf.@["h4W^daDC<
[+g5DH18l\"e-&NZV?P&#\?tUg#Q>8N;^H/+c'&47a2<,ZndtDk/m0)o'Y9I
"Af)p(^a#(U5qJ$"NO<.;GoitP^.[:Han@R-<rae6mU=%"(\3,<62Ukk;'3j
J8R*"'.6O_PqZ""f(6jTifp8^JCuAY/jbZCkH[Ypb0gkk-"GD*+ddO1:J[AF
6%f;38gK(_r17IFK[Cs1b9qdXYQm/LVYK6:5p]/rr:?Q\KM?DX(()r39Q@pt
-n"irbC8u%rSmof*/>"EJk':6\TnrLq,.c]R(i1M-HV6>$DWiJn<kX[9Ho]=
-M`!\n]=,n#c/6->Wu`pbXf8^#tsp$Blf[o2f0&&E8Fj;UkH;2KPeTN'9<-`
_E>O(dS$eNYO@/]?Jm>IbNhuC)(3i7QGjt[o_n[]],>Y46C;2%ZOfU,n6RL6
pQXGh.Ts48AWn&r=TE#APblWI!jfTH5qs'iZ7I([Rcm#)4]s3/IWG@.!hl8%
k"5Ai2hk31"fITC&?Wl%R3r7DZT<9r#jE`;DgM?VnOPTHJ6NEF=DX0oV=;jR
N"ee-'gN(,,1IMA,*\r!P!#ZJb/Yi%P$?h-bS)ApoF1$2S`.D2UXU#ifa/5t
gE^EM\-Jt.FMpZj7&UVY^aA_J@B/D`\QM+D5?Y%:r8SkQX)mILmG#,5Qa$@m
8\`%IN+JM>F2lkn-6bE9+'C"P4$:%88J]Hko.1njrgkG16n$[KbII#_p%Qu7
AE+ku0`TXT)a,W-TbqN<#jU93V[&HNckm'+eCt(+$2Wka!3/NpDgDtsPjuY!
&Osl;iABPJ;B\[/"UG*'SN<VH-9&JJ!>M&U8$BW">.&+qW`H6*^OH,o4LAeL
6:XCa%o6PiB$Hd`4)!?TBp0l<RU-?(2"pE<#`Tf\CtPsX#k]jiP>=C<`"Pp/
m\$/,\foSn:tn@>>.&+rXN:c=IYfebFG+3NbiMdW>Wh$%Tb9lJ,Z=l?0N&Gh
%hOq[K8PLeJg*I1A&jUDW1GZEB0I@H?K&bTn$qD<]C*82Gk'c!.Um,ORPB1S
X.(7fr^"6`JoT&6a&>e<rVQ>Uf-b?fn#),:EYL950ZtXh\U7\pG(iO\9lOq#
XrZT?%Us\o*&sSo7H!XR3"?ul#`4f!Zb])99lfrHjSo#-^]+6,^OPUTa&(g]
,XjL"\_WnqMA+tu)_%J0.!LUQk"/iU(.j?`YBf'ePuh98R"@p`^A)0l[V`R2
gPKuukg6#2UgK&_!SG#.Y9G=NE!Qjc;%hIeB-:05)Dr'p+snP*bJ%1&<a&H-
d2;tLNJt8rI#=V><!lpKq*ZV^P`gLqn=[E9NZXdCFAo)4?+kRWdA'4V2?cQ"
#''Y?Gm#\OTi1HX*Ot!Vs#lg`@)7Fce;=tkcCI&kdqoTOHN*j<QmB4io(Ot;
ehV]m8eigT:`-&!&shVmQ)n2I@ttO7i"S,?3HHMS-S6o%d]FE1@eeo;+(13'
3`u]j''#Ki^Q=kX7>i@((p'?IgAp1[a)GE\GTFH2IL`l^S2o(A6m?6E<2l$L
;Y'R(,(@?ZKiF0"q<+@tT&PK,F%g#(oSZil5CQj_]O[q`Br_?MX^AjBUQ7T"
@`4'cHhKk=]U=<Bo^jkJ`aG&9HE[l.fdY]@]YS4)Rb`8PSbLra?^irj/Cu8Q
c\<To:*/p$0N&I>,@T<#7>mE&],fEsJ/^mkC9$&OG7q&6HTG<AG3snm51lMo
K24`1oZ3.>\$(lqac@H(VP3,j+0.uF2VMDhWa371^%^Af^3o`WX]fl=THUV8
;J-N15UCZnZ$lNCS@!1iRd72#ac[r!.4H&c>e#3_/&6:Xk!k\T$ULAU46i)h
KH%IBj[)gcEr,Fm8/F9"JG-bqWJ=P0'Sa_a8O+\a'e<<9=gB:gLMs_T<?eHK
8.*orJ-,WQ2A&<m->H*TS32)&7f!:AMCG&[J)1AofJl$\;g^ZSq!^Cknt;Dc
rq^D)=Ld1@AECt!d)V]q@7Ekg^RdT8Q7,V)DV_mO20\KDKS0K@4tMr8-me_+
6ALSS;34Fo$;PSrC"&qrfWZNdMAT:eiJ/N9h/.>n:)McoCDR=<?bUp+k'W,J
,td=ERtjQRjM;IW,*Y-3iCdE\>g&EbB?cmQGOOBGCXu1L3)ObU2-@^S6cq05
nc5;/mQ%?`p.hBGdaHQ]G81hMC-X9k5CORVD$e$*2eaH?-X<`[^HO@dZM4=l
hab9!R=Or%o^Ut^'0p7ELITD^<^"<p,DLe3;l35k\od2,3HN3")ooGD]6@>+
Y!l5XU?A.u?="`9krB9aJ"#6+F6Cj4:db>5(9+:4@Z;6SRum`F3</-1Dp"@t
>IA4r#nnWs&Oa4CR=Gqu:(/!q"AuW/k>2KVoY(R4ecMKT7N&8fNoIBR'&aTu
_%a8nlP$gt1hjg.A&aJ$<eK?EYlH<h7L.MsTEnDO'2?O*I.?48\T6du2J17)
H0Wm.pV4G+gBG35ml!)WpcUWa&5$Go1dk@P+))q3AL')`eqWcF@;^>sW.\U=
KOa]?e`5]MM*PY*DnCl6E32BB-7:0ra%\H4"(mN22(Eh<gdh^pEgKV4IDo^P
\ojA`d74\<dX"0rc?02dZreESV(X\/>njW*?28pfK@J`[[!MH!B8[HQK"!jf
o&R]D%nHJm"5F<T3HIZ]T'Pj5H!7t3rJhm[:s4.TjMA`:]6<T/9-OJAY[G9K
NKLGMKV5#/(.N#&X<tn*M>eBE%?@jo3S$g"8jar0l.N@RCY?!>0pJlFiV":,
&g1[(4*Jhq4I[qd=t#2]@%_3GZgHMV8%Q>l$=k!K4DE4hF[E))8cG<U-`H*$
K+_uu+jaaJq0j6(oV)S%q9/s%Udg=^3HO?DH;[X=0Ma/fOIDUFG@6N6P.S5]
B&.q-br=b,Q)e0#o&.?:p[-]Ol1/EfdaHQu%3&m]@R"g>MmOmSJk?qlY!GSG
'_ngSBXG<dP7i9`EK?enfs5/s'I^bFW)t"$HSI3J;%8+g&Lr/7AM*klB[NRP
q=?O]fPoigM+<UJNHBG%!@]HHRKb&NR:28VB?MC]ME\c75rf;JIb62sI2Xl7
'VB3*@OP!/(+oC06P!W)G4!uul'Dm!1P#)'D;-sNj',d-ep<$Wj2[5,Pq*Y#
GP:CV;(s9slbGS3<jMZ*6n8`-dlK(HYBVu/A!9r]^h,$4me05_Mi:MCH1U1#
=gR8SdA%3n4;d>W%WF4CmbBfH-3VQK-:?/N?Na1r%YB8a/6fP63Waj9$Pl!n
+l7<N)f[,bjj)KnKB2T;SX.kj=GN-QoVFP/``"Hm["sWuCYH/[Zt\"E^4lVb
N74\#qc56<mGbKuoB)>j>8A\fLp2K7U;6T>E8cDG6!4WXc7"?Hb4Wk7fh,^l
Gu-2k?<out[ZIS+RrJ9bJ)Z;4YjD.6nFu;&Z]T_*!&k"u6jf/`q"CA[=0E[]
ouA/(S=H)hl1/EfIe_lWTgOTm39K8S"p+"-Z<a2@oe?(+\oEpSk*GEKZYYFK
-P\.4,kg;3.or_W"s(Ygp@$lLCYWLn<em?]S<bg8%\$;'6rL"`WKAfO-3,\8
P6##/2f;mF6e/2:FVGng:o-c!4&uib;Pd"4UdBbB%3%4ToI+(%Ph:YO_EsM9
;5.$h;UEl>3!Y7cm+Skj[`5QE>n)0T9M@!8U^1;abaC7_SidkoJoUefH/9?E
m[7^Z+i%f8.H9CJ_lri9)WY8p75:$OAAe5ELDN`>?bUp7P;"RLL(age=oA'T
O+^%JPcaC(_^&i&\OMW$?*I^&jCHZ47FAA,!\WBYV+\4^X;sfD#_(f_`)u%D
ioZYkE\3NqppFke.P<?V;56So-VfV\iPYaPJ.)mLo#?Y.f7`'7l*"+cq3F"7
B[NQmj*Vdd]:Z!tV=!'K;tKsk$!Q@pM\]cGYY+K\ZuqUUprZuQ`H(+bft)=l
cThFlQsCOR3-!p\4E>j4>CKh1_F!5H&-r[]0L18NU;5m^/LH4?c?Q`Oc+.f>
e'lc1r:!(0,K&T&5#R9!O*0a;.9*5W'_;b]%M6T=E8Z8c8n+!r1V8tF-R:'I
+$4X^F::4AG[id#s#kMi'IFbKBbr[3@`!<Mi)lsVV$A)iYZJ#7dF$PWi+df*
"-;79S)!D,3@6("&jS<lgj$ht)97aX],3sPl:12lbGRXSRU`:d\`'BO?G]#l
r:%T=.T@6EE+!e[2$E\W+B4ggD1Y&;o43A_P9s#HOX!B.G4!$Ank3Hf8/F:M
ESWu^W>p_(!L,Yf9&7*"3cmV!eZ2bigph@OdFSrfZ>_)pa+!F0[?c:Jha3e$
Wb9YLH1U1ceu]n+M;lM9Y4]K4f5O5c]&>)%37YT_leK$l5PsfR1M=uAFuG9k
S2bN*&eV9`ZAkZR>FRNf$5=o8Vb`p:>IHrQH3h7\I94<8qod?[6Y2su'8LFG
A#!QR2/8@+="a7_215o7IMTF;cpp)Z910VdA>cG-X&c)k)<>H!hS%<OSur_"
qIsYXn%A7P"s*Xe"C%<*n?I<4lF;4[^A2BjoJHdH=mXkM9;t&*dp'+gM)N'/
4>ARq=Ku>CCY/RHP>@o_)Usb^#_d/Y<H?-M>Q.l\.UBW-ac[tIp$9)0ldcnS
7'Q`g\Me<Y"HUbb_'!S<X_lb%5%Vm$S2kXKCY!=igpt6FN<V^BCm-3bgH\p!
3\?_s`u]SDo]X\"e(5-R"$hk<oQ7_X&^&oig@gTI%t+--GOsn;e#?7n^;Y#I
AO<rr5&8_#\7;R5.+`,1:]sV^g9o+i/K8,_oecl.HCR*C&h8`%"O;qCY\M^g
[Vab_nA#,sc@ucIU+@O/h1/Y'7ZG8+g"Jsa#1f6Vqt/?5a2Q$*DVZ5'3VrRj
!aHM?WN!0q_P.SWL;:bhFm9MG]`8!.4*Ku#(_p>f2ib4WcY?R`Dh*LdI@Sfe
<D0qR&>'.EM&=(sh7GC/YXT4glkDrBMHTQ5bpueo<4-Jk7ZJI6i4snO\K1c?
oYqhgpuXipp4\#IjiWi=;P_CgDniu2oB(rc?XlqA[q3$bf`Gq?"eh]Y"fM.j
l)109b*<A',p=Gj`/,->/G:ZL[;4B'K.OcM)%!,a1qTu2iPK0LQMp$BO&AkR
/d?ud!>#gE>IRAG0akrjfr;0hqML2`"qA_A0-B`WJcuO6Y"?Od\T>#Gm\6$d
cGr?W:`VT=aI+hsh7@aLN>lMG0*e#)8m"T5H@!.X'&cYVJo?#.k^fU"@(uX:
lQ?`MW4E9K-9rP&dNX0:*P9Hb5c^2&>@u-K(!AdN`f,_TFEH?aGskaV*NJ8_
acl#'21JE1amp(+#hr=aABE]AHY^aP8/M(<`0K13r&T_6?b_'DD+tcQ._2#c
o!)N7HFV*<4*ID<,IQUdD*b#^J?&%QJHP[iQI+[i9+RQQi,QW!3d'^eXB<k.
@>RT]<fl*p5&IK^"TFunNjUajD7_4A.o`HDY[Bc"XBrS$JqA=AO1suXhFp='
^2(cL*JoW0@MAB*oDk.ujN=Q,Zc\L]e"B!Zace)BrK=&r==E'.]6E^mn%JHV
GOF8!H1M4]lIW6>Uk^<a^oX;h`f;(/P*-G,$+\4Ah?r"e6iidmL(,*[%VBC:
"'I#amF+iqc''MNldi1Nc^l/H9:fIuIF"KJ91?Plo#oR`<NC'fb*Od-Z!=h[
:i+dg@Ap7uM99s*m^<mFiT@lV:V:Z*6;g^Eq0;K)k0KZ\D;mNnhE5>G:S0iH
o&W5ZLp3V&4To+BADdNcV57$RIJ`_dl`IXBHI-,gm`DtYj)C0""m(6!\CCq3
i@8gGr-=;eL(N$>3.:Y1m#fWIRhrr),tg)R[!1uqfWqG_nl-8MBbrl$iF5@C
NZC3iG3rI-+1#t+2O05B^=p>O^Up#Z`Q1X;<R1*F'uY.=Sit8`0=Rd/gm*Ju
i/*c."1CN4%ACHm[r1#Z#!6e^^ki^P;#WD'N#XQL@Mn6SJ5%"<>6G,+9:,YQ
j,\EPgj,*AG8$(0Sj%Adh!*:cc^6EhkB;`8:HV=@30E-=bEaa7[r3X3;R5`7
R58(f4aQaf0k3\3(kH$Q1^)QTJ3Rr+[Z,e(h7GW*].20N4aQaFrUndSGOM[u
BYh"Q0>-ekW)9=7_;s\<eC;tR%bH@V<;Y1E;e_Ja1M7?;'5Pg[1IiA?6@1^l
)U+tXR_fi2j%ZX[[uT'k=Z<\XWFlso2,Efan2_(Er,C2d<MO0nAKMC&3eZ8=
.g4T7i6=4<jJXr[]63EDA]B`NMf)KQ>Y7VGG1>&==R1G$g9n!4?>eAt*TB,#
jN'oV->hJDaXhe7gqRRPVJ16(:s-\.*_MYF;7q-n^;?q#m^_LoAV=2P?_iVp
:/O>E_@-qdlLW=ds5Jqi+OjX,MFZGE`PR+IS*G[1THSel[VQhbF8Yh'S)[bU
?b`1!;RQ`=.'j9,3I3Z'hRnge2s.e1kic&gZYpDE2fI9eC4`kuE;9[k[Vboc
1XGPBIYD+#'3"Ji%Yi\`6YP>h3IetT7EVpJR1Lnro[/!OO$<E=E[K_,7ij*X
VTdrtrcalo\om>uh@C\l>b5[ub)Ft?"Pa)^W6[TA$TKFo,u/Hu&4g%\!A:pA
@aL!>i[8[qI)UO2pANF:$>#.)cU3-+Sk@9YE8J?Zru=%>Zu=ini^MrU/8-`)
@XApFT'o-$9GJaQZY%HJK*GI;*3BO4ZtZqmKX/#1TiK-n*O,cBRP_iI7<ZRm
fbt,+CW*!RA]os!!ZhWfOsNa6.AI%8HQtLTP=K,SW&+o/[%]8,<\Xtp8[Pc'
hn"09$e7`tEJfJi2f9U1+Ir#5$CQgZZo"^5Z5`*i;W]Vp:gb1c:S'[>$Qa$S
X`VMIn<spOI1P%<c.uff,;ddV6!@F7P4L>3,=hshgs0.:8h45VC=NY[UjX;d
Y9?emeEPG[)`26$AA5J[JQ&jK!(([Qi.2,Rk0/Z'5S>9>3Urpn9UINUK*[0Z
JQ!QY!+i8H<Cp4;]!>9"8C\;1=fB:]Bh+V.jiWkVW`,>B(2-I^H:gJB0&'oi
U-/,7f.U+%&2H_&*V!*/VLpfo',!ZHB.2C%':WAFd1Ff@e#!Qh,&/6=r8(^<
9P_X_W>;T\JH2aS!=Kb7^4oq*G#b_P*?Jqp*F(eL,uXuL0Me3Lc^qghiPK74
c.e+T'5u[9ER^paY&0>IZ?V8%B_An@R4SHeQ!LW877>&l)_bY"TeV$BT).OQ
UN1Dj'dJWA&M>N929>m$:pk&g0k855HU^C4TqKE0@DfIiRd9+X6I>p`Ctc71
JH?"J$,JCHi8"nb4S[K3Dn0Y;Bm3kM!=JUZBEe4m5-jMk,<?M>c)g-Nh:#!a
TBm94\@=MYf]Z&!2Vn9D)K=+oN#7,$L-\-'OA&e*V.""_0]12>](l\nEWS+-
!V#iM?@$>Ti5*>kmUcorgDi_D*20=L7ocQgOZu\A;Gb8,4RiQnYeL*mO7gY#
Uo(#(QYLA?BXCYS"e3#"]68&.Gu6peHGbIHBQ?`Jg.o7^/,=NGMi\'-V<Vm7
pBXe?X\<018Xq>rg00.2G^[*0]]nqE_tWNNF#2#%!mQAY;hhPea$M1s=<r,&
VduBL=Jdd%NX,1S/?>X-9,IC)KVG`]rlZUg+VY*tq7"U!Q2&mO*aKaGEocZE
]Cl%L@$"bLo%eNIaktPon)BIib4Tb=1+0:`C7k[:)jL$U\D+`-TjE!&"oQ'&
2/=BKiQZRfWmQ7;7j!0OcpJ?>`^cH?#P]'$2/CbOdBtC_ju54b4oQLU6L*JC
[>2LbOlZKjOcD/jjs_l/'qISlRH#Z,5oIkN><%87U<.'bmUKa.I)$K8V'c`s
NoN(q4OAK&K^7UQ`8NZ6a&k\fBQ?B^.FQM444Sn2m+ATAqtKDBr/p063-!r5
++C^<J(s^Mo^m8)bMBZCKh!HK6ud]mnX21G\=m-tn=*crVuK1=)!;K8[r-m-
HhZs)bX`,,A+s?AF=Ae^V>MCTmbPM8mpW)-=XmJP_A1I+Enb$ISZrRV[V_Kk
CY&:UGkEq!P@Wt!4H#ktE+[Y#<SP!$a5<b7O>hR:C[H0(pTP_,\,hi<P;i_<
PUMYMB27Ls>sWP5?b[YE^epm9ZqHjCn:o4n`c3rk#fQt@#VkiF-;9f"(drO>
[%^q;)`G@hN]Z[?l`MF#MELR];lC'_N0<XB_rl+eN1tH`2fHu)PEV3d&MKM?
j;G-g.7)T63p9Tg,CqQJ#uX1'-mJ@FCn)VLCY#T7.X_/#4^sk\X)mQlMT%\p
hRo7SnLhJ:ln<Mk;;pLnhg>OdW:QY+nFK&$!SQDVfPZr"3"KL^n=&,J$7"O)
nB_rmGCrD03[>6d=;3@+Bi)o3iU=E@omid3JT0lY%NO-9It*oDVt7XfUu7S%
g:"$dg@1X`U):lX-\3*Albe/?aU]@N^n$=$D;?o!.@[B=/0BA`Pq,qJG3sOs
2,/%eEG7CWrTpl:@P=>D^^6a\.o861[VXpiW.-oR.SX,"Nq>"L"H&'^:fQLS
$A@tXOt;+rVi4c+otUY?'J!4CVmL?tRZJBtOH651Q,7bhKL:J&J_IK%`9EVp
>\hroV:n05puA&8L[lY%eEG;T,pD7a@Y=/Hk.C)rRhnBTnOrdp)cInqjb?jr
"`="nM_?u%d"!)++sI^&L@cYor.Vmi5F84YAaF#S^sD'ja?9$MIR=TnofuW4
%.fs&*orQ7l9R$QD_u%J'Q0aXKi*[K9_O"2k"WBWOgnU"X']<bd'VS,]5;Sa
EY&Q;'Gma^@Ddii:d4GT6kN.6o]T.Z:'N5DJN\WJ;#-V+iQ0bD*bZ,m7QnX!
IPBCV5N<u_hQpijT$ED%5$0"QcZd3g''e!n9&^1*OG.b5c0Os9!>H>1Z!eB5
56lus/g"=c6<n(=%ei"Vnr5Tb&<E9+B\^*Pk:#Efp$6*6T6oudlA$/6>h`m1
>dD.s:7XFC$-3+XQYNU&X]d"]qLNFXFMnN-;5O]pYB9$WYXo5Z(+N:^@)7GJ
=3q;nMfud7RsXhD5gU:R(IlOQ29(9F.C]HXGt4)?6A89e23M;-eWm`X$Y6]a
'IrhH`ujJFl:f.U,I_QJ@nm;W'Urp[PIS`ZjbTYQ0f5h$f1p2<\5@tbLj_=A
@N5tuatEt@i7b`$G2ihK.TOaBnZ4@tIt86j0@Z%_No9>).lAj?=XW!gB2N0;
=kCaSKM^Vp085dlImFbC`G[`fa?%_+qF@][H0,un8XV;;>i@+&Uja`F.A\B@
+iT:?"&5A9qIp(t]CAb3:1fu3%5CT2Ppl4\/+!NUStNmc[VXV0qXB^b/QuNu
["C8c,:?2J4Se'%>j(>_%8PID:tl*B>)aFXGer[qX)irH'U8lsd8A1(4_TcW
-^Jk[6m$qR%soug4o!rf]EK"u^a+A&Fj\R7kf`\thB:"g4NK"PN2P#fU6W/L
<fR5i6]KR)H1L$ArqY^hF\%(d7e`YH/IcCXFI-%L[]2dplkjW]bO=i=mSX"l
/A7^JAPNdd7$LkDY[)U8&Q`T_&<E]C+Icrt&Y!=)1ji9Seb-qo+?AY5*Wc"@
hiDEDd&7E(M3NtcO`?8aWR?/F6gTqPF`>5IlenYmLp[/XUJXpBU+O<e@31AI
R#h1@o=&JbM?:j$m,u1d.+(OaZ48=+7:D.dG3t/'KL\Etis0%SI%7L=@W<uE
&13%micerV6Ilnh19;#)Ja]g7S'/G@cHBUP;uAm=$O>h9&0CRBf)l58i.;ml
r7mfGKeI>\gkHl8%7.[)lJ^jC`qsJk+.SLnW`?)8Q&iLGXbCu%h&rDIa(Z@>
QTPMA7_ZH=&[a'HldDV&[VXVn>kn5A01:1#:(pnf9@c]u<YUonTM_XfcM7i;
LL457(.ZQigVm;=fL7NZ59_6b"sWNn^L&#f8)ae13bE\;.N`Y8o;$;%'^h'!
j;A,]n7,;MeV:&HA7"-lp^k@p+;TbF7L`XcX[dJqA:@,"K2tjkTe1_arR,(s
bofeXXrt%+TgK'b'S3.^1mX;O$C"eB`)1"iGdOE&8&pb#+Ddr5\YhMm>8nC4
FrOV33A)pZ':c7<mH'Rs'S7-',;oQtGaoVhFjWf4isL!r/(gdtUP9i./8S?M
%i?*,\<gNJ$0?d`_P4je\VTO.P-pIhP,WJiV%`j&5nmq>?l#7V\3lPn*o`""
Fo80CW@o1/fL0R,9d01#gJQqZ!uJ4=K_];(%HnO3EE++`^\DB\NZGH:ab&&t
"ZEp,r'O>BF8hnRK4^qG/,MJ7UDW3-,SPr3]ioX^r'c[te#am)QCCt'7:"kb
@Zq.;IDPK4GTr0?U)p$YAK)=V$K@;q'g7t%)LEoDXcRhP!VaW#,t<McPR"LQ
%)G8N4.#Cf%oBCDml<lndBo,O1?(3JCNB5a5)u.S@UYL7V%AK)*%L_SX@/2^
LHrqU"XUOQK[LPs.!t[SD;)@j*Ii6k">@_%+sF'T^p5)iE!d5o.IICs6m$qf
&o4/$lk/EjI%9-o@6q+rLje7!KddiG%CM7`#_T-XX_M:2`Dc&]&q,^8Z;rks
<o[fR#NGW#*IU8dj*P>)#UQ!Ie2"U.h1+!(kX0HeS..?Y['<e;=UW4/apQ9I
'G+-h.S#L=3/T+XCm-pb_bS,O(rR/W!1>G9R<`[BJ7qt4e5N9.\odU5h+Fmk
L$g(a,W;X#^2XiPSHT9NoLEdR`39suS$1>2+MPAEP"pB=0Gi$O."+K.+lmm\
Qrh4Y)p5QHlXgpTG[sc/6?,EG&/_@a\$XQ'*]S^O>l;qNA8tm=BLSc>=s6Wh
C4<t/\oa3qd/4CHlJh\\K!.r!N2a[urp5jMe/`o[H@eZ5KHRJE%A4VpTH&Y;
>60/j0*h``GXkL_:O:K<qtAu#F7HM.!OH$+Pm]n=&sZ_>A6rX5il.T@V5!7@
/R*u.c,AIRoFHs%Q)QgBo$u8#Xd!pJj(1j`MFXD(Gtf'ME9+H,l(*%TM.u*b
E("_!,NWqQ'>r'&'I`I_hu2u7Hg\^m(T1f5P\Mn-ORh=2:k86)f.1&28)4$6
SbS^9;+Wc2Yts6qS+Ja<VLA@8Lgjh&imFMkQRl9kg_tfqYsoO@P"%NPNKb$:
F+b<1MC5-:OUr*mf`n!d71?I/\)2.VEl1&uoaq^o"Q50=P)YJuIa>*Y:#(7M
b3$MSbS,Ol/IRW(b-TJ-2?9^tkK^Se80``,cYTb>%sF([PFGrG=upmd"JmI+
rY\*Y@oe3nPQh7)&r.,5;:VR>SK\-;i^#],*.m9#6n%AedVr?KSUaG#nIr%_
'SPIH]H+gZ-LT/HS^?.K1aZP+?d,65Uth1fOqT6rA`=u'O]e+9!4de.[-ugp
hu/<pr.-q>SnosAn]3%`_9Kanm;I4(EQ>84rG*mYD;2K)][&SP!BK=_\.]R5
)TM)q<]j6)#'U?FSVU#2(qGLL,`,#,'Bodr&3M$1h07cHXhC]:,s)@%lWKaV
B$=G8H?N%(.M]16p$-\ceu:F\)6tlmP]#$XUr7?s=p1mW5k7d\$#6E^M$iDo
HXm/A#c50U5NBG=;C%Ypas>)"a[3Od;U>b/+fH)Z]..&WIP-@1HO?5"NWLU9
agjMs=X?gf2#a'YVnNB>9lfsgmr="3pYUHbIn+="$8i5dWd:lLb(^sO*f$R@
D#Ch<ld1;QbP6W47>gRj!]7iJ(X0Bfi9Gm^6%u)#1oH^u'q;:K6QVmoQ.!;l
2C;_\=+um5q2nnRgL'sN(H=`=,!Q@2H"@b+=aCVq"W^%ne(i`B]C?i.,g4ni
)?MjKEG/=a^=:Y3JkG?4ZI$^d.m+`FL/WZ3Pl1D8J7rNWgn2BSIk=d,J/>Sr
XNS]o&/V=6kF[6qpmi'W.:KbNX!k!.![-G0(G8+n+OV#InWg\[e@Wa]-iAZ*
_&/kIX&lKb)PL$,=9O8BU)s(=V?GkUBuDGZVe8Z(d&+mal#!5PB&tVUKciH'
$Y@cqnTtWZ/4cUCG/JNrK1*gi&G8<(e_1+D.Z2WT@MXtGi>Y2CT$YWc&-d4R
A>(D$/g&5qlGDN@V'$7S."mbGP.tYRi^h:Y2/?6Qr)XSrKp(J/S._r#(S"=&
e2*OLZUSi1UnjZABK37g/ftOXkFeDjUj[auAc/>aJ`O`Y_\G,X=M,PO_V%<,
Cu;sTf</C9MP]#XHXK"@*7Y@L&[@G<c$N[/:5$JWLEI-;`PPtMA/j-/#mZkG
:8mkJ4T+lUJ*k[\Mm@VG*+Zail?>T.d'T>4>]]Di/=]B<jJ%OU[aNM02U+.j
!Khs_RLaC<('S'jMW*"1$m3.]c#8'Kc2[HDrtPQ"Bd73m*KXt&gpt'Z21s\Y
$#(XG+5V$Gb8*AZm[ulj?o0Sj*&Rh`hJduFn4V$^J6&n,i0X>9oJ3#8GPq5U
]Q@Hh*[qoa=t=lBYUOMI]G(@FaIPE%fOWj0W8o;L\Y>#cKj:rr%DaU'JQu@A
Uu](\-_71Z5dkL^po#a9AL*45ErQhI!N8^[CtuNTZf[N_51%:f+__]a?0>l]
V.9U[;N=(`Ym)YfrA)G&3fUVDm=+`/?h&:RFj$(&(VM!d;W\bib?A'F_RO4)
=-c1[n40-oBKO<.mC1uaSt>CX4:[K@0PEl>\QH+G-t+Mh@4W=;j^0B_X%Y1M
7VR:`E.<`BUVjVuTc^:e3lFo)%mdrb"/H2:)+,-8Ec/$pe.55=M5m)=oC'Be
?:t4[5Q;TMV>a>0MM@5^_hSb420a>)Dc'\6,:1j3CW#s-U?&iqKu=ee/%eU3
&tTJHCr:Hoan"VF)T\6u+8Y0$YJ0QR_.9-R,TbD/S-'.i`%55_,P%p:i1A8A
BG:M&PWV38>uSt!J5Cbt5URX9GYhm"WdBhi13*D5X8?PUSm<@OmUTX!e0/E&
T%J]en2MnZ=3)p#779Ul;/]Xl)G[9@6A1MmOp<TaKks:`bX..e>f#HcFCCX6
0D2!\a1[V1Ab7\nc=S^:DHbA8i!sH4I:r\N8b;8YX`&n8H]"Cc*E"A%O4&LU
p"*:N,F$k"=-@hFPUGJOVAI6W$L%dFME;J!;BG.GPKm#P_-K5qYp["LQ8!0q
15hOTKUrf$h#'rtqNEu>@)9-[b;?h0&N!"\'1cjlP4e+o:ik;@c?UG;*4hRh
P+8nd1tn;YQCi(/F_rL&:2nO@2\[eI,3/H-rquSj+Cu_?a0X!Bn6c4g?bB-b
!X0tn9gG,3Mm+bD]KT!bTqF)ME/1HG9l&@`jW+,1pk0h?QVdG4G9?S*R564J
Ab"d!Zp$t%VT,*pB1""j23*n+]2)inDr.!e(5c.Y#=Wa3)4F_/7k7lg"6>sh
62=W*Hq6Rt>pF\%(mX^Ihu4B9`>)@NlC[3k-C?L=d's.\5s[E7cF$8:*V_62
ba<aA!7'Ga,ti>mbCR9f%OW61(]8$ll^g7d:7XF7dtfI56ElCO(HI%F1`93-
X2u*`,_Kl/\2baTf3NUZT:j)_*'&U`9C\fs$mL`.O#TEH+;FS"5R7fF;?5ga
O&DZZ@0+mg"d%ngkK]V\H1Jb%"'2\i4D`c\N>@XJP!'Gf,!p:$B]6Ut[$-Z9
Ukb.tPI6eRAQ*u6Up(>J&=Y2hGZgsj<'EKu3IB>XCBGi<U]9h=5N%AaI-u_=
5V^,&R3s^^.<IP'D1YU2R/j6YP:#')H]$B#8tu#oGc2[8aG%^kF3d#5F2X=N
_$*P,9Z.p;$,N,p2p2Gf%1#BABdSGFe?u/#m.[`IC.GPeol]WR&YDcRM8Uk.
>[;pYJ>XnlAA4ZMXNN.5Pd]WHBMMcZJ4>;jLleEV63ra%BLRjFASF=0E%*2n
9Pm1Tgh^7aL1qP-aY1F,dUe3%%uWiK)![6udj!\!s#lOE1q3]WD@EHWA=EqX
^`Eku/73&J>H.rDa'3%;&6(W#_d\&nSd:$2im(LY[hYB3H^5g6Rmm"uf!IUD
caY&=o7>2R6YKtkA?aRg9+.JOO[bp[agr3;<bTdjD7:ZacaM:k$m5W,8#a?S
NRgq77*-,<R@5<c!MGK7F"ItIW!<Yr@6:uZGs-KGW73eiX@.`LXE?sOK'?-%
JnP`.icQB"YmDJn4NU>AFUpV(!)GnN1dqZnjK386(E]d?rY7(m*00&l+s]*,
e]WE#l)3fC.9$JY#H_ZW@U9M&PY6OmiuS0[5Q1cRh1gS3#O!Ke?l?h3V*dmP
D^d+ane4hQW$@]a>I22>.)7SBe;WZ.h$"12Xp.Hqq5S(fZiZ<8GQSDDPs)DR
F`.,o'hX/aV>sd8e[gVh$Xk.Q0t6/_Zjr@O\Zp,^EcKp'"aU_EUE11'>e"qB
<\1-=2T?,KKEL>S!Q^lt58DB%1euB\k&s15B9Z)U/6Pg'G`ir*hF+0q!IMOH
jtmjT5r);']\refqt2V"C/+V@#SoR;mY6b7+I]aP#:-*^gU:tQ[,Hfq_P?/j
Zmdker,C%Q8#RM%VFk?XC=]K.I;nnaj&?iHBh(,0B0&u&'L.TP<82X@6F]f&
VeudSOgMWGE/2K]7^Or$BPDN"b/PG>Tf@)ms8CjTV/2AG;\lsB;5dn,P114O
E6XU!KS#qdjF0?QotP:RNTM7kOoR1N8u$h3mC.s`:S0h10;i?m0+>*_VF?@V
_.6JAq"#CWb!h=Q!Z%hnq24<eI67uILi(*7Jtu!Z=>jB9;;FN"Y1^,NX#A_L
L+)9+L^,MifP</F(L;2$>\9\=\KMbh)\tfoi,F7fdJDXd[i"@(DUOTBn-=9d
X::cBqk?2ePRM.IaYSKfEpse+qA*dr>VI?S/e2BB;_@<cU8,)!kt#)W4Zk.E
B+m6!J_;SYoF`8Nig4t[1p!Eoldk'aS*O!ZJtnJk:lIm)a,67c@i*cG5%Q"D
)F]Q"`@4,$i.p7-nJdFL)aIO:Y;1Qo@#jdpi<p966dXX4'B]'U=DA[+&Xl@_
>W$Z[]i!,u2jIIA.]B'X?[P__CIr_IX,:#)4.]3BaAH"saW:%%R6a.^)AS93
i*!&T1tKrM)8<X)U'(.cH>-+!;4d:)k)=7J@]t_IJ)kL7"5&:0F(\1*E^jjA
7e2@'iPSK/(k[q\mUXY8SbhO(%3%3]K5Qa5%$MVPa[:-?,!42.+PCYnSA:Q4
Q!:1>-Q+T7Z&Y'(Wm7(m0<KapQU1>%YG`jR6,GR$:I??<HYs!!#V/aE;K;V4
K8W,&bO=[`EO6]MGgsifGU1j*)9@hh5X]<D*bQ>sZUu.NV_27Lfmkr#1ZZZi
WH,Q>k(iF\?bUnU7T9Yr%UfrV)4N0oY,NC;8SN5b,GBB\[ap*9pfVdW-?T1M
:Ob^G;>@hOpKeqi"Eu1)4su&^&uZ6g)>!\U39?YGTnIed1V)@r#1F'$JFL?H
>)J[NJ_/s`g_+/;bs/hGD;u1<36$WK%(hhE685!e!+YSujL&dTg9`(`Rk8>5
Id-"[06UhOG?g7/"aL]=hu2te8A_ZDb75LOJCeGIDs"e`]carRNYE*H1br=u
gO]p,70W\a\%bAa:^EqJ`26t0JtaGO-o#:l1XMGdDB<>`ok`#0%4h`h6km0H
@W-$8'4mg^h0!1DGe%'CnVDA<rpOHae:0&16*V*!+I39508N2OBGq6Dp-<?A
KSK*7/8UN0jb%#79"<rFT21l]B$H4D6)-dHji`ulo5N@sT63](DqB6p:5r?;
>b&Z%EPr=#qsM)l08A4%pNq=sao4a-o*Vd"e<TS;e>*?r8"'e/OWt)a:8>=o
_UO1Ora01Be&Hft$FD="U9p:eP8:K'1,ku@\N^u`-Z`YtHc,t'#giZg8-@8F
#iUmj7kfN5X_g2njhShXRr.,-k.7.U$9#bjXS4sZo07a#b?oM+K*Mo"]\lVS
B.M-W\Tm1=-'#9$k.IZs-k)C:lX0Z1O.Dn?Cp#:hj+dA^6K"A'7m-QI)=f;c
1=U7J*P%r+C]G)GL\tO%[qs_A06-[MeJKW-K<dVMCSu!VQ7a5s.G>J>[IYM&
V5[AB)mr)/LhM;P=Y]`!`\0uYbAnb'@[<k8XWIo0i/I2M]Pa7EC"&rq'HH7=
[;'F2/EbtZ-HolNe9E4)jrR^P'\3*Xhu=`*`Oi(LoL]7sH7I$[:eN2A9rR-l
dEb]JkTZ.I>/aBLJ,-%Z@lDhDIIS6HVfpR7>!>ibS7@or+$PWaeC6TK`EYS]
CLe:+^0!UdA7!.d:g=Mnn,R<fPa"T35Pse'L%+&U8Ukge`VG7*%gu*cYilVk
d>iG+E<g@i-0P9k`im,Qapf*Am"%JKF6[SYMa!TOes6:7n,MOqk[(9@Ro<B@
mf_Yb*5NrZa-^SObuXs)=q_%oAM)g0?u%FUh@R+o"1G)Xm+J_=$m\_iA><S@
b`Q_*PcCmR_*T1oN'^_;NF>+>63=TV#@W@O2HQX!#+:B8(,=LP5$9D4c/!gs
BSGNB_g1IoV+YM..S;/(C*EAb5'PsFXb3Ddb#/mjQ4J"Uo/lERZZ+m?";a!P
EPiT6V5C,)pkSDoW"CLICdR)WDq#q1c&38h?5sSlre5G45(dN[S<>8'@C5rp
Atl;Lm+@GlSrT815(,K'g'uI^ql5R?*-7;DAoo_)#T/hWV1r,dX]),mBm>Ap
<7-]kQ#Xc0)i`ElZi)L6\.q>Nf3NSLRAlTTfN,j;DGJ<5I=h"@HB)5H:2^8*
Pc;H4VrVebqA)!oU7$.F8!WBbFc3?L*/'MiBk\GAk^isGW-MU.`Hn:q[9/@t
.L8VCiNVQ]G:JeGe1,i&V(HDafnCW4ki;:2d-'d`J-Bq4EC^IKTTsdOacFG4
fRS#hcY]=+Os\poaZURc@JN&M,&[Vl'L97.J)gi;Jifnm%$S8s1g!)D$&fHd
S%pOVkiAm+Te#U<htu=1mGE0AN2Ih+/$71iP`>7Wpprp%';O8K43:_O<9r/>
s8)&bjXQXgd[1C;m2Th435p#Weq!0Lj^H]><H*`%p8t&s!Ji7u-D_^Dmnm.)
K7V[rj$hi8%kW9>-a$<6Srj0$AP.&'$ZKVgA::\R8/F/-,A:uDj?NY=,7uXR
%hFp`csJt[TFP*tJ.H\9UCh5<,4u3aEYlDa"H<r$),-L;A2Dmf-N],tJ5kPK
]&!*E5=F9`$Y=`(b"E!sU/q(Zm);[+^i..9)]dmTrbag4$X/upCf1[1bA'>j
4F-Me@p0YJ''A\-V=I#&Rh)?'asIrLC%uLbo5$UTfVF(Gb",o4W,m>i*,jn:
Cm*DJ'C4D,<lcYAE_#lWeD3V7E07Y+%?9[E(k1L]E^:,ZUFAEbJhh,)Z52"F
>#BEq[$2[&i9_opc"BBmTG=1LhbP`LneG+f(H"ql-*q[U:-:AeRbta)]$@/,
?,Ifm^a:+XZI6N`=r)DY.C9D>1<_?m/M>LS3!*;j"MU8HkCu<L"La0=q=C6Y
bTlTaeu`/#dE1.9$A^Z\]dPeuC0&l]Q+L"XjWuah;<.&S3DW_[*"5gXX@jjn
T,Nb\naL?&(+b9U_P>:^ef.W*j4*1$>=$q1$oni%QCPruZ!rEQaIkP,25QcV
3n_A$[bZ\^P8l\%UaSLa:HF&6G`maf(#j3mZ"M@PiCM4'TqG3V!$iF/H$tJ^
A5puQrgng@10_D?[VXW9lF>gCj2X)rg^&`ZNfQeQr+*?OB_7%BkI1#Z)(A\k
fYjOB8/OPr%?S,:!ji$Z6?tEV=NodlG]CtBUF)rX'G2'H@!M%jYsX9V+ff:*
R_T3*G`',TF]Y"u".?#[R6jme7\OHqY$?fQjd3=mUiQdqR%H9![*g:dM5@!H
n%%U&C>drqmmU71?7Lc^Z=V57`O/qe:+dE6s35J2K/u=EXQR[qhTBt+!T%!I
TM(S%l)S?Kn9aot?*n8Ws&JR6D)G/.2+El6Q]oP;LjX1beTUlC`fY/mZq8G<
C-7,C=1<6gY3A(H-@F$ub:,!AL,%F,@+MNWc47"MY)=#F7WWtOh01=N"pLkP
FQsc2k7F;Lndc_fV6W__8FnTQC'K4ZLb#<uIOGrF;ds2[AVNp@`<I@9?jWnL
Pf]IX2f8i:VM/1>BN[OcPVNj_%1S7/_!fgT%6)8H8X0j3a8c(`s.m*^Md/>:
S'1Pi[GoT@numN8.rIOro&NJO4cC=X"/mFmYKT*u<\m6V+-#!=)1fU^8RpdC
5ROM*9u9tX4"6.-+](TU0j$e>:K;0P?;?Sa-jJoMTYX5'5_D)I\&DE>,L+8'
rq<h96&5@*]8mk_!fCcp*q7*YU"iJc!]5APc2[RZ5A&$#KteiglCjO-,(<dj
h,.tfnh:"EB6aZnfuqqZ5q=[A`]2onWOGVqgUW=[pIBu]"um@)n%\o"^Io/9
::DGS(;N"")HXt"<pK4Yjah/7%+%$0H`'Z3^3Jau'?UdU8n#(fONEt`SU;UE
5V(IkF32PGe=14*k.4`RbSIf(Caji!ee+,sK9A'i4E,$A>qoj/%%<>,WioGm
#@X9Ar.V"9ltI%?)<*rM-#tn4>sa?Z6`t)L\RYg]W!F6<YAA<]NQ4Cr&>*um
,ndbj]?WFOjBGlC]C3HQ=+M0=Vn^S^HrtkT2HiWPj3qG0GZZBHUeu(I]f>uF
Dnd;WIQWn;=7Hd],R]ttfWfDS6<iF3U=Td@R[Ug"bo1+$iCASGSGX45d\'Qq
"tgOMC-b1dKbcuLD2C[pEYR+QT6qhU&T43$EDZp&#6YcS#(];C,2S,.<D(.D
.8kh4S`\i;L@qj1c<7R8>bQp]*85ptL/!gKj<'MZeL7t3QACABP)R6q'3^1<
D*Bf)e>Z@i<)X$>2*uBF#<VL_MkV?3M\e%$HL@GD[im^sDnm]DX9Eoap?^I;
Qf51!]p^t.heaEu$bM2r_2WOEWL^4)=%kMU&J#,D;qk7]Fb8M2"ei&4*K!7C
Qs1t+VVD@<r/j(f,-!S:%%a2E/\,<=JZYQ&`utsQ;>cR-TnI(o#XtNX:rEZD
6#'(OrfXI)1CI:oW1i<C7UH2CNAt_>eu]]dn?6-0G/8thQ`fc?%Yl"b9od,Q
@?Q"`76$!&N97s56E\\cBQujRUqN<$Zn=ZK6(k$.TD@nBI'(3hQ6e<pAI/BZ
,Lm'hW+t)lCmMA51lXsV,#kL>b,GQM19P%6bj,gKBkpQe"Ojn#79*6M@WP>`
Rl@'BM7bYr_$=:ZqXj#iSQk9_eXj`A#%-&4$EY1@Lh_cChq^+!"N0NZnH9U$
`>;n6-tTl[cGo&%+I:F#68\*js+9gUKJQ5]+qaD(q/@";!KBJ4i.6d&PV6=R
'ELHV\[OG!dSXdtQjQ9I_%_*6NDJCZ$q*:(n/u04S2kZ#8@-`$3"3/%mOMkA
l"A;3W>46=$"r_$-efQhJYSfa"_cM+o2tY*UIUC)!epZt]u"VBfR96Di7fhf
[Nm.F+eRsT>LuMhI^t9.Vi&?X)-7\(Q+B\,#b:GfqP]3>3?Q=24]=6WOkR73
^JljMPq>)^NZP`/NU]&C9?]He#SESm7'e=G*2+t921<:>kdrXYLOuhCo$sOJ
2hs1D]O5!\Mt9r\misd#J[IDr"52.HP>nhG8XUM!kAUm2LYgs%1kET_$H\,G
Z$Z65bGkrM#[N3iM`u\m[&bTN;c2>9lP+t9L)8SOXQ=6-O4>2@X]o;omu&-8
7.EoL#?M2]GnHXH=[J@(7rr=8`P:qOHbR,6gpepWNlu>3VsD'hKn$c%6f"[3
K#@rKEC5XPEIn6^jD[sOhR%mC[e9,q=Bs/YhP6(S7jh]!0JV9+K.C-@s#MW.
;j1T)2bA#)7sC^/X4ZpV>K)>hr93+FQ$+lU"r*L%Rd?ctPi;X/>hs,)QI\u\
*2(^b$lGZ)'sqjMpha;N^[+$[Z*Z&MTNZ#0g/Kq>H7?MZG%Z"GUO1B9PJ46U
7mee+Z&'-TcCgl76NAmU_i<P-'CjPJauk=6d+k"2/a_cMap@\6gMc8sPD;C-
Q0\9/iOA[:B4W]#q$_c(caJ0)Rd+YQ%5WtgA:7.B*-ChGiFc=d'S3pn)Ru4k
>Xs?pM)MrBU;d8ARB-T(C,mVNQIa:#bsNuOk08eg`bE2NXcGd+kUO+m$`+><
%5EH5*$J:8$5HaQCl)5`nYi>c;#kS:-X<u$X?T\U<GhVi_1MtOC!reRTgIB\
m<okq,Vi1,b1PH6#Rr;iDHtKIj5]aoc`d;r1EQ3'+DO.iU]j?Nj2otQpSa'r
Y>V2hWD]Ps%NK08f)S49]mB@W%UA%V7RTKcY10CIUN#2/\9t>XXnq.&(_:RY
@K$&q]mKM)gdW6h4YR$:4m8cg+9DR&FW]Wd:B0KAs(V96GOhF'ft"&\%@ZU&
Xo!5F\4o7kUi!s[!6p4Fku+m,hnD@,!c?Yu=h&FE"rd]TkcL.e;_p7h>XpSP
*BJ;hEo/*3NkE2"X9!2`*'Sapo&Rp;Rl@g1!o3U=3bd0HR4Y+OnI!D$=Ms<o
Iu[lKe(\`WGD0!-$5Jd]B?iu+)C6XSfW`Ht;%L=LM%_8r]kE(s_;s[B='h:M
A]hiA#:!O&>6q0iiPUF<-o:'FJ'\U)I!g=mXBAc8C,Kqd]YLhn%e)q'04(09
R&F<QI6\X8/6N%D0&*oSZT*$g%">M:l_M$^@?f&Qe>SKkGAd%Npt2JEd>I#G
AF1>7;.jB+Rr[5WA>;VR;D18LZlq[8cpF+<ZV?aPYbW@2S7c<0GMdi#k'@/f
.(V_A@[4=lN`NQ9dt;6lC3goP[2m&a=gNpX!g+&FXBC/nP%3iJ:NH@iKXF@5
,(uS@"qB!'q259IU)gW0Ue-bVHgN[fWFlM1Yue,8`)b-O2+(,NcC>bo9cCb@
if!NtgY39'X_4K<=d1ISh7@a3>e+V#XGQ1+FQcPsb8]AOi9].'++3R/(-&^e
:3A0NKtGdGH1R1F9;6QcUk5a@5oC!R0%&s'3jCQ&+B3`9HsBo]-E]u]i78.%
'/S^p]@Rt<2YF\+n(s<[="[UZ+CD6X^HNJ=.A2Kq2l6:cd#gClJeMr6(5h"B
Lk:RRN*tDKD6J<5RS35DCh45J;FK*tb*D;M^V=\"DCj9%^juTL8?"_R)I_rq
gQHPfbEa_ZW6hTK^8fSAOY1[)Rt6hT<tYRJ"VQI/V.6uPh22pt<i8]`;56V6
:(mZZY$J*%H:jQ?I^'Yrd2FS*X*F0oV+R$$im3`>Dh+;[/U;*N8.5FL_HGTj
,@A04/R#NK5(.a=1H3OI2c%&dBK9Wi+1:rSX&c?CkK[A8>.(%kLP@=R=>oSE
%/c2!,=ZeBg/ZmZ=Qj;K#sPe8h)^&br2AV/$Q!,`(RS;,F;QoP(c>erG*p$W
+.n#Ykq#uC1i:rgb*4=mmnXt^G!ri4r5i0$!..+9D2U5c!F)[VWqA7lJ,Ji2
7>l36G+&\uSt8]j6(C]:_UdTH[;4C>Sio/9D!p)hQX)-d5SV"(X*sm=C&FPl
le-.f>4n,<=K%)l/!_eng3/p@<69&-*'8>F9:%:!16o9cm^(5'X.:caQS4D2
V](mT?QLVi(r<4PWt5^,$u>0L)m][k'7ms_dA)?I#Gt:[PERS!ZHSn(En%\C
b"02Bm^jDsD@@4VN'O][?4K97PI@ta=7?E8jiU"7TN.`h_%;cmP&0;.gB5<[
"Y`gX$PogI[Hc,46[.qO($Y8npncnY"HbRQeD7K&4L,unEF\"fiXhKq`5H'1
OT@n(G=U14@WGs,*M7W>)>q0;N>bN]3&,e:oDha=E8u!4lrcY#/O6>pB=:a+
3/%T>[r1$W\T?g+X^&F-qUXG[8rOTAJlkSk8\<EX#ltconVWBgc]]^eFpdM?
C!!a_d/b1J["&+)9G0Beo66-og9t=%M@((J'J<Y#GOOCX2fB2YoM]G&fH*2%
BLd(\.?;_9J7#^!e\^Fsp&mUlTR).C([gq2<NB0JoQ'YAp47%DdLf`>:$'N_
,7qA^'cNhdLCYIrs/<7qCpK09(.hA;,taEceZ7<up$:H4h#]tdN#+9^beQHJ
jl6ab9HbcDF69Q*YMS?^P@Jll7\;#Y,MFHgZK9fJ;`bDrB[MF8MA.L;^3o`B
K*L_qYp3/c%e*-/*@UpIO$=*l1'C0F*,YR%]<jm_2#C\Sm+FZoiaSkOk004q
EAV(Lh(B.W)6NJlc!.)@Saka\B?Gt8!H*>DfY@F^lNi#aV3D(W/q3<u,DA\L
cCGn9[=%f@)#%6>,;j5cW92?o_]Ua5Z;X`"1(m<N2FS4ONb6S,)%8Q`DO=h-
VP`A<,66GedeY7!==DEXGiOcB2Jh"W"AhF2H@#>Rh5,qO2X-aSKNXgYd#g6-
p?hSg+Bl$beLI@]4)!AVBnb1`'^%oC(4G8+8,DoE[r^`X8=0'O!O3n>>U_iU
)=+k`S=k]/kKf25>.8BT0^'oSnC_HH`Q-$B0H"\"APNdIr&p;3Y[PF#&;XIN
AM:c3djA1,Z')C(mZt$nW=g79pu$d4&bt"pi5(%cooY-p6BJf'^aZD4a>"h]
+UA2ZoB+:BJ84,;[0,\*MWN$JYB&aI,=ddL[r5WLb8]AOi7tka0>IFj'"g+@
9bp>Z$\,?\X]egT4MV+.('N*Z%+(eQZY#LT[tM<3R=ch\RUjO'V.%8re##hI
k$pkDIL9rV.pXX*,YhKQXhiFsb*4>WY[FqXh3*qa@Q_VBTH8FQm&<.s73_$D
[S>q<O*0a;acReQ'cSQqW.ut#]Of8%3WIO4E`\Ln'=g(O>.!K\%mAF?:EQ<c
8/FCOE.agI-Vn3`WB(nA=f%E-5V"=jI/3>YoB,Go[Hi\b.fr-R,?VU'0qO4-
,pT7*TN)9=$0J3j[;&'`%,&=@GGNE/X'j\jD43mA7:\b1TT[M7(JBu@JM)97
Xg_+p5t3%fOH>RnjHE@`$mlqQO`aS8-KN:4#LZ><4?;&I`@uf@r2*2XWno;G
f/s1"Em0k'hkQ5r3cO#m4aZlj]"A&mEQIJ3gUHVb:HT42*tN?B"99&IbYs,u
%3SW^G4"G;SSNk<!e!.Jgpj8RHHQ.K<L;>`$e;b,j)!DSTrc7o*NQT7K1_&J
S3(qt9:%7f3j"IWKiZc[,2#4\W`5rqW)00h??p,Xo&[^S"%3+frRKLBgLN!)
4oY6:EH-!FD8qMP_)/)-!La\>e>Q4h,EuuAA>)V\.TNcbakj^XJ,AWB_31_5
KaS^.FmDMVM*'^ZC/!eg7(@VJE\/,M'I-.@9#<]I:ddl!P[LAg5_0!%.THi,
6Z@&;kYZ_8ji2][^E?M/Z=Sq//(UIcO4C:4#Dsqp+b)[!+e_Ab)FR0ildp(-
YT_5*kb56dIE\9G45Wf%1eARA+:nMl2f=kgOZbJ+DVd.m_Q9(S=0>oFITs:!
NHBFJr3EQK:jr67Khqp(cprcK]TEHHMEp,!qsT%&\`[SNSfIq8!qhkHQq704
nR+4DFZgH@[Q]3?r3^=l*]7\38kM^OM]CYei;EEBGke[]eWPUf%6PaP10@(<
`JPCOjN,`F9:)JJQNe<6_oRrbW@3Zch7us4$;OH:>b='"C+N/"NY0?!*BJ9J
imar+LG6jsPkfd,hr;V5UM8V7qe^IM#6*IJYP*d2Pi?aS7p+oD,IRnFFm@H_
>8F<R*$\Rj@Kl`PKR1Lf#hA-:'J3Lq;Pctf"q9.g@Da5n`)DGo&K1N.8m`SK
iE@=F*Q>W/*'AK8aH7]op?ZMFY+9,l3Q?D2s1gCM>U4VF:nU)JmbLsH=qs_`
M@nd+i6aiha$YrdB>G;[JnUZ)5AVcX2bU6G!mcVZNjWihJCoZ)_+"ab%SG&S
$JSh-5$e]$oG;^)N6D4W*P88T_&5qhi!!*qb48[f_SB6lMA=SsW*g54fKnE/
I4J9qJ9+Vl?G3pmlZ0r<K2'Kc.(H\gKsAjUP3iT&KVff<K.\EinqC=@\t[j:
;HO:[#TGrr_KE55!u3BAApm%\451<Iqj1M^hiE17EW+_f;V'ZsHGE<G=UcH:
gbsNj&Db,46##B)iUt_0TiS:!(bC]O%#SK"?l;F+7'l;2;+;0E.5I<57F&;G
G/X[#RA_'9>_;a0SLo1$DYWQ'4sT'I=nOMp-&u8NWFlC@hq2_%W\/Lk7U3o!
7:j`4PtF\?8-gs`0`n'X-r[Zsjm!n%G]9&s:-g;=JqBInfAI"4Ngkcr_+QE"
>QM8F9dZ1o(akq)nT!#(RZWE$H"EE_l$@78ML"bQD3l+^>CGZe+6D4e4l(#5
\(DrI)9YiKEH-!rGM]uX_3/RgK%6o'=8#IuC=R(LWejP9*W\&mn-J$P\(=<=
6-N5NE4?Q0Q<fe!G%0%@[;1qQ4#,L>b(4?:>_g[s9OYrj-i"a1mUc07AZ+<J
>!9q]DB+82o)fusgpqKMmbBfO.4Np=4[q,RqXcOSb2DI#W@Ar1HgEJSAHo3$
#=VahQ)3'L]7<2"&<q)lK-`Ft>+'M0$t@f1JhR(#*u1BWGn46^AOaVPEnP)4
\HB]#S`4\7kU+k"f3F<o;T9.eD7l1^NOooY?G'[^Jj"GP#Y%%u%R0g[_Zq92
Y\FHJ#p.4A;^>ApK:Rfs7Oqu7jX]*l.pNdR`3>;SfejF9Y*eSa+06FLqjHR:
)5cnZa\@Nb7b#&dTX*Ip*IAeAVF>/q,9PTuVc"$#oB/VH;8Y[h,'M>@CY+=_
H:VA7b`dE==X]YkOfIdL:732;ek0mAjdu@*-?J<1LU'E6V_S0KR)s<b.q=A#
VmX$VnZJd\KcSs"^2Bt.noF/*HsrRK7Q2oulhZMg"P<1=*jTA#7ZEBF1Zl"7
0nV$'o\nT9EsMu'.T`cXq=<VhIItoZPq!ZX'N1@Z-T7BlZIm<YPWV*QjH<.a
bJP9a_?hMHfiQE<=<>6ujE%0$gaL:26ZDFTBP%3d$g&5TCo*95[BmT`q<%-C
7JG\h5NgLm9fmL_<2?!E^s0Zg6\hm9\0ZgSO*Z=QYXuPN8$U1;Q0aa)VNC90
H@VNt,;(O='#dP"9.%1dIQ,+0)F$$ajk;A[9lVaX3(GODYrngN6bYh3jgb1D
[m*V8ekbJc8hB"`.&`XrF1,l9DS^o._<AoV_=H^299^jpnA>d[4=N,gQ,KZe
%[9VQOg8@%(`-F=(![(DO>jAhkNVdHQhkab^4'D?a(p.gCjhXTc(+SDQGX6Z
Hi&Q+\i4`[(XG),7CWYFZ\HJ,ISd=\aT;VQ]_^ooX&c?[F?9`;8_CCae&sDZ
$mSB2/mYhtd:+/SH[ocU0?&Pb8qg)&KSMmER"'<V`k`lC\EBOOV'pNk^iqm1
SK$q9);OC9i%(CiW:8b1YkKVFU^5+Rd\KINju'CG>`lR<kJ$H&$^dM(f7N9h
LWf\fZ58ALPRIkR^:gA9,$jGu!EL6d21GJu@$AWu_VrCf'+tq(p[8":HggXt
d'mrN4oqeo<egab.:?)UiR"8cX&lLEaoB?_kMHEP@AlBan)#4k.FrIp_hAI7
FHW5em^j+i3hU5p8e,MLb6V99EtQo7bTaB^hX2&uOq?,1J,fTO":,P]5_&h8
!X&c?+M]Rhrs*>,Oe2~>
EI

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1,3 @@
del reference.pdf
python ..\tools\yaml2pdf.py reference.yml
start reference.pdf

View File

@ -0,0 +1,29 @@
#!/bin/env python
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/reference/genreference.py
__version__=''' $Id: genreference.py 2385 2004-06-17 15:26:05Z rgbecker $ '''
__doc__ = """
This module contains the script for building the reference.
"""
def run(verbose=None, outDir=None):
import os, sys, shutil
from reportlab.tools.docco import yaml2pdf
from reportlab.lib.utils import _RL_DIR
if verbose is None: verbose=('-s' not in sys.argv)
yaml2pdf.run('reference.yml','reference.pdf')
if verbose: print 'Saved reference.pdf'
docdir = os.path.join(_RL_DIR,'docs')
if outDir: docDir = outDir
destfn = docdir + os.sep + 'reference.pdf'
shutil.copyfile('reference.pdf', destfn)
if verbose: print 'copied to %s' % destfn
def makeSuite():
"standard test harness support - run self as separate process"
from reportlab.test.utils import ScriptThatMakesFileTest
return ScriptThatMakesFileTest('../docs/reference', 'genreference.py', 'reference.pdf')
if __name__=='__main__':
run()

View File

@ -0,0 +1,217 @@
.t ReportLab API Reference
.nextPageTemplate Normal
.h1 Introduction
This is the API reference for the ReportLab library. All public
classes, functions and methods are documented here.
Most of the reference text is built automatically from the
documentation strings in each class, method and function.
That's why it uses preformatted text and doesn't look very
pretty.
Please note the following points:
.bu <seqdefault id='list'/><bullet>(<seq/>)</bullet>Items with one leading underscore are considered private
to the modules they are defined in; they are not documented
here and we make no commitment to their maintenance.
.bu <bullet>(<seq/>)</bullet>Items ending in a digit (usually zero) are experimental;
they are released to allow widespread testing, but are
guaranteed to be broken in future (if only by dropping the
zero). By all means play with these and give feedback, but
do not use them in production scripts.
.h2 Package Architecture
The reportlab package is broken into a number of subpackages.
These are as follows:
.df <font name="Courier"><b>reportlab.pdfgen</b></font>
- this is the programming
interface to the PDF file format. The Canvas (and its co-workers,
TextObject and PathObject) provide everything you need to
create PDF output working at a low level - individual shapes
and lines of text. Internally, it constructs blocks of
<i>page marking operators</i> which match your drawing commands,
and hand them over to the <font name="Courier">pdfbase</font>
package for drawing.
.df <font name="Courier"><b>reportlab.pdfbase</b></font>
- this is not part of the
public interface. It contains code to handle the 'outer
structure' of PDF files, and utilities to handle text metrics
and compressed streams.
.df <font name="Courier"><b>reportlab.platypus</b></font>
- PLATYPUS stands for
"Page Layout and Typography Using Scripts". It provides a
higher level of abstraction dealing with paragraphs, frames
on the page, and document templates. This is used for multi-
page documents such as this reference.
.df <font name="Courier"><b>reportlab.lib</b></font>
- this contains code of
interest to application developers which cuts across
both of our libraries, such as standard colors, units, and
page sizes. It will also contain more drawable and flowable
objects in future.
There is also a demos directory containing various demonstrations,
and a docs directory. These can be accessed with package
notation but should not be thought of as packages.
Each package is documented in turn.
.pageBreak
.h1 <i>reportlab.pdfgen</i> subpackage
This package contains three modules, canvas.py, textobject.py
and pathobject.py, which define three classes of corresponding
names. The only class users should construct directly is
the Canvas, defined in reportlab.pdfgen.canvas; it provides
methods to obtain PathObjects and TextObjects.
.getClassDoc reportlab.pdfgen.canvas Canvas
.pageBreak
The method Canvas.beginPath allows users to construct
a PDFPathObject, which is defined in reportlab/pdfgen/pathobject.py.
.getClassDoc reportlab.pdfgen.pathobject PDFPathObject
.pageBreak
The method Canvas.beginText allows users to construct
a PDFTextObject, which is defined in reportlab/pdfgen/textobject.py.
.getClassDoc reportlab.pdfgen.textobject PDFTextObject
.pageBreak
.h1 <i>reportlab.platypus</i> subpackage
The platypus package defines our high-level page layout API.
The division into modules is far from final and has been
based more on balancing the module lengths than on any
particular programming interface. The __init__ module
imports the key classes into the top level of the package.
.h2 Overall Structure
Abstractly Platypus currently can be thought of has having four
levels: documents, pages, frames and flowables (things which can fit into frames in some way).
In practice there is a fifth level, the canvas, so that if you want
you can do anything that pdfgen's canvas allows.
.h2 Document Templates
.h3 BaseDocTemplate
The basic document template class; it provides for initialisation and
rendering of documents. A whole bunch of methods
<b><font name=courier>handle_XXX</font></b> handle document
rendering events. These event routines all contain some
significant semantics so while these may be overridden that
may require some detailed knowledge. Some other methods are
completely virtual and are designed to be overridden.
.h3 BaseDocTemplate
.getClassDoc reportlab.platypus.doctemplate BaseDocTemplate
.pageBreak
A simple document processor can be made using derived class,
<b><font name=courier>SimpleDocTemplate</font></b>.
.pageBreak
.h3 SimpleDocTemplate
.getClassDoc reportlab.platypus.doctemplate SimpleDocTemplate
.pageBreak
.h2 Flowables
.getClassDoc reportlab.platypus.paragraph Paragraph
.getClassDoc reportlab.platypus.flowables Flowable
.getClassDoc reportlab.platypus.flowables XBox
.getClassDoc reportlab.platypus.flowables Preformatted
.getClassDoc reportlab.platypus.flowables Image
.getClassDoc reportlab.platypus.flowables Spacer
.getClassDoc reportlab.platypus.flowables PageBreak
.getClassDoc reportlab.platypus.flowables CondPageBreak
.getClassDoc reportlab.platypus.flowables KeepTogether
.getClassDoc reportlab.platypus.flowables Macro
.getClassDoc reportlab.platypus.xpreformatted XPreformatted
.getClassDoc reportlab.platypus.xpreformatted PythonPreformatted
.pageBreak
.h1 <i>reportlab.lib</i> subpackage
This package contains a number of modules which either add utility
to pdfgen and platypus, or which are of general use in graphics
applications.
.h2 <i>reportlab.lib.colors</i> module
.getModuleDoc reportlab.lib.colors
.h2 <i>reportlab.lib.corp</i> module
.getModuleDoc reportlab.lib.corp
.h2 <i>reportlab.lib.enums</i> module
.getModuleDoc reportlab.lib.enums
.h2 <i>reportlab.lib.fonts</i> module
.getModuleDoc reportlab.lib.fonts
.h2 <i>reportlab.lib.pagesizes</i> module
.getModuleDoc reportlab.lib.pagesizes
.h2 <i>reportlab.lib.sequencer</i> module
.getModuleDoc reportlab.lib.sequencer
.pageBreak
.h1 Appendix A - CVS Revision History
.beginPre Code
$Log: reference.yml,v $
Revision 1.1 2001/10/05 12:33:33 rgbecker
Moved from original project docs, history lost
Revision 1.13 2001/08/30 10:32:38 dinu_gherman
Added missing flowables.
Revision 1.12 2001/07/11 09:21:27 rgbecker
Typo fix from Jerome Alet
Revision 1.11 2000/07/10 23:56:09 andy_robinson
Paragraphs chapter pretty much complete. Fancy cover.
Revision 1.10 2000/07/03 15:39:51 rgbecker
Documentation fixes
Revision 1.9 2000/06/28 14:52:43 rgbecker
Documentation changes
Revision 1.8 2000/06/19 23:52:31 andy_robinson
rltemplate now simple, based on UserDocTemplate
Revision 1.7 2000/06/17 07:46:45 andy_robinson
Small text changes
Revision 1.6 2000/06/14 21:22:52 andy_robinson
Added docs for library
Revision 1.5 2000/06/12 11:26:34 andy_robinson
Numbered list added
Revision 1.4 2000/06/12 11:13:09 andy_robinson
Added sequencer tags to paragraph parser
Revision 1.3 2000/06/09 01:44:24 aaron_watters
added automatic generation for pathobject and textobject modules.
Revision 1.2 2000/06/07 13:39:22 andy_robinson
Added some text to the first page of reference, and a build batch file
Revision 1.1.1.1 2000/06/05 16:39:04 andy_robinson
initial import
.endPre

View File

@ -0,0 +1,113 @@
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/userguide/app_demos.py
from reportlab.tools.docco.rl_doc_utils import *
Appendix1("ReportLab Demos")
disc("""In the subdirectories of $reportlab/demos$ there are a number of working examples showing
almost all aspects of reportlab in use.""")
heading2("""Odyssey""")
disc("""
The three scripts odyssey.py, dodyssey.py and fodyssey.py all take the file odyssey.txt
and produce PDF documents. The included odyssey.txt is short; a longer and more testing version
can be found at ftp://ftp.reportlab.com/odyssey.full.zip.
""")
eg("""
Windows
cd reportlab\\demos\\odyssey
python odyssey.py
start odyssey.pdf
Linux
cd reportlab/demos/odyssey
python odyssey.py
acrord odyssey.pdf
""")
disc("""Simple formatting is shown by the odyssey.py script. It runs quite fast,
but all it does is gather the text and force it onto the canvas pages. It does no paragraph
manipulation at all so you get to see the XML &lt; &amp; &gt; tags.
""")
disc("""The scripts fodyssey.py and dodyssey.py handle paragraph formatting so you get
to see colour changes etc. Both scripts
use the document template class and the dodyssey.py script shows the ability to do dual column
layout and uses multiple page templates.
""")
heading2("""Standard Fonts and Colors""")
disc("""In $reportlab/demos/stdfonts$ the script stdfonts.py can be used to illustrate
ReportLab's standard fonts. Run the script using""")
eg("""
cd reportlab\\demos\\stdfonts
python stdfonts.py
""")
disc("""
to produce two PDF documents, StandardFonts_MacRoman.pdf &amp;
StandardFonts_WinAnsi.pdf which show the two most common built in
font encodings.
""")
disc("""The colortest.py script in $reportlab/demos/colors$ demonstrates the different ways in which
reportlab can set up and use colors.""")
disc("""Try running the script and viewing the output document, colortest.pdf. This shows
different color spaces and a large selection of the colors which are named
in the $reportlab.lib.colors$ module.
""")
heading2("""Py2pdf""")
disc("""Dinu Gherman (&lt;gherman@europemail.com&gt;) contributed this useful script
which uses reportlab to produce nicely colorized PDF documents from Python
scripts including bookmarks for classes, methods and functions.
To get a nice version of the main script try""")
eg("""
cd reportlab/demos/py2pdf
python py2pdf.py py2pdf.py
acrord py2pdf.pdf
""")
disc("""i.e. we used py2pdf to produce a nice version of py2pdf.py in
the document with the same rootname and a .pdf extension.
""")
disc("""
The py2pdf.py script has many options which are beyond the scope of this
simple introduction; consult the comments at the start of the script.
""")
heading2("Gadflypaper")
disc("""
The Python script, gfe.py, in $reportlab/demos/gadflypaper$ uses an inline style of
document preparation. The script almost entirely produced by Aaron Watters produces a document
describing Aaron's $gadfly$ in memory database for Python. To generate the document use
""")
eg("""
cd reportlab\\gadflypaper
python gfe.py
start gfe.pdf
""")
disc("""
everything in the PDF document was produced by the script which is why this is an inline style
of document production. So, to produce a header followed by some text the script uses functions
$header$ and $p$ which take some text and append to a global story list.
""")
eg('''
header("Conclusion")
p("""The revamped query engine design in Gadfly 2 supports
..........
and integration.""")
''')
heading2("""Pythonpoint""")
disc("""Andy Robinson has refined the pythonpoint.py script (in $reportlab\\demos\\pythonpoint$)
until it is a really useful script. It takes an input file containing an XML markup
and uses an xmllib style parser to map the tags into PDF slides. When run in its own directory
pythonpoint.py takes as a default input the file pythonpoint.xml and produces pythonpoint.pdf
which is documentation for Pythonpoint! You can also see it in action with an older paper
""")
eg("""
cd reportlab\\demos\\pythonpoint
python pythonpoint.py monterey.xml
start monterey.pdf
""")
disc("""
Not only is pythonpoint self documenting, but it also demonstrates reportlab and PDF. It uses
many features of reportlab (document templates, tables etc).
Exotic features of PDF such as fadeins and bookmarks are also shown to good effect. The use of
an XML document can be contrasted with the <i>inline</i> style of the gadflypaper demo; the
content is completely separate from the formatting
""")

View File

@ -0,0 +1,693 @@
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/userguide/ch1_intro.py
from reportlab.tools.docco.rl_doc_utils import *
import reportlab
title("ReportLab PDF Library")
title("User Guide")
centred('ReportLab Version ' + reportlab.Version)
nextTemplate("Normal")
########################################################################
#
# Chapter 1
#
########################################################################
heading1("Introduction")
heading2("About this document")
disc("""This document is an introduction to the ReportLab PDF library.
Some previous programming experience
is presumed and familiarity with the Python Programming language is
recommended. If you are new to Python, we tell you in the next section
where to go for orientation.
""")
disc("""
This manual does not cover 100% of the features, but should explain all
the main concepts and help you get started, and point you at other
learning resources.
After working your way through this, you should be ready to begin
writing programs to produce sophisticated reports.
""")
disc("""In this chapter, we will cover the groundwork:""")
bullet("What is ReportLab all about, and why should I use it?")
bullet("What is Python?")
bullet("How do I get everything set up and running?")
todo("""
We need your help to make sure this manual is complete and helpful.
Please send any feedback to our user mailing list,
which is signposted from <a href="http://www.reportlab.org/">www.reportlab.org</a>.
""")
heading2("What is the ReportLab PDF Library?")
disc("""This is a software library that lets you directly
create documents in Adobe's Portable Document Format (PDF) using
the Python programming language. It also creates charts and data graphics
in various bitmap and vector formats as well as PDF.""")
disc("""PDF is the global standard for electronic documents. It
supports high-quality printing yet is totally portable across
platforms, thanks to the freely available Acrobat Reader. Any
application which previously generated hard copy reports or driving a printer
can benefit from making PDF documents instead; these can be archived,
emailed, placed on the web, or printed out the old-fashioned way.
However, the PDF file format is a complex
indexed binary format which is impossible to type directly.
The PDF format specification is more than 600 pages long and
PDF files must provide precise byte offsets -- a single extra
character placed anywhere in a valid PDF document can render it
invalid. This makes it harder to generate than HTML.""")
disc("""Most of the world's PDF documents have been produced
by Adobe's Acrobat tools, or rivals such as JAWS PDF Creator, which act
as 'print drivers'. Anyone wanting to automate PDF production would
typically use a product like Quark, Word or Framemaker running in a loop
with macros or plugins, connected to Acrobat. Pipelines of several
languages and products can be slow and somewhat unwieldy.
""")
disc("""The ReportLab library directly creates PDF based on
your graphics commands. There are no intervening steps. Your applications
can generate reports extremely fast - sometimes orders
of magnitude faster than traditional report-writing
tools. This approach is shared by several other libraries - PDFlib for C,
iText for Java, iTextSharp for .NET and others. However, The ReportLab library
differs in that it can work at much higher levels, with a full featured engine
for laying out documents complete with tables and charts. """)
disc("""In addition, because you are writing a program
in a powerful general purpose language, there are no
restrictions at all on where you get your data from,
how you transform it, and the kind of output
you can create. And you can reuse code across
whole families of reports.""")
disc("""The ReportLab library is expected to be useful
in at least the following contexts:""")
bullet("Dynamic PDF generation on the web")
bullet("High-volume corporate reporting and database publishing")
bullet("""An embeddable print engine for other applications, including
a 'report language' so that users can customize their own reports. <i>
This is particularly relevant to cross-platform apps which cannot
rely on a consistent printing or previewing API on each operating
system</i>.""")
bullet("""A 'build system' for complex documents with charts, tables
and text such as management accounts, statistical reports and
scientific papers """)
bullet("""Going from XML to PDF in one step!""")
heading2("What is Python?")
disc("""
Python is an <i>interpreted, interactive, object-oriented</i> programming language. It is often compared to Tcl, Perl,
Scheme or Java.
""")
disc("""
Python combines remarkable power with very clear syntax. It has modules, classes, exceptions, very high level
dynamic data types, and dynamic typing. There are interfaces to many system calls and libraries, as well as to
various windowing systems (X11, Motif, Tk, Mac, MFC). New built-in modules are easily written in C or C++.
Python is also usable as an extension language for applications that need a programmable interface.
""")
disc("""
Python is as old as Java and has been growing steadily in popularity for 13 years; since our
library first came out it has entered the mainstream. Many ReportLab library users are
already Python devotees, but if you are not, we feel that the language is an excellent
choice for document-generation apps because of its expressiveness and ability to get
data from anywhere.
""")
disc("""
Python is copyrighted but <b>freely usable and distributable, even for commercial use</b>.
""")
heading2("Acknowledgements")
disc("""Many people have contributed to ReportLab. We would like to thank
in particular (in approximately chronological order) Chris Lee, Magnus Lie Hetland,
Robert Kern, Jeff Bauer (who contributed normalDate.py); Jerome Alet (numerous patches
and the rlzope demo), Andre Reitz, Max M, Albertas Agejevas, T Blatter, Ron Peleg,
Gary Poster, Steve Halasz, Andrew Mercer, Paul McNett, Chad Miller, Tim Roberts,
Jorge Godoy and Benn B.""")
disc("""Special thanks go to Just van Rossum for his valuable assistance with
font technicalities and the LettErrorRobot-Chrome type 1 font.""")
disc("""Marius Gedminas deserves a big hand for contributing the work on TrueType fonts and we
are glad to include these in the toolkit. Finally we thank Bigelow &amp; Holmes Inc ($design@bigelowandholmes.com$)
for Luxi Serif Regular and Ray Larabie ($http://www.larabiefonts.com$) for the Rina TrueType font.""")
heading2("Installation and Setup")
disc("""
Below we provide an abbreviated setup procedure for Python experts and a more
verbose procedure for people who are new to Python.
""")
heading3("Installation for experts")
disc("""First of all, we'll give you the high-speed version for experienced
Python developers:""")
list("""Install Python 2.3 or later (2.4 recommended). ReportLab 2.x uses
Python 2.3 features and will use 2.4 going forwards. We also maintain
a 1.x branch which works back to Python 2.1.
""")
list("""If you want to produce compressed PDF files (recommended),
check that zlib is installed.""")
list("""If you want to work with bitmap images, install and
test the Python Imaging Library""")
list("""Unpack the reportlab package (reportlab.zip
or reportlab.tgz) into a directory on your path. (You can also use ^python setup.py install^ if you wish)""")
list("""Unpack the rl_addons package and build the C extensions with distutils; or grab the
corresponding .pyd files from our download page. """)
list("""$cd$ to ^reportlab/test^ and execute $runAll.py$.
This will create many PDF files. """)
list("""You may also want to download and run the ^rl_check.py^ on our site, which
health-checks an installation and reports on any missing options. """)
disc(" ")
disc("""If you have any problems, check the 'Detailed Instructions' section below.""")
heading3("A note on available versions")
disc("""The $reportlab$ library can be found at $ftp.reportlab.com$ in
the top-level directory or at http://www.reportlab.com/ftp/.
Each successive version is stored in both zip
and tgz format, but the contents are identical apart from line endings.
Versions are numbered: $ReportLab_1_00.zip$, $ReportLab_1_01.zip$ and so on. The
latest stable version is also available as just $reportlab.zip$ (or
$reportlab.tgz$), which is actually a symbolic link to the latest
numbered version. Finally, daily snapshots off the trunk are available as
$current.zip$ (or $current.tgz$).
""")
heading3("Instructions for novices: Windows")
disc("""This section assumes you
don't know much about Python. We cover all of the steps for three
common platforms, including how to verify that each one is complete.
While this may seem like a long list, everything takes 5 minutes if
you have the binaries at hand.""")
restartList()
list("""Get and install Python from $http://www.python.org/.$
Reportlab 2.x works with Python 2.3 upwards but we strongly recommend to use
the latest stable version of Python (2.4.3 at the time of writing).
Follow the links to 'Download' and get the latest
official version. This will install itself into $C:\Python24$
After installing, you should be able to run the
'Python (command line)' option from the Start Menu.""")
list("""If on Windows, we strongly recommend installing the Python Windows
Extensions, which let you use access all the Windows data sources, and provide
a very nice IDE. This can be found at ^http://sourceforge.net/projects/pywin32/^.
Once this is installed, you can start
Pythonwin from the Start Menu and get a GUI application.""")
list("""The next step is optional and only necessary if you want to
include images in your reports; it can also be carried out later. However
we always recommend a full installation if time permits.""")
list("""Install the Python Imaging Library ($PIL$) from $http://www.pythonware.com/products/pil/$.
""")
list("""Now you are ready to install reportlab itself. Unzip the archive straight into
your Python directory; it creates a subdirectory named
$reportlab$. You should now be able to go to a Python
command line interpreter and type $import reportlab$ without getting
an error message.""")
list("""Download the zip file of precompiled DLLs for your Python version from
the bottom of the ^http://www.reportlab.org/downloads.html^ downloads page, and unzip
them into ^C:\Python24\lib\site-packages^ (or its equivalent for other Python versions""")
list("""Open up a $MS-DOS$ command prompt and CD to
"$..\\reportlab\\test$". Enter "$runAll.py$". You should see lots of dots
and no error messages. This will also create many PDF files and generate
the manuals in ^reportlab/docs^ (including this one). """)
list("""
Finally, we recommend you download and run the script ^rl_check.py^ from
^^http://www.reportlab.org/ftp/^. This will health-check all the above
steps and warn you if anything is missing or mismatched.""")
heading3("Instructions for Python novices: Unix")
restartList()
list("""On a large number of Unix and Linux distributions, Python is already installed,
or is avaialable as a standard package you can install with the relevant package manager.""")
list("""If you want to compile from
source download the latest
sources from http://www.python.org (currently the latest source is
in http://www.python.org/ftp/python/2.4.3/Python-2.4.3.tgz). If you wish to use
binaries
get the latest RPM or DEB or whatever package and install (or get your
super user (system administrator) to do the work).""")
list("""If you are building Python yourself, unpack the sources into a
temporary directory using a tar command e.g. $tar xzvf Python-2.4.3.tgz$;
this will create a subdirectory called Python-2.4.3 (or whatever). cd
into this directory. Then read the file $README$! It contains the
latest information on how to install Python.""")
list("""If your system has the gzip libz library installed
check that the zlib extension will be installed by default by editing
the file Modules/Setup.in and ensuring that (near line 405) the line
containing zlib zlibmodule.c is uncommented i.e. has no hash '#' character at the
beginning. You also need to decide if you will be installing in the default location
(/usr/local/) or in some other place.
The zlib module is needed if you want compressed PDF and for some images.""")
list("""Invoke the command $./configure --prefix=/usr/local$ this should configure
the source directory for building. Then you can build the binaries with
a $make$ command. If your $make$ command is not up to it try building
with $make MAKE=make$. If all goes well install with $make install$.""")
list("""If all has gone well and python is in the execution search path
you should now be able to type $python$ and see a <b>Python</b> prompt.""")
list("""
Once you can do that it's time to try and install ReportLab.
First get the latest reportlab.tgz.
If ReportLab is to be available to all then the reportlab archive should be unpacked in
the lib/site-python directory (typically /usr/local/lib/site-python) if necessary by
a superuser.
Otherwise unpack in a directory of your choice and arrange for that directory to be on your
$PYTHONPATH$ variable.
""")
eg("""
#put something like this in your
#shell rcfile
PYTHONPATH=$HOME/mypythonpackages
export PYTHONPATH
""",after=0.1)
list("""You should now be able to run python and execute the python statement
""",doBullet=0)
eg("""import reportlab""",after=0.1)
list("""If you want to use images you should certainly consider
getting &amp; installing the Python Imaging Library - follow the
directions from
$http://www.python.org/sigs/image-sig/index.html$ or get it directly from
$http://www.pythonware.com/products/pil/$.""")
heading3("Instructions for Python novices: Mac")
disc("""
This is much, much easier with Mac OS X since Python (usually 2.3) is installed on your
system as standard. Just follow the instructions for installing the ReportLab archive
above.
""")
heading3("Instructions for Jython (Java implementation of Python) users")
disc("""
A port to Java was done in 2004. This involved some changes to the framework
and creating Java equivalents of the C extensions. At the end of this work
the entire output of the test suite produced byte-for-byte identical output.
However, we have not been testng against Jython since, because (a) as far as
we know no one used it, and (b) Jython has not kept up with Python features
which we need to use. We suggest you use ReportLab v1.19 or v1.20 which
were Python-2.1 compatible. We'd welcome test reports and/or a volunteer to
refresh things now that Jython is progressing.""")
disc("""
The Jython version was 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.
""")
restartList()
list("""
Before installing Jython, make sure you have a supported version of
Java Virtual Machine installed. For the list of supported JVM's see
$http://www.jython.org/platform.html$
""")
list("""
To install Jython, download the setup package from $www.jython.org$ and
follow installation instructions.
""")
list("""
To set ReportLab toolkit under Jython PATH, edit $JYTHON_HOME/registry$ file
and include line that tells Jython where to look for packages. To include
ReportLab toolkit under Jython PATH, directory that contains Reportlab
should be included: $python.path=REPORTLAB_HOME_PARENT_DIR$
For example, if your Reportlab toolkit is installed under $C:\code\\reportlab$
the path line should be: $python.path=C:\\\\code$ (note two backslashes!)
""")
heading3("Instructions for IronPython (Python for .NET) users")
disc("""
We haven't tackled this yet officially, but IronPython can apparently
run much of our code. We do need to go through the same exercises we did for Jython
- finding the .NET equivalents of _rl_accel, pyRXP, _renderPM and PIL -
to get 100% managed code. Hopefully this will happen soon and we'd be
delighted to work with anyone on this.
""")
heading2("Getting Involved")
disc("""ReportLab is an Open Source project. Although we are
a commercial company we provide the core PDF generation
sources freely, even for commercial purposes, and we make no income directly
from these modules. We also welcome help from the community
as much as any other Open Source project. There are many
ways in which you can help:""")
bullet("""General feedback on the core API. Does it work for you?
Are there any rough edges? Does anything feel clunky and awkward?""")
bullet("""New objects to put in reports, or useful utilities for the library.
We have an open standard for report objects, so if you have written a nice
chart or table class, why not contribute it?""")
bullet("""Demonstrations and Case Studies: If you have produced some nice
output, send it to us (with or without scripts). If ReportLab solved a
problem for you at work, write a little 'case study' and send it in.
And if your web site uses our tools to make reports, let us link to it.
We will be happy to display your work (and credit it with your name
and company) on our site!""")
bullet("""Working on the core code: we have a long list of things
to refine or to implement. If you are missing some features or
just want to help out, let us know!""")
disc("""The first step for anyone wanting to learn more or
get involved is to join the mailing list. To Subscribe visit
$http://two.pairlist.net/mailman/listinfo/reportlab-users$.
From there you can also browse through the group's archives
and contributions. The mailing list is
the place to report bugs and get support. """)
heading2("Site Configuration")
disc("""There are a number of options which most likely need to be configured globally for a site.
The python script module $reportlab/rl_config.py$ may be edited to change the values of several
important sitewide properties.""")
bullet("""verbose: set to integer values to control diagnostic output.""")
bullet("""shapeChecking: set this to zero to turn off a lot of error checking in the graphics modules""")
bullet("""defaultEncoding: set this to WinAnsiEncoding or MacRomanEncoding.""")
bullet("""defaultPageSize: set this to one of the values defined in reportlab/lib/pagesizes.py; as delivered
it is set to pagesizes.A4; other values are pagesizes.letter etc.""")
bullet("""defaultImageCaching: set to zero to inhibit the creation of .a85 files on your
hard-drive. The default is to create these preprocessed PDF compatible image files for faster loading""")
bullet("""T1SearchPath: this is a python list of strings representing directories that
may be queried for information on Type 1 fonts""")
bullet("""TTFSearchPath: this is a python list of strings representing directories that
may be queried for information on TrueType fonts""")
bullet("""CMapSearchPath: this is a python list of strings representing directories that
may be queried for information on font code maps.""")
bullet("""showBoundary: set to non-zero to get boundary lines drawn.""")
bullet("""ZLIB_WARNINGS: set to non-zero to get warnings if the Python compression extension is not found.""")
bullet("""pageComression: set to non-zero to try and get compressed PDF.""")
bullet("""allowtableBoundsErrors: set to 0 to force an error on very large Platypus table elements""")
bullet("""emptyTableAction: Controls behaviour for empty tables, can be 'error' (default), 'indicate' or 'ignore'.""")
heading2("Learning More About Python")
disc("""
If you are a total beginner to Python, you should check out one or more from the
growing number of resources on Python programming. The following are freely
available on the web:
""")
bullet("""<b>Introductory Material on Python. </b>
A list of tutorials on the Python.org web site.
$http://www.python.org/doc/Intros.html$
""")
bullet("""<b>Python Tutorial. </b>
The official Python Tutorial by Guido van Rossum (edited by Fred L. Drake, Jr.)
$http://www.python.org/doc/tut/$
""")
bullet("""<b>Learning to Program. </b>
A tutorial on programming by Alan Gauld. Has a heavy emphasis on
Python, but also uses other languages.
$http://www.freenetpages.co.uk/hp/alan.gauld/$
""")
bullet("""<b>How to think like a computer scientist</b> (Python version)</b>.
$http://www.ibiblio.org/obp/thinkCSpy/$
""")
bullet("""<b>Instant Python</b>.
A 6-page minimal crash course by Magnus Lie Hetland.
$http://www.hetland.org/python/instant-python.php$
""")
bullet("""<b>Dive Into Python</b>.
A free Python tutorial for experienced programmers.
$http://diveintopython.org/$
""")
from reportlab.lib.codecharts import SingleByteEncodingChart
from reportlab.tools.docco.stylesheet import getStyleSheet
styles = getStyleSheet()
indent0_style = styles['Indent0']
indent1_style = styles['Indent1']
heading2("What's New in ReportLab 2.0")
disc("""
Many new features have been added, foremost amongst which is the support
for unicode. This page documents what has changed since version 1.20.""")
disc("""
Adding full unicode support meant that we had to break backwards-compatibility,
so old code written for ReportLab 1 will sometimes need changes before it will
run correctly with ReportLab 2. Now that we have made the clean break to
introduce this important new feature, we intend to keep the API
backwards-compatible throughout the 2.* series.
""")
heading3("Goals for the 2.x series")
disc("""
The main rationale for 2.0 was an incompatible change at the character level:
to properly support Unicode input. Now that it's out we will maintain compatibility
with 2.0. There are no pressing feature wishlists and new features will be driven,
as always, by contributions and the demands of projects.""")
disc("""
Our 1.x code base is still Python 2.1 compatible. The new version lets us move forwards
with a baseline of Python 2.4 (2.3 will work too, for the moment, but we don't promise
that going forwards) so we can use newer language features freely in our development.""")
disc("""
One area where we do want to make progress from release to release is with documentation
and installability. We'll be looking into better support for distutils, setuptools,
eggs and so on; and into better examples and tools to help people learn what's in the
(substantial) code base.""")
disc("""
Bigger ideas and more substantial rewrites are deferred to Version 3.0, with no particular
target dates.
""")
heading3("Contributions")
disc("""Thanks to everybody who has contributed to the open-source toolkit in the run-up
to the 2.0 release, whether by reporting bugs, sending patches, or contributing to the
reportlab-users mailing list. Thanks especially to the following people, who contributed
code that has gone into 2.0: Andre Reitz, Max M, Albertas Agejevas, T Blatter, Ron Peleg,
Gary Poster, Steve Halasz, Andrew Mercer, Paul McNett, Chad Miller.
""")
todo("""If we missed you, please let us know!""")
heading3("Unicode support")
disc("""
This is the Big One, and the reason some apps may break. You must now pass in text either
in UTF-8 or as unicode string objects. The library will handle everything to do with output
encoding. There is more information on this below.
Since this is the biggest change, we'll start by reviewing how it worked in the past.""")
disc("""
In ReportLab 1.x, any string input you passed to our APIs was supposed to be in the same
encoding as the font you selected for output. If using the default fonts in Acrobat Reader
(Helvetica/Times/Courier), you would have implicitly used WinAnsi encoding, which is almost
exactly the same as Latin-1. However, if using TrueType fonts, you would have been using UTF-8.""")
disc("""For Asian fonts, you had a wide choice of encodings but had to specify which one
(e.g Shift-JIS or EUC for Japanese). This state of affairs meant that you had
to make sure that every piece of text input was in the same encoding as the font used
to display it.""")
disc("""Input text encoding is UTF-8 or Python Unicode strings""")
disc("""
Any text you pass to a canvas API (drawString etc.), Paragraph or other flowable
constructor, into a table cell, or as an attribute of a graphic (e.g. chart.title.text),
is supposed to be unicode. If you use a traditional Python string, it is assumed to be UTF-8.
If you pass a Unicode object, we know it's unicode.""", style=indent1_style)
disc("""Font encodings""")
disc("""
Fonts still work in different ways, and the built-in ones will still use WinAnsi or MacRoman
internally while TrueType will use UTF-8. However, the library hides this from you; it converts
as it writes out the PDF file. As before, it's still your job to make sure the font you use has
the characters you need, or you may get either a traceback or a visible error character.""",style=indent1_style)
disc("""Asian CID fonts""")
disc("""
You no longer need to specify the encoding for the built-in Asian fonts, just the face name.
ReportLab knows about the standard fonts in Adobe's Asian Language Packs
""", style=indent1_style)
disc("""Asian Truetype fonts""")
disc("""
The standard Truetype fonts differ slightly for Asian languages (e.g msmincho.ttc).
These can now be read and used, albeit somewhat inefficiently.
""", style=indent1_style)
disc("""Asian word wrapping""")
disc("""
Previously we could display strings in Asian languages, but could not properly
wrap paragraphs as there are no gaps between the words. We now have a basic word wrapping
algorithm.
""", style=indent1_style)
disc("""unichar tag""")
disc("""
A convenience tag, &lt;unichar/&gt; has also been added. You can now do <unichar code="0xfc"/>
or &lt;unichar name='LATIN SMALL LETTER U WITH DIAERESIS'/&gt; and
get a lowercase u umlaut. Names should be those in the Unicode Character Database.
""", style=indent1_style)
disc("""Accents, greeks and symbols""")
disc("""
The correct way to refer to all non-ASCII characters is to use their unicode representation.
This can be literal Unicode or UTF-8. Special symbols and Greek letters (collectively, "greeks")
inserted in paragraphs using the greek tag (e.g. &lt;greek&gt;lambda&lt;/greek&gt;) or using the entity
references (e.g. &lambda;) are now processed in a different way than in version 1.""", style=indent1_style)
disc("""
Previously, these were always rendered using the Zapf Dingbats font. Now they are always output
in the font you specified, unless that font does not support that character. If the font does
not support the character, and the font you specified was an Adobe Type 1 font, Zapf Dingbats
is used as a fallback. However, at present there is no fallback in the case of TTF fonts.
Note that this means that documents that contain greeks and specify a TTF font may need
changing to explicitly specify the font to use for the greek character, or you will see a black
square in place of that character when you view your PDF output in Acrobat Reader.
""", style=indent1_style)
# Other New Features Section #######################
heading3("Other New Features")
disc("""PDF""")
disc("""Improved low-level annotation support for PDF "free text annotations"
""", style=indent0_style)
disc("""FreeTextAnnotation allows showing and hiding of an arbitrary PDF "form"
(reusable chunk of PDF content) depending on whether the document is printed or
viewed on-screen, or depending on whether the mouse is hovered over the content, etc.
""", style=indent1_style)
disc("""TTC font collection files are now readable"
""", style=indent0_style)
disc("""ReportLab now supports using TTF fonts packaged in .TTC files""", style=indent1_style)
disc("""East Asian font support (CID and TTF)""", style=indent0_style)
disc("""You no longer need to specify the encoding for the built-in Asian fonts,
just the face name. ReportLab knows about the standard fonts in Adobe's Asian Language Packs.
""", style=indent1_style)
disc("""Native support for JPEG CMYK images""", style=indent0_style)
disc("""ReportLab now takes advantage of PDF's native JPEG CMYK image support,
so that JPEG CMYK images are no longer (lossily) converted to RGB format before including
them in PDF.""", style=indent1_style)
disc("""Platypus""")
disc("""Link support in paragraphs""", style=indent0_style)
disc("""
Platypus paragraphs can now contain link elements, which support both internal links
to the same PDF document, links to other local PDF documents, and URL links to pages on
the web. Some examples:""", style=indent1_style)
disc("""Web links:""", style=indent1_style)
disc("""&lt;link href="http://www.reportlab.com/"&gt;ReportLab&lt;link&gt;""", style=styles['Link'])
disc("""Internal link to current PDF document:""", style=indent1_style)
disc("""&lt;link href="summary"&gt;ReportLab&lt;link&gt;""", style=styles['Link'])
disc("""External link to a PDF document on the local filesystem:""", style=indent1_style)
disc("""&lt;link href="pdf:C:/john/report.pdf"&gt;ReportLab&lt;link&gt;""", style=styles['Link'])
disc("""Improved wrapping support""", style=indent0_style)
disc("""Support for wrapping arbitrary sequence of flowables around an image, using
reportlab.platypus.flowables.ImageAndFlowables (similar to ParagraphAndImage)."""
,style=indent1_style)
disc("""KeepInFrame""", style=indent0_style)
disc("""Sometimes the length of a piece of text you'd like to include in a fixed piece
of page "real estate" is not guaranteed to be constrained to a fixed maximum length.
In these cases, KeepInFrame allows you to specify an appropriate action to take when
the text is too long for the space allocated for it. In particular, it can shrink the text
to fit, mask (truncate) overflowing text, allow the text to overflow into the rest of the document,
or raise an error.""",style=indent1_style)
disc("""Improved convenience features for inserting unicode symbols and other characters
""", style=indent0_style)
disc("""<unichar/> lets you conveniently insert unicode characters using the standard long name
or code point. Characters inserted with the &lt;greek&gt; tags (e.g. <greek>lambda</greek>) or corresponding
entity references (e.g. &lambda;) support arbitrary fonts (rather than only Zapf Dingbats).""",style=indent1_style)
disc("""Improvements to Legending""", style=indent0_style)
disc("""Instead of manual placement, there is now a attachment point (N, S, E, W, etc.), so that
the legend is always automatically positioned correctly relative to the chart. Swatches (the small
sample squares of colour / pattern fill sometimes displayed in the legend) can now be automatically
created from the graph data. Legends can now have automatically-computed totals (useful for
financial applications).""",style=indent1_style)
disc("""More and better ways to place piechart labels""", style=indent0_style)
disc("""New smart algorithms for automatic pie chart label positioning have been added.
You can now produce nice-looking labels without manual positioning even for awkward cases in
big runs of charts.""",style=indent1_style)
disc("""Adjustable piechart slice ordering""", style=indent0_style)
disc("""For example. pie charts with lots of small slices can be configured to alternate thin and
thick slices to help the lagel placememt algorithm work better.""",style=indent1_style)
disc("""Improved spiderplots""", style=indent0_style)
# Noteworthy bug fixes Section #######################
heading3("Noteworthy bug fixes")
disc("""Fixes to TTF splitting (patch from Albertas Agejevas)""")
disc("""This affected some documents using font subsetting""", style=indent0_style)
disc("""Tables with spans improved splitting""")
disc("""Splitting of tables across pages did not work correctly when the table had
row/column spans""", style=indent0_style)
disc("""Fix runtime error affecting keepWithNext""")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,513 @@
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/userguide/ch2a_fonts.py
from reportlab.tools.docco.rl_doc_utils import *
from reportlab.lib.codecharts import SingleByteEncodingChart
from reportlab.platypus import Image
import reportlab
heading1("Fonts and encodings")
disc("""
This chapter covers fonts, encodings and Asian language capabilities.
If you are purely concerned with generating PDFs for Western
European languages, you can just read the "Unicode is the default" section
below and skip the rest on a first reading.
We expect this section to grow considerably over time. We
hope that Open Source will enable us to give better support for
more of the world's languages than other tools, and we welcome
feedback and help in this area.
""")
heading2("Unicode and UTF8 are the default input encodings")
disc("""
Starting with reportlab Version 2.0 (May 2006), all text input you
provide to our APIs should be in UTF8 or as Python Unicode objects.
This applies to arguments to canvas.drawString and related APIs,
table cell content, drawing object parameters, and paragraph source
text.
""")
disc("""
We considered making the input encoding configurable or even locale-dependent,
but decided that "explicit is better than implicit".""")
disc("""
This simplifies many things we used to do previously regarding greek
letters, symbols and so on. To display any character, find out its
unicode code point, and make sure the font you are using is able
to display it.""")
disc("""
If you are adapting a ReportLab 1.x application, or reading data from
another source which contains single-byte data (e.g. latin-1 or WinAnsi),
you need to do a conversion into Unicode. The Python codecs package now
includes converters for all the common encodings, including Asian ones.
""")
disc(u"""
If your data is not encoded as UTF8, you will get a UnicodeDecodeError as
soon as you feed in a non-ASCII character. For example, this snippet below is
attempting to read in and print a series of names, including one with a French
accent: ^Marc-Andr\u00e9 Lemburg^. The standard error is quite helpful and tells you
what character it doesn't like:
""")
eg(u"""
>>> from reportlab.pdfgen.canvas import Canvas
>>> c = Canvas('temp.pdf')
>>> y = 700
>>> for line in file('latin_python_gurus.txt','r'):
... c.drawString(100, y, line.strip())
...
Traceback (most recent call last):
...
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 9-11: invalid data
-->\u00e9 L<--emburg
>>>
""")
disc("""
The simplest fix is just to convert your data to unicode, saying which encoding
it comes from, like this:""")
eg("""
>>> for line in file('latin_input.txt','r'):
... uniLine = unicode(line, 'latin-1')
... c.drawString(100, y, uniLine.strip())
>>>
>>> c.save()
""")
heading2("Changing the built-in fonts output encoding")
disc("""
There are still a number of places in the code, including the rl_config
defaultEncoding parameter, and arguments passed to various Font constructors.
These generally relate to the OUTPUT encoding used when we write data in the font
file. This affects which characters are actually available in the font if
you are using Type 1 fonts, since only 256 glyphs can be available at
one time. Unless you have a very specific need for
MacRoman or MacExpert encoding characters, we advise you to ignore
this. By default the standard fonts (Helvetica, Courier, Times Roman)
will offer the glyphs available in Latin-1. If you try to print a non-Latin-1
character using the built-in Helvetica, you'll see a rectangle or blob.
""")
heading2("Using non-standard Type 1 fonts")
disc("""
As discussed in the previous chapter, 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 available to your code and
will be embedded in the PDF document.""")
disc("""
You can use the mechanism described below to include arbitrary
fonts in your documents. Just van Rossum has kindly donated a Type 1
font named <i>LettErrorRobot-Chrome</i> which we may
use for testing and/or documenting purposes (and which you may
use as well). It comes bundled with the ReportLab distribution in the
directory $reportlab/fonts$.
""")
disc("""
Right now font-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 $reportlab/fonts$ directory contains the files
$'LeERC___.AFM'$ and $'LeERC___.PFB'$ that are used as an example
font.
""")
disc("""
In the following example locate the folder containing the test font and
register it for future use with the $pdfmetrics$ module,
after which we can use it like any other standard font.
""")
eg("""
import os
import reportlab
folder = os.path.dirname(reportlab.__file__) + os.sep + 'fonts'
afmFile = os.path.join(folder, 'LeERC___.AFM')
pfbFile = os.path.join(folder, 'LeERC___.PFB')
from reportlab.pdfbase import pdfmetrics
justFace = pdfmetrics.EmbeddedType1Face(afmFile, pfbFile)
faceName = 'LettErrorRobot-Chrome' # pulled from AFM file
pdfmetrics.registerTypeFace(justFace)
justFont = pdfmetrics.Font('LettErrorRobot-Chrome',
faceName,
'WinAnsiEncoding')
pdfmetrics.registerFont(justFont)
canvas.setFont('LettErrorRobot-Chrome', 32)
canvas.drawString(10, 150, 'This should be in')
canvas.drawString(10, 100, 'LettErrorRobot-Chrome')
""")
disc("""
Note that the argument "WinAnsiEncoding" has nothing to do with the input;
it's to say which set of characters within the font file will be active
and available.
""")
illust(examples.customfont1, "Using a very non-standard font")
disc("""
The font's facename comes from the AFM file's $FontName$ field.
In the example above we knew the name in advance, but quite
often the names of font description files are pretty cryptic
and then you might want to retrieve the name from an AFM file
automatically.
When lacking a more sophisticated method you can use some
code as simple as this:
""")
eg("""
class FontNameNotFoundError(Exception):
pass
def findFontName(path):
"Extract a font name from an AFM file."
f = open(path)
found = 0
while not found:
line = f.readline()[:-1]
if not found and line[:16] == 'StartCharMetrics':
raise FontNameNotFoundError, path
if line[:8] == 'FontName':
fontName = line[9:]
found = 1
return fontName
""")
disc("""
In the <i>LettErrorRobot-Chrome</i> example we explicitely specified
the place of the font description files to be loaded.
In general, you'll prefer to store your fonts in some canonic
locations and make the embedding mechanism aware of them.
Using the same configuration mechanism we've already seen at the
beginning of this section we can indicate a default search path
for Type-1 fonts.
""")
disc("""
Unfortunately, there is no reliable standard yet for such
locations (not even on the same platform) and, hence, you might
have to edit the file $reportlab/rl_config.py$ to modify the
value of the $T1SearchPath$ identifier to contain additional
directories. Our own recommendation is to use the ^reportlab/fonts^
folder in development; and to have any needed fonts as packaged parts of
your application in any kind of controlled server deployment. This insulates
you from fonts being installed and uninstalled by other software or system
administrator.
""")
heading3("Warnings about missing glyphs")
disc("""If you specify an encoding, it is generally assumed that
the font designer has provided all the needed glyphs. However,
this is not always true. In the case of our example font,
the letters of the alphabet are present, but many symbols and
accents are missing. The default behaviour is for the font to
print a 'notdef' character - typically a blob, dot or space -
when passed a character it cannot draw. However, you can ask
the library to warn you instead; the code below (executed
before loading a font) will cause warnings to be generated
for any glyphs not in the font when you register it.""")
eg("""
import reportlab.rl_config
reportlab.rl_config.warnOnMissingFontGlyphs = 0
""")
heading2("Standard Single-Byte Font Encodings")
disc("""
This section shows you the glyphs available in the common encodings.
""")
disc("""The code chart below shows the characters in the $WinAnsiEncoding$.
This is the standard encoding on Windows and many Unix systems in America
and Western Europe. It is also knows as Code Page 1252, and is practically
identical to ISO-Latin-1 (it contains one or two extra characters). This
is the default encoding used by the Reportlab PDF Library. It was generated from
a standard routine in $reportlab/lib$, $codecharts.py$,
which can be used to display the contents of fonts. The index numbers
along the edges are in hex.""")
cht1 = SingleByteEncodingChart(encodingName='WinAnsiEncoding',charsPerRow=32, boxSize=12)
illust(lambda canv: cht1.drawOn(canv, 0, 0), "WinAnsi Encoding", cht1.width, cht1.height)
disc("""The code chart below shows the characters in the $MacRomanEncoding$.
as it sounds, this is the standard encoding on Macintosh computers in
America and Western Europe. As usual with non-unicode encodings, the first
128 code points (top 4 rows in this case) are the ASCII standard and agree
with the WinAnsi code chart above; but the bottom 4 rows differ.""")
cht2 = SingleByteEncodingChart(encodingName='MacRomanEncoding',charsPerRow=32, boxSize=12)
illust(lambda canv: cht2.drawOn(canv, 0, 0), "MacRoman Encoding", cht2.width, cht2.height)
disc("""These two encodings are available for the standard fonts (Helvetica,
Times-Roman and Courier and their variants) and will be available for most
commercial fonts including those from Adobe. However, some fonts contain non-
text glyphs and the concept does not really apply. For example, ZapfDingbats
and Symbol can each be treated as having their own encoding.""")
cht3 = SingleByteEncodingChart(faceName='ZapfDingbats',encodingName='ZapfDingbatsEncoding',charsPerRow=32, boxSize=12)
illust(lambda canv: cht3.drawOn(canv, 0, 0), "ZapfDingbats and its one and only encoding", cht3.width, cht3.height)
cht4 = SingleByteEncodingChart(faceName='Symbol',encodingName='SymbolEncoding',charsPerRow=32, boxSize=12)
illust(lambda canv: cht4.drawOn(canv, 0, 0), "Symbol and its one and only encoding", cht4.width, cht4.height)
CPage(5)
heading2("TrueType Font Support")
disc("""
Marius Gedminas ($mgedmin@delfi.lt$) with the help of Viktorija Zaksiene ($vika@pov.lt$)
have contributed support for embedded TrueType fonts. TrueType fonts work in Unicode/UTF8
and are not limited to 256 characters.""")
CPage(3)
disc("""We use <b>$reportlab.pdfbase.ttfonts.TTFont$</b> to create a true type
font object and register using <b>$reportlab.pdfbase.pdfmetrics.registerFont$</b>.
In pdfgen drawing directly to the canvas we can do""")
eg("""
# we know some glyphs are missing, suppress warnings
import reportlab.rl_config
reportlab.rl_config.warnOnMissingFontGlyphs = 0
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
pdfmetrics.registerFont(TTFont('Rina', 'rina.ttf'))
canvas.setFont(Rina, 32)
canvas.drawString(10, 150, "Some text encoded in UTF-8")
canvas.drawString(10, 100, "In the Rina TT Font!")
""")
illust(examples.ttffont1, "Using a the Rina TrueType Font")
disc("""In the above example the true type font object is created using""")
eg("""
TTFont(name,filename)
""")
disc("""so that the ReportLab internal name is given by the first argument and the second argument
is a string(or file like object) denoting the font's TTF file. In Marius' original patch the filename
was supposed to be exactly correct, but we have modified things so that if the filename is relative
then a search for the corresponding file is done in the current directory and then in directories
specified by $reportlab.rl_config.TTFSearchpath$!""")
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.fonts import addMapping
addMapping('Rina', 0, 0, 'Rina')
addMapping('Rina', 0, 1, 'Rina')
addMapping('Rina', 1, 0, 'Rina')
addMapping('Rina', 1, 1, 'Rina')
disc("""Before using the TT Fonts in Platypus we should add a mapping from the family name to the
individual font names that describe the behaviour under the $<b>$ and $<i>$ attributes.""")
eg("""
from reportlab.lib.fonts import addMapping
addMapping('Rina', 0, 0, 'Rina') #normal
addMapping('Rina', 0, 1, 'Rina') #italic
addMapping('Rina', 1, 0, 'Rina') #bold
addMapping('Rina', 1, 1, 'Rina') #italic and bold
""")
disc("""We only have a Rina regular font, no bold or italic, so we must map all to the
same internal fontname. ^&lt;b&gt;^ and ^&lt;i&gt;^ tags may now be used safely, but
have no effect.
After registering and mapping
the Rina font as above we can use paragraph text like""")
parabox2("""<font name="Times-Roman" size="14">This is in Times-Roman</font>
<font name="Rina" color="magenta" size="14">and this is in magenta <b>Rina!</b></font>""","Using TTF fonts in paragraphs")
heading2("Asian Font Support")
disc("""The Reportlab PDF Library aims to expose full support for Asian fonts.
PDF is the first really portable solution for Asian text handling. There are
two main approaches for this: Adobe's Asian Language Packs, or TrueType fonts.
""")
heading3("Asian Language Packs")
disc("""
This approach offers the best performance since nothing needs embedding in the PDF file;
as with the standard fonts, everything is on the reader.""")
disc("""
Adobe makes available add-ons for each main language. In Adobe Reader 6.0 and 7.0, you
will be prompted to download and install these as soon as you try to open a document
using them. In earlier versions, you would see an error message on opening an Asian document
and had to know what to do.
""")
disc("""
Japanese, Traditional Chinese (Taiwan/Hong Kong), Simplified Chinese (mainland China)
and Korean are all supported and our software knows about the following fonts:
""")
bullet("""
$chs$ = Chinese Simplified (mainland): '$STSong-Light$'
""")
bullet("""
$cht$ = Chinese Traditional (Taiwan): '$MSung-Light$', '$MHei-Medium$'
""")
bullet("""
$kor$ = Korean: '$HYSMyeongJoStd-Medium$','$HYGothic-Medium$'
""")
bullet("""
$jpn$ = Japanese: '$HeiseiMin-W3$', '$HeiseiKakuGo-W5$'
""")
disc("""Since many users will not have the font packs installed, we have included
a rather grainy ^bitmap^ of some Japanese characters. We will discuss below what is needed to
generate them.""")
# include a bitmap of some Asian text
I=os.path.join(os.path.dirname(reportlab.__file__),'docs','images','jpnchars.jpg')
try:
getStory().append(Image(I))
except:
disc("""An image should have appeared here.""")
disc("""Prior to Version 2.0, you had to specify one of many native encodings
when registering a CID Font. In version 2.0 you should a new UnicodeCIDFont
class.""")
eg("""
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.cidfonts import UnicodeCIDFont
pdfmetrics.registerFont(UnicodeCIDFont('HeiseiMin-W3'))
canvas.setFont('HeiseiMin-W3', 16)
# the two unicode characters below are "Tokyo"
msg = u'\u6771\u4EAC : Unicode font, unicode input'
canvas.drawString(100, 675, msg)
""")
#had to double-escape the slashes above to get escapes into the PDF
disc("""The old coding style with explicit encodings should still work, but is now
only relevant if you need to construct vertical text. We aim to add more readable options
for horizontal and vertical text to the UnicodeCIDFont constructor in future.
The following four test scripts generate samples in the corresponding languages:""")
eg("""reportlab/test/test_multibyte_jpn.py
reportlab/test/test_multibyte_kor.py
reportlab/test/test_multibyte_chs.py
reportlab/test/test_multibyte_cht.py""")
## put back in when we have vertical text...
##disc("""The illustration below shows part of the first page
##of the Japanese output sample. It shows both horizontal and vertical
##writing, and illustrates the ability to mix variable-width Latin
##characters in Asian sentences. The choice of horizontal and vertical
##writing is determined by the encoding, which ends in 'H' or 'V'.
##Whether an encoding uses fixed-width or variable-width versions
##of Latin characters also depends on the encoding used; see the definitions
##below.""")
##
##Illustration(image("../images/jpn.gif", width=531*0.50,
##height=435*0.50), 'Output from test_multibyte_jpn.py')
##
##caption("""
##Output from test_multibyte_jpn.py
##""")
disc("""In previous versions of the ReportLab PDF Library, we had to make
use of Adobe's CMap files (located near Acrobat Reader if the Asian Language
packs were installed). Now that we only have one encoding to deal with, the
character width data is embedded in the package, and CMap files are not needed
for generation. The CMap search path in ^rl_config.py^ is now deprecated
and has no effect if you restrict yourself to UnicodeCIDFont.
""")
heading3("TrueType fonts with Asian characters")
disc("""
This is the easy way to do it. No special handling at all is needed to
work with Asian TrueType fonts. Windows users who have installed, for example,
Japanese as an option in Control Panel, will have a font "msmincho.ttf" which
can be used. However, be aware that it takes time to parse the fonts, and that
quite large subsets may need to be embedded in your PDFs. We can also now parse
files ending in .ttc, which are a slight variation of .ttf.
""")
heading3("To Do")
disc("""We expect to be developing this area of the package for some time.accept2dyear
Here is an outline of the main priorities. We welcome help!""")
bullet("""
Ensure that we have accurate character metrics for all encodings in horizontal and
vertical writing.""")
bullet("""
Add options to ^UnicodeCIDFont^ to allow vertical and proportional variants where the font permits it.""")
bullet("""
Improve the word wrapping code in paragraphs and allow vertical writing.""")
CPage(5)
heading2("RenderPM tests")
disc("""This may also be the best place to mention the test function of $reportlab/graphics/renderPM.py$,
which can be considered the cannonical place for tests which exercise renderPM (the "PixMap Renderer",
as opposed to renderPDF, renderPS or renderSVG).""")
disc("""If you run this from the command line, you should see lots of output like the following.""")
eg("""C:\\code\\reportlab\\graphics>renderPM.py
wrote pmout\\renderPM0.gif
wrote pmout\\renderPM0.tif
wrote pmout\\renderPM0.png
wrote pmout\\renderPM0.jpg
wrote pmout\\renderPM0.pct
...
wrote pmout\\renderPM12.gif
wrote pmout\\renderPM12.tif
wrote pmout\\renderPM12.png
wrote pmout\\renderPM12.jpg
wrote pmout\\renderPM12.pct
wrote pmout\\index.html""")
disc("""This runs a number of tests progressing from a "Hello World" test, through various tests of
Lines; text strings in a number of sizes, fonts, colours and alignments; the basic shapes; translated
and rotated groups; scaled coordinates; rotated strings; nested groups; anchoring and non-standard fonts.""")
disc("""It creates a subdirectory called $pmout$, writes the image files into it, and writes an
$index.html$ page which makes it easy to refer to all the results.""")
disc("""The font-related tests which you may wish to look at are test #11 ('Text strings in a non-standard font')
and test #12 ('Test Various Fonts').""")
##### FILL THEM IN

View File

@ -0,0 +1,271 @@
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/userguide/ch3_pdffeatures.py
from reportlab.tools.docco.rl_doc_utils import *
heading1("Exposing PDF Special Capabilities")
disc("""PDF provides a number of features to make electronic
document viewing more efficient and comfortable, and
our library exposes a number of these.""")
heading2("Forms")
disc("""The Form feature lets you create a block of graphics and text
once near the start of a PDF file, and then simply refer to it on
subsequent pages. If you are dealing with a run of 5000 repetitive
business forms - for example, one-page invoices or payslips - you
only need to store the backdrop once and simply draw the changing
text on each page. Used correctly, forms can dramatically cut
file size and production time, and apparently even speed things
up on the printer.
""")
disc("""Forms do not need to refer to a whole page; anything which
might be repeated often should be placed in a form.""")
disc("""The example below shows the basic sequence used. A real
program would probably define the forms up front and refer to
them from another location.""")
eg(examples.testforms)
heading2("Links and Destinations")
disc("""PDF supports internal hyperlinks. There is a very wide
range of link types, destination types and events which
can be triggered by a click. At the moment we just
support the basic ability to jump from one part of a document
to another, and to control the zoom level of the window after
the jump. The bookmarkPage method defines a destination that
is the endpoint of a jump.""")
#todo("code example here...")
eg("""
canvas.bookmarkPage(name,
fitType="Fit",
left=None,
top=None,
bottom=None,
right=None,
zoom=None
)
""")
disc("""
By default the $bookmarkPage$ method defines the page itself as the
destination. After jumping to an endpoint defined by bookmarkPage,
the PDF browser will display the whole page, scaling it to fit the
screen:""")
eg("""canvas.bookmarkPage(name)""")
disc("""The $bookmarkPage$ method can be instructed to display the
page in a number of different ways by providing a $fitType$
parameter.""")
eg("")
t = Table([
['fitType','Parameters Required','Meaning'],
['Fit',None,'Entire page fits in window (the default)'],
['FitH','top','Top coord at top of window, width scaled to fit'],
['FitV','left','Left coord at left of window, height scaled to fit'],
['FitR','left bottom right top','Scale window to fit the specified rectangle'],
['XYZ','left top zoom','Fine grained control. If you omit a parameter\nthe PDF browser interprets it as "leave as is"']
])
t.setStyle(TableStyle([
('FONT',(0,0),(-1,1),'Times-Bold',10,12),
('VALIGN',(0,0),(-1,-1),'MIDDLE'),
('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
('BOX', (0,0), (-1,-1), 0.25, colors.black),
]))
getStory().append(t)
caption("""Table <seq template="%(Chapter)s-%(Table+)s"/> - Required attributes for different fit types""")
disc("""
Note : $fitType$ settings are case-sensitive so $fitType="FIT"$ is invalid$
""")
disc("""
Sometimes you want the destination of a jump to be some part of a page.
The $FitR$ fitType allows you to identify a particular rectangle, scaling
the area to fit the entire page.
""")
disc("""
To set the display to a particular x and y coordinate of the page and to
control the zoom directly use fitType="XYZ".
""")
eg("""
canvas.bookmarkPage('my_bookmark',fitType="XYZ",left=0,top=200)
""")
disc("""
This destination is at the leftmost of the page with the top of the screen
at position 200. Because $zoom$ was not set the zoom remains at whatever the
user had it set to.
""")
eg("""
canvas.bookmarkPage('my_bookmark',fitType="XYZ",left=0,top=200,zoom=2)
""")
disc("""This time zoom is set to expand the page 2X its normal size.""")
disc("""
Note : Both $XYZ$ and $FitR$ fitTypes require that their positional parameters
($top, bottom, left, right$) be specified in terms of the default user space.
They ignore any geometric transform in effect in the canvas graphic state.
""")
pencilnote()
disc("""
<i>Note:</i> Two previous bookmark methods are supported but deprecated now
that bookmarkPage is so general. These are $bookmarkHorizontalAbsolute$
and $bookmarkHorizontal$.
""")
heading3("Defining internal links")
eg("""
canvas.linkAbsolute(contents, destinationname, Rect=None, addtopage=1, name=None, **kw)
""")
disc("""
The $linkAbsolute$ method defines a starting point for a jump. When the user
is browsing the generated document using a dynamic viewer (such as Acrobat Reader)
when the mouse is clicked when the pointer is within the rectangle specified
by $Rect$ the viewer will jump to the endpoint associated with $destinationname$.
As in the case with $bookmarkHorizontalAbsolute$ the rectangle $Rect$ must be
specified in terms of the default user space. The $contents$ parameter specifies
a chunk of text which displays in the viewer if the user left-clicks on the region.
""")
disc("""
The rectangle $Rect$ must be specified in terms of a tuple ^(x1,y1,x2,y2)^ identifying
the lower left and upper right points of the rectangle in default user space.
""")
disc("""
For example the code
""")
eg("""
canvas.bookmarkPage("Meaning_of_life")
""")
disc("""
defines a location as the whole of the current page with the identifier
$Meaning_of_life$. To create a rectangular link to it while drawing a possibly
different page, we would use this code:
""")
eg("""
canvas.linkAbsolute("Find the Meaning of Life", "Meaning_of_life",
(inch, inch, 6*inch, 2*inch))
""")
disc("""
By default during interactive viewing a rectangle appears around the
link. Use the keyword argument $Border='[0 0 0]'$ to
suppress the visible rectangle around the during viewing link.
For example
""")
eg("""
canvas.linkAbsolute("Meaning of Life", "Meaning_of_life",
(inch, inch, 6*inch, 2*inch), Border='[0 0 0]')
""")
heading2("Outline Trees")
disc("""Acrobat Reader has a navigation page which can hold a
document outline; it should normally be visible when you
open this guide. We provide some simple methods to add
outline entries. Typically, a program to make a document
(such as this user guide) will call the method
$canvas.addOutlineEntry(^self, title, key, level=0,
closed=None^)$ as it reaches each heading in the document.
""")
disc("""^title^ is the caption which will be displayed in
the left pane. The ^key^ must be a string which is
unique within the document and which names a bookmark,
as with the hyperlinks. The ^level^ is zero - the
uppermost level - unless otherwise specified, and
it is an error to go down more than one level at a time
(for example to follow a level 0 heading by a level 2
heading). Finally, the ^closed^ argument specifies
whether the node in the outline pane is closed
or opened by default.""")
disc("""The snippet below is taken from the document template
that formats this user guide. A central processor looks
at each paragraph in turn, and makes a new outline entry
when a new chapter occurs, taking the chapter heading text
as the caption text. The key is obtained from the
chapter number (not shown here), so Chapter 2 has the
key 'ch2'. The bookmark to which the
outline entry points aims at the whole page, but it could
as easily have been an individual paragraph.
""")
eg("""
#abridged code from our document template
if paragraph.style == 'Heading1':
self.chapter = paragraph.getPlainText()
key = 'ch%d' % self.chapterNo
self.canv.bookmarkPage(key)
self.canv.addOutlineEntry(paragraph.getPlainText(),
key, 0, 0)
""")
heading2("Page Transition Effects")
eg("""
canvas.setPageTransition(self, effectname=None, duration=1,
direction=0,dimension='H',motion='I')
""")
disc("""
The $setPageTransition$ method specifies how one page will be replaced with
the next. By setting the page transition effect to "dissolve" for example
the current page will appear to melt away when it is replaced by the next
page during interactive viewing. These effects are useful in spicing up
slide presentations, among other places.
Please see the reference manual for more detail on how to use this method.
""")
heading2("Internal File Annotations")
eg("""
canvas.setAuthor(name)
canvas.setTitle(title)
canvas.setSubject(subj)
""")
disc("""
These methods have no automatically seen visible effect on the document.
They add internal annotations to the document. These annotations can be
viewed using the "Document Info" menu item of the browser and they also can
be used as a simple standard way of providing basic information about the
document to archiving software which need not parse the entire
file. To find the annotations view the $*.pdf$ output file using a standard
text editor (such as $notepad$ on MS/Windows or $vi$ or $emacs$ on unix) and look
for the string $/Author$ in the file contents.
""")
eg(examples.testannotations)
disc("""
If you want the subject, title, and author to automatically display
in the document when viewed and printed you must paint them onto the
document like any other text.
""")
illust(examples.annotations, "Setting document internal annotations")

View File

@ -0,0 +1,509 @@
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/userguide/ch4_platypus_concepts.py
from reportlab.tools.docco.rl_doc_utils import *
#####################################################################################################3
heading1("PLATYPUS - Page Layout and Typography Using Scripts")
heading2("Design Goals")
disc("""
Platypus stands for &quot;Page Layout and Typography Using Scripts&quot;. It is a high
level page layout library which lets you programmatically create complex
documents with a minimum of effort.
""")
disc("""
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.
""")
disc("""
The overall design of Platypus can be thought of has having
several layers, top down, these are""")
disc("<b>$DocTemplates$</b> the outermost container for the document;")
disc("<b>$PageTemplates$</b> specifications for layouts of pages of various kinds;")
disc("<b>$Frames$</b> specifications of regions in pages that can contain flowing text or graphics.")
disc("""<b>$Flowables$</b> 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).""")
disc("""<b>$pdfgen.Canvas$</b> the lowest level which ultimately receives the painting of the
document from the other layers.""")
illust(examples.doctemplateillustration, "Illustration of DocTemplate structure")
disc("""
The illustration above graphically illustrates the concepts of $DocTemplates$,
$PageTemplates$ and $Flowables$. It is deceptive, however, because each
of the $PageTemplates$ actually may specify the format for any number of pages
(not just one as might be inferred from the diagram).
""")
disc("""
$DocTemplates$ contain one or more $PageTemplates$ each of which contain one or more
$Frames$. $Flowables$ are things which can be <i>flowed</i> into a $Frame$ e.g.
a $Paragraph$ or a $Table$.
""")
disc("""
To use platypus you create a document from a $DocTemplate$ class and pass
a list of $Flowable$s to its $build$ method. The document
$build$ method knows how to process the list of flowables
into something reasonable.
""")
disc("""
Internally the $DocTemplate$ class implements page layout and formatting
using various events. Each of the events has a corresponding handler method
called $handle_XXX$ where $XXX$ is the event name. A typical event is
$frameBegin$ which occurs when the machinery begins to use a frame for the
first time.
""")
disc("""
A Platypus story consists of a sequence of basic elements called $Flowables$
and these elements drive the data driven Platypus formatting engine.
To modify the behavior of the engine
a special kind of flowable, $ActionFlowables$, tell the layout engine to,
for example, skip to the next
column or change to another $PageTemplate$.
""")
heading2("""Getting started""")
disc("""Consider the following code sequence which provides
a very simple "hello world" example for Platypus.""")
eg(examples.platypussetup)
disc("""First we import some constructors, some paragraph styles
and other conveniences from other modules.""")
eg(examples.platypusfirstpage)
disc("""We define the fixed features of the first page of the document
with the function above.""")
eg(examples.platypusnextpage)
disc("""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.
""")
eg(examples.platypusgo)
disc("""
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.
""")
disc("""
To see the output of this example program run the module
$docs/userguide/examples.py$ (from the ReportLab $docs$ distribution)
as a "top level script". The script interpretation $python examples.py$ will
generate the Platypus output $phello.pdf$.
""")
heading2("$Flowables$")
disc("""
$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()$.
""")
disc("""
It should be noted that the $Flowable$ class is an <i>abstract</i> class and is normally
only used as a base class.
""")
k=startKeep()
disc("""
To illustrate the general way in which $Flowables$ are used we show how a derived class $Paragraph$
is used and drawn on a canvas. $Paragraphs$ are so important they will get a whole chapter
to themselves.
""")
eg("""
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Paragraph
from reportlab.pdfgen.canvas import Canvas
styleSheet = getSampleStyleSheet()
style = styleSheet['BodyText']
P=Paragraph('This is a very silly example',style)
canv = Canvas('doc.pdf')
aW = 460 # available width and height
aH = 800
w,h = P.wrap(aW, aH) # find required space
if w<=aW and h<=aH:
P.drawOn(canv,0,aH)
aH = aH - h # reduce the available height
canv.save()
else:
raise ValueError, "Not enough room"
""")
endKeep(k)
heading3("$Flowable$ User Methods")
eg("""
Flowable.draw()
""")
disc("""This will be called to ask the flowable to actually render itself.
The $Flowable$ class does not implement $draw$.
The calling code should ensure that the flowable has an attribute $canv$
which is the $pdfgen.Canvas$ which should be drawn to an that the $Canvas$
is in an appropriate state (as regards translations rotations, etc). Normally
this method will only be called internally by the $drawOn$ method. Derived classes
must implement this method.
""")
eg("""
Flowable.drawOn(canvas,x,y)
""")
disc("""
This is the method which controlling programs use to render the flowable to a particular
canvas. It handles the translation to the canvas coordinate (<i>x</i>,<i>y</i>) and ensuring that
the flowable has a $canv$ attribute so that the
$draw$ method (which is not implemented in the base class) can render in an
absolute coordinate frame.
""")
eg("""
Flowable.wrap(availWidth, availHeight)
""")
disc("""This will be called by the enclosing frame before objects
are asked their size, drawn or whatever. It returns the
size actually used.""")
eg("""
Flowable.split(self, availWidth, availheight):
""")
disc("""This will be called by more sophisticated frames when
wrap fails. Stupid flowables should return [] meaning that they are unable to split.
Clever flowables should split themselves and return a list of flowables. It is up to
the client code to ensure that repeated attempts to split are avoided.
If the space is sufficient the split method should return [self].
Otherwise
the flowable should rearrange itself and return a list $[f0,...]$ of flowables
which will be considered in order. The implemented split method should avoid
changing $self$ as this will allow sophisticated layout mechanisms to do multiple
passes over a list of flowables.
""")
heading2("Guidelines for flowable positioning")
disc("""Two methods, which by default return zero, provide guidance on vertical
spacing of flowables:
""")
eg("""
Flowable.getSpaceAfter(self):
Flowable.getSpaceBefore(self):
""")
disc("""These methods return how much space should follow or precede
the flowable. The space doesn't belong to the flowable itself i.e. the flowable's
$draw$ method shouldn't consider it when rendering. Controlling programs
will use the values returned in determining how much space is required by
a particular flowable in context.
""")
disc("""All flowables have an $hAlign$ property: $('LEFT', 'RIGHT', 'CENTER' or 'CENTRE')$.
For paragraphs, which fill the full width of the frame, this has no effect. For tables,
images or other objects which are less than the width of the frame, this determines their
horizontal placement.
""")
disc("""The chapters which follow will cover the most important
specific types of flowables: Paragraphs and Tables.""")
heading2("Frames")
disc("""
$Frames$ are active containers which are themselves contained in $PageTemplates$.
$Frames$ have a location and size and maintain a concept of remaining drawable
space. The command
""")
eg("""
Frame(x1, y1, width,height, leftPadding=6, bottomPadding=6,
rightPadding=6, topPadding=6, id=None, showBoundary=0)
""")
disc("""creates a $Frame$ instance with lower left hand corner at coordinate $(x1,y1)$
(relative to the canvas at use time) and with dimensions $width$ x $height$. The $Padding$
arguments are positive quantities used to reduce the space available for drawing.
The $id$ argument is an identifier for use at runtime e.g. 'LeftColumn' or 'RightColumn' etc.
If the $showBoundary$ argument is non-zero then the boundary of the frame will get drawn
at run time (this is useful sometimes).
""")
heading3("$Frame$ User Methods")
eg("""
Frame.addFromList(drawlist, canvas)
""")
disc("""consumes $Flowables$ from the front of $drawlist$ until the
frame is full. If it cannot fit one object, raises
an exception.""")
eg("""
Frame.split(flowable,canv)
""")
disc('''Asks the flowable to split using up the available space and return
the list of flowables.
''')
eg("""
Frame.drawBoundary(canvas)
""")
disc("draws the frame boundary as a rectangle (primarily for debugging).")
heading3("Using $Frames$")
disc("""
$Frames$ can be used directly with canvases and flowables to create documents.
The $Frame.addFromList$ method handles the $wrap$ &amp; $drawOn$ calls for you.
You don't need all of the Platypus machinery to get something useful into
PDF.
""")
eg("""
from reportlab.pdfgen.canvas import Canvas
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch
from reportlab.platypus import Paragraph, Frame
styles = getSampleStyleSheet()
styleN = styles['Normal']
styleH = styles['Heading1']
story = []
#add some flowables
story.append(Paragraph("This is a Heading",styleH))
story.append(Paragraph("This is a paragraph in <i>Normal</i> style.",
styleN))
c = Canvas('mydoc.pdf')
f = Frame(inch, inch, 6*inch, 9*inch, showBoundary=1)
f.addFromList(story,c)
c.save()
""")
heading2("Documents and Templates")
disc("""
The $BaseDocTemplate$ class implements the basic machinery for document
formatting. An instance of the class contains a list of one or more
$PageTemplates$ that can be used to describe the layout of information
on a single page. The $build$ method can be used to process
a list of $Flowables$ to produce a <b>PDF</b> document.
""")
CPage(3.0)
heading3("The $BaseDocTemplate$ class")
eg("""
BaseDocTemplate(self, filename,
pagesize=defaultPageSize,
pageTemplates=[],
showBoundary=0,
leftMargin=inch,
rightMargin=inch,
topMargin=inch,
bottomMargin=inch,
allowSplitting=1,
title=None,
author=None,
_pageBreakQuick=1)
""")
disc("""
creates a document template suitable for creating a basic document. It comes with quite a lot
of internal machinery, but no default page templates. The required $filename$ can be a string,
the name of a file to receive the created <b>PDF</b> document; alternatively it
can be an object which has a $write$ method such as a $StringIO$ or $file$ or $socket$.
""")
disc("""
The allowed arguments should be self explanatory, but $showBoundary$ controls whether or
not $Frame$ boundaries are drawn which can be useful for debugging purposes. The
$allowSplitting$ argument determines whether the builtin methods should try to <i>split</i>
individual $Flowables$ across $Frames$. The $_pageBreakQuick$ argument determines whether
an attempt to do a page break should try to end all the frames on the page or not, before ending
the page.
""")
heading4("User $BaseDocTemplate$ Methods")
disc("""These are of direct interest to client programmers
in that they are normally expected to be used.
""")
eg("""
BaseDocTemplate.addPageTemplates(self,pageTemplates)
""")
disc("""
This method is used to add one or a list of $PageTemplates$ to an existing documents.
""")
eg("""
BaseDocTemplate.build(self, flowables, filename=None, canvasmaker=canvas.Canvas)
""")
disc("""
This is the main method which is of interest to the application
programmer. Assuming that the document instance is correctly set up the
$build$ method takes the <i>story</i> in the shape of the list of flowables
(the $flowables$ argument) and loops through the list forcing the flowables
one at a time through the formatting machinery. Effectively this causes
the $BaseDocTemplate$ instance to issue calls to the instance $handle_XXX$ methods
to process the various events.
""")
heading4("User Virtual $BaseDocTemplate$ Methods")
disc("""
These have no semantics at all in the base class. They are intended as pure virtual hooks
into the layout machinery. Creators of immediately derived classes can override these
without worrying about affecting the properties of the layout engine.
""")
eg("""
BaseDocTemplate.afterInit(self)
""")
disc("""
This is called after initialisation of the base class; a derived class could overide
the method to add default $PageTemplates$.
""")
eg("""
BaseDocTemplate.afterPage(self)
""")
disc("""This is called after page processing, and
immediately after the afterDrawPage method
of the current page template. A derived class could
use this to do things which are dependent on information in the page
such as the first and last word on the page of a dictionary.
""")
eg("""
BaseDocTemplate.beforeDocument(self)
""")
disc("""This is called before any processing is
done on the document, but after the processing machinery
is ready. It can therefore be used to do things to the instance\'s
$pdfgen.canvas$ and the like.
""")
eg("""
BaseDocTemplate.beforePage(self)
""")
disc("""This is called at the beginning of page
processing, and immediately before the
beforeDrawPage method of the current page
template. It could be used to reset page specific
information holders.""")
eg("""
BaseDocTemplate.filterFlowables(self,flowables)
""")
disc("""This is called to filter flowables at the start of the main handle_flowable method.
Upon return if flowables[0] has been set to None it is discarded and the main
method returns immediately.
""")
eg("""
BaseDocTemplate.afterFlowable(self, flowable)
""")
disc("""Called after a flowable has been rendered. An interested class could use this
hook to gather information about what information is present on a particular page or frame.""")
heading4("$BaseDocTemplate$ Event handler Methods")
disc("""
These methods constitute the greater part of the layout engine. Programmers shouldn't
have to call or override these methods directly unless they are trying to modify the layout engine.
Of course, the experienced programmer who wants to intervene at a particular event, $XXX$,
which does not correspond to one of the virtual methods can always override and
call the base method from the drived class version. We make this easy by providing
a base class synonym for each of the handler methods with the same name prefixed by an underscore '_'.
""")
eg("""
def handle_pageBegin(self):
doStuff()
BaseDocTemplate.handle_pageBegin(self)
doMoreStuff()
#using the synonym
def handle_pageEnd(self):
doStuff()
self._handle_pageEnd()
doMoreStuff()
""")
disc("""
Here we list the methods only as an indication of the events that are being
handled.
Interested programmers can take a look at the source.
""")
eg("""
handle_currentFrame(self,fx)
handle_documentBegin(self)
handle_flowable(self,flowables)
handle_frameBegin(self,*args)
handle_frameEnd(self)
handle_nextFrame(self,fx)
handle_nextPageTemplate(self,pt)
handle_pageBegin(self)
handle_pageBreak(self)
handle_pageEnd(self)
""")
disc("""
Using document templates can be very easy; $SimpleDoctemplate$ is a class derived from
$BaseDocTemplate$ which provides its own $PageTemplate$ and $Frame$ setup.
""")
eg("""
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.pagesizes import letter
from reportlab.platypus import Paragraph, SimpleDocTemplate
styles = getSampleStyleSheet()
styleN = styles['Normal']
styleH = styles['Heading1']
story = []
#add some flowables
story.append(Paragraph("This is a Heading",styleH))
story.append(Paragraph("This is a paragraph in <i>Normal</i> style.",
styleN))
doc = SimpleDocTemplate('mydoc.pdf',pagesize = letter)
doc.build(story)
""")
heading3("$PageTemplates$")
disc("""
The $PageTemplate$ class is a container class with fairly minimal semantics. Each instance
contains a list of $Frames$ and has methods which should be called at the start and end
of each page.
""")
eg("PageTemplate(id=None,frames=[],onPage=_doNothing,onPageEnd=_doNothing)")
disc("""
is used to initialize an instance, the $frames$ argument should be a list of $Frames$
whilst the optional $onPage$ and $onPageEnd$ arguments are callables which should have signature
$def XXX(canvas,document)$ where $canvas$ and $document$
are the canvas and document being drawn. These routines are intended to be used to paint non-flowing (i.e. standard)
parts of pages. These attribute functions are exactly parallel to the pure virtual methods
$PageTemplate.beforPage$ and $PageTemplate.afterPage$ which have signature
$beforPage(self,canvas,document)$. The methods allow class derivation to be used to define
standard behaviour, whilst the attributes allow instance changes. The $id$ argument is used at
run time to perform $PageTemplate$ switching so $id='FirstPage'$ or $id='TwoColumns'$ are typical.
""")

View File

@ -0,0 +1,319 @@
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/userguide/ch5_paragraphs.py
from reportlab.tools.docco.rl_doc_utils import *
#begin chapter oon paragraphs
heading1("Paragraphs")
disc("""
The $reportlab.platypus.Paragraph$ class is one of the most useful of the Platypus $Flowables$;
it can format fairly arbitrary text and provides for inline font style and colour changes using
an XML style markup. The overall shape of the formatted text can be justified, right or left ragged
or centered. The XML markup can even be used to insert greek characters or to do subscripts.
""")
disc("""The following text creates an instance of the $Paragraph$ class:""")
eg("""Paragraph(text, style, bulletText=None)""")
disc("""The $text$ argument contains the text of the
paragraph; excess white space is removed from the text at the ends and internally after
linefeeds. This allows easy use of indented triple quoted text in <b>Python</b> scripts.
The $bulletText$ argument provides the text of a default bullet for the paragraph.
The font and other properties for the paragraph text and bullet are set using the style argument.
""")
disc("""
The $style$ argument should be an instance of class $ParagraphStyle$ obtained typically
using""")
eg("""
from reportlab.lib.styles import ParagraphStyle
""")
disc("""
this container class provides for the setting of multiple default paragraph attributes
in a structured way. The styles are arranged in a dictionary style object called a $stylesheet$
which allows for the styles to be accessed as $stylesheet['BodyText']$. A sample style
sheet is provided.
""")
eg("""
from reportlab.lib.styles import getSampleStyleSheet
stylesheet=getSampleStyleSheet()
normalStyle = stylesheet['Normal']
""")
disc("""
The options which can be set for a $Paragraph$ can be seen from the $ParagraphStyle$ defaults.
""")
heading4("$class ParagraphStyle$")
eg("""
class ParagraphStyle(PropertySet):
defaults = {
'fontName':'Times-Roman',
'fontSize':10,
'leading':12,
'leftIndent':0,
'rightIndent':0,
'firstLineIndent':0,
'alignment':TA_LEFT,
'spaceBefore':0,
'spaceAfter':0,
'bulletFontName':'Times-Roman',
'bulletFontSize':10,
'bulletIndent':0,
'textColor': black
}
""")
heading2("Using Paragraph Styles")
#this will be used in the ParaBox demos.
sample = """You are hereby charged that on the 28th day of May, 1970, you did
willfully, unlawfully, and with malice of forethought, publish an
alleged English-Hungarian phrase book with intent to cause a breach
of the peace. How do you plead?"""
disc("""The $Paragraph$ and $ParagraphStyle$ classes together
handle most common formatting needs. The following examples
draw paragraphs in various styles, and add a bounding box
so that you can see exactly what space is taken up.""")
s1 = ParagraphStyle('Normal')
parabox(sample, s1, 'The default $ParagraphStyle$')
disc("""The two attributes $spaceBefore$ and $spaceAfter$ do what they
say, except at the top or bottom of a frame. At the top of a frame,
$spaceBefore$ is ignored, and at the bottom, $spaceAfter$ is ignored.
This means that you could specify that a 'Heading2' style had two
inches of space before when it occurs in mid-page, but will not
get acres of whitespace at the top of a page. These two attributes
should be thought of as 'requests' to the Frame and are not part
of the space occupied by the Paragraph itself.""")
disc("""The $fontSize$ and $fontName$ tags are obvious, but it is
important to set the $leading$. This is the spacing between
adjacent lines of text; a good rule of thumb is to make this
20% larger than the point size. To get double-spaced text,
use a high $leading$.""")
disc("""The figure below shows space before and after and an
increased leading:""")
parabox(sample,
ParagraphStyle('Spaced',
spaceBefore=6,
spaceAfter=6,
leading=16),
'Space before and after and increased leading'
)
disc("""The $leftIndent$ and $rightIndent$ attributes do exactly
what you would expect; $firstLineIndent$ is added to the $leftIndent$ of the
first line. If you want a straight left edge, remember
to set $firstLineIndent$ equal to 0.""")
parabox(sample,
ParagraphStyle('indented',
firstLineIndent=+24,
leftIndent=24,
rightIndent=24),
'one third inch indents at left and right, two thirds on first line'
)
disc("""Setting $firstLineIndent$ equal to a negative number, $leftIndent$
much higher, and using a
different font (we'll show you how later!) can give you a
definition list:.""")
parabox('<b><i>Judge Pickles: </i></b>' + sample,
ParagraphStyle('dl',
leftIndent=36),
'Definition Lists'
)
disc("""There are four possible values of $alignment$, defined as
constants in the module <i>reportlab.lib.enums</i>. These are
TA_LEFT, TA_CENTER or TA_CENTRE, TA_RIGHT and
TA_JUSTIFY, with values of 0, 1, 2 and 4 respectively. These
do exactly what you would expect.""")
heading2("Paragraph XML Markup Tags")
disc("""XML markup can be used to modify or specify the
overall paragraph style, and also to specify intra-
paragraph markup.""")
heading3("The outermost &lt; para &gt; tag")
disc("""
The paragraph text may optionally be surrounded by
&lt;para attributes....&gt;
&lt;/para&gt;
tags. The attributes if any of the opening &lt;para&gt; tag affect the style that is used
with the $Paragraph$ $text$ and/or $bulletText$.
""")
disc(" ")
from reportlab.platypus.paraparser import _addAttributeNames, _paraAttrMap, _bulletAttrMap
def getAttrs(A):
_addAttributeNames(A)
S={}
for k, v in A.items():
a = v[0]
if not S.has_key(a):
S[a] = k
else:
S[a] = "%s, %s" %(S[a],k)
K = S.keys()
K.sort()
D=[('Attribute','Synonyms')]
for k in K:
D.append((k,S[k]))
cols=2*[None]
rows=len(D)*[None]
return D,cols,rows
t=apply(Table,getAttrs(_paraAttrMap))
t.setStyle(TableStyle([
('FONT',(0,0),(-1,1),'Times-Bold',10,12),
('FONT',(0,1),(-1,-1),'Courier',8,8),
('VALIGN',(0,0),(-1,-1),'MIDDLE'),
('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
('BOX', (0,0), (-1,-1), 0.25, colors.black),
]))
getStory().append(t)
caption("""Table <seq template="%(Chapter)s-%(Table+)s"/> - Synonyms for style attributes""")
disc("""Some useful synonyms have been provided for our Python attribute
names, including lowercase versions, and the equivalent properties
from the HTML standard where they exist. These additions make
it much easier to build XML-printing applications, since
much intra-paragraph markup may not need translating. The
table below shows the allowed attributes and synonyms in the
outermost paragraph tag.""")
heading2("Intra-paragraph markup")
disc("""'<![CDATA[Within each paragraph, we use a basic set of XML tags
to provide markup. The most basic of these are bold (<b>...</b>)
and italic (<i>...</i>). It is also legal to use an underline
tag (<u>...</u> but it has no effect; PostScript fonts don't
support underlining, and neither do we, yet.]]>""")
parabox2("""<b>You are hereby charged</b> that on the 28th day of May, 1970, you did
willfully, unlawfully, and <i>with malice of forethought</i>, publish an
alleged English-Hungarian phrase book with intent to cause a breach
of the peace. <u>How do you plead</u>?""", "Simple bold and italic tags")
heading3("The $&lt;font&gt;$ tag")
disc("""The $&lt;font&gt;$ tag can be used to change the font name,
size and text color for any substring within the paragraph.
Legal attributes are $size$, $face$, $name$ (which is the same as $face$),
$color$, and $fg$ (which is the same as $color$). The $name$ is
the font family name, without any 'bold' or 'italic' suffixes.
Colors may be
HTML color names or a hex string encoded in a variety of ways;
see ^reportlab.lib.colors^ for the formats allowed.""")
parabox2("""<font face="times" color="red">
You are hereby charged</font> that on the 28th day of May, 1970, you did
willfully, unlawfully, and <font size=14>with malice of forethought</font>,
publish an
alleged English-Hungarian phrase book with intent to cause a breach
of the peace. How do you plead?""", "The $font$ tag")
heading3("Superscripts and Subscripts")
disc("""Superscripts and subscripts are supported with the
<![CDATA[<super> and <sub> tags, which work exactly
as you might expect. In addition, most greek letters
can be accessed by using the <greek></greek>
tag, or with mathML entity names.]]>""")
##parabox2("""<greek>epsilon</greek><super><greek>iota</greek>
##<greek>pi</greek></super> = -1""", "Greek letters and subscripts")
parabox2("""Equation (&alpha;): <greek>e</greek> <super><greek>ip</greek></super> = -1""",
"Greek letters and superscripts")
heading3("Numbering Paragraphs and Lists")
disc("""The $&lt;seq&gt;$ tag provides comprehensive support
for numbering lists, chapter headings and so on. It acts as
an interface to the $Sequencer$ class in ^reportlab.lib.sequencer^.
These are used to number headings and figures throughout this
document.
You may create as many separate 'counters' as you wish, accessed
with the $id$ attribute; these will be incremented by one each
time they are accessed. The $seqreset$ tag resets a counter.
If you want it to resume from a number other than 1, use
the syntax &lt;seqreset id="mycounter" base="42"&gt;.
Let's have a go:""")
parabox2("""<seq id="spam"/>, <seq id="spam"/>, <seq id="spam"/>.
Reset<seqreset id="spam"/>. <seq id="spam"/>, <seq id="spam"/>,
<seq id="spam"/>.""", "Basic sequences")
disc("""You can save specifying an ID by designating a counter ID
as the <i>default</i> using the &lt;seqdefault id="Counter"&gt;
tag; it will then be used whenever a counter ID
is not specified. This saves some typing, especially when
doing multi-level lists; you just change counter ID when
stepping in or out a level.""")
parabox2("""<seqdefault id="spam"/>Continued... <seq/>,
<seq/>, <seq/>, <seq/>, <seq/>, <seq/>, <seq/>.""",
"The default sequence")
disc("""Finally, one can access multi-level sequences using
a variation of Python string formatting and the $template$
attribute in a &lt;seq&gt; tags. This is used to do the
captions in all of the figures, as well as the level two
headings. The substring $%(counter)s$ extracts the current
value of a counter without incrementing it; appending a
plus sign as in $%(counter)s$ increments the counter.
The figure captions use a pattern like the one below:""")
parabox2("""Figure <seq template="%(Chapter)s-%(FigureNo+)s"/> - Multi-level templates""",
"Multi-level templates")
disc("""We cheated a little - the real document used 'Figure',
but the text above uses 'FigureNo' - otherwise we would have
messed up our numbering!""")
heading2("Bullets and Paragraph Numbering")
disc("""In addition to the three indent properties, some other
parameters are needed to correctly handle bulleted and numbered
lists. We discuss this here because you have now seen how
to handle numbering. A paragraph may have an optional
^bulletText^ argument passed to its constructor; alternatively,
bullet text may be placed in a $<![CDATA[<bullet>..</bullet>]]>$
tag at its head. The text will be drawn on the first line of
the paragraph, with its x origin determined by the $bulletIndent$
attribute of the style, and in the font given in the
$bulletFontName$ attribute. For genuine bullets, a good
idea is to select the Times-Roman font in the style, and
use a character such as $\\xe2\\x80\\xa2)$:""")
t=apply(Table,getAttrs(_bulletAttrMap))
t.setStyle([
('FONT',(0,0),(-1,1),'Times-Bold',10,12),
('FONT',(0,1),(-1,-1),'Courier',8,8),
('VALIGN',(0,0),(-1,-1),'MIDDLE'),
('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
('BOX', (0,0), (-1,-1), 0.25, colors.black),
])
getStory().append(t)
caption("""Table <seq template="%(Chapter)s-%(Table+)s"/> - &lt;bullet&gt; attributes &amp; synonyms""")
disc("""The &lt;bullet&gt; tag is only allowed once in a given paragraph and its use
overrides the implied bullet style and ^bulletText^ specified in the ^Paragraph^
creation.
""")
parabox("""<bullet>\xe2\x80\xa2</bullet>this is a bullet point. Spam
spam spam spam spam spam spam spam spam spam spam spam
spam spam spam spam spam spam spam spam spam spam """,
styleSheet['Bullet'],
'Basic use of bullet points')
disc("""Exactly the same technique is used for numbers,
except that a sequence tag is used. It is also possible
to put a multi-character string in the bullet; with a deep
indent and bold bullet font, you can make a compact
definition list.""")

View File

@ -0,0 +1,419 @@
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/userguide/ch6_tables.py
from reportlab.tools.docco.rl_doc_utils import *
from reportlab.platypus import Image
import reportlab
heading1("Tables and TableStyles")
disc("""
The $Table$ and $LongTable$ classes derive from the $Flowable$ class and are intended
as a simple textual gridding mechanisms. The $longTable$ class uses a greedy algorithm
when calculating column widths and is intended for long tables where speed counts.
$Table$ cells can hold anything which can be converted to
a <b>Python</b> $string$ or $Flowables$ (or lists of $Flowables$).
""")
disc("""
Our present tables are a trade-off between efficient drawing and specification
and functionality. We assume the reader has some familiarity with HTML tables.
In brief, they have the following characteristics:
""")
bullet("""They can contain anything convertible to a string; flowable
objects such as other tables; or entire sub-stories""")
bullet("""They can work out the row heights to fit the data if you don't supply
the row height. (They can also work out the widths, but generally it is better
for a designer to set the width manually, and it draws faster).""")
bullet("""They can split across pages if needed (see the canSplit attribute).
You can specify that a number of rows at the top and bottom should be
repeated after the split (e.g. show the headers again on page 2,3,4...)""")
bullet("""For very wide tables, they can also split 'by column'. You can choose
whether tou want to split down-and-across or across-and-down""")
bullet("""They have a simple and powerful notation for specifying shading and
gridlines which works well with financial or database tables, where you
don't know the number of rows up front. You can easily say 'make the last row
bold and put a line above it'""")
bullet("""The style and data are separated, so you can declare a handful of table
styles and use them for a family of reports. Styes can also 'inherit', as with
paragraphs.""")
disc("""There is however one main limitation compared to an HTML table.
They define a simple rectangular grid. There is no simple row or column
spanning; if you need to span cells, you must nest tables inside table cells instead or use a more
complex scheme in which the lead cell of a span contains the actual contents.""")
disc("""
$Tables$ are created by passing the constructor an optional sequence of column widths,
an optional sequence of row heights, and the data in row order.
Drawing of the table can be controlled by using a $TableStyle$ instance. This allows control of the
color and weight of the lines (if any), and the font, alignment and padding of the text.
A primitive automatic row height and or column width calculation mechanism is provided for.
""")
heading2('$Table$ User Methods')
disc("""These are the main methods which are of interest to the client programmer.""")
heading4("""$Table(data, colWidths=None, rowHeights=None, style=None, splitByRow=1,
repeatRows=0, repeatCols=0)$""")
disc("""The $data$ argument is a sequence of sequences of cell values each of which
should be convertible to a string value using the $str$ function or should be a Flowable instance (such as a $Paragraph$) or a list (or tuple) of such instances.
If a cell value is a $Flowable$ or list of $Flowables$ these must either have a determined width
or the containing column must have a fixed width.
The first row of cell values
is in $data[0]$ i.e. the values are in row order. The $i$, $j$<sup>th.</sup> cell value is in
$data[i][j]$. Newline characters $'\\n'$ in cell values are treated as line split characters and
are used at <i>draw</i> time to format the cell into lines.
""")
disc("""The other arguments are fairly obvious, the $colWidths$ argument is a sequence
of numbers or possibly $None$, representing the widths of the columns. The number of elements
in $colWidths$ determines the number of columns in the table.
A value of $None$ means that the corresponding column width should be calculated automatically.""")
disc("""The $rowHeights$ argument is a sequence
of numbers or possibly $None$, representing the heights of the rows. The number of elements
in $rowHeights$ determines the number of rows in the table.
A value of $None$ means that the corresponding row height should be calculated automatically.""")
disc("""The $style$ argument can be an initial style for the table.""")
disc("""The $splitByRow$ argument is only needed for tables both too tall and too wide
to fit in the current context. In this case you must decide whether to 'tile'
down and across, or across and then down. This parameter is a Boolean indicating that the
$Table$ should split itself
by row before attempting to split itself by column when too little space is available in
the current drawing area and the caller wants the $Table$ to split.""")
disc("""The $repeatRows$ and $repeatCols$ arguments specify the number of leading rows and columns
that should be repeated when the $Table$ is asked to split itself.""")
heading4('$Table.setStyle(tblStyle)$')
disc("""
This method applies a particular instance of class $TableStyle$ (discussed below)
to the $Table$ instance. This is the only way to get $tables$ to appear
in a nicely formatted way.
""")
disc("""
Successive uses of the $setStyle$ method apply the styles in an additive fashion.
That is, later applications override earlier ones where they overlap.
""")
heading2('$TableStyle$')
disc("""
This class is created by passing it a sequence of <i>commands</i>, each command
is a tuple identified by its first element which is a string; the remaining
elements of the command tuple represent the start and stop cell coordinates
of the command and possibly thickness and colors, etc.
""")
heading2("$TableStyle$ User Methods")
heading3("$TableStyle(commandSequence)$")
disc("""The creation method initializes the $TableStyle$ with the argument
command sequence as an example:""")
eg("""
LIST_STYLE = TableStyle(
[('LINEABOVE', (0,0), (-1,0), 2, colors.green),
('LINEABOVE', (0,1), (-1,-1), 0.25, colors.black),
('LINEBELOW', (0,-1), (-1,-1), 2, colors.green),
('ALIGN', (1,1), (-1,-1), 'RIGHT')]
)
""")
heading3("$TableStyle.add(commandSequence)$")
disc("""This method allows you to add commands to an existing
$TableStyle$, i.e. you can build up $TableStyles$ in multiple statements.
""")
eg("""
LIST_STYLE.add('BACKGROUND', (0,0), (-1,0), colors.Color(0,0.7,0.7))
""")
heading3("$TableStyle.getCommands()$")
disc("""This method returns the sequence of commands of the instance.""")
eg("""
cmds = LIST_STYLE.getCommands()
""")
heading2("$TableStyle$ Commands")
disc("""The commands passed to $TableStyles$ come in three main groups
which affect the table background, draw lines, or set cell styles.
""")
disc("""The first element of each command is its identifier,
the second and third arguments determine the cell coordinates of
the box of cells which are affected with negative coordinates
counting backwards from the limit values as in <b>Python</b>
indexing. The coordinates are given as
(column, row) which follows the spreadsheet 'A1' model, but not
the more natural (for mathematicians) 'RC' ordering.
The top left cell is (0, 0) the bottom right is (-1, -1). Depending on
the command various extra (???) occur at indices beginning at 3 on.
""")
heading3("""$TableStyle$ Cell Formatting Commands""")
disc("""The cell formatting commands all begin with an identifier, followed by
the start and stop cell definitions and the perhaps other arguments.
the cell formatting commands are:""")
eg("""
FONT - takes fontname, optional fontsize and optional leading.
FONTNAME (or FACE) - takes fontname.
FONTSIZE (or SIZE) - takes fontsize in points; leading may get out of sync.
LEADING - takes leading in points.
TEXTCOLOR - takes a color name or (R,G,B) tuple.
ALIGNMENT (or ALIGN) - takes one of LEFT, RIGHT and CENTRE (or CENTER) or DECIMAL.
LEFTPADDING - takes an integer, defaults to 6.
RIGHTPADDING - takes an integer, defaults to 6.
BOTTOMPADDING - takes an integer, defaults to 3.
TOPPADDING - takes an integer, defaults to 3.
BACKGROUND - takes a color.
ROWBACKGROUNDS - takes a list of colors to be used cyclically.
COLBACKGROUNDS - takes a list of colors to be used cyclically.
VALIGN - takes one of TOP, MIDDLE or the default BOTTOM
""")
disc("""This sets the background cell color in the relevant cells.
The following example shows the $BACKGROUND$, and $TEXTCOLOR$ commands in action:""")
EmbeddedCode("""
data= [['00', '01', '02', '03', '04'],
['10', '11', '12', '13', '14'],
['20', '21', '22', '23', '24'],
['30', '31', '32', '33', '34']]
t=Table(data)
t.setStyle(TableStyle([('BACKGROUND',(1,1),(-2,-2),colors.green),
('TEXTCOLOR',(0,0),(1,-1),colors.red)]))
""")
disc("""To see the effects of the alignment styles we need some widths
and a grid, but it should be easy to see where the styles come from.""")
EmbeddedCode("""
data= [['00', '01', '02', '03', '04'],
['10', '11', '12', '13', '14'],
['20', '21', '22', '23', '24'],
['30', '31', '32', '33', '34']]
t=Table(data,5*[0.4*inch], 4*[0.4*inch])
t.setStyle(TableStyle([('ALIGN',(1,1),(-2,-2),'RIGHT'),
('TEXTCOLOR',(1,1),(-2,-2),colors.red),
('VALIGN',(0,0),(0,-1),'TOP'),
('TEXTCOLOR',(0,0),(0,-1),colors.blue),
('ALIGN',(0,-1),(-1,-1),'CENTER'),
('VALIGN',(0,-1),(-1,-1),'MIDDLE'),
('TEXTCOLOR',(0,-1),(-1,-1),colors.green),
('INNERGRID', (0,0), (-1,-1), 0.25, colors.black),
('BOX', (0,0), (-1,-1), 0.25, colors.black),
]))
""")
heading3("""$TableStyle$ Line Commands""")
disc("""
Line commands begin with the identifier, the start and stop cell coordinates
and always follow this with the thickness (in points) and color of the desired lines. Colors can be names,
or they can be specified as a (R, G, B) tuple, where R, G and B are floats and (0, 0, 0) is black. The line
command names are: GRID, BOX, OUTLINE, INNERGRID, LINEBELOW, LINEABOVE, LINEBEFORE
and LINEAFTER. BOX and OUTLINE are equivalent, and GRID is the equivalent of applying both BOX and
INNERGRID.
""")
CPage(4.0)
disc("""We can see some line commands in action with the following example.
""")
EmbeddedCode("""
data= [['00', '01', '02', '03', '04'],
['10', '11', '12', '13', '14'],
['20', '21', '22', '23', '24'],
['30', '31', '32', '33', '34']]
t=Table(data,style=[('GRID',(1,1),(-2,-2),1,colors.green),
('BOX',(0,0),(1,-1),2,colors.red),
('LINEABOVE',(1,2),(-2,2),1,colors.blue),
('LINEBEFORE',(2,1),(2,-2),1,colors.pink),
])
""")
disc("""Line commands cause problems for tables when they split; the following example
shows a table being split in various positions""")
EmbeddedCode("""
data= [['00', '01', '02', '03', '04'],
['10', '11', '12', '13', '14'],
['20', '21', '22', '23', '24'],
['30', '31', '32', '33', '34']]
t=Table(data,style=[
('GRID',(0,0),(-1,-1),0.5,colors.grey),
('GRID',(1,1),(-2,-2),1,colors.green),
('BOX',(0,0),(1,-1),2,colors.red),
('BOX',(0,0),(-1,-1),2,colors.black),
('LINEABOVE',(1,2),(-2,2),1,colors.blue),
('LINEBEFORE',(2,1),(2,-2),1,colors.pink),
('BACKGROUND', (0, 0), (0, 1), colors.pink),
('BACKGROUND', (1, 1), (1, 2), colors.lavender),
('BACKGROUND', (2, 2), (2, 3), colors.orange),
])
""")
t=getStory()[-1]
getStory().append(Spacer(0,6))
for s in t.split(4*inch,30):
getStory().append(s)
getStory().append(Spacer(0,6))
getStory().append(Spacer(0,6))
for s in t.split(4*inch,36):
getStory().append(s)
getStory().append(Spacer(0,6))
disc("""When unsplit and split at the first or second row.""")
CPage(4.0)
heading3("""Complex Cell Values""")
disc("""
As mentioned above we can have complicated cell values including $Paragraphs$, $Images$ and other $Flowables$
or lists of the same. To see this in operation consider the following code and the table it produces.
Note that the $Image$ has a white background which will obscure any background you choose for the cell.
To get better results you should use a transparent background.
""")
import os, reportlab.platypus
I = '../images/replogo.gif'
EmbeddedCode("""
I = Image('%s')
I.drawHeight = 1.25*inch*I.drawHeight / I.drawWidth
I.drawWidth = 1.25*inch
P0 = Paragraph('''
<b>A pa<font color=red>r</font>a<i>graph</i></b>
<super><font color=yellow>1</font></super>''',
styleSheet["BodyText"])
P = Paragraph('''
<para align=center spaceb=3>The <b>ReportLab Left
<font color=red>Logo</font></b>
Image</para>''',
styleSheet["BodyText"])
data= [['A', 'B', 'C', P0, 'D'],
['00', '01', '02', [I,P], '04'],
['10', '11', '12', [P,I], '14'],
['20', '21', '22', '23', '24'],
['30', '31', '32', '33', '34']]
t=Table(data,style=[('GRID',(1,1),(-2,-2),1,colors.green),
('BOX',(0,0),(1,-1),2,colors.red),
('LINEABOVE',(1,2),(-2,2),1,colors.blue),
('LINEBEFORE',(2,1),(2,-2),1,colors.pink),
('BACKGROUND', (0, 0), (0, 1), colors.pink),
('BACKGROUND', (1, 1), (1, 2), colors.lavender),
('BACKGROUND', (2, 2), (2, 3), colors.orange),
('BOX',(0,0),(-1,-1),2,colors.black),
('GRID',(0,0),(-1,-1),0.5,colors.black),
('VALIGN',(3,0),(3,0),'BOTTOM'),
('BACKGROUND',(3,0),(3,0),colors.limegreen),
('BACKGROUND',(3,1),(3,1),colors.khaki),
('ALIGN',(3,1),(3,1),'CENTER'),
('BACKGROUND',(3,2),(3,2),colors.beige),
('ALIGN',(3,2),(3,2),'LEFT'),
])
t._argW[3]=1.5*inch
"""%I)
heading3("""$TableStyle$ Span Commands""")
disc("""Our $Table$ classes support the concept of spanning, but it isn't specified in the same way
as html. The style specification
""")
eg("""
SPAN, (sc,sr), (ec,er)
""")
disc("""indicates that the cells in columns $sc$ - $ec$ and rows $sr$ - $er$ should be combined into a super cell
with contents determined by the cell $(sc, sr)$. The other cells should be present, but should contain empty strings
or you may get unexpected results.
""")
EmbeddedCode("""
data= [['Top\\nLeft', '', '02', '03', '04'],
['', '', '12', '13', '14'],
['20', '21', '22', 'Bottom\\nRight', ''],
['30', '31', '32', '', '']]
t=Table(data,style=[
('GRID',(0,0),(-1,-1),0.5,colors.grey),
('BACKGROUND',(0,0),(1,1),colors.palegreen),
('SPAN',(0,0),(1,1)),
('BACKGROUND',(-2,-2),(-1,-1), colors.pink),
('SPAN',(-2,-2),(-1,-1)),
])
""")
disc("""notice that we don't need to be conservative with our $GRID$ command. The spanned cells are not drawn through.
""")
heading3("""Special $TableStyle$ Indeces""")
disc("""In any style command the first row index may be set to one of the special strings
$'splitlast'$ or $'splitfirst'$ to indicate that the style should be used only for the last row of
a split table, or the first row of a continuation. This allows splitting tables with nicer effects around the split.""")
heading1("""Other Useful $Flowables$""")
heading2("""$Preformatted(text, style, bulletText = None, dedent=0)$""")
disc("""
Creates a preformatted paragraph which does no wrapping, line splitting or other manipulations.
No $XML$ style tags are taken account of in the text.
If dedent is non zero $dedent$ common leading
spaces will be removed from the front of each line.
""")
heading2("""$XPreformatted(text, style, bulletText = None, dedent=0, frags=None)$""")
disc("""
This is a non rearranging form of the $Paragraph$ class; $XML$ tags are allowed in
$text$ and have the same meanings as for the $Paragraph$ class.
As for $Preformatted$, if dedent is non zero $dedent$ common leading
spaces will be removed from the front of each line.
""")
EmbeddedCode("""
from reportlab.lib.styles import getSampleStyleSheet
stylesheet=getSampleStyleSheet()
normalStyle = stylesheet['Normal']
text='''
This is a non rearranging form of the <b>Paragraph</b> class;
<b><font color=red>XML</font></b> tags are allowed in <i>text</i> and have the same
meanings as for the <b>Paragraph</b> class.
As for <b>Preformatted</b>, if dedent is non zero <font color=red size=+1>dedent</font>
common leading spaces will be removed from the
front of each line.
You can have &amp;amp; style entities as well for &amp; &lt; &gt; and &quot;.
'''
t=XPreformatted(text,normalStyle,dedent=3)
""")
heading2("""$Image(filename, width=None, height=None)$""")
disc("""Create a flowable which will contain the image defined by the data in file $filename$.
The default <b>PDF</b> image type <i>jpeg</i> is supported and if the <b>PIL</b> extension to <b>Python</b>
is installed the other image types can also be handled. If $width$ and or $height$ are specified
then they determine the dimension of the displayed image in <i>points</i>. If either dimension is
not specified (or specified as $None$) then the corresponding pixel dimension of the image is assumed
to be in <i>points</i> and used.
""")
I=os.path.join(os.path.dirname(reportlab.__file__),'docs','images','lj8100.jpg')
eg("""
Image("lj8100.jpg")
""",after=0.1)
disc("""will display as""")
try:
getStory().append(Image(I))
except:
disc("""An image should have appeared here.""")
disc("""whereas""")
eg("""
im = Image("lj8100.jpg", width=2*inch, height=2*inch)
im.hAlign = 'CENTER'
""", after=0.1)
disc('produces')
try:
im = Image(I, width=2*inch, height=2*inch)
im.hAlign = 'CENTER'
getStory().append(Image(I, width=2*inch, height=2*inch))
except:
disc("""An image should have appeared here.""")
heading2("""$Spacer(width, height)$""")
disc("""This does exactly as would be expected; it adds a certain amount of space into the story.
At present this only works for vertical space.
""")
CPage(1)
heading2("""$PageBreak()$""")
disc("""This $Flowable$ represents a page break. It works by effectively consuming all vertical
space given to it. This is sufficient for a single $Frame$ document, but would only be a
frame break for multiple frames so the $BaseDocTemplate$ mechanism
detects $pageBreaks$ internally and handles them specially.
""")
CPage(1)
heading2("""$CondPageBreak(height)$""")
disc("""This $Flowable$ attempts to force a $Frame$ break if insufficient vertical space remains
in the current $Frame$. It is thus probably wrongly named and should probably be renamed as
$CondFrameBreak$.
""")
CPage(1)
heading2("""$KeepTogether(flowables)$""")
disc("""
This compound $Flowable$ takes a list of $Flowables$ and attempts to keep them in the same $Frame$.
If the total height of the $Flowables$ in the list $flowables$ exceeds the current frame's available
space then all the space is used and a frame break is forced.
""")

View File

@ -0,0 +1,81 @@
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/userguide/ch7_custom.py
from reportlab.tools.docco.rl_doc_utils import *
heading1("Writing your own $Flowable$ Objects")
disc("""
Flowables are intended to be an open standard for creating
reusable report content, and you can easily create your
own objects. We hope that over time we will build up
a library of contributions, giving reportlab users a
rich selection of charts, graphics and other "report
widgets" they can use in their own reports. This section
shows you how to create your own flowables.""")
todo("""we should put the Figure class in the
standard library, as it is a very useful base.""")
heading2("A very simple $Flowable$")
disc("""
Recall the $hand$ function from the $pdfgen$ section of this user guide which
generated a drawing of a hand as a closed figure composed from Bezier curves.
""")
illust(examples.hand, "a hand")
disc("""
To embed this or any other drawing in a Platypus flowable we must define a
subclass of $Flowable$
with at least a $wrap$ method and a $draw$ method.
""")
eg(examples.testhandannotation)
disc("""
The $wrap$ method must provide the size of the drawing -- it is used by
the Platypus mainloop to decide whether this element fits in the space remaining
on the current frame. The $draw$ method performs the drawing of the object after
the Platypus mainloop has translated the $(0,0)$ origin to an appropriate location
in an appropriate frame.
""")
disc("""
Below are some example uses of the $HandAnnotation$ flowable.
""")
from reportlab.lib.colors import blue, pink, yellow, cyan, brown
from reportlab.lib.units import inch
handnote()
disc("""The default.""")
handnote(size=inch)
disc("""Just one inch high.""")
handnote(xoffset=3*inch, size=inch, strokecolor=blue, fillcolor=cyan)
disc("""One inch high and shifted to the left with blue and cyan.""")
heading2("Modifying a Built in $Flowable$")
disc("""To modify an existing flowable, you should create a derived class
and override the methods you need to change to get the desired behaviour""")
disc("""As an example to create a rotated image you need to override the wrap
and draw methods of the existing Image class""")
import os
from reportlab.platypus import *
I = '../images/replogo.gif'
EmbeddedCode("""
class RotatedImage(Image):
def wrap(self,availWidth,availHeight):
h, w = Image.wrap(self,availHeight,availWidth)
return w, h
def draw(self):
self.canv.rotate(90)
Image.draw(self)
I = RotatedImage('%s')
I.hAlign = 'CENTER'
""" % I,'I')

View File

@ -0,0 +1,35 @@
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/userguide/ch9_future.py
from reportlab.tools.docco.rl_doc_utils import *
heading1("Future Directions")
disc("""We have a very long list of things we plan to do
and what we do first will most likely be inspired by customer
or user interest.
""")
disc("""
We plan to provide a large number of pre-designed Platypus example
document types -- brochure, newsletter, business letter, thesis, memo,
etcetera, to give our users a better boost towards the solutions they
desire.
""")
disc("""
We plan to fully support adding fonts and internationalization, which are
not well supported in the current release.""")
disc("""
We plan to fully support some of the more obscure features of PDF
such as general hyperlinks, which are not yet well supported.
""")
disc("""
We are also open for suggestions. Please let us know what you think
is missing. You can also offer patches or contributions. Please
look to $http://www.reportlab.com$ for the latest mailing list and
contact information.""")
# this comment is a trivial test of SF checkin rights - delete it some time! AR 2001-04-17

View File

@ -0,0 +1,85 @@
#!/bin/env python
#Copyright ReportLab Europe Ltd. 2000-2004
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/userguide/genuserguide.py
__version__=''' $Id: genuserguide.py 2900 2006-05-22 21:49:00Z andy $ '''
__doc__ = """
This module contains the script for building the user guide.
"""
def run(pagesize=None, verbose=0, outDir=None):
import os
from reportlab.tools.docco.rl_doc_utils import setStory, getStory, RLDocTemplate, defaultPageSize
from reportlab.tools.docco import rl_doc_utils
from reportlab.lib.utils import open_and_read, _RL_DIR
if not outDir: outDir = os.path.join(_RL_DIR,'docs')
destfn = os.path.join(outDir,'userguide.pdf')
doc = RLDocTemplate(destfn,pagesize = pagesize or defaultPageSize)
#this builds the story
setStory()
G = {}
exec 'from reportlab.tools.docco.rl_doc_utils import *' in G, G
for f in (
'ch1_intro',
'ch2_graphics',
'ch2a_fonts',
'ch3_pdffeatures',
'ch4_platypus_concepts',
'ch5_paragraphs',
'ch6_tables',
'ch7_custom',
'ch9_future',
'app_demos',
):
exec open_and_read(f+'.py',mode='t') in G, G
del G
story = getStory()
if verbose: print 'Built story contains %d flowables...' % len(story)
doc.build(story)
if verbose: print 'Saved "%s"' % destfn
def makeSuite():
"standard test harness support - run self as separate process"
from reportlab.test.utils import ScriptThatMakesFileTest
return ScriptThatMakesFileTest('../docs/userguide', 'genuserguide.py', 'userguide.pdf')
def main():
import sys
outDir = filter(lambda x: x[:9]=='--outdir=',sys.argv)
if outDir:
outDir = outDir[0]
sys.argv.remove(outDir)
outDir = outDir[9:]
else:
outDir = None
verbose = '-s' not in sys.argv
if not verbose: sys.argv.remove('-s')
timing = '-timing' in sys.argv
if timing: sys.argv.remove('-timing')
prof = '-prof' in sys.argv
if prof: sys.argv.remove('-prof')
if len(sys.argv) > 1:
try:
pagesize = (w,h) = eval(sys.argv[1])
except:
print 'Expected page size in argument 1', sys.argv[1]
raise
if verbose:
print 'set page size to',sys.argv[1]
else:
pagesize = None
if timing:
from time import time
t0 = time()
run(pagesize, verbose,outDir)
if verbose:
print 'Generation of userguide took %.2f seconds' % (time()-t0)
elif prof:
import profile
profile.run('run(pagesize,verbose,outDir)','genuserguide.stats')
else:
run(pagesize, verbose,outDir)
if __name__=="__main__":
main()

View File

@ -0,0 +1,2 @@
Test of ability to create new files in sourceforge CVS, which
seems not to be working. Can be removed any time.

29
bin/reportlab/license.txt Normal file
View File

@ -0,0 +1,29 @@
#####################################################################################
#
# Copyright (c) 2000-2004, ReportLab Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of the company nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE OFFICERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#####################################################################################