port to new django, AI automated

This commit is contained in:
2026-03-30 22:35:36 +02:00
parent e2d166e437
commit 372da3caa9
215 changed files with 9283 additions and 2981 deletions

View File

@@ -1,95 +1,157 @@
# ----------------------------- Pdf Views ------------------------------------------
from django.http import HttpResponse
from scoremanager.models import Piece
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate, Flowable, Table, PageBreak, NextPageTemplate
from reportlab.lib import pagesizes, units, utils
from reportlab.lib.colors import Color
"""
PDF generation views for the score manager application.
"""
import os
class RepertoireDocTemplate( BaseDocTemplate ):
def __init__(self, *args, **kwargs ):
BaseDocTemplate.__init__(self,*args, **kwargs)
from django.http import HttpResponse
from reportlab.lib import pagesizes, units, utils
from reportlab.lib.colors import Color
from reportlab.platypus import (
BaseDocTemplate,
Flowable,
Frame,
NextPageTemplate,
PageBreak,
PageTemplate,
Table,
)
self.pagesize = kwargs['pagesize']
from .models import Piece
leftBorder = 1 * units.cm
rightBorder = 1 * units.cm
topBorder = 3 * units.cm
bottomBorder = 1 * units.cm
frameWidth = (self.pagesize[0] - rightBorder - leftBorder ) /2
frameHeight = (self.pagesize[1] - topBorder - bottomBorder )
class RepertoireDocTemplate(BaseDocTemplate):
"""Document template for repertoire PDFs with header and two-column layout."""
leftColumn = Frame( leftBorder, bottomBorder, frameWidth, frameHeight, showBoundary=0 )
rightColumn = Frame( leftBorder+frameWidth , bottomBorder, frameWidth, frameHeight, showBoundary=0 )
def __init__(self, *args, **kwargs):
BaseDocTemplate.__init__(self, *args, **kwargs)
tocTemplate = PageTemplate( id='TOC', frames=[leftColumn,rightColumn], onPage=RepertoireDocTemplate._drawHeader )
fullPageTemplate = PageTemplate( id='FullPage', frames = [ Frame(0,0, self.pagesize[0], self.pagesize[1] ) ] )
self.pagesize = kwargs["pagesize"]
self.addPageTemplates( [ tocTemplate, fullPageTemplate ] )
left_border = 1 * units.cm
right_border = 1 * units.cm
top_border = 3 * units.cm
bottom_border = 1 * units.cm
frame_width = (self.pagesize[0] - right_border - left_border) / 2
frame_height = self.pagesize[1] - top_border - bottom_border
left_column = Frame(
left_border, bottom_border, frame_width, frame_height, showBoundary=0
)
right_column = Frame(
left_border + frame_width,
bottom_border,
frame_width,
frame_height,
showBoundary=0,
)
toc_template = PageTemplate(
id="TOC",
frames=[left_column, right_column],
onPage=RepertoireDocTemplate._draw_header,
)
full_page_template = PageTemplate(
id="FullPage",
frames=[Frame(0, 0, self.pagesize[0], self.pagesize[1])],
)
self.addPageTemplates([toc_template, full_page_template])
@staticmethod
def _drawHeader(canvas,document):
def _draw_header(canvas, document):
"""Draw the header with logo and gradient background."""
current_path = os.path.dirname(os.path.realpath(__file__))
logo_image_file = current_path + "/static/pdfImg/logo.png"
bg_image_file = current_path + "/static/pdfImg/body_bg.jpg"
currentPath = os.path.dirname(os.path.realpath(__file__))
logoImageFile = currentPath + "/static/pdfImg/logo.png"
bgImageFile = currentPath + "/static/pdfImg/body_bg.jpg"
#Gradient
titleAreaHeight = 2 * units.cm
gradientColors = [ Color(0.1,0.1,0.1), Color(0.2,0.2,0.2)]
# Gradient
title_area_height = 2 * units.cm
gradient_colors = [Color(0.1, 0.1, 0.1), Color(0.2, 0.2, 0.2)]
ps = document.pagesize
gradientStart = ( ps[0]/2, ps[1] )
gradientEnd = ( ps[0]/2, ps[1] - titleAreaHeight)
canvas.linearGradient( gradientStart[0],gradientStart[1], gradientEnd[0], gradientEnd[1],gradientColors, extend=False )
titleAreaMidY = 0.5 * ( gradientStart[1] + gradientEnd[1] )
gradient_start = (ps[0] / 2, ps[1])
gradient_end = (ps[0] / 2, ps[1] - title_area_height)
canvas.linearGradient(
gradient_start[0],
gradient_start[1],
gradient_end[0],
gradient_end[1],
gradient_colors,
extend=False,
)
title_area_mid_y = 0.5 * (gradient_start[1] + gradient_end[1])
# Draw Logo
logoImg = utils.ImageReader( logoImageFile )
logoSize = logoImg.getSize()
logoFraction = 0.6
logoSize = (logoFraction * logoSize[0], logoFraction*logoSize[1])
logoPosition = ( ps[0] - 5*units.cm, titleAreaMidY - 0.5*logoSize[1] )
canvas.drawImage( logoImg, logoPosition[0], logoPosition[1], width=logoSize[0], height=logoSize[1], mask=Color(0,0,0) )
if os.path.exists(logo_image_file):
logo_img = utils.ImageReader(logo_image_file)
logo_size = logo_img.getSize()
logo_fraction = 0.6
logo_size = (logo_fraction * logo_size[0], logo_fraction * logo_size[1])
logo_position = (
ps[0] - 5 * units.cm,
title_area_mid_y - 0.5 * logo_size[1],
)
canvas.drawImage(
logo_img,
logo_position[0],
logo_position[1],
width=logo_size[0],
height=logo_size[1],
mask=Color(0, 0, 0),
)
# Draw Title
text = canvas.beginText()
text.setTextOrigin( 1 * units.cm, titleAreaMidY-25/2 )
text.setFillColorRGB( 0.95,0.95,0.95 )
text.setFont( 'Helvetica', 25 )
text.textLine( "Inhaltsverzeichnis" )
canvas.drawText( text )
text.setTextOrigin(1 * units.cm, title_area_mid_y - 25 / 2)
text.setFillColorRGB(0.95, 0.95, 0.95)
text.setFont("Helvetica", 25)
text.textLine("Inhaltsverzeichnis")
canvas.drawText(text)
# Draw Background
bgImage = utils.ImageReader( bgImageFile )
bgImageSize = bgImage.getSize()
curPos = [0, gradientEnd[1]-bgImageSize[1] ]
while curPos[1] > -bgImageSize[1]:
curPos[0] = 0
while curPos[0] < ps[0]:
canvas.drawImage( bgImage, curPos[0], curPos[1] )
curPos[0] += bgImageSize[0]
curPos[1] -= bgImageSize[1]
if os.path.exists(bg_image_file):
bg_image = utils.ImageReader(bg_image_file)
bg_image_size = bg_image.getSize()
cur_pos = [0, gradient_end[1] - bg_image_size[1]]
while cur_pos[1] > -bg_image_size[1]:
cur_pos[0] = 0
while cur_pos[0] < ps[0]:
canvas.drawImage(bg_image, cur_pos[0], cur_pos[1])
cur_pos[0] += bg_image_size[0]
cur_pos[1] -= bg_image_size[1]
class PdfImage(Flowable):
"""PdfImage wraps the first page from a PDF file as a Flowable
which can be included into a ReportLab Platypus document.
Based on the vectorpdf extension in rst2pdf (http://code.google.com/p/rst2pdf/)"""
"""
PdfImage wraps the first page from a PDF file as a Flowable
which can be included into a ReportLab Platypus document.
def __init__(self, filename_or_object, page=0, width=None, height=None, kind='direct'):
from pdfrw import PdfReader
from pdfrw.buildxobj import pagexobj
Based on the vectorpdf extension in rst2pdf (http://code.google.com/p/rst2pdf/)
"""
def __init__(
self, filename_or_object, page=0, width=None, height=None, kind="direct"
):
Flowable.__init__(self)
try:
from pdfrw import PdfReader
from pdfrw.buildxobj import pagexobj
except ImportError:
raise ImportError(
"pdfrw is required for PDF embedding. Install it with: pip install pdfrw"
)
# If using StringIO buffer, set pointer to beginning
if hasattr(filename_or_object, 'read'):
if hasattr(filename_or_object, "read"):
filename_or_object.seek(0)
page = PdfReader(filename_or_object, decompress=False).pages[page]
self.xobj = pagexobj(page)
pdf_pages = PdfReader(filename_or_object, decompress=False).pages
if page >= len(pdf_pages):
page = 0
self.xobj = pagexobj(pdf_pages[page])
self.imageWidth = width
self.imageHeight = height
x1, y1, x2, y2 = self.xobj.BBox
@@ -99,36 +161,42 @@ class PdfImage(Flowable):
self.imageWidth = self._w
if not self.imageHeight:
self.imageHeight = self._h
self.__ratio = float(self.imageWidth)/self.imageHeight
if kind in ['direct','absolute'] or width==None or height==None:
self.__ratio = float(self.imageWidth) / self.imageHeight
if kind in ["direct", "absolute"] or width is None or height is None:
self.drawWidth = width or self.imageWidth
self.drawHeight = height or self.imageHeight
elif kind in ['bound','proportional']:
factor = min(float(width)/self._w,float(height)/self._h)
self.drawWidth = self._w*factor
self.drawHeight = self._h*factor
elif kind in ["bound", "proportional"]:
factor = min(float(width) / self._w, float(height) / self._h)
self.drawWidth = self._w * factor
self.drawHeight = self._h * factor
def wrap(self, aW, aH):
return self.drawWidth, self.drawHeight
def drawOn(self, canv, x, y, _sW=0):
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT
from pdfrw.toreportlab import makerl
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
if _sW > 0 and hasattr(self, 'hAlign'):
try:
from pdfrw.toreportlab import makerl
except ImportError:
raise ImportError("pdfrw is required for PDF embedding.")
if _sW > 0 and hasattr(self, "hAlign"):
a = self.hAlign
if a in ('CENTER', 'CENTRE', TA_CENTER):
x += 0.5*_sW
elif a in ('RIGHT', TA_RIGHT):
if a in ("CENTER", "CENTRE", TA_CENTER):
x += 0.5 * _sW
elif a in ("RIGHT", TA_RIGHT):
x += _sW
elif a not in ('LEFT', TA_LEFT):
elif a not in ("LEFT", TA_LEFT):
raise ValueError("Bad hAlign value " + str(a))
xobj = self.xobj
xobj_name = makerl(canv._doc, xobj)
xscale = self.drawWidth/self._w
yscale = self.drawHeight/self._h
xscale = self.drawWidth / self._w
yscale = self.drawHeight / self._h
x -= xobj.BBox[0] * xscale
y -= xobj.BBox[1] * yscale
@@ -141,81 +209,97 @@ class PdfImage(Flowable):
class Bookmark(Flowable):
""" Utility class to display PDF bookmark. """
"""Utility class to display PDF bookmark."""
def __init__(self, title, key):
self.title = title
self.key = key
Flowable.__init__(self)
def wrap(self, availWidth, availHeight):
""" Doesn't take up any space. """
"""Doesn't take up any space."""
return (0, 0)
def draw(self):
# set the bookmark outline to show when the file's opened
self.canv.showOutline()
# step 1: put a bookmark on the
# step 1: put a bookmark on the page
self.canv.bookmarkPage(self.key)
# step 2: put an entry in the bookmark outline
self.canv.addOutlineEntry(self.title, self.key, 0, 0)
def repertoire_pdf( request ):
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="Repertoire.pdf"'
def repertoire_pdf(request):
"""Generate a PDF containing the full repertoire with scores."""
response = HttpResponse(content_type="application/pdf")
response["Content-Disposition"] = 'attachment; filename="Repertoire.pdf"'
# Create the PDF object, using the response object as its "file.
# Create the PDF object, using the response object as its "file"
doc = RepertoireDocTemplate(response, pagesize=pagesizes.A4)
elements = []
elements.append( Bookmark("Inhaltsverzeichnis", "Contents") )
#TOC
elements.append(Bookmark("Inhaltsverzeichnis", "Contents"))
# Table of Contents
data = []
for piece in Piece.getRepertoire():
data.append( [ "%d %s" % ( piece.repertoire_nr, piece.title ) ] )
table = Table(data)
table.hAlign = "LEFT"
elements.append(table)
for piece in Piece.get_repertoire():
data.append([f"{piece.repertoire_nr} {piece.title}"])
if data:
table = Table(data)
table.hAlign = "LEFT"
elements.append(table)
elements.append( NextPageTemplate('FullPage') )
elements.append(NextPageTemplate("FullPage"))
elements.append(PageBreak())
pagesize=pagesizes.A4
for piece in Piece.getRepertoire():
score = piece.get_score_for_user( request.user )
pagesize = pagesizes.A4
for piece in Piece.get_repertoire():
score = piece.get_score_for_user(request.user)
if score is None:
continue
filename = score.file
bookmarkTitle = "%02d %s - %s " % ( piece.repertoire_nr, piece.title, score.score_type )
elements.append( Bookmark( bookmarkTitle, str(piece.id) ) )
#TODO support also multiple pages!!
image_flowable = PdfImage( filename, 0, width=pagesize[0]*0.98, height=pagesize[1] *0.98 )
image_flowable.hAlign = "CENTER"
elements.append( image_flowable )
bookmark_title = (
f"{piece.repertoire_nr:02d} {piece.title} - {score.score_type}"
)
elements.append(Bookmark(bookmark_title, str(piece.id)))
try:
# TODO: support multiple pages
image_flowable = PdfImage(
filename, 0, width=pagesize[0] * 0.98, height=pagesize[1] * 0.98
)
image_flowable.hAlign = "CENTER"
elements.append(image_flowable)
except Exception as e:
# Skip this score if PDF processing fails
print(f"Error processing PDF for {piece.title}: {e}")
continue
doc.build(elements)
return response
def repertoire_toc(request):
"""Generate a PDF containing only the table of contents."""
response = HttpResponse(content_type="application/pdf")
response["Content-Disposition"] = 'attachment; filename="Inhaltsverzeichnis.pdf"'
def repertoire_toc( request ):
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="Inhaltsverzeichnis.pdf"'
# Create the PDF object, using the response object as its "file.
doc = RepertoireDocTemplate(response,pagesize=pagesizes.A4 )
# Create the PDF object, using the response object as its "file"
doc = RepertoireDocTemplate(response, pagesize=pagesizes.A4)
elements = []
data = []
for piece in Piece.getRepertoire():
data.append( [ "%d %s" % ( piece.repertoire_nr, piece.title ) ] )
for piece in Piece.get_repertoire():
data.append([f"{piece.repertoire_nr} {piece.title}"])
table = Table(data)
table.hAlign = "LEFT"
elements.append(table)
if data:
table = Table(data)
table.hAlign = "LEFT"
elements.append(table)
doc.build(elements)
return response