[reportlab-users] User Guidance Required

51 views
Skip to first unread message

Prabhakar Moka

unread,
Oct 12, 2016, 12:02:24 PM10/12/16
to reportl...@lists2.reportlab.com

Hi All,

 

I am using ReportLab 2.7 with Python 2.7.  I am able to  create a pdf with clickable bookmarks in the table of contents (toc) and  created a pdf with "x of y" page numbering also. Here my problem is  bookmarkpage(key) appears to break when I try to do both. Only FooterCanvas is working for me.  And also you check the below code snippet which was failed.

 

Could someone please help me to resolve this?

 

I really appreciate any help you can provide.

 

Regards,

Prabhakar

 

 

 

class FooterCanvas(canvas.Canvas):

 

    def __init__(self, *args, **kwargs):

        canvas.Canvas.__init__(self, *args, **kwargs)

        self.pages = []

 

    def showPage(self):

        self.pages.append(dict(self.__dict__))

        self._startPage()

 

    def save(self):

        page_count = len(self.pages)

        for page in self.pages:

            self.__dict__.update(page)

            self.draw_canvas(page_count)

            canvas.Canvas.showPage(self)

        canvas.Canvas.save(self)

 

    def draw_canvas(self, page_count):

        page = "Page %s of %s" % (self._pageNumber, page_count)

        x = 128

        self.saveState()

        self.setStrokeColorRGB(0, 0, 0)

        self.setLineWidth(0.5)

        self.line(66, 78, LETTER[0] - 66, 78)

        self.setFont('Times-Roman', 10)

        self.drawString(LETTER[0]-x, 65, page)

        self.restoreState()

       

 

class MyDocTemplate(BaseDocTemplate):

    def __init__(self, filename, **kw):

        self.allowSplitting = 0

        apply(BaseDocTemplate.__init__, (self, filename), kw)

        template = PageTemplate('normal', [Frame(2.5*cm, 2.5*cm, 15*cm, 25*cm, id='F1')])

        self.addPageTemplates(template)

 

    # Entries to the table of contents can be done either manually by

    # calling the addEntry method on the TableOfContents object or automatically

    # by sending a 'TOCEntry' notification in the afterFlowable method of

    # the DocTemplate you are using. The data to be passed to notify is a list

    # of three or four items countaining a level number, the entry text, the page

    # number and an optional destination key which the entry should point to.

    # This list will usually be created in a document template's method like

    # afterFlowable(), making notification calls using the notify() method

    # with appropriate data.

 

    def afterFlowable(self, flowable):

        "Registers TOC entries."

        if flowable.__class__.__name__ == 'Paragraph':

            text = flowable.getPlainText()

            style = flowable.style.name

            if style == 'Heading1':

                level = 0

            elif style == 'Heading2':

                level = 1

            else:

                return

            E = [level, text, self.page]

            #if we have a bookmark name append that to our notify data

            bn = getattr(flowable,'_bookmarkName',None)

            if bn is not None: E.append(bn)

            self.notify('TOCEntry', tuple(E))

 

centered = PS(name = 'centered', fontSize = 30,leading = 16, alignment = 1,spaceAfter = 20)

 

h1 = PS(name = 'Heading1',fontSize = 14,leading = 16)

h2 = PS(name = 'Heading2',fontSize = 12,leading = 14)

 

 

# Build story.

story = []

 

# Create an instance of TableOfContents. Override the level styles (optional)

# and add the object to the story

 

toc = TableOfContents()

toc.levelStyles = [

    PS(fontName='Times-Bold', fontSize=20, name='TOCHeading1', leftIndent=20, firstLineIndent=-20, spaceBefore=10, leading=16),

    PS(fontSize=18, name='TOCHeading2', leftIndent=40, firstLineIndent=-20, spaceBefore=5, leading=12),

]

story.append(Paragraph('<b>Table of contents</b>', centered))

story.append(toc)

 

 

#this function makes our headings

def doHeading(text,sty):

    from hashlib import sha1

    #create bookmarkname

    bn=sha1(text+sty.name).hexdigest()

    #modify paragraph text to include an anchor point with name bn

    h=Paragraph(text+'<a name="%s"/>' % bn,sty)

    #store the bookmark name on the flowable so afterFlowable can see this

    h._bookmarkName=bn

    story.append(h)

 

#story.append(Paragraph('<b>Table of contents</b>', centered))

story.append(PageBreak())

doHeading('First heading', h1)

story.append(Paragraph('Text in first heading', PS('body')))

doHeading('First sub heading', h2)

story.append(Paragraph('Text in first sub heading', PS('body')))

story.append(PageBreak())

doHeading('Second sub heading', h2)

story.append(Paragraph('Text in second sub heading', PS('body')))

story.append(PageBreak())

doHeading('Last heading', h1)

story.append(Paragraph('Text in last heading', PS('body')))

doc = MyDocTemplate('mintoc.pdf')

doc.multiBuild(story, canvasmaker = FooterCanvas)

Robin Becker

unread,
Oct 12, 2016, 12:16:53 PM10/12/16
to reportlab-users
Hi Prabhakar,

I could not run your example. Please paste the whole working example so

1) we don't have to do all the imports ourselves

2) we don't have to guess what PS does.

3) it would also help if you didn't add * around certain lines and also did not
add empty lines, but 1 and 2 would really help.


On 12/10/2016 17:02, Prabhakar Moka wrote:
> Hi All,
>
>
>
> I am using ReportLab 2.7 with Python 2.7. I am able to create a pdf with
> clickable bookmarks in the table of contents (toc) and created a pdf with
> "x of y" page numbering also. Here my problem is bookmarkpage(key) appears
> to break when I try to do both. Only *FooterCanvas *is working for me. And
> also you check the below code snippet which was failed.
>
>
>
> Could someone please help me to resolve this?
>
>
>
> I really appreciate any help you can provide.
>
>
>
> Regards,
>
> Prabhakar
>


--
Robin Becker
_______________________________________________
reportlab-users mailing list
reportl...@lists2.reportlab.com
https://pairlist2.pair.net/mailman/listinfo/reportlab-users

Hans Schmidt

unread,
Nov 27, 2017, 2:11:53 PM11/27/17
to reportlab-users
Hi,
I know this answer is all to late. But as I have currently struggled with exactly the same problem I want to post my solution here in case that someone else is finding this helpful.
I also had the problem that implementing the "page x of y" workaround (see also http://code.activestate.com/recipes/576832-improved-reportlab-recipe-for-page-x-of-y/) broke the internal links (bookmarks) I've generated. After some debugging within the ReportLab framework I found that the problem lies in the pagenumber of the "Destination" which is always set to page 1 due to the uncomplete overwriting of showPage (which normally is doing the update of the pagenumber after each new page).

So my working solution of the "NumberedCanvas" class looks like following now:

class NumberedCanvas(canvas.Canvas):

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._doc.pageCounter += 1
self._startPage()

def save(self):
"""add page info to each page (page x of y)"""
num_pages = len(self._saved_page_states)
self._doc.pageCounter = 1
for state in self._saved_page_states:
self.__dict__.update(state)
self.draw_page_number(num_pages)
canvas.Canvas.showPage(self)
canvas.Canvas.save(self)

def draw_page_number(self, page_count):
page_info = "{}/{}".format(self._pageNumber, page_count)
self.drawRightString(200 * mm, 7 * mm, page_info)


Hope that helps someone!

Best regards,
Wusaweki

Deeksha :)

unread,
Jan 8, 2018, 4:32:30 PM1/8/18
to reportlab-users
Not too late! It helped me. Thank you very much!! :)
Reply all
Reply to author
Forward
0 new messages