开发者

Generate PDF from Plone content types

开发者 https://www.devze.com 2023-04-07 18:29 出处:网络
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 basic

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 blo开发者_开发百科bs) 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?


It seems that you are searching for these:

  • Reportlab (official site) for a custom solution
  • collective.sendaspdf for an ootb solution


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号