Index: main/waeup.kofa/trunk/src/waeup/kofa/browser/interfaces.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/browser/interfaces.py	(revision 8045)
+++ main/waeup.kofa/trunk/src/waeup/kofa/browser/interfaces.py	(revision 8059)
@@ -163,2 +163,32 @@
         """Get captcha chosen for a certain site or default.
         """
+
+class IPDFCreator(Interface):
+    """A component that knows where logo graphics for PDFs are stored
+    and can generate PDF documents.
+
+    It is a utility (and not a simple function or class) to make these
+    data customizable in derived packages.
+    """
+    header_logo_path = schema.TextLine(
+        title = u'Path to header logo JPG')
+    watermark_path = schema.TextLine(
+        title = u'Path to watermark logo JPG')
+    def paint_background(canvas, doc):
+        """A callback function to render background of PDFs.
+        """
+    def create_pdf(data, headerline=None, title=None):
+        """Create a PDF.
+
+        `data` is expected to be a list of reportlab flowables
+        (paragraphs, images, tables, etc.), that will be rendered into
+        some background.
+
+        `headerline` will be displayed in page head and `title` under
+        the top bar.
+
+        If no `headerline` is given, a default will be rendered (name
+        of university).
+
+        If no `title` is given, nothing will be rendered.
+        """
Index: main/waeup.kofa/trunk/src/waeup/kofa/browser/pdf.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/browser/pdf.py	(revision 8059)
+++ main/waeup.kofa/trunk/src/waeup/kofa/browser/pdf.py	(revision 8059)
@@ -0,0 +1,120 @@
+## $Id$
+##
+## Copyright (C) 2012 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+## 
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+## 
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""
+Reusable components for pdf generation.
+"""
+import grok
+import os
+from cStringIO import StringIO
+from datetime import datetime
+from reportlab.lib.units import cm, inch
+from reportlab.lib.pagesizes import A4, landscape, portrait
+from reportlab.platypus import SimpleDocTemplate
+from waeup.kofa.browser.interfaces import IPDFCreator
+
+class PDFCreator(grok.GlobalUtility):
+    grok.implements(IPDFCreator)
+
+    header_logo_path = os.path.join(
+        os.path.dirname(__file__), 'static', 'pdf_logo.jpg')
+    watermark_path = os.path.join(
+        os.path.dirname(__file__), 'static', 'pdf_watermark.jpg')
+
+    def paint_background(self, canvas, doc):
+        """Paint background of a PDF, including watermark, title, etc.
+
+        The `doc` is expected to be some reportlab SimpleDocTemplate
+        or similar object.
+
+        Text of headerline is extracted from doc.kofa_headtitle, the
+        document title (under the head) from doc.kofa_title.
+
+        This is a callback method that will be called from reportlab
+        when creating PDFs with :meth:`create_pdf`.
+        """
+        canvas.saveState()
+        width, height = doc.width, doc.height
+        width += doc.leftMargin + doc.rightMargin
+        height += doc.topMargin + doc.bottomMargin
+
+        # Watermark
+        if self.watermark_path is not None:
+            canvas.saveState()
+            canvas.drawImage(self.watermark_path, 26, 100)
+            canvas.restoreState()
+
+        # Header
+        head_title = getattr(
+            doc, 'kofa_headtitle', getattr(grok.getSite(), 'name',
+                                           u'Sample University'))
+        canvas.setFont("Helvetica-Bold", 18)
+        canvas.drawString(1.5*cm, height-1.7*cm, head_title)
+        canvas.line(1.5*cm,height-1.9*cm,width-1.5*cm,height-1.7*cm)
+        if self.header_logo_path is not None:
+            canvas.drawImage(self.header_logo_path, 507, 170, width=40,
+                             preserveAspectRatio=True, anchor='ne')
+
+        # Title
+        canvas.saveState()
+        canvas.setFont("Helvetica-Bold", 14)
+        title = getattr(doc, 'kofa_title', '')
+        if '\n' in title:
+            title_lines = title.split('\n')
+            for num, line in enumerate(title_lines):
+                canvas.drawCentredString(
+                    width/2.0, height-2.8*cm-(num*0.7*cm), line)
+        elif title:
+            canvas.drawCentredString(width/2.0, height-2.8*cm, title)
+        canvas.restoreState()
+
+        # Footer
+        canvas.saveState()
+        canvas.line(2.2*cm, 0.62*inch, width-2.2*cm, 0.62*inch)
+        canvas.setFont("Helvetica", 9)
+        if not getattr(doc, 'kofa_nodate', False):
+            today = datetime.now().strftime('%d/%m/%Y %H:%M:%S')
+            canvas.drawString(2.2*cm, 0.5 * inch, "Date: %s" % today)
+        canvas.drawRightString(
+            width-2.2*cm, 0.5 * inch, "page %d" % (doc.page,))
+        canvas.restoreState()
+        canvas.restoreState()
+        return
+
+    def create_pdf(self, data, headerline=None, title=None):
+        """Returns a binary data stream which is a PDF document.
+        """
+        pdf_stream = StringIO()
+        doc = SimpleDocTemplate(
+            pdf_stream,
+            bottomMargin=1.1*inch,
+            topMargin=1.6*inch,
+            title=title,
+            pagesize=portrait(A4),
+            showBoundary=False,
+            )
+        # XXX: more things to set here, like author, etc.
+
+        # Set some attributes that are needed when rendering the background.
+        if headerline is not None:
+            doc.kofa_headtitle = headerline
+        doc.kofa_title = title
+        doc.build(data, onFirstPage=self.paint_background,
+                  onLaterPages=self.paint_background)
+        result = pdf_stream.getvalue()
+        pdf_stream.close()
+        return result
