RL2
bzr revid: pinky-6e2b8c053bc91a80362d7d3867ff412eb65b09c7
|
@ -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
|
|
@ -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)
|
|
@ -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!
|
|
@ -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)
|
|
@ -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. """)
|
||||
|
|
@ -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.
|
||||
""")
|
|
@ -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")
|
|
@ -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')
|
|
@ -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()
|
After Width: | Height: | Size: 9.5 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 12 KiB |
|
@ -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$EDZpYcS#(];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
|
After Width: | Height: | Size: 16 KiB |
|
@ -0,0 +1,3 @@
|
|||
del reference.pdf
|
||||
python ..\tools\yaml2pdf.py reference.yml
|
||||
start reference.pdf
|
|
@ -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()
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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 < & > 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 &
|
||||
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 (<gherman@europemail.com>) 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
|
||||
""")
|
|
@ -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 & 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 & 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, <unichar/> has also been added. You can now do <unichar code="0xfc"/>
|
||||
or <unichar name='LATIN SMALL LETTER U WITH DIAERESIS'/> 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. <greek>lambda</greek>) or using the entity
|
||||
references (e.g. λ) 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("""<link href="http://www.reportlab.com/">ReportLab<link>""", style=styles['Link'])
|
||||
|
||||
disc("""Internal link to current PDF document:""", style=indent1_style)
|
||||
disc("""<link href="summary">ReportLab<link>""", style=styles['Link'])
|
||||
|
||||
disc("""External link to a PDF document on the local filesystem:""", style=indent1_style)
|
||||
disc("""<link href="pdf:C:/john/report.pdf">ReportLab<link>""", 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 <greek> tags (e.g. <greek>lambda</greek>) or corresponding
|
||||
entity references (e.g. λ) 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""")
|
|
@ -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. ^<b>^ and ^<i>^ 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
|
|
@ -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")
|
|
@ -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 "Page Layout and Typography Using Scripts". It is a high
|
||||
level page layout library which lets you programmatically create complex
|
||||
documents with a minimum of effort.
|
||||
""")
|
||||
|
||||
|
||||
|
||||
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$ & $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.
|
||||
""")
|
|
@ -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 < para > tag")
|
||||
|
||||
|
||||
disc("""
|
||||
The paragraph text may optionally be surrounded by
|
||||
<para attributes....>
|
||||
</para>
|
||||
tags. The attributes if any of the opening <para> 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 $<font>$ tag")
|
||||
disc("""The $<font>$ 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 (α): <greek>e</greek> <super><greek>ip</greek></super> = -1""",
|
||||
"Greek letters and superscripts")
|
||||
|
||||
heading3("Numbering Paragraphs and Lists")
|
||||
disc("""The $<seq>$ 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 <seqreset id="mycounter" base="42">.
|
||||
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 <seqdefault id="Counter">
|
||||
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 <seq> 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"/> - <bullet> attributes & synonyms""")
|
||||
disc("""The <bullet> 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.""")
|
|
@ -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; style entities as well for & < > and ".
|
||||
|
||||
'''
|
||||
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.
|
||||
""")
|
|
@ -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')
|
|
@ -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
|
|
@ -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()
|
|
@ -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.
|
|
@ -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.
|
||||
#
|
||||
#####################################################################################
|