You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kompass/jdav_web/members/pdf.py

157 lines
4.4 KiB
Python

from datetime import datetime
import unicodedata
import os
import subprocess
import time
import glob
from io import BytesIO
from pypdf import PdfReader, PdfWriter, PageObject
from django import template
from django.template.loader import get_template
from django.conf import settings
from django.http import HttpResponse, HttpResponseRedirect
from wsgiref.util import FileWrapper
from contrib.media import media_path, media_dir, serve_media, ensure_media_dir, find_template
from utils import normalize_filename
from PIL import Image
def serve_pdf(filename_pdf):
return serve_media(filename_pdf, 'application/pdf')
def generate_tex(name, template_path, context, date=None):
filename = normalize_filename(name, date=date)
filename_tex = filename + '.tex'
tmpl = get_template(template_path)
res = tmpl.render(dict(context, creation_date=datetime.today().strftime('%d.%m.%Y')))
ensure_media_dir()
with open(media_path(filename_tex), 'w', encoding='utf-8') as f:
f.write(res)
return filename
def render_docx(name, template_path, context, date=None, save_only=False):
filename = generate_tex(name, template_path, context, date=date)
filename_tex = filename + '.tex'
filename_docx = filename + '.docx'
oldwd = os.getcwd()
os.chdir(media_dir())
subprocess.call(['pandoc', filename_tex, '-o', filename_docx])
time.sleep(1)
os.chdir(oldwd)
if save_only:
return filename_docx
return serve_media(filename_docx, 'application/docx')
def render_tex(name, template_path, context, date=None, save_only=False):
filename = generate_tex(name, template_path, context, date=date)
filename_tex = filename + '.tex'
filename_pdf = filename + '.pdf'
# compile using pdflatex
oldwd = os.getcwd()
os.chdir(media_dir())
subprocess.call(['pdflatex', '-halt-on-error',filename_tex])
time.sleep(1)
# do some cleanup
for f in glob.glob('*.log'):
os.remove(f)
for f in glob.glob('*.aux'):
os.remove(f)
#os.remove(filename_tex)
#os.remove(filename_table)
os.chdir(oldwd)
if save_only:
return filename_pdf
return serve_pdf(filename_pdf)
def scale_pdf_page_to_a4(page):
A4_WIDTH, A4_HEIGHT = 595, 842
page_width = page.mediabox.width
page_height = page.mediabox.height
scale_x = A4_WIDTH / page_width
scale_y = A4_HEIGHT / page_height
scale_factor = min(scale_x, scale_y)
new_page = PageObject.create_blank_page(width=A4_WIDTH, height=A4_HEIGHT)
page.scale_by(scale_factor)
x_offset = (A4_WIDTH - page.mediabox.width) / 2
y_offset = (A4_HEIGHT - page.mediabox.height) / 2
new_page.merge_translated_page(page, x_offset, y_offset)
return new_page
def scale_pdf_to_a4(pdf):
scaled_pdf = PdfWriter()
for page in pdf.pages:
scaled_pdf.add_page(scale_pdf_page_to_a4(page))
return scaled_pdf
def fill_pdf_form(name, template_path, fields, attachments=[], date=None, save_only=False):
filename = normalize_filename(name, date=date)
filename_pdf = filename + '.pdf'
path = find_template(template_path)
ensure_media_dir()
reader = PdfReader(path)
writer = PdfWriter()
writer.append(reader)
writer.update_page_form_field_values(None, fields, auto_regenerate=False)
for fp in attachments:
try:
if fp.endswith(".pdf"):
# append pdf directly
img_pdf = PdfReader(fp)
else:
# convert ensures that png files with an alpha channel can be appended
img = Image.open(fp).convert("RGB")
img_io = BytesIO()
img.save(img_io, "pdf")
img_io.seek(0)
img_pdf = PdfReader(img_io)
img_pdf_scaled = scale_pdf_to_a4(img_pdf)
writer.append(img_pdf_scaled)
except Exception as e:
print("Could not add image", fp)
print(e)
with open(media_path(filename_pdf), 'wb') as output_stream:
writer.write(output_stream)
if save_only:
return filename_pdf
return serve_pdf(filename_pdf)
def merge_pdfs(name, filenames, date=None, save_only=False):
merger = PdfWriter()
for pdf in filenames:
merger.append(media_path(pdf))
filename = normalize_filename(name, date=date)
filename_pdf = filename + ".pdf"
merger.write(media_path(filename_pdf))
merger.close()
if save_only:
return filename_pdf
return serve_pdf(filename_pdf)