[reportlab-users] Extra Canvas Translation?

Carl waldbie at verizon.net
Sat Sep 17 18:39:32 EDT 2005


I have been experimenting with the interaction between the flowable elements 
of the Platypus engine and the non-flowing drawing routines of pdfgen.  In 
one of my examples, I am rotating a page so it will print out landscape-wise.  
I place a non-flowing banner on it with the PageTemplate event hooks, and I 
place some paragraph text on the page with the Platypus engine.

However, I also attempted to place some non-flowing content on the page by use 
of a variation on the Macro flowable.  I was puzzled when it did not show up 
as expected, but then I decided to print out the absolute coordinates of the 
canvas origin in each case.  To my surprise, the origin has been translated 
off the page!  Can anyone help me understand why this is happening?  My 
example program follows:

--------------------------------------------------------------------------------------------

from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, 
PageBreak, KeepTogether
from reportlab.platypus import BaseDocTemplate, PageTemplate, Frame, Spacer, 
Flowable
from reportlab.lib.units import inch
from reportlab.lib import colors
from reportlab.rl_config import defaultPageSize
from reportlab.platypus import Paragraph
from reportlab.lib.enums import TA_CENTER
from reportlab.lib.styles import ParagraphStyle
#from reportlab.lib.styles import getSampleStyleSheet
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen.canvas import Canvas

from reportlab.lib.pagesizes import landscape

import os.path
import traceback

#####################################################################
# Register Arial font.
#####################################################################
fontdir = "/usr/share/fonts/truetype/msttcorefonts" #font directory may need 
to be specified on some systems.
#fontdir = ""
arial_font = TTFont('MyArial', os.path.join(fontdir, 'Arial.ttf'))
pdfmetrics.registerFont(arial_font)
Arial = "MyArial"
arial_bold_font = TTFont('MyArialBold', os.path.join(fontdir, 
'Arial_Bold.ttf')) #'ARIALBD.ttf'))
#arial_bold_font = TTFont('MyArialBold', fontdir + 'ARIALBD.ttf')
pdfmetrics.registerFont(arial_bold_font)
Arial_Bold = "MyArialBold"

# Metric constants.
PAGE_WIDTH = 11.0 * inch 
PAGE_HEIGHT = 8.5 * inch 

################################################################################################

class MacroCommand(Flowable):
 """This is not actually drawn (i.e. it has zero height)
 but is executed when it would fit in the frame.
 Calls command(canvas).
 """
 def __init__(self, command):
  self.command = command
 def __repr__(self):
  return "MacroCommand(%s)" % repr(self.command)
 def wrap(self, availWidth, availHeight):
  return (0,0)
 def draw(self):
  self.command(self.canv)

################################################################################################
def make_report(filename_or_stream):
 doc = BaseDocTemplate(filename_or_stream, leftMagin=0, rightMargin=0, 
topMargin=0, bottomMargin=0)
 main_frame = Frame(0,0, PAGE_WIDTH, PAGE_HEIGHT, leftPadding=0, 
rightPadding=0, topPadding=0, bottomPadding=0)
 later_frame = Frame(0,0, PAGE_WIDTH, PAGE_HEIGHT, leftPadding=0, 
rightPadding=0, topPadding=0, bottomPadding=0)
 main_page_template = PageTemplate(id="main", onPage=main_onpage, 
onPageEnd=main_onpageend, frames=[main_frame])
 later_page_template = PageTemplate(id="later", onPage=later_onpage, 
onPageEnd=later_onpageend, frames=[later_frame])
 doc.addPageTemplates(main_page_template)
 doc.addPageTemplates(later_page_template)
 
 story=[]
 story.append(Spacer(PAGE_WIDTH, 2*inch)) #Make room for non-flowing header.
 story.append(Paragraph("A paragraph.", 
ParagraphStyle(ParagraphStyle.defaults)))
 story.append(make_macro(PAGE_WIDTH*0.5, PAGE_HEIGHT*0.5, "Hello!"))
 doc.build(story)
 

def main_onpage(canv, doc):
 #Only first page should have a bunch of header info.
 doc.handle_nextPageTemplate('later')
 #Translate to landscape and write the static parts of the header.
 canv.saveState()
 #Translate the page to landscape.
 xlate_landscape(canv)
 #Print the main page banner.
 print_banner(canv)
 
def print_banner(canv):
 print "print_banner() origin: (%d,%d)" % canv.absolutePosition(0,0)
 canv.setFillColor(colors.steelblue)
 canv.rect(0, PAGE_HEIGHT, PAGE_WIDTH, -2*inch, True, True)
 canv.setFont(Arial, 32)
 canv.setFillColor(colors.white)
 canv.drawCentredString(PAGE_WIDTH*0.5, PAGE_HEIGHT - 1.5*inch, "Banner")
 
def main_onpageend(canv, doc):
 canv.restoreState()
 
def later_onpage(canv, doc):
 canv.saveState()
 #Translate the page to landscape.
 xlate_landscape(canv)
 
def later_onpageend(canv, doc):
 canv.restoreState()
 
def xlate_landscape(canv):
 """
  Translate the page for landscape printing.
 """
 canv.rotate(90)
 canv.translate(0,-PAGE_HEIGHT)
 canv.setPageSize((PAGE_HEIGHT, PAGE_WIDTH))

def make_macro(x, y, expr):
 #Create closure.
 def make_dynamic_non_flowing(canvas):
  print "make_dynamic_non_flowing() origin: (%d,%d)" % 
canvas.absolutePosition(0,0)
  canvas.saveState()
  canvas.setFillColor(colors.black)
  canvas.setFont(Arial, 12)
  canvas.drawString(x, y, expr)
  canvas.restoreState()
 return MacroCommand(make_dynamic_non_flowing)

if __name__ == "__main__":
 make_report("test.pdf")


More information about the reportlab-users mailing list