-
Notifications
You must be signed in to change notification settings - Fork 51
/
page.py
125 lines (100 loc) · 4.1 KB
/
page.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
##############################################################################
#
# Copyright (c) 2007 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.
#
##############################################################################
"""Page Drawing Related Element Processing
"""
import io
from z3c.rml import attr
from z3c.rml import directive
from z3c.rml import interfaces
try:
import pikepdf
from pikepdf import Object # noqa: F401 imported but unused
except ImportError:
# We don't want to require pikepdf, if you do not want to use the features
# in this module.
pikepdf = None
def mergePage(layerPage, mainPage, pdf, name) -> None:
contentsForName = pdf.copy_foreign(
pikepdf.Page(layerPage).as_form_xobject()
)
newContents = b'q\n %s Do\nQ\n' % (name.encode())
if not mainPage.Resources.get("/XObject"):
mainPage.Resources["/XObject"] = pikepdf.Dictionary({})
mainPage.Resources["/XObject"][name] = contentsForName
# Use the MediaBox from the merged page
mainPage.MediaBox = layerPage.MediaBox
mainPage.contents_add(
contents=pikepdf.Stream(pdf, newContents),
prepend=True
)
class MergePostProcessor:
def __init__(self):
self.operations = {}
def process(self, inputFile1):
input1 = pikepdf.open(inputFile1)
count = 0
for (num, page) in enumerate(input1.pages):
if num in self.operations:
for mergeFile, mergeNumber in self.operations[num]:
mergePdf = pikepdf.open(mergeFile)
toMerge = mergePdf.pages[mergeNumber]
name = f"/Fx{count}"
mergePage(toMerge, page, input1, name)
outputFile = io.BytesIO()
input1.save(outputFile)
return outputFile
class IMergePage(interfaces.IRMLDirectiveSignature):
"""Merges an existing PDF Page into the one to be generated."""
filename = attr.File(
title='File',
description=('Reference to the PDF file to extract the page from.'),
required=True)
page = attr.Integer(
title='Page Number',
description='The page number of the PDF file that is used to merge..',
required=True)
class MergePage(directive.RMLDirective):
signature = IMergePage
def getProcessor(self):
manager = attr.getManager(self, interfaces.IPostProcessorManager)
procs = dict(manager.postProcessors)
if 'MERGE' not in procs:
proc = MergePostProcessor()
manager.postProcessors.append(('MERGE', proc))
return proc
return procs['MERGE']
def process(self):
if pikepdf is None:
raise Exception(
'pikepdf is not installed, so this feature is not available.')
inputFile, inPage = self.getAttributeValues(valuesOnly=True)
manager = attr.getManager(self, interfaces.ICanvasManager)
outPage = manager.canvas.getPageNumber() - 1
proc = self.getProcessor()
pageOperations = proc.operations.setdefault(outPage, [])
pageOperations.append((inputFile, inPage))
class MergePageInPageTemplate(MergePage):
def process(self):
if pikepdf is None:
raise Exception(
'pikepdf is not installed, so this feature is not available.')
inputFile, inPage = self.getAttributeValues(valuesOnly=True)
onPage = self.parent.pt.onPage
def drawOnCanvas(canvas, doc):
onPage(canvas, doc)
outPage = canvas.getPageNumber() - 1
proc = self.getProcessor()
pageOperations = proc.operations.setdefault(outPage, [])
pageOperations.append((inputFile, inPage))
self.parent.pt.onPage = drawOnCanvas