You must go to the next level and use DocTemplates. The images are pretty lightweight, but using bullets is really hard - you need to define styles and more!
I use a set of classes as shown below:
# -*- coding: utf-8 -*- from django.utils.encoding import smart_str from reportlab.lib.colors import Color from reportlab.lib.pagesizes import A4 from reportlab.lib.styles import StyleSheet1, ParagraphStyle from reportlab.lib.units import cm from reportlab.pdfgen import canvas from reportlab.platypus.doctemplate import BaseDocTemplate, PageTemplate, \ _doNothing from reportlab.platypus.frames import Frame from reportlab.platypus.paragraph import Paragraph import copy import re from reportlab.platypus.flowables import KeepTogether, Image, PageBreak from htmlentitydefs import name2codepoint from atom.http_core import HttpResponse import tempfile def htmlentitydecode(s): return re.sub('&(%s);' % '|'.join(name2codepoint), lambda m: smart_str(unichr(name2codepoint[m.group(1)])), s) PS = ParagraphStyle stylesheet = StyleSheet1() stylesheet.add(PS(name='Normal', leading=15)) stylesheet.add(PS(name='Bullet', parent=stylesheet['Normal'], bulletFontName = 'Symbol', bulletIndent = 0, bulletFontSize = 13, bulletColor = Color(0.93,0,0), bulletOffsetY = -1.5, leftIndent = 15.8, firstLineIndent = 0, ), alias='bu') stylesheet.add(PS(name='Heading1', parent=stylesheet['Normal'], fontSize=18, spaceAfter=23.5), alias='h1') stylesheet.add(PS(name='Heading2', parent=stylesheet['Normal'], fontSize=14, spaceAfter=4), alias='h2') stylesheet.add(PS(name='Heading3', parent=stylesheet['Normal'], textColor=Color(0.93,0,0) ), alias='h3') stylesheet.add(PS(name='Heading4', parent=stylesheet['Heading3'], textColor='black'), alias='h4') BulletStyle = copy.deepcopy(stylesheet["Bullet"]) H1Style = copy.deepcopy(stylesheet["Heading1"]) H2Style = copy.deepcopy(stylesheet["Heading2"]) H3Style = copy.deepcopy(stylesheet["Heading3"]) H4Style = copy.deepcopy(stylesheet["Heading4"]) NormalStyle = copy.deepcopy(stylesheet["Normal"]) top_margin = A4[1] - 1.22*cm bottom_margin = 1.5*cm left_margin = 2.8*cm frame_width = 17.02*cm right_margin = left_margin + frame_width frame_height = 22.7*cm letter_top_margin = 25.0*cm letter_bottom_margin = 3.0*cm letter_left_margin = 2.5*cm letter_right_margin = A4[0] - 2.5*cm letter_frame_width = A4[0] - 5.0*cm letter_frame_height = letter_top_margin - letter_bottom_margin class LetterTemplate(BaseDocTemplate): _invalidInitArgs = ('pageTemplates',) def handle_pageBegin(self): self._handle_pageBegin() self._handle_nextPageTemplate('First') def build(self, flowables, onFirstPage=_doNothing, canvasmaker=canvas.Canvas): self._calc() frameT = Frame(letter_left_margin, letter_bottom_margin, letter_frame_width, letter_frame_height, leftPadding=0, bottomPadding=0, rightPadding=0, topPadding=0, id='normal') self.addPageTemplates([PageTemplate(id='First',frames=frameT, onPage=onFirstPage, pagesize=self.pagesize)]) if onFirstPage is _doNothing and hasattr(self,'onFirstPage'): self.pageTemplates[0].beforeDrawPage = self.onFirstPage BaseDocTemplate.build(self, flowables, canvasmaker=canvasmaker) class PdfA4Letter(object): def __init__(self, filename): self.title = filename self._keep_together = False self.elements = [] self._keep_together_elements = [] self.doc = LetterTemplate(filename,showBoundary=False) self.elements = [] def _process_text(self, txt): text_elems = []
You can then handle the creation of the PDF in your view, for example:
def view(request): file = tempfile.NamedTemporaryFile() e = PdfA4Letter(file.name) ref = '/absolute/path/to/image.png' e.image(ref, width=frame_width, height=10*cm) e.h1((u'Γber Mich')) e.h3('Next header') t = """ ascasc<br /> ascascasc<br /> <ul> <li>sdv1</li> <li>sdv2</li> <li>sdv3</li> </ul> ascasc<br /> ascasc<br /> """ e.text(t) e.blankline(2) e.end_keep_together() e.build() response = HttpResponse(mimetype='application/pdf') response['Content-Disposition'] = 'attachment; filename=gugus.pdf' response.write(file.read()) file.close() return response