A Reportlab Link in Table Cell Workaround

Front matter: You’re generating a table inside a PDF document with Reportlab, and one of the cells needs to feature a link to an external website. Links aren’t supported (as far as I know) outside a Paragraph object, but shoving a Paragraph into the table cell results in some pretty fucked up word wrapping and table-cell sizing.

It’s ugly, and unacceptable.

According to the Reportlab mailing list:

Paragraphs behave well inside a table cell with a fixed width.

I won’t even try to re-find the post wherein this valuable nugget lies, but it’s somewhere in the mailing-list archives.

The biggest problem here is: You cannot specify individual widths of table cells to fulfill whatever random “okay, now it works” behavior. When you create a Table object, there’s an optional cell-width argument (colWidths), but it applies across the board to every cell in the table. So, for example, if you have one cell with a number and another with a long string of text, you can’t say, “Make the number cell X wide, and make the text cell Y wide.”

Update August 21, 2008: The above paragraph is completely wrong. See my post “ReportLab Table Cell Follow-Up” for more information.

Of course, you can just leave the cell-width calculation up to the Table class when you instantiate it… but that merely results in the aforementioned fucked up shit.

You see the problem, eh?

My solution is:

1. Create the link within a Paragraph. Again, AFAIK, this is the only way to link.
2. Determine the length of the linked text. Use pdfmetrics.stringWidth.
3. Create a Table with only one cell whose width is that determined in step 2. This makes things “behave”.
4. Drop that Table into the cell of the real Table you actually want displayed in the final PDF.

Here:

from reportlab.pdfbase import pdfmetrics
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.platypus.tables import Table

doc = SimpleDocTemplate('filename_of_pdf')
Story = []

str = 'linked text'
url = '<link href="http://the/actual/url.html">%s</link>' % str

L = pdfmetrics.stringWidth(str, your_font_name, your_font_size)
inside_Table = Table([[Paragraph(url, your_paragraph_style)]], colWidths=L)

real_Table_data = ['a', 'b', inside_Table, 'c', 'd']
t = Table(real_Table_data)

Story.append(t)
doc.build(Story)

For the most part: Blickity-Blam!

Sometimes the pdfmetrics.stringWidth() call will still cause your shit to wrap, but throw a +1 after the call in the L declaration (to add a single point, which is 1/72 of an inch) and things will work beautifully.

Advertisements

2 thoughts on “A Reportlab Link in Table Cell Workaround

  1. Thanks for the post!
    ReportLab is quite badly documented so the help of volunteers is needed : )
    I would just like to point out that using str as a variable name should be avoided as it shadows a built-in function str(). Using str() later in the program will cause errors as str object (type: String) is not callable.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s