Add support for PDFTK

This commit is contained in:
Raphael Michel
2018-11-26 13:43:06 +01:00
parent ca59237ebf
commit 7eab1982fe
3 changed files with 54 additions and 20 deletions

View File

@@ -295,5 +295,13 @@ various places like order codes, secrets in the ticket QR codes, etc. Example::
; Voucher code needs to be < 255 characters, default is 16 ; Voucher code needs to be < 255 characters, default is 16
voucher_code=16 voucher_code=16
External tools
--------------
pretix can make use of some external tools if they are installed. Currently, they are all optional. Example::
[tools]
pdftk=/usr/bin/pdftk
.. _Python documentation: https://docs.python.org/3/library/configparser.html?highlight=configparser#supported-ini-file-structure .. _Python documentation: https://docs.python.org/3/library/configparser.html?highlight=configparser#supported-ini-file-structure
.. _Celery documentation: http://docs.celeryproject.org/en/latest/userguide/configuration.html .. _Celery documentation: http://docs.celeryproject.org/en/latest/userguide/configuration.html

View File

@@ -1,11 +1,15 @@
import copy import copy
import logging import logging
import os
import re import re
import subprocess
import tempfile
import uuid import uuid
from collections import OrderedDict from collections import OrderedDict
from io import BytesIO from io import BytesIO
import bleach import bleach
from django.conf import settings
from django.contrib.staticfiles import finders from django.contrib.staticfiles import finders
from django.utils.formats import date_format from django.utils.formats import date_format
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@@ -222,10 +226,11 @@ class Renderer:
self.layout = layout self.layout = layout
self.background_file = background_file self.background_file = background_file
self.variables = get_variables(event) self.variables = get_variables(event)
if self.background_file: if not settings.PDFTK:
self.bg_pdf = PdfFileReader(BytesIO(self.background_file.read()), strict=False) if self.background_file:
else: self.bg_pdf = PdfFileReader(BytesIO(self.background_file.read()), strict=False)
self.bg_pdf = None else:
self.bg_pdf = None
@classmethod @classmethod
def _register_fonts(cls): def _register_fonts(cls):
@@ -340,21 +345,40 @@ class Renderer:
canvas.showPage() canvas.showPage()
def render_background(self, buffer, title=_('Ticket')): def render_background(self, buffer, title=_('Ticket')):
from PyPDF2 import PdfFileWriter, PdfFileReader if settings.PDFTK:
buffer.seek(0) buffer.seek(0)
new_pdf = PdfFileReader(buffer) with tempfile.TemporaryDirectory() as d:
output = PdfFileWriter() with open(os.path.join(d, 'back.pdf'), 'wb') as f:
f.write(self.background_file.read())
with open(os.path.join(d, 'front.pdf'), 'wb') as f:
f.write(buffer.read())
subprocess.run([
settings.PDFTK,
os.path.join(d, 'front.pdf'),
'multistamp',
os.path.join(d, 'back.pdf'),
'output',
os.path.join(d, 'out.pdf'),
'compress'
], check=True)
with open(os.path.join(d, 'out.pdf'), 'rb') as f:
return BytesIO(f.read())
else:
from PyPDF2 import PdfFileWriter, PdfFileReader
buffer.seek(0)
new_pdf = PdfFileReader(buffer)
output = PdfFileWriter()
for page in new_pdf.pages: for page in new_pdf.pages:
bg_page = copy.copy(self.bg_pdf.getPage(0)) bg_page = copy.copy(self.bg_pdf.getPage(0))
bg_page.mergePage(page) bg_page.mergePage(page)
output.addPage(bg_page) output.addPage(bg_page)
output.addMetadata({ output.addMetadata({
'/Title': str(title), '/Title': str(title),
'/Creator': 'pretix', '/Creator': 'pretix',
}) })
outbuffer = BytesIO() outbuffer = BytesIO()
output.write(outbuffer) output.write(outbuffer)
outbuffer.seek(0) outbuffer.seek(0)
return outbuffer return outbuffer

View File

@@ -57,6 +57,8 @@ else:
debug_fallback = "runserver" in sys.argv debug_fallback = "runserver" in sys.argv
DEBUG = config.getboolean('django', 'debug', fallback=debug_fallback) DEBUG = config.getboolean('django', 'debug', fallback=debug_fallback)
PDFTK = config.get('tools', 'pdftk', fallback=None)
db_backend = config.get('database', 'backend', fallback='sqlite3') db_backend = config.get('database', 'backend', fallback='sqlite3')
if db_backend == 'postgresql_psycopg2': if db_backend == 'postgresql_psycopg2':
db_backend = 'postgresql' db_backend = 'postgresql'