pypdf 1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pyPdf-1.4/CHANGELOG ADDED
@@ -0,0 +1,64 @@
1
+ Version 1.4, 2006-01-27
2
+ -----------------------
3
+
4
+ - Add capability to merge pages from multiple PDF files into a single page
5
+ using the PageObject.mergePage function. See example code (README or web
6
+ site) for more information.
7
+
8
+ - Add ability to modify a page's MediaBox, CropBox, BleedBox, TrimBox, and
9
+ ArtBox properties through PageObject. See example code (README or web site)
10
+ for more information.
11
+
12
+ - Refactor pdf.py into multiple files: generic.py (contains objects like
13
+ NameObject, DictionaryObject), filters.py (contains filter code),
14
+ utils.py (various). This does not affect importing PdfFileReader
15
+ or PdfFileWriter.
16
+
17
+ - Add new decoding functions for standard PDF filters ASCIIHexDecode and
18
+ ASCII85Decode.
19
+
20
+ - Change url and download_url to refer to new pybrary.net web site.
21
+
22
+
23
+ Version 1.3, 2006-01-23
24
+ -----------------------
25
+
26
+ - Fix new bug introduced in 1.2 where PDF files with \r line endings did not
27
+ work properly anymore. A new test suite developed with various PDF files
28
+ should prevent regression bugs from now on.
29
+
30
+ - Fix a bug where inheriting attributes from page nodes did not work.
31
+
32
+
33
+ Version 1.2, 2006-01-23
34
+ -----------------------
35
+
36
+ - Improved support for files with CRLF-based line endings, fixing a common
37
+ reported problem stating "assertion error: assert line == "%%EOF"".
38
+
39
+ - Software author/maintainer is now officially a proud married person, which
40
+ is sure to result in better software... somehow.
41
+
42
+
43
+ Version 1.1, 2006-01-18
44
+ -----------------------
45
+
46
+ - Add capability to rotate pages.
47
+
48
+ - Improved PDF reading support to properly manage inherited attributes from
49
+ /Type=/Pages nodes. This means that page groups that are rotated or have
50
+ different media boxes or whatever will now work properly.
51
+
52
+ - Added PDF 1.5 support. Namely cross-reference streams and object streams.
53
+ This release can mangle Adobe's PDFReference16.pdf successfully.
54
+
55
+
56
+ Version 1.0, 2006-01-17
57
+ -----------------------
58
+
59
+ - First distutils-capable true public release. Supports a wide variety of PDF
60
+ files that I found sitting around on my system.
61
+
62
+ - Does not support some PDF 1.5 features, such as object streams,
63
+ cross-reference streams.
64
+
pyPdf-1.4/PKG-INFO ADDED
@@ -0,0 +1,29 @@
1
+ Metadata-Version: 1.0
2
+ Name: pyPdf
3
+ Version: 1.4
4
+ Summary: PDF toolkit
5
+ Home-page: http://pybrary.net/pyPdf/
6
+ Author: Mathieu Fenniak
7
+ Author-email: mfenniak@pobox.com
8
+ License: UNKNOWN
9
+ Download-URL: http://pybrary.net/pyPdf/pyPdf-1.4.tar.gz
10
+ Description:
11
+ A Pure-Python library built as a PDF toolkit. It is capable of:
12
+
13
+ - splitting documents page by page,
14
+ - merging documents page by page,
15
+ - cropping pages,
16
+ - merging multiple pages into a single page.
17
+
18
+ By being Pure-Python, it should run on any Python platform without any
19
+ dependencies on external libraries. It can also work entirely on StringIO
20
+ objects rather than file streams, allowing for PDF manipulation in memory.
21
+ It is therefore a useful tool for websites that manage or manipulate PDFs.
22
+
23
+ Platform: UNKNOWN
24
+ Classifier: Development Status :: 4 - Beta
25
+ Classifier: Intended Audience :: Developers
26
+ Classifier: License :: OSI Approved :: BSD License
27
+ Classifier: Programming Language :: Python
28
+ Classifier: Operating System :: OS Independent
29
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
pyPdf-1.4/README ADDED
@@ -0,0 +1,38 @@
1
+ Example:
2
+
3
+ from pyPdf import PdfFileWriter, PdfFileReader
4
+
5
+ output = PdfFileWriter()
6
+ input1 = PdfFileReader(file("document1.pdf", "rb"))
7
+
8
+ # add page 1 from input1 to output document, unchanged
9
+ output.addPage(input1.getPage(0))
10
+
11
+ # add page 2 from input1, but rotated clockwise 90 degrees
12
+ output.addPage(input1.getPage(1).rotateClockwise(90))
13
+
14
+ # add page 3 from input1, rotated the other way:
15
+ output.addPage(input1.getPage(2).rotateCounterClockwise(90))
16
+ # alt: output.addPage(input1.getPage(2).rotateClockwise(270))
17
+
18
+ # add page 4 from input1, but first add a watermark from another pdf:
19
+ page4 = input1.getPage(3)
20
+ watermark = PdfFileReader(file("watermark.pdf", "rb"))
21
+ page4.mergePage(watermark.getPage(0))
22
+
23
+ # add page 5 from input1, but crop it to half size:
24
+ page5 = input1.getPage(4)
25
+ page5.mediaBox.upperRight = (
26
+ page5.mediaBox.getUpperRight_x() / 2,
27
+ page5.mediaBox.getUpperRight_y() / 2
28
+ )
29
+ output.addPage(page5)
30
+
31
+ # print how many pages input1 has:
32
+ print "document1.pdf has %s pages." % input1.getNumPages())
33
+
34
+ # finally, write "output" to document-output.pdf
35
+ outputStream = file("document-output.pdf", "wb")
36
+ output.write(outputStream)
37
+
38
+
@@ -0,0 +1,2 @@
1
+ from pdf import PdfFileReader, PdfFileWriter
2
+ __all__ = ["pdf"]
@@ -0,0 +1,178 @@
1
+ # vim: sw=4:expandtab:foldmethod=marker
2
+ #
3
+ # Copyright (c) 2006, Mathieu Fenniak
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are
8
+ # met:
9
+ #
10
+ # * Redistributions of source code must retain the above copyright notice,
11
+ # this list of conditions and the following disclaimer.
12
+ # * Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ # * The name of the author may not be used to endorse or promote products
16
+ # derived from this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ # POSSIBILITY OF SUCH DAMAGE.
29
+
30
+
31
+ """
32
+ Implementation of stream filters for PDF.
33
+ """
34
+ __author__ = "Mathieu Fenniak"
35
+ __author_email__ = "mfenniak@pobox.com"
36
+
37
+ import zlib
38
+ from generic import NameObject
39
+
40
+ class FlateDecode(object):
41
+ def decode(data, decodeParms):
42
+ data = zlib.decompress(data)
43
+ predictor = 1
44
+ if decodeParms:
45
+ predictor = decodeParms.get("/Predictor", 1)
46
+ # predictor 1 == no predictor
47
+ if predictor != 1:
48
+ columns = decodeParms["/Columns"]
49
+ if predictor >= 10:
50
+ newdata = ""
51
+ # PNG prediction can vary from row to row
52
+ rowlength = columns + 1
53
+ assert len(data) % rowlength == 0
54
+ prev_rowdata = "\x00"*rowlength
55
+ for row in range(len(data) / rowlength):
56
+ rowdata = list(data[(row*rowlength):((row+1)*rowlength)])
57
+ filterByte = ord(rowdata[0])
58
+ if filterByte == 0:
59
+ pass
60
+ elif filterByte == 1:
61
+ for i in range(2, rowlength):
62
+ rowdata[i] = chr((ord(rowdata[i]) + ord(rowdata[i-1])) % 256)
63
+ elif filterByte == 2:
64
+ for i in range(1, rowlength):
65
+ rowdata[i] = chr((ord(rowdata[i]) + ord(prev_rowdata[i])) % 256)
66
+ else:
67
+ # unsupported PNG filter
68
+ assert False
69
+ prev_rowdata = rowdata
70
+ newdata += ''.join(rowdata[1:])
71
+ data = newdata
72
+ else:
73
+ # unsupported predictor
74
+ assert False
75
+ return data
76
+ decode = staticmethod(decode)
77
+
78
+ class ASCIIHexDecode(object):
79
+ def decode(data, decodeParms=None):
80
+ retval = ""
81
+ char = ""
82
+ x = 0
83
+ while True:
84
+ c = data[x]
85
+ if c == ">":
86
+ break
87
+ elif c.isspace():
88
+ x += 1
89
+ continue
90
+ char += c
91
+ if len(char) == 2:
92
+ retval += chr(int(char, base=16))
93
+ char = ""
94
+ x += 1
95
+ assert char == ""
96
+ return retval
97
+ decode = staticmethod(decode)
98
+
99
+ class ASCII85Decode(object):
100
+ def decode(data, decodeParms=None):
101
+ retval = ""
102
+ group = []
103
+ x = 0
104
+ hitEod = False
105
+ while not hitEod:
106
+ c = data[x]
107
+ if len(retval) == 0 and c == "<" and data[x+1] == "~":
108
+ x += 2
109
+ continue
110
+ elif c.isspace():
111
+ x += 1
112
+ continue
113
+ elif c == 'z':
114
+ assert len(group) == 0
115
+ retval += '\x00\x00\x00\x00'
116
+ continue
117
+ elif c == "~" and data[x+1] == ">":
118
+ if len(group) != 0:
119
+ # cannot have a final group of just 1 char
120
+ assert len(group) > 1
121
+ cnt = len(group) - 1
122
+ group += [ 85, 85, 85 ]
123
+ hitEod = cnt
124
+ else:
125
+ break
126
+ else:
127
+ c = ord(c) - 33
128
+ assert c >= 0 and c < 85
129
+ group += [ c ]
130
+ if len(group) >= 5:
131
+ b = group[0] * (85**4) + \
132
+ group[1] * (85**3) + \
133
+ group[2] * (85**2) + \
134
+ group[3] * 85 + \
135
+ group[4]
136
+ assert b < (2**32 - 1)
137
+ c4 = chr((b >> 0) % 256)
138
+ c3 = chr((b >> 8) % 256)
139
+ c2 = chr((b >> 16) % 256)
140
+ c1 = chr(b >> 24)
141
+ retval += (c1 + c2 + c3 + c4)
142
+ if hitEod:
143
+ retval = retval[:-4+hitEod]
144
+ group = []
145
+ x += 1
146
+ return retval
147
+ decode = staticmethod(decode)
148
+
149
+ def decodeStreamData(stream):
150
+ filters = stream.get("/Filter", ())
151
+ if len(filters) and not isinstance(filters[0], NameObject):
152
+ # we have a single filter instance
153
+ filters = (filters,)
154
+ data = stream['__streamdata__']
155
+ for filterType in filters:
156
+ if filterType == "/FlateDecode":
157
+ data = FlateDecode.decode(data, stream.get("/DecodeParms"))
158
+ elif filterType == "/ASCIIHexDecode":
159
+ data = ASCIIHexDecode.decode(data)
160
+ elif filterType == "/ASCII85Decode":
161
+ data = ASCII85Decode.decode(data)
162
+ else:
163
+ # unsupported filter
164
+ assert False
165
+ return data
166
+
167
+ if __name__ == "__main__":
168
+ assert "abc" == ASCIIHexDecode.decode('61\n626\n3>')
169
+
170
+ ascii85Test = """
171
+ <~9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKF<GL>Cj@.4Gp$d7F!,L7@<6@)/0JDEF<G%<+EV:2F!,
172
+ O<DJ+*.@<*K0@<6L(Df-\\0Ec5e;DffZ(EZee.Bl.9pF"AGXBPCsi+DGm>@3BB/F*&OCAfu2/AKY
173
+ i(DIb:@FD,*)+C]U=@3BN#EcYf8ATD3s@q?d$AftVqCh[NqF<G:8+EV:.+Cf>-FD5W8ARlolDIa
174
+ l(DId<j@<?3r@:F%a+D58'ATD4$Bl@l3De:,-DJs`8ARoFb/0JMK@qB4^F!,R<AKZ&-DfTqBG%G
175
+ >uD.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c~>
176
+ """
177
+ ascii85_originalText="Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."
178
+ assert ASCII85Decode.decode(ascii85Test) == ascii85_originalText