Colors in Reportlab

Looking for an exhaustive list of the colors in ReportLab, I was surprised that there wasn’t a list of them — with examples — in the ReportLab docs. Then, when I didn’t quickly find one with Google, I thought I would turn this into a test of my coding chops.

So, this might seem simple to you, but I needed quite a few tries to get it going. Which means, of course, that I’m pretty proud of it.

Here’s the code I wrote:

from reportlab.lib.pagesizes import A4
from reportlab.lib.enums import TA_LEFT
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.colors import getAllNamedColors

doc = []
document = SimpleDocTemplate('colors.pdf', pagesize = A4, rightMargin = 72, leftMargin = 72, topMargin = 72,
                                     bottomMargin = 34)
styles = getSampleStyleSheet()

for color in getAllNamedColors():
    styles.add(ParagraphStyle(name=color, alignment=TA_LEFT, fontSize=12, leading=22, fontName='Helvetica',
                              backColor=color))
    doc.append(Paragraph('Test color '+color, styles[color]))

document.build(doc)

And here is the result of the code: colors.pdf

Advertisements

Numbered Lists (sort of) in Reportlab

So, for the first time, I think I may have stumbled upon something I wanted to do in code for which Google searches didn’t give me a quick and easy answer. (When it’s not quick, it generally because I’m slow to understand.)

So, since I worked out a solution for myself and am more than usually proud of it, here’s what I have.

The challenge:
I’m automatically generating worksheets in PDF format. For them, I’d like to have exercises in a nice numbered list. You know the format, it’s pretty easy to do in most software.

  1. This is an exercise.
  2. So is this.
  3. And here is a blank to fill ____________.

However, even though Reportlab includes numbering in the bullets, I spent most of yesterday evening trying to tweak different indentation settings to get it to do what I want. And it didn’t. (Again, maybe I’m slow to understand.)

The problem was that either the text didn’t wrap right (it should wrap to be beneath the beginning of the text, not to beneath the number) or I couldn’t get the spacing between the number and the content to look right.

My solution:
I wound up using a table for this. It’s not what I wanted and I feel like the way I have it is a bit of a hack, with different methods checking the length of the list that feeds the table, so that I can add lines via a method an arbitrary number of times. Nonetheless, I’m pretty happy with how the result looks.

from reportlab.lib.pagesizes import A4
from reportlab.lib.enums import TA_LEFT
from reportlab.platypus import SimpleDocTemplate, Paragraph, Table, TableStyle
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle, ListStyle
from reportlab.lib.units import cm

# We need some text to use. I happen to like this one
lines=['Sing, Goddess, sing of the rage of Achilles, son of Peleus--',
       'that murderous anger which condemned Achaeans',
       'to countless agonies and threw many warrior souls',
       'deep into Hades, leaving their dead bodies',
       'carrion food for dogs and birds--',
       'all in fulfilment of the will of Zeus.']

style=ParagraphStyle(name='Normal', alignment=TA_LEFT, fontSize=12, leading=18, fontName='Helvetica')
doc=SimpleDocTemplate('iliad.pdf', pageSize=A4)
document=[]

# Add a title, straightforward enough.
document.append(Paragraph('<b>The Iliad</b> by Homer', style))

# Now, add numbered lines
epic=[]
for line in lines:
    epic.append([Paragraph('<b>'+str(len(epic)+1)+'.</b>', style),
                 Paragraph(line, style)])

t=Table(epic, colWidths=(1.2*cm, None))
t.setStyle(TableStyle([
    ('VALIGN', (0,0), (-1,-1), 'TOP')
]))

document.append(t)

doc.build(document)

That gives you this result: iliad.pdf.

About it
Obviously, it’s a table which is made up of a list of lists. The various ‘cells’ (entries in one list) need to be wrapped in Paragraph objects in order to get the wrapping and formatting right. (It seems the <b>bold</b> tags are processed by the Paragraph object, if you’re curious.)

As for the TableStyle, that sets the vertical alignment to ‘TOP’ as it defaults to middle, which looks odd when the line it’s numbering wraps.

Lastly, it was interesting — and helpful — to me that the table cells could be numbered with the negative notation that is familiar from things like lists and strings. That is to say that (0,0) is the top left and (-1, -1) is the bottom right, because it counts from the end of the list. That was nice. (I was ready to start doing janky things with len(list) to get it right.)

Maybe I overestimate the problem I solved…
I would be surprised if I’m the only one who has done this, but it is the best I could come up with. I’d be happy to know if I overlooked some obvious solution / reference. How have you (or others) solved the same problem?