PDF rendering: Do not create TTFont if already cached (#5748)

This provides a massive speedup for invoice rendering
This commit is contained in:
Raphael Michel
2026-01-05 12:15:35 +01:00
committed by GitHub
parent 449b960438
commit bb5a9bdbf1
4 changed files with 39 additions and 32 deletions
+10 -10
View File
@@ -46,7 +46,6 @@ from reportlab.lib.styles import ParagraphStyle, StyleSheet1
from reportlab.lib.units import mm from reportlab.lib.units import mm
from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.pdfmetrics import stringWidth from reportlab.pdfbase.pdfmetrics import stringWidth
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen.canvas import Canvas from reportlab.pdfgen.canvas import Canvas
from reportlab.platypus import ( from reportlab.platypus import (
BaseDocTemplate, Flowable, Frame, KeepTogether, NextPageTemplate, BaseDocTemplate, Flowable, Frame, KeepTogether, NextPageTemplate,
@@ -59,7 +58,8 @@ from pretix.base.services.currencies import SOURCE_NAMES
from pretix.base.signals import register_invoice_renderers from pretix.base.signals import register_invoice_renderers
from pretix.base.templatetags.money import money_filter from pretix.base.templatetags.money import money_filter
from pretix.helpers.reportlab import ( from pretix.helpers.reportlab import (
FontFallbackParagraph, ThumbnailingImageReader, reshaper, FontFallbackParagraph, ThumbnailingImageReader, register_ttf_font_if_new,
reshaper,
) )
from pretix.presale.style import get_fonts from pretix.presale.style import get_fonts
@@ -234,25 +234,25 @@ class BaseReportlabInvoiceRenderer(BaseInvoiceRenderer):
""" """
Register fonts with reportlab. By default, this registers the OpenSans font family Register fonts with reportlab. By default, this registers the OpenSans font family
""" """
pdfmetrics.registerFont(TTFont('OpenSans', finders.find('fonts/OpenSans-Regular.ttf'))) register_ttf_font_if_new('OpenSans', finders.find('fonts/OpenSans-Regular.ttf'))
pdfmetrics.registerFont(TTFont('OpenSansIt', finders.find('fonts/OpenSans-Italic.ttf'))) register_ttf_font_if_new('OpenSansIt', finders.find('fonts/OpenSans-Italic.ttf'))
pdfmetrics.registerFont(TTFont('OpenSansBd', finders.find('fonts/OpenSans-Bold.ttf'))) register_ttf_font_if_new('OpenSansBd', finders.find('fonts/OpenSans-Bold.ttf'))
pdfmetrics.registerFont(TTFont('OpenSansBI', finders.find('fonts/OpenSans-BoldItalic.ttf'))) register_ttf_font_if_new('OpenSansBI', finders.find('fonts/OpenSans-BoldItalic.ttf'))
pdfmetrics.registerFontFamily('OpenSans', normal='OpenSans', bold='OpenSansBd', pdfmetrics.registerFontFamily('OpenSans', normal='OpenSans', bold='OpenSansBd',
italic='OpenSansIt', boldItalic='OpenSansBI') italic='OpenSansIt', boldItalic='OpenSansBI')
for family, styles in get_fonts(event=self.event, pdf_support_required=True).items(): for family, styles in get_fonts(event=self.event, pdf_support_required=True).items():
pdfmetrics.registerFont(TTFont(family, finders.find(styles['regular']['truetype']))) register_ttf_font_if_new(family, finders.find(styles['regular']['truetype']))
if family == self.event.settings.invoice_renderer_font: if family == self.event.settings.invoice_renderer_font:
self.font_regular = family self.font_regular = family
if 'bold' in styles: if 'bold' in styles:
self.font_bold = family + ' B' self.font_bold = family + ' B'
if 'italic' in styles: if 'italic' in styles:
pdfmetrics.registerFont(TTFont(family + ' I', finders.find(styles['italic']['truetype']))) register_ttf_font_if_new(family + ' I', finders.find(styles['italic']['truetype']))
if 'bold' in styles: if 'bold' in styles:
pdfmetrics.registerFont(TTFont(family + ' B', finders.find(styles['bold']['truetype']))) register_ttf_font_if_new(family + ' B', finders.find(styles['bold']['truetype']))
if 'bolditalic' in styles: if 'bolditalic' in styles:
pdfmetrics.registerFont(TTFont(family + ' B I', finders.find(styles['bolditalic']['truetype']))) register_ttf_font_if_new(family + ' B I', finders.find(styles['bolditalic']['truetype']))
def _normalize(self, text): def _normalize(self, text):
# reportlab does not support unicode combination characters # reportlab does not support unicode combination characters
+11 -11
View File
@@ -71,9 +71,7 @@ from reportlab.lib.colors import Color
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.lib.styles import ParagraphStyle from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.units import mm from reportlab.lib.units import mm
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.pdfmetrics import getAscentDescent from reportlab.pdfbase.pdfmetrics import getAscentDescent
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfgen.canvas import Canvas from reportlab.pdfgen.canvas import Canvas
from reportlab.platypus import Paragraph from reportlab.platypus import Paragraph
@@ -84,7 +82,9 @@ from pretix.base.signals import layout_image_variables, layout_text_variables
from pretix.base.templatetags.money import money_filter from pretix.base.templatetags.money import money_filter
from pretix.base.templatetags.phone_format import phone_format from pretix.base.templatetags.phone_format import phone_format
from pretix.helpers.daterange import datetimerange from pretix.helpers.daterange import datetimerange
from pretix.helpers.reportlab import ThumbnailingImageReader, reshaper from pretix.helpers.reportlab import (
ThumbnailingImageReader, register_ttf_font_if_new, reshaper,
)
from pretix.presale.style import get_fonts from pretix.presale.style import get_fonts
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -794,19 +794,19 @@ class Renderer:
def _register_fonts(cls, event: Event = None): def _register_fonts(cls, event: Event = None):
if hasattr(cls, '_fonts_registered'): if hasattr(cls, '_fonts_registered'):
return return
pdfmetrics.registerFont(TTFont('Open Sans', finders.find('fonts/OpenSans-Regular.ttf'))) register_ttf_font_if_new('Open Sans', finders.find('fonts/OpenSans-Regular.ttf'))
pdfmetrics.registerFont(TTFont('Open Sans I', finders.find('fonts/OpenSans-Italic.ttf'))) register_ttf_font_if_new('Open Sans I', finders.find('fonts/OpenSans-Italic.ttf'))
pdfmetrics.registerFont(TTFont('Open Sans B', finders.find('fonts/OpenSans-Bold.ttf'))) register_ttf_font_if_new('Open Sans B', finders.find('fonts/OpenSans-Bold.ttf'))
pdfmetrics.registerFont(TTFont('Open Sans B I', finders.find('fonts/OpenSans-BoldItalic.ttf'))) register_ttf_font_if_new('Open Sans B I', finders.find('fonts/OpenSans-BoldItalic.ttf'))
for family, styles in get_fonts(event, pdf_support_required=True).items(): for family, styles in get_fonts(event, pdf_support_required=True).items():
pdfmetrics.registerFont(TTFont(family, finders.find(styles['regular']['truetype']))) register_ttf_font_if_new(family, finders.find(styles['regular']['truetype']))
if 'italic' in styles: if 'italic' in styles:
pdfmetrics.registerFont(TTFont(family + ' I', finders.find(styles['italic']['truetype']))) register_ttf_font_if_new(family + ' I', finders.find(styles['italic']['truetype']))
if 'bold' in styles: if 'bold' in styles:
pdfmetrics.registerFont(TTFont(family + ' B', finders.find(styles['bold']['truetype']))) register_ttf_font_if_new(family + ' B', finders.find(styles['bold']['truetype']))
if 'bolditalic' in styles: if 'bolditalic' in styles:
pdfmetrics.registerFont(TTFont(family + ' B I', finders.find(styles['bolditalic']['truetype']))) register_ttf_font_if_new(family + ' B I', finders.find(styles['bolditalic']['truetype']))
cls._fonts_registered = True cls._fonts_registered = True
+8
View File
@@ -100,3 +100,11 @@ class FontFallbackParagraph(Paragraph):
if (original_font.endswith("Bd") or original_font.endswith(" B")) and "bold" in styles: if (original_font.endswith("Bd") or original_font.endswith(" B")) and "bold" in styles:
return family + " B" return family + " B"
return family return family
def register_ttf_font_if_new(name, path):
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
if name not in pdfmetrics.getRegisteredFontNames():
pdfmetrics.registerFont(TTFont(name, path))
+10 -11
View File
@@ -69,7 +69,9 @@ from pretix.base.timeframes import (
resolve_timeframe_to_datetime_start_inclusive_end_exclusive, resolve_timeframe_to_datetime_start_inclusive_end_exclusive,
) )
from pretix.control.forms.filter import OverviewFilterForm from pretix.control.forms.filter import OverviewFilterForm
from pretix.helpers.reportlab import FontFallbackParagraph from pretix.helpers.reportlab import (
FontFallbackParagraph, register_ttf_font_if_new,
)
from pretix.presale.style import get_fonts from pretix.presale.style import get_fonts
@@ -130,21 +132,18 @@ class ReportlabExportMixin:
@staticmethod @staticmethod
def register_fonts(): def register_fonts():
from reportlab.pdfbase import pdfmetrics register_ttf_font_if_new('OpenSans', finders.find('fonts/OpenSans-Regular.ttf'))
from reportlab.pdfbase.ttfonts import TTFont register_ttf_font_if_new('OpenSansIt', finders.find('fonts/OpenSans-Italic.ttf'))
register_ttf_font_if_new('OpenSansBd', finders.find('fonts/OpenSans-Bold.ttf'))
pdfmetrics.registerFont(TTFont('OpenSans', finders.find('fonts/OpenSans-Regular.ttf')))
pdfmetrics.registerFont(TTFont('OpenSansIt', finders.find('fonts/OpenSans-Italic.ttf')))
pdfmetrics.registerFont(TTFont('OpenSansBd', finders.find('fonts/OpenSans-Bold.ttf')))
for family, styles in get_fonts(None, pdf_support_required=True).items(): for family, styles in get_fonts(None, pdf_support_required=True).items():
pdfmetrics.registerFont(TTFont(family, finders.find(styles['regular']['truetype']))) register_ttf_font_if_new(family, finders.find(styles['regular']['truetype']))
if 'italic' in styles: if 'italic' in styles:
pdfmetrics.registerFont(TTFont(family + ' I', finders.find(styles['italic']['truetype']))) register_ttf_font_if_new(family + ' I', finders.find(styles['italic']['truetype']))
if 'bold' in styles: if 'bold' in styles:
pdfmetrics.registerFont(TTFont(family + ' B', finders.find(styles['bold']['truetype']))) register_ttf_font_if_new(family + ' B', finders.find(styles['bold']['truetype']))
if 'bolditalic' in styles: if 'bolditalic' in styles:
pdfmetrics.registerFont(TTFont(family + ' B I', finders.find(styles['bolditalic']['truetype']))) register_ttf_font_if_new(family + ' B I', finders.find(styles['bolditalic']['truetype']))
def get_doc_template(self): def get_doc_template(self):
from reportlab.platypus import BaseDocTemplate from reportlab.platypus import BaseDocTemplate