# ----------------------------- 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 import os class RepertoireDocTemplate( BaseDocTemplate ): def __init__(self, *args, **kwargs ): BaseDocTemplate.__init__(self,*args, **kwargs) self.pagesize = kwargs['pagesize'] 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 ) leftColumn = Frame( leftBorder, bottomBorder, frameWidth, frameHeight, showBoundary=0 ) rightColumn = Frame( leftBorder+frameWidth , bottomBorder, frameWidth, frameHeight, showBoundary=0 ) 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.addPageTemplates( [ tocTemplate, fullPageTemplate ] ) @staticmethod def _drawHeader(canvas,document): 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)] 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] ) # 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) ) # 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 ) # 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] 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/)""" def __init__(self, filename_or_object, page=0, width=None, height=None, kind='direct'): from pdfrw import PdfReader from pdfrw.buildxobj import pagexobj # If using StringIO buffer, set pointer to beginning if hasattr(filename_or_object, 'read'): filename_or_object.seek(0) page = PdfReader(filename_or_object, decompress=False).pages[page] self.xobj = pagexobj(page) self.imageWidth = width self.imageHeight = height x1, y1, x2, y2 = self.xobj.BBox self._w, self._h = x2 - x1, y2 - y1 if not self.imageWidth: 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.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 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 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): x += _sW 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 x -= xobj.BBox[0] * xscale y -= xobj.BBox[1] * yscale canv.saveState() canv.translate(x, y) canv.scale(xscale, yscale) canv.doForm(xobj_name) canv.restoreState() class Bookmark(Flowable): """ 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. """ 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 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"' # Create the PDF object, using the response object as its "file. doc = RepertoireDocTemplate(response, pagesize=pagesizes.A4) elements = [] elements.append( Bookmark("Inhaltsverzeichnis", "Contents") ) #TOC data = [] for piece in Piece.getRepertoire(): data.append( [ "%d %s" % ( piece.repertoire_nr, piece.title ) ] ) table = Table(data) table.hAlign = "LEFT" elements.append(table) elements.append( NextPageTemplate('FullPage') ) elements.append(PageBreak()) pagesize=pagesizes.A4 for piece in Piece.getRepertoire(): score = piece.get_score_for_user( request.user ) 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 ) doc.build(elements) return response 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 ) elements = [] data = [] for piece in Piece.getRepertoire(): data.append( [ "%d %s" % ( piece.repertoire_nr, piece.title ) ] ) table = Table(data) table.hAlign = "LEFT" elements.append(table) doc.build(elements) return response