[reportlab-users] TOC and page x of y canvas
brian
a001 at yakkadesign.com
Wed Nov 11 09:33:35 EST 2015
Below is the code. I also attached it in case the formatting in the
email gets lost.
I only want <pages x of y>. I don't care about multiple passes.
I'm new to ReportLab and PDF gen. It seems the bookmarks are tied to a
position in the document. I don't see the need to know the page numbers
when creating the TOC. You guys may be abstracting that detail away
behind the scenes.
I can tell you don't like the numbered canvas but I don't understand
what the solution is to get <page x of y>. Can you give me more details
of how to do this?
Thanks for your help!!!!
Brian
"""
reportgen with numbered canvas
"""
import sys
from reportlab.pdfgen import canvas
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.units import inch
from reportlab.lib.units import mm
from reportlab.platypus import SimpleDocTemplate
from reportlab.platypus.tableofcontents import TableOfContents
from reportlab.platypus import PageBreak
from reportlab.platypus import Paragraph
styles = getSampleStyleSheet()
styleN = styles['Normal']
styleH = styles['Heading1']
styleH2 = styles['Heading2']
styleTitle = styles['Title']
elements = []
class NumberedCanvas(canvas.Canvas):
"""
for adding page x of y to each page
based on: http://code.activestate.com/recipes/576832/
modified:
skip title page
renamed draw_page_number to draw_footer since footer is more
than page number
"""
def __init__(self, *args, **kwargs):
canvas.Canvas.__init__(self, *args, **kwargs)
self._saved_page_states = []
def showPage(self):
self._saved_page_states.append(dict(self.__dict__))
self._startPage()
def save(self):
"""
add page info to each page (page x of y)
"""
num_pages = len(self._saved_page_states)
#modify so will skip the first page for adding footer
for (i, state) in enumerate(self._saved_page_states):
self.__dict__.update(state)
if i!=0:
self.draw_footer(num_pages)
canvas.Canvas.showPage(self)
canvas.Canvas.save(self)
def draw_footer(self, page_count):
"""
draws the footer on the page
originally called draw_page_number but renamed since adding
complete footer
"""
self.setFont("Helvetica", 7)
self.drawRightString(200*mm, 20*mm,
"Page %d of %d" % (self._pageNumber, page_count))
class ModifiedSimpleDocTemplate(SimpleDocTemplate):
"""
modified version of SimpleDocTemplate
"""
def afterFlowable(self, flowable):
"""
called after a flowable has been rendered
based on user manual to add TOC
Detect Level 1 and 2 headings, build outline, and track chapter title.
"""
if isinstance(flowable, Paragraph):
txt = flowable.getPlainText()
#had to add style
style = flowable.style.name
if style=='Heading1':
#make h1 clickable
key = 'h1-%s'%self.seq.nextf('heading1')
#logger.debug( 'heading 1: txt=%s and key = %s and
page=%s'%(txt, key, self.page))
self.canv.bookmarkPage(key)
self.notify('TOCEntry', (0, txt, self.page, key))
elif style=='Heading2':
key = 'h2-%s'%self.seq.nextf('heading2')
self.canv.bookmarkPage(key)
self.notify('TOCEntry', (1, txt, self.page, key))
doc = ModifiedSimpleDocTemplate('testing.pdf')
#TOC
if True:
elements.append( Paragraph('Table of Contents',styleH) )
toc = TableOfContents()
PS = ParagraphStyle
toc.levelStyles = [
PS(fontName='Times-Bold', fontSize=14,
name='TOCHeading1',
leftIndent=20, firstLineIndent=-20,
spaceBefore=5, leading=16),
PS(fontSize=12, name='TOCHeading2',
leftIndent=40, firstLineIndent=-20,
spaceBefore=0, leading=12),
PS(fontSize=10, name='TOCHeading3',
leftIndent=60, firstLineIndent=-20,
spaceBefore=0, leading=12),
PS(fontSize=10, name='TOCHeading4',
leftIndent=100, firstLineIndent=-20,
spaceBefore=0, leading=12),
]
elements.append(toc)
elements.append( PageBreak() )
#generate filler elements
if True:
for i in range(100):
#p = Paragraph("This is a Heading %s"%i,styleH)
p = Paragraph("This is a Heading %s"%i,styleH2)
elements.append( p )
doc.multiBuild( elements, canvasmaker=NumberedCanvas)
#canvasmaker=NumberedCanvas canvasmaker=canvas.Canvas
On 11/11/2015 07:01 AM, Robin Becker wrote:
> On 09/11/2015 20:35, brian wrote:
>> Does anyone know the answer to this question:
>> http://stackoverflow.com/questions/16041397/python-reportlab-clickable-toc-with-x-of-y-page-numbering
>>
>>
>>
>> I'm doing a similar thing and when I create the TOC with a numbered
>> canvas the
>> links don't work. If I remove the numbered canvas, the links work.
>> I'd like to
>> not have to roll my own TOC solution.
>>
>> Brian
>
> Perhaps you could post some code, and please not like the link above
> which doesn't work without considerable editing and guessing. The
> attempt is being made there to defer page building until the end which
> is a bit daft.
>
> Do not use the numbered canvas it is wholly problematic/idiotic. It
> might be possible to defer all page writing until the very end, but
> Canvas and everything else wasn't written with that intention so it's
> almost certainly not a good idea.
>
> Anyhoo if I do make the code work as intended the links are clickable,
> but I still don't like the idea of using the NumberedCanvas.
>
>
> So far as I can understand it there is/are two possible reasons to use
> the NumberedCanvas. We need to find the total number of pages and
> possibly we need to avoid having multiple passes.
>
> Well if we don't know the number of Toc entries up front we cannot
> avoid multiple passes because of a variable number of TOC pages. If we
> know the TOC will fit on n pages then it is possible to do both TOC &
> page x of y with one pass. So 1) we assume a for "y" the total number
> of pages and 2) we assume form(s) for the whole TOC.
>
> If that solution won't do then you are probably back to doing
> multi-build anyway and that easily allows for variable length TOC and
> for collection of the number of pages at the end of the story. Three
> passes will suffice.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: reportGen_numberedCanvas.py
Type: text/x-python-script
Size: 3897 bytes
Desc: not available
URL: <https://pairlist2.pair.net/pipermail/reportlab-users/attachments/20151111/00fe039e/attachment.bin>
More information about the reportlab-users
mailing list