Creating Rich Text Format Documents

Introduction
Most business application developers understand the importance of generating reports that need to be simple as well as elegant. While modules shipped along with Python’s standard distribution is good enough to create simple reports, you need to look elsewhere for building more elegant reports.

One of the best document standards for generating reports is Rich Text Format (RTF). It is an open standard and almost all word processing tools, from Microsoft Word to Apple Works, support RTF. RTF supports multiple fonts of different colors, sizes and shapes. You can also create tables and even integrate pictures in an RTF document.

PyRTF
PyRTF is a third party module, developed by Simon Cussack, that lets you create trendy RTF documents on the fly from Python programs. It is distributed under GNU’s LGPL license. The library has no external dependency and is reasonably stable for most report generating applications. You can download the module from http://www.pyrtf.sourceforge.net/.

Installation of the module is simple. You need to uncompress files from the compressed archive, which is downloaded, and then build and install the module as shown below.

> python setup.py build # Builds the package for install
> python setup.py install # Installs the package

The PyRTF files will be installed in a folder called PyRTF in the site-packages folder (usually found in the Lib folder of the Python installation directory, but may vary depending on your platform). 

To test whether your installation works fine in your Python interactive shell or window, type in this command

>>> from PyRTF import *

If no error is evoked, it is safe to assume that the module is installed correctly.

Creating simple RTF files
PyRTF module has a number of classes that simulate a list. Using these classes and various methods supported by Python, lists are used to create and manipulate RTF documents. 

RTF documents are described as instances of the Document class in the PyRTF module. Different parts of an RTF document can further be dissected into sections. Each section is created as an instance of Section class. Since these classes can be simulated as a list, you can add content by appending objects to the instances created by the classes.

The Renderer class instance is used to physically create a file that will store the RTF document. You can write a Document instance into a file using the Write method in a Renderer instance. The script in example 1 illustrates how you can create a simple RTF file using Python.

Example 1: Creating a simple RTF document

para = "This is a new paragraph"

from PyRTF import *
def makertf():
doc = Document() # a new Document instance
ss = doc.StyleSheet # Standard Stylesheet for the document
section = doc.NewSection() # new section is created 
section.append("This is a new RTF document") # A String is appended
section.append(para) # The string para is appended
return doc



if __name__ == "__main__":
DR = Renderer()
DR.Write(makertf(), open("rtf1.rtf", 'w')) # The arguments passed
# are the Document instance and the file in which the document is stored

Stylizing documents
The idea of Rich Text Format is appealing because you can create stylish documents. To create text rich documents using PyRTF, it is advisable to follow these steps:
1. Create the document as a Document instance;
2. Create a Section instance and append it to the Document instance;
3. Divide each part of the document into specific objects such as paragraphs (created as an instance of the Paragraph class), tables (created as Table instances) or images (using Image class instances);
4. Append each object into the Section instance, which is appended to the Document instance;
5. To stylize each object, use property set class associated with that object such as ParagraphPS (an alias class for ParagraphPropertySet) for Paragraph objects;
6. Create as many objects as required, but ensure that they are appended to the Document instance or Section instances appended to the Document instance; and
7. Create Renderer instance and write the document object into a file.

To understand how you can stylize a document, check the code in example 2. The idea is to create an RTF document with a level 1 heading, a sub-heading, a paragraph and the current date.

Here, a Document instance is created and a section object appended to the document. Each object is appended to the section object.

Much of the stylizing is achieved using Property Sets. PropertySets group common attributes together; each property set is used to control a specific part during the rendering of objects. Each object can be rendered using one or more PropertySets. For example, TextPropertySet is used to stylize both paragraphs (Paragraph class instances) and Text class instances. PyRTF objects can pass supported PropertySets as arguments when they are instantiated.

In example 2, to stylize the main heading a ParagraphPS (para_ps) instance is created. Using SetLeftIndent method, the paragraph is indented by four tabs. The heading is created as a Paragraph object stylized using ParagraphStyles.Heading1 and the PropertySet instance para_ps, which are passed as arguments.

Similarly, the TextPS (text_ps) instance is created to stylize the sub-heading. The TEXT function in PyRTF module can create objects that can be appended into a Paragraph object.

Example 2: Stylizing a Document

from PyRTF import *
import datetime
def makertf() :
doc = Document()
ss = doc.StyleSheet
section = Section()
doc.Sections.append( section )

para_ps = ParagraphPS()
para_ps.SetLeftIndent(TabPropertySet.DEFAULT_WIDTH *4)
p = Paragraph("Press Release ", ss.ParagraphStyles.Heading1, para_ps )
section.append(p)
text_ps =TextPS(font = ss.Fonts.Garamond, size=24, bold = True, italic = True, colour=ss.Colours.Red ) 
sub_heading = Text( ‘Developer IQ- A Magazine for Developer’ , text_ps )
p1 = Paragraph()
p1.append(sub_heading)
section.append(p1)
section.append( '' )
pdate=Paragraph(ss.ParagraphStyles.Normal)
pdate.append(datetime.date.today().isoformat())
section.append( pdate )
para1= """Developer IQ is a 5 year old magazine. In the November 2005 edition watch out for the stuff on Ajax. Ajax is a hot technology. There will be more on Python. Python is a programming language that is ubiquitous and very powerful. Python was originally authored by Guido Von Rossum."""
p1 = Paragraph(ss.ParagraphStyles.Normal)
p1.append(TEXT(para1, font =ss.Fonts.LucidaConsole, colour=ss.Colours.Green))
section.append(p1)
return doc

if __name__ == "__main__":
DR = Renderer()
DR.Write(makertf(), open("pr.rtf", 'w'))


When specifying fonts and colors, it is imperative that you specify the colors using style sheet of the document and not the Colours or Fonts class. 

Creating Tables in RTF documents
The Table class in PyRTF module lets you create tables. Each table consists of cells which are created using Cell class. Contents in each cell are usually created as Paragraph objects, which can store strings. You can create frames for cells using the PropertySet classes FramePS and BorderPS. 

In example 3, a multiplication table is created for 16, for range 0 to 15. The integers are converted into string using str function in Python and passed as arguments to Paragraph instances.

Example 3: Creating a multiplication table using tables

from PyRTF import *
def makertf() :
doc = Document()
ss = doc.StyleSheet
section = Section()
doc.Sections.append( section )
p = Paragraph( ss.ParagraphStyles.Heading1 )
p.append( 'Multiplication Table' )
section.append( p )
table = Table( TabPS.DEFAULT_WIDTH * 3, TabPS.DEFAULT_WIDTH * 3, TabPS.DEFAULT_WIDTH * 3 )
c1 = Cell( Paragraph( 'Multiplier' ) )
c2 = Cell( Paragraph( 'Multiplicant' ) )
c3 = Cell( Paragraph( 'Result' ) )
table.AddRow(c1, c2, c3)
for i in range (16):
c1 = Cell(Paragraph(str(i)))
c2 = Cell(Paragraph (str(16)))
c3 = Cell(Paragraph (str(16*i)))
table.AddRow(c1, c2, c3)
section.append(table)
return doc
if __name__ == "__main__":
DR = Renderer()
DR.Write(makertf(), open("rtf4.rtf", 'w'))


Python is today ubiquitous and finds application practically everywhere. This is just an example of where Python can be used.



Added on June 14, 2007 Comment

Comments

Post a comment