[reportlab-users] Setting TrueType fonts in table cell

1,977 views
Skip to first unread message

Nils Smeds

unread,
Sep 25, 2013, 6:38:36 AM9/25/13
to reportl...@lists2.reportlab.com
I am having problem setting the font to a TrueType font in reportlab.

Here is my snippet:

    base_style=[('GRID', (0,0), (-1,-1), 1, (0,0,0)),
                ('FONT', (0,0), (0,-1), 'Courier'),
                ('BOX', (0,0), (-1,-1), 3, (0,0,0)),
                ('ALIGN',(1,0),(1,-1),'RIGHT'),
                ('ALIGN',(3,0),(3,-1),'RIGHT'),
                ('VALIGN',(0,0),(-1,-1),'TOP')]
   
[...]
    t=Table(data)
    styles=list(base_style)
    if(cur_name_span[1]>cur_name_span[0]):
          spans.append(('SPAN',(0,cur_name_span[0]),(0,cur_name_span[1])))
    if(cur_simsatt_span[1]>cur_simsatt_span[0]):
            spans.append(('SPAN',(2,cur_simsatt_span[0]),(2,cur_simsatt_span[1])))
    for s in spans:
          #print "Adding span: ",s
           styles.append(s)
           t.setStyle(TableStyle(styles))


This works great with the built-in font Courier. However I do need a more complete font so I am doing the following in the beginning of my script

    from reportlab.pdfbase import pdfmetrics
    from reportlab.pdfbase.ttfonts import TTFont
    from reportlab.pdfbase.pdfmetrics import registerFontFamily


    pdfmetrics.registerFont(TTFont('SansR', '/usr/share/fonts/liberation/LiberationSans-Regular.ttf'))
    pdfmetrics.registerFont(TTFont('SansB', '/usr/share/fonts/liberation/LiberationSans-Bold.ttf'))
    pdfmetrics.registerFont(TTFont('SansI', '/usr/share/fonts/liberation/LiberationSans-Italic.ttf'))
    pdfmetrics.registerFont(TTFont('SansBI', '/usr/share/fonts/liberation/LiberationSans-BoldItalic.ttf'))
    registerFontFamily('Sans',normal='SansR',bold='SansB',italic='SansI',boldItalic='SansBI')


This works great for all regular paragraphs and graphical objects. I get the special characters I need. But, I can not specify my SansR fontname in the table format.
If I substitute 'Courier' above with any of the Sans names I get:

Traceback (most recent call last):
  File "/home/nsmeds/bin/GetDiplomDBI-oop.py", line 650, in <module>
    doc.PDFcanvas.save()
  File "/usr/lib64/python2.7/site-packages/reportlab/pdfgen/canvas.py", line 1123, in save
    self._doc.SaveToFile(self._filename, self)
  File "/usr/lib64/python2.7/site-packages/reportlab/pdfbase/pdfdoc.py", line 235, in SaveToFile
    f.write(self.GetPDFData(canvas))
  File "/usr/lib64/python2.7/site-packages/reportlab/pdfbase/pdfdoc.py", line 247, in GetPDFData
    fnt.addObjects(self)
  File "/usr/lib64/python2.7/site-packages/reportlab/pdfbase/ttfonts.py", line 1126, in addObjects
    pdfFont.ToUnicode = doc.Reference(cmapStream, 'toUnicodeCMap:' + baseFontName)
  File "/usr/lib64/python2.7/site-packages/reportlab/pdfbase/pdfdoc.py", line 516, in Reference
    raise ValueError, "redefining named object: "+repr(name)
ValueError: redefining named object: 'toUnicodeCMap:AAAAAA+LiberationSans'


Any ideas what might go wrong?

This is python-reportlab-2.5-7.fc19.x86_64

Nils Smeds

unread,
Sep 25, 2013, 5:36:55 PM9/25/13
to reportl...@reportlab.com
Nils Smeds <nils.smeds <at> gmail.com> writes:

Here is a simple test case:
Modify the base_style array as indicated to expose the problem I see.

/Nils

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import MySQLdb

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter, A4, inch,cm
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Paragraph, SimpleDocTemplate, PageBreak
from PIL import Image
from datetime import datetime

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter, A4, inch, cm
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Paragraph, SimpleDocTemplate, PageBreak


from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfbase.pdfmetrics import registerFontFamily

# My Liberation fonts are installed in: /usr/share/fonts/liberation


pdfmetrics.registerFont(TTFont('SansR',
'/usr/share/fonts/liberation/LiberationSans-Regular.ttf'))
pdfmetrics.registerFont(TTFont('SansB',
'/usr/share/fonts/liberation/LiberationSans-Bold.ttf'))
pdfmetrics.registerFont(TTFont('SansI',
'/usr/share/fonts/liberation/LiberationSans-Italic.ttf'))
pdfmetrics.registerFont(TTFont('SansBI',
'/usr/share/fonts/liberation/LiberationSans-BoldItalic.ttf'))
registerFontFamily('Sans',normal='SansR',bold='SansB',italic='SansI',boldIta
lic='SansBI')

filename='mytest.pdf'

page_width, page_height = A4
PDFdoc = SimpleDocTemplate(filename,pagesize=A4)
PDFdoc_elements=[]



from reportlab.lib.colors import black
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Table,TableStyle
from reportlab.platypus import Paragraph, SimpleDocTemplate, PageBreak

styles = getSampleStyleSheet()
styleH = styles['Heading1']
styleN = styles['Normal']

base_style=[('GRID', (0,0), (-1,-1), 1, (0,0,0)),

('FONT', (1,0), (1,-1), 'SansR'),
# ('FONT', (1,0), (1,-1), 'Courier'),


('BOX', (0,0), (-1,-1), 3, (0,0,0)),
('ALIGN',(1,0),(1,-1),'RIGHT'),
('ALIGN',(3,0),(3,-1),'RIGHT'),
('VALIGN',(0,0),(-1,-1),'TOP')]

data=[('ČOL1','ČOL2','ČOL3','COL4','COL5')]
data.append(['ČOL1','ČOL2','ČOL3','COL4','COL5'])
data.append(['ČOL1','ČOL2','ČOL3','COL4','COL5'])
data.append(['ČOL1','ČOL2','ČOL3','COL4','COL5'])
t=Table(data)
styles=list(base_style)
t.setStyle(TableStyle(styles))
PDFdoc_elements.append(t)
PDFdoc.build(PDFdoc_elements)

PDFcanvas=PDFdoc.canv

PDFcanvas.setStrokeColorRGB(132.0/255,0.0/255,50.0/255)
PDFcanvas.setFont("Courier", 20)
PDFcanvas.drawString(5*cm, page_height - 8*cm, 'Č TALLY HOOO!!! č')
PDFcanvas.setFont("SansB", 20)
PDFcanvas.drawString(5*cm, page_height - 10*cm, 'Č TALLY HOOO!!! č')

PDFcanvas.showPage()
PDFcanvas.save()


_______________________________________________
reportlab-users mailing list
reportl...@lists2.reportlab.com
http://two.pairlist.net/mailman/listinfo/reportlab-users

Robin Becker

unread,
Sep 26, 2013, 9:16:24 AM9/26/13
to reportlab-users
Hi Nils,

I think the error is that you are re-using the canvas at the end of the build.

Effectively you are re-using the canvas page and saving it again. That
probably means you are re-defining the subset fonts again in the document.

I think the intent is for your extra code to write on the last document page.

The correct way to do that is to to have your page template have an onPageEnd
attribute.


On 25/09/2013 22:36, Nils Smeds wrote:
............
> PDFdoc.build(PDFdoc_elements)
>

> PDFcanvas=PDFdoc.canv
>
> PDFcanvas.setStrokeColorRGB(132.0/255,0.0/255,50.0/255)
> PDFcanvas.setFont("Courier", 20)
> PDFcanvas.drawString(5*cm, page_height - 8*cm, 'Č TALLY HOOO!!! č')
> PDFcanvas.setFont("SansB", 20)
> PDFcanvas.drawString(5*cm, page_height - 10*cm, 'Č TALLY HOOO!!! č')
>
> PDFcanvas.showPage()
> PDFcanvas.save()

SimpleDocTemplate doesn't really allow you to specify the onPageEnd attributes
too easily, but you can get the onPage attributes set fairly easily eg


> def myOnPage(PDFcanvas,doc):


> PDFcanvas.setStrokeColorRGB(132.0/255,0.0/255,50.0/255)
> PDFcanvas.setFont("Courier", 20)

> PDFcanvas.drawString(5*cm, page_height - 8*cm, 'C TALLY HOOO!!! c')
> PDFcanvas.setFont("SansB", 20)
> PDFcanvas.drawString(5*cm, page_height - 10*cm, 'C TALLY HOOO!!! c')
..........
> PDFdoc.build(PDFdoc_elements,onFirstPage=myOnPage,onLaterPages=myOnPage)

--
Robin Becker

Tim Roberts

unread,
Sep 26, 2013, 12:29:33 PM9/26/13
to reportlab-users
Nils Smeds wrote:
> Here is a simple test case:
> Modify the base_style array as indicated to expose the problem I see.

I can give you a workaround for this, although it is somewhat unsatisfying.

The root of the issue, I think, is that you have a document serving two
masters. You are using SimpleDocTemplate to create a document object.
That document object expects to be in charge. When you call "build", he
does the drawing, he does a showPage, and he does a saveFile. He thinks
he's done. Then, you go fetch his canvas, do additional drawing, do
another showPage and another saveFile. At that point, the fonts get
enumerated again and confusion results.

To work around this problem, you can just tell the document to forget
about the fonts it already handled. So, add one line:
PDFdoc.build(PDCdoc_elements)
PDFcanvas=PDFdoc.canv
PDFcanvas._doc.delayedFonts = [] # <<<

I'm afraid I will have to leave it to the ReportLab folks to figure out
whether this is preventable, or if this is a usage problem.

--
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.

Andrés Osorio

unread,
Dec 14, 2023, 4:59:45 PM12/14/23
to reportlab-users
Thanks, Tim.
Your answer has been very useful, almost 10 years later and this is still a problem. But your solution has been delightful and useful.

Reply all
Reply to author
Forward
0 new messages