Files
PyRIGS/z3c/rml/pdfinclude.py
2014-12-07 17:32:25 +00:00

150 lines
4.6 KiB
Python

##############################################################################
#
# Copyright (c) 2012 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""``pdfInclude`` Directive.
"""
__docformat__ = "reStructuredText"
import cStringIO
try:
import PyPDF2
from PyPDF2.generic import NameObject
except ImportError:
PyPDF2 = None
from reportlab.platypus import flowables
from z3c.rml import attr, flowable, interfaces, occurence, page
class ConcatenationPostProcessor(object):
def __init__(self):
self.operations = []
def process(self, inputFile1):
input1 = PyPDF2.PdfFileReader(inputFile1)
merger = PyPDF2.PdfFileMerger()
merger.output._info.getObject().update(input1.documentInfo)
prev_insert = 0
for start_page, inputFile2, pages, num_pages in self.operations:
if prev_insert < start_page:
merger.append(inputFile1, pages=(prev_insert, start_page))
if not pages:
merger.append(inputFile2)
else:
# Note, users start counting at 1. ;-)
for page in pages:
merger.append(inputFile2, pages=(page-1, page))
prev_insert = start_page + num_pages
input1 = PyPDF2.PdfFileReader(inputFile1)
num_pages = input1.getNumPages()
if prev_insert < num_pages:
merger.append(
inputFile1, pages=(prev_insert, num_pages))
outputFile = cStringIO.StringIO()
merger.write(outputFile)
return outputFile
class PDFPageFlowable(flowables.Flowable):
def __init__(self, width, height):
flowables.Flowable.__init__(self)
self.width = width
self.height = height
def draw(self):
pass
def split(self, availWidth, availheight):
return [self]
class IncludePdfPagesFlowable(flowables.Flowable):
def __init__(self, pdf_file, pages, concatprocessor):
flowables.Flowable.__init__(self)
self.pdf_file = pdf_file
self.proc = concatprocessor
self.pages = pages
self.width = 10<<32
self.height = 10<<32
def draw():
return NotImplementedError('PDFPages shall be drawn not me')
def split(self, availWidth, availheight):
pages = self.pages
if not pages:
pdf = PyPDF2.PdfFileReader(self.pdf_file)
num_pages = pdf.getNumPages()
pages = range(num_pages)
else:
num_pages = len(pages)
start_page = self.canv.getPageNumber()
self.proc.operations.append(
(start_page, self.pdf_file, self.pages, num_pages))
result = []
for i in pages:
result.append(flowables.PageBreak())
result.append(PDFPageFlowable(availWidth, availheight))
return result
class IIncludePdfPages(interfaces.IRMLDirectiveSignature):
"""Inserts a set of pages from a given PDF."""
filename = attr.File(
title=u'Path to file',
description=u'The pdf file to include.',
required=True)
pages = attr.IntegerSequence(
title=u'Pages',
description=u'A list of pages to insert.',
required=False)
class IncludePdfPages(flowable.Flowable):
signature = IIncludePdfPages
def getProcessor(self):
manager = attr.getManager(self, interfaces.IPostProcessorManager)
procs = dict(manager.postProcessors)
if 'CONCAT' not in procs:
proc = ConcatenationPostProcessor()
manager.postProcessors.append(('CONCAT', proc))
return proc
return procs['CONCAT']
def process(self):
if PyPDF2 is None:
raise Exception(
'PyPDF2 is not installed, so this feature is not available.')
args = dict(self.getAttributeValues())
proc = self.getProcessor()
self.parent.flow.append(
IncludePdfPagesFlowable(args['filename'], args.get('pages'), proc))
flowable.Flow.factories['includePdfPages'] = IncludePdfPages
flowable.IFlow.setTaggedValue(
'directives',
flowable.IFlow.getTaggedValue('directives') +
(occurence.ZeroOrMore('includePdfPages', IIncludePdfPages),)
)