Here's my code. My first function is based on the /Lib/site-packages/reportlab/lib/styles.py
source code, to create an array of style
:
def create_styles(p_tuples):
retour = StyleSheet1()
parent = None
for p_name, font_name, font in p_tuples:
# (!) change path if Linux:
ttf_file = "C:/Windows/Fonts/{}.ttf".format(font)
pdfmetrics.registerFont(TTFont(font_name, ttf_file))
if parent is None:
p = ParagraphStyle(name=p_name,
fontName=font_name,
fontSize=10,
leading=12)
retour.add(p)
parent = p
else:
retour.add(ParagraphStyle(name=p_name,
parent=parent,
fontName=font_name,
fontSize=10,
leading=12))
return retour
Then I build my own array with my installed fonts:
def render_to_response(self, context, **response_kwargs):
# this is a response for Django, but the question is about styles
response = HttpResponse(content_type='application/pdf; charset=utf-8')
# ! Hint : no filename -> the browser extracts it from the URL!
# -> create URLs like http://pdfreportlab.com/extract/myfilename.pdf
# this is the way to go to have 100% working UTF-8 filenames!
response['Content-Disposition'] = 'attachment; filename=""'
my_styles = self.create_styles([
('ms-regular', 'montserrat-regular',
'Montserrat-Regular'),
('ms-black', 'montserrat-black',
'Montserrat-Black'),
('ms-black-italic', 'montserrat-black-italic',
'Montserrat-BlackItalic'),
('ms-bold', 'montserrat-bold',
'Montserrat-Bold'),
('ms-bold-italic', 'montserrat-bold-italic',
'Montserrat-BoldItalic'),
])
doc = SimpleDocTemplate(response)
elements = []
c = canvas.Canvas(response, pagesize=A4, )
for idx in my_styles.byName:
p = Paragraph("Hello World <i>italic</i> <b>bold</b>",
style=my_styles[idx])
width, height = p.wrapOn(c, A4[0], A4[1])
elements.append(p)
doc.build(elements)
return response
Everything is working except the (very annoying) fact that the <i></i>
and <b></b>
tags are ignored! It only uses the current font in the style.
How could you modify my code so that it takes in account the tags and I finally get styles with the tags in the text itself?
You need to register a font family if you want Platypus to auto-select fonts - you're creating a different style for every font variant so of course the <i>
and <b>
tags have no effect - it doesn't know what fonts to use for them as the passed style references a single font.
Here's how to build a style using a font family:
from reportlab.lib.styles import ParagraphStyle
from reportlab.pdfbase.pdfmetrics import registerFont, registerFontFamily
from reportlab.pdfbase.ttfonts import TTFont
def create_paragraph_style(name, font_name, **kwargs):
ttf_path = "C:/Windows/Fonts/{}.ttf"
family_args = {} # store arguments for the font family creation
for font_type in ("normal", "bold", "italic", "boldItalic"): # recognized font variants
if font_type in kwargs: # if this type was passed...
font_variant = "{}-{}".format(font_name, font_type) # create font variant name
registerFont(TTFont(font_variant, ttf_path.format(kwargs[font_type])))
family_args[font_type] = font_variant # add it to font family arguments
registerFontFamily(font_name, **family_args) # register a font family
return ParagraphStyle(name=name, fontName=font_name, fontSize=10, leading=12)
Then you can create your paragraph style as:
pstyle = create_paragraph_style("ms", "montserrat",
normal="Montserrat-Regular",
bold="Montserrat-Bold",
boldItalic="Montserrat-BoldItalic")
assuming, of course, that you have TTF files with those names in your fonts directory.
You can then add it to your stylesheet (especially if you want parent inheritance - make sure you add it as an argument to be forwarded to the ParagraphStyle
creation) or directly use it as:
p = Paragraph("Hello World <i>italic</i> <b>bold</b> <b><i>boldItalic</i></b>", style=pstyle)
(the standalone italic won't be affected as we didn't define it in the family, tho).