|
39 | 39 | from .utils import PdfReadError, ord_, chr_, paethPredictor |
40 | 40 | from sys import version_info |
41 | 41 | if version_info < ( 3, 0 ): |
42 | | - from cStringIO import StringIO |
| 42 | + from cStringIO import StringIO as BytesIO |
| 43 | + bytearray = buffer |
43 | 44 | else: |
44 | | - from io import StringIO |
| 45 | + from io import BytesIO |
45 | 46 | import struct |
46 | 47 |
|
47 | 48 | try: |
@@ -123,39 +124,52 @@ def decode(data, decodeParms): |
123 | 124 | columns = decodeParms["/Columns"] |
124 | 125 | # PNG prediction: |
125 | 126 | if predictor >= 10 and predictor <= 15: |
126 | | - output = StringIO() |
127 | | - # PNG prediction can vary from row to row |
128 | | - rowlength = columns + 1 |
129 | | - assert len(data) % rowlength == 0 |
| 127 | + bitsPerComponent = decodeParms.get("/BitsPerComponent") |
| 128 | + output = BytesIO() |
| 129 | + |
| 130 | + # PNG predictor can vary by row and so is the lead byte on each row |
| 131 | + rowlength = math.ceil(columns * bitsPerComponent / 8) + 1 # number of bytes |
| 132 | + if len(data) % rowlength != 0: |
| 133 | + raise PdfReadError("Image data is not rectangular") |
| 134 | + |
130 | 135 | prev_rowdata = (0,) * rowlength |
131 | 136 | for row in range(len(data) // rowlength): |
132 | 137 | rowdata = [ord_(x) for x in data[(row*rowlength):((row+1)*rowlength)]] |
133 | 138 | filterByte = rowdata[0] |
134 | | - if filterByte == 0: |
135 | | - pass |
136 | | - elif filterByte == 1: |
137 | | - for i in range(2, rowlength): |
138 | | - rowdata[i] = (rowdata[i] + rowdata[i-1]) % 256 |
139 | | - elif filterByte == 2: |
140 | | - for i in range(1, rowlength): |
141 | | - rowdata[i] = (rowdata[i] + prev_rowdata[i]) % 256 |
142 | | - elif filterByte == 3: |
143 | | - for i in range(1, rowlength): |
144 | | - left = rowdata[i-1] if i > 1 else 0 |
145 | | - floor = math.floor(left + prev_rowdata[i])/2 |
146 | | - rowdata[i] = (rowdata[i] + int(floor)) % 256 |
147 | | - elif filterByte == 4: |
148 | | - for i in range(1, rowlength): |
149 | | - left = rowdata[i - 1] if i > 1 else 0 |
150 | | - up = prev_rowdata[i] |
151 | | - up_left = prev_rowdata[i - 1] if i > 1 else 0 |
152 | | - paeth = paethPredictor(left, up, up_left) |
153 | | - rowdata[i] = (rowdata[i] + paeth) % 256 |
| 139 | + |
| 140 | + if bitsPerComponent == 1: |
| 141 | + # bitmap data, filters don't make sense but the filter byte is still present |
| 142 | + if filterByte != 0: |
| 143 | + raise PdfReadError("Unsupported filter byte in bitmap mode: %r" % (filterByte,)) |
| 144 | + |
154 | 145 | else: |
155 | | - # unsupported PNG filter |
156 | | - raise PdfReadError("Unsupported PNG filter %r" % filterByte) |
| 146 | + if filterByte == 0: |
| 147 | + pass |
| 148 | + elif filterByte == 1: |
| 149 | + for i in range(2, rowlength): |
| 150 | + rowdata[i] = (rowdata[i] + rowdata[i-1]) % 256 |
| 151 | + elif filterByte == 2: |
| 152 | + for i in range(1, rowlength): |
| 153 | + rowdata[i] = (rowdata[i] + prev_rowdata[i]) % 256 |
| 154 | + elif filterByte == 3: |
| 155 | + for i in range(1, rowlength): |
| 156 | + left = rowdata[i-1] if i > 1 else 0 |
| 157 | + floor = math.floor(left + prev_rowdata[i])/2 |
| 158 | + rowdata[i] = (rowdata[i] + int(floor)) % 256 |
| 159 | + elif filterByte == 4: |
| 160 | + for i in range(1, rowlength): |
| 161 | + left = rowdata[i - 1] if i > 1 else 0 |
| 162 | + up = prev_rowdata[i] |
| 163 | + up_left = prev_rowdata[i - 1] if i > 1 else 0 |
| 164 | + paeth = paethPredictor(left, up, up_left) |
| 165 | + rowdata[i] = (rowdata[i] + paeth) % 256 |
| 166 | + |
| 167 | + else: |
| 168 | + # unsupported PNG filter |
| 169 | + raise PdfReadError("Unsupported PNG filter %r" % filterByte) |
| 170 | + |
157 | 171 | prev_rowdata = rowdata |
158 | | - output.write(''.join([chr(x) for x in rowdata[1:]])) |
| 172 | + output.write(bytearray(rowdata[1:])) |
159 | 173 | data = output.getvalue() |
160 | 174 | else: |
161 | 175 | # unsupported predictor |
|
0 commit comments