Question

I need to create PDFs from content types (made with dexerity if that matters) so that the user creates a new document and after filling the form a PDF is generated and ready to be downloaded. So basically after creating/modifying the document a PDF should be created and stored in ZODB (actually I'm using blobs) so that I could link the view with a "Download as PDF".

I've seen PDFNode but it doesn't seem to be what I'm looking for. There's also Produce & Publish but it's a webservice(?) and the company I'm going to develop this for doesn't want (for privacy) to send data outside their datacenters.

Any idea?

Was it helpful?

Solution

It seems that you are searching for these:

OTHER TIPS

I actually do this sort of thing a lot on a project of mine. I used Products.SmartPrintNG and fop for it though and didn't do it the standard way that the product uses(I think it uses javascript to initiate the conversion.. weird).

Couple things:

  • I had to sanitize the output since fop is pretty touchy
  • used lxml
  • mine uses archetypes

Anyways, my event handler for creating the PDF ends up looking something like this:

from Products.SmartPrintNG.browser import SmartPrintView
from lxml.cssselect import CSSSelector
from lxml.html import fromstring, tostring
import re

san_re = re.compile('(?P<width>width\=("|\')\d{1,5}(px|%|in|cm|mm|em|ex|pt|pc)?("|\'))')

class Options(object):

    def __init__(self, __dict):
        self.__dict = __dict

    def __getattr__(self, attr):
        if self.__dict.has_key(attr):
            return self.__dict[attr]
        raise AttributeError(attr)

def sanitize_xml(xml):
    selector = CSSSelector('table,td,tr')
    elems = selector(xml)
    for el in elems:
        if el.attrib.has_key('width'):
            width = el.attrib['width']
            style = el.attrib.get('style', '').strip()
            if style and not style.endswith(';'):
                style += ';'
            style += 'width:%s;' % width
            del el.attrib['width'] 
            el.attrib['style'] = style

    return xml

def save_pdf(obj, event):
    smartprint = SmartPrintView(obj, obj.REQUEST)
    html = obj.restrictedTraverse('view')()
    xml = fromstring(html)
    selector = CSSSelector('div#content')
    xml = selector(xml)
    html = tostring(sanitize_xml(xml[0]))
    res = smartprint.convert(
        html=html,
        format='pdf2',
        options=Options({'stylesheet': 'pdf_output_stylesheet', 'template': 'StandardTemplate'})
    )

    field = obj.getField('generatedPDF')
    field.set(obj, res, mimetype='application/pdf', _initializing_=True)
    field.setFilename(obj, obj.getId() + '.pdf')

Produce and Publish Lite is self-contained, open-source code and the successor to SmartPrintNG. http://pypi.python.org/pypi/zopyx.smartprintng.lite/

use z3c.rml, works very well to produce pdf from an rml template, instead of converting from html which can be tricky.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top