Glymur 0.13.2__py3-none-any.whl → 0.13.3__py3-none-any.whl
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.
- {Glymur-0.13.2.dist-info → Glymur-0.13.3.dist-info}/METADATA +1 -1
- {Glymur-0.13.2.dist-info → Glymur-0.13.3.dist-info}/RECORD +11 -11
- {Glymur-0.13.2.dist-info → Glymur-0.13.3.dist-info}/WHEEL +1 -1
- glymur/codestream.py +3 -4
- glymur/jp2box.py +1 -1
- glymur/jp2k.py +17 -19
- glymur/jp2kr.py +67 -38
- glymur/version.py +1 -1
- {Glymur-0.13.2.dist-info → Glymur-0.13.3.dist-info}/LICENSE.txt +0 -0
- {Glymur-0.13.2.dist-info → Glymur-0.13.3.dist-info}/entry_points.txt +0 -0
- {Glymur-0.13.2.dist-info → Glymur-0.13.3.dist-info}/top_level.txt +0 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
glymur/__init__.py,sha256=k14IfdaYuTWXSpAIDR3LVDtXt9XKjr-ZSNXCyu8pQko,586
|
|
2
2
|
glymur/_iccprofile.py,sha256=_WfQsT-BqEWQzQVTtuY7tSXqPjOtwvWGW36rKxlLv1s,4148
|
|
3
|
-
glymur/codestream.py,sha256=
|
|
3
|
+
glymur/codestream.py,sha256=qZbCCJGrsIy4Q9zzeITNN_bP90HtCHFOcbZdInDfAAY,60011
|
|
4
4
|
glymur/command_line.py,sha256=jm-6dD2jcU_G7mJAJ0U5sanfG9kRy-j0-G3eSN_Ieek,7476
|
|
5
5
|
glymur/config.py,sha256=ceGulS8TN2OYiTPtq3mAdhXrCCRlxjuLmvN_UG0009Y,4139
|
|
6
6
|
glymur/core.py,sha256=IDkk8FESyukQTB10LHBZ4VQM36NwKE4CXCcuJ407Kzg,3638
|
|
7
|
-
glymur/jp2box.py,sha256
|
|
8
|
-
glymur/jp2k.py,sha256=
|
|
9
|
-
glymur/jp2kr.py,sha256=
|
|
7
|
+
glymur/jp2box.py,sha256=-fprGcnwgm4HC9D8jxWmvsMZbDdum6C1Zc4cCJWNIZM,112390
|
|
8
|
+
glymur/jp2k.py,sha256=QS1bIi013b0AWRPvc90kwdVXMwblbJXU8MvP9zigy3g,54455
|
|
9
|
+
glymur/jp2kr.py,sha256=hUxFRXaJI9qmnZ7wNPr_4N-c-JEP7YiM_ea4FpmWD_w,32358
|
|
10
10
|
glymur/options.py,sha256=Y777g4wpxPqRAF8s963goeAIogfLqIe_Dyd9f77MfmU,4428
|
|
11
11
|
glymur/tiff.py,sha256=2uoKfyoyPQWAsdPWB0IxW_npqpP4O10qVADQZf10jXs,41115
|
|
12
|
-
glymur/version.py,sha256=
|
|
12
|
+
glymur/version.py,sha256=dGkLU9MNyK0Ikb9XIC4M4aoDNPJQDZ0zq1OTF7zgtiU,981
|
|
13
13
|
glymur/data/__init__.py,sha256=n2KZrHV15it7Wu4YCaBLXui1ZleQ30dnZ92dyP6q05k,955
|
|
14
14
|
glymur/data/goodstuff.j2k,sha256=xKQG68KMu33gYjRUDTQvam1Cue2tdio85rNp5J-rYZE,115220
|
|
15
15
|
glymur/data/heliov.jpx,sha256=KXnYdBZgl25jcGLu-m-QfhuP9pqUXV0Hp9HHEdJqr34,1399071
|
|
@@ -17,9 +17,9 @@ glymur/data/nemo.jp2,sha256=yJ1NkTEwU0B_gBtAiA1c5hxtGYSJtJgq6cHC2IHpj70,1132373
|
|
|
17
17
|
glymur/lib/__init__.py,sha256=JnM9oPfcZhBDLKo7_yLS-lIRQ1wXb1N9hKKQ-G7vYVk,127
|
|
18
18
|
glymur/lib/openjp2.py,sha256=VHCy_TnBSDqQ8YlIQHkyFqUXOQ2E5C3jxJoziG73s0I,45052
|
|
19
19
|
glymur/lib/tiff.py,sha256=2o29IzYTsprVR_C6VDNHOzqk_U7aUdCoLQ2fjiyyoaI,50777
|
|
20
|
-
Glymur-0.13.
|
|
21
|
-
Glymur-0.13.
|
|
22
|
-
Glymur-0.13.
|
|
23
|
-
Glymur-0.13.
|
|
24
|
-
Glymur-0.13.
|
|
25
|
-
Glymur-0.13.
|
|
20
|
+
Glymur-0.13.3.dist-info/LICENSE.txt,sha256=G9pvBgkJdPTtZqQmoRyIgAydtic1ZwWtOWBea9VMW7I,1077
|
|
21
|
+
Glymur-0.13.3.dist-info/METADATA,sha256=dCBeH__9F8mkVEsr9w8_5KpWn92be25pGQY7IAlqGy0,1020
|
|
22
|
+
Glymur-0.13.3.dist-info/WHEEL,sha256=mguMlWGMX-VHnMpKOjjQidIo1ssRlCFu4a4mBpz1s2M,91
|
|
23
|
+
Glymur-0.13.3.dist-info/entry_points.txt,sha256=inzxpDbDDfIxtdXpCncAHdAdwJfjtXt3xKvIOsuZsG8,93
|
|
24
|
+
Glymur-0.13.3.dist-info/top_level.txt,sha256=D0SvtBUoPxOs40OTRW3l-kjGFHM6VrXS8yZPK5Fx2wY,7
|
|
25
|
+
Glymur-0.13.3.dist-info/RECORD,,
|
glymur/codestream.py
CHANGED
|
@@ -767,11 +767,10 @@ class Codestream(object):
|
|
|
767
767
|
num_tiles_y = (xysiz[1] - xyosiz[1]) / (xytsiz[1] - xytosiz[1])
|
|
768
768
|
except ZeroDivisionError:
|
|
769
769
|
msg = (
|
|
770
|
-
f"Invalid tile specification
|
|
771
|
-
f"size of {xytsiz[1]} x {xytsiz[0]}
|
|
772
|
-
f"offset of {xytosiz[1]} x {xytsiz[0]}."
|
|
770
|
+
f"Invalid tile specification in SIZ segment at byte offset "
|
|
771
|
+
f"{offset}: tile size of {xytsiz[1]} x {xytsiz[0]}."
|
|
773
772
|
)
|
|
774
|
-
|
|
773
|
+
raise ZeroDivisionError(msg)
|
|
775
774
|
else:
|
|
776
775
|
numtiles = np.ceil(num_tiles_x) * np.ceil(num_tiles_y)
|
|
777
776
|
if numtiles > 65535:
|
glymur/jp2box.py
CHANGED
|
@@ -71,7 +71,7 @@ _EXIF_UUID = UUID(bytes=b'JpgTiffExif->JP2')
|
|
|
71
71
|
_XMP_UUID = UUID('be7acfcb-97a9-42e8-9c71-999491e3afac')
|
|
72
72
|
|
|
73
73
|
|
|
74
|
-
class InvalidJp2kWarning(
|
|
74
|
+
class InvalidJp2kWarning(UserWarning):
|
|
75
75
|
"""Issue this warning in case the file is technically invalid but we can
|
|
76
76
|
still read the image.
|
|
77
77
|
"""
|
glymur/jp2k.py
CHANGED
|
@@ -258,7 +258,7 @@ class Jp2k(Jp2kr):
|
|
|
258
258
|
header box if we were so instructed. This requires a wrapping
|
|
259
259
|
operation.
|
|
260
260
|
"""
|
|
261
|
-
jp2h =
|
|
261
|
+
jp2h = next(filter(lambda x: x.box_id == 'jp2h', self.box), None)
|
|
262
262
|
|
|
263
263
|
extra_boxes = []
|
|
264
264
|
if self._capture_resolution is not None:
|
|
@@ -1125,8 +1125,7 @@ class Jp2k(Jp2kr):
|
|
|
1125
1125
|
|
|
1126
1126
|
def _validate_jp2_colr(self, boxes):
|
|
1127
1127
|
"""Validate JP2 requirements on colour specification boxes."""
|
|
1128
|
-
|
|
1129
|
-
jp2h = lst[0]
|
|
1128
|
+
jp2h = next(filter(lambda x: x.box_id == 'jp2h', boxes), None)
|
|
1130
1129
|
for colr in [box for box in jp2h.box if box.box_id == 'colr']:
|
|
1131
1130
|
if colr.approximation != 0:
|
|
1132
1131
|
msg = (
|
|
@@ -1161,19 +1160,21 @@ class Jp2k(Jp2kr):
|
|
|
1161
1160
|
def _validate_jp2c(self, boxes):
|
|
1162
1161
|
"""Validate the codestream box in relation to other boxes."""
|
|
1163
1162
|
# jp2c must be preceeded by jp2h
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1163
|
+
jp2h_idx, _ = next(
|
|
1164
|
+
filter(lambda x: x[1].box_id == 'jp2h', enumerate(boxes)),
|
|
1165
|
+
(None, None)
|
|
1166
|
+
)
|
|
1167
|
+
jp2c_idx, _ = next(
|
|
1168
|
+
filter(lambda x: x[1].box_id == 'jp2c', enumerate(boxes)),
|
|
1169
|
+
(None, None)
|
|
1170
|
+
)
|
|
1171
|
+
if jp2c_idx is None:
|
|
1170
1172
|
msg = (
|
|
1171
1173
|
"A codestream box must be defined in the outermost list of "
|
|
1172
1174
|
"boxes."
|
|
1173
1175
|
)
|
|
1174
1176
|
raise InvalidJp2kError(msg)
|
|
1175
1177
|
|
|
1176
|
-
jp2c_idx = jp2c_lst[0]
|
|
1177
1178
|
if jp2h_idx >= jp2c_idx:
|
|
1178
1179
|
msg = "The codestream box must be preceeded by a jp2 header box."
|
|
1179
1180
|
raise InvalidJp2kError(msg)
|
|
@@ -1182,8 +1183,7 @@ class Jp2k(Jp2kr):
|
|
|
1182
1183
|
"""Validate the JP2 Header box."""
|
|
1183
1184
|
self._check_jp2h_child_boxes(boxes, 'top-level')
|
|
1184
1185
|
|
|
1185
|
-
|
|
1186
|
-
jp2h = jp2h_lst[0]
|
|
1186
|
+
jp2h = next(filter(lambda x: x.box_id == 'jp2h', boxes), None)
|
|
1187
1187
|
|
|
1188
1188
|
# 1st jp2 header box cannot be empty.
|
|
1189
1189
|
if len(jp2h.box) == 0:
|
|
@@ -1199,20 +1199,18 @@ class Jp2k(Jp2kr):
|
|
|
1199
1199
|
raise InvalidJp2kError(msg)
|
|
1200
1200
|
|
|
1201
1201
|
# colr must be present in jp2 header box.
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
]
|
|
1205
|
-
if len(colr_lst) == 0:
|
|
1202
|
+
colr = next(filter(lambda x: x.box_id == 'colr', jp2h.box), None)
|
|
1203
|
+
if colr is None:
|
|
1206
1204
|
msg = "The jp2 header box must contain a color definition box."
|
|
1207
1205
|
raise InvalidJp2kError(msg)
|
|
1208
|
-
colr = jp2h.box[colr_lst[0]]
|
|
1209
1206
|
|
|
1210
1207
|
self._validate_channel_definition(jp2h, colr)
|
|
1211
1208
|
|
|
1212
1209
|
def _validate_channel_definition(self, jp2h, colr):
|
|
1213
1210
|
"""Validate the channel definition box."""
|
|
1214
|
-
cdef_lst = [
|
|
1215
|
-
|
|
1211
|
+
cdef_lst = [
|
|
1212
|
+
idx for (idx, box) in enumerate(jp2h.box) if box.box_id == 'cdef'
|
|
1213
|
+
]
|
|
1216
1214
|
if len(cdef_lst) > 1:
|
|
1217
1215
|
msg = ("Only one channel definition box is allowed in the "
|
|
1218
1216
|
"JP2 header.")
|
glymur/jp2kr.py
CHANGED
|
@@ -9,11 +9,11 @@ License: MIT
|
|
|
9
9
|
# Standard library imports...
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
from contextlib import ExitStack
|
|
12
|
-
from itertools import filterfalse
|
|
13
12
|
import ctypes
|
|
14
13
|
import pathlib
|
|
15
14
|
import re
|
|
16
15
|
import struct
|
|
16
|
+
import sys
|
|
17
17
|
import warnings
|
|
18
18
|
|
|
19
19
|
# Third party library imports
|
|
@@ -22,7 +22,7 @@ import numpy as np
|
|
|
22
22
|
# Local imports...
|
|
23
23
|
from .codestream import Codestream
|
|
24
24
|
from . import core, version, get_option
|
|
25
|
-
from .jp2box import Jp2kBox, FileTypeBox, InvalidJp2kError
|
|
25
|
+
from .jp2box import Jp2kBox, FileTypeBox, InvalidJp2kError, InvalidJp2kWarning
|
|
26
26
|
from .lib import openjp2 as opj2
|
|
27
27
|
|
|
28
28
|
|
|
@@ -108,8 +108,8 @@ class Jp2kr(Jp2kBox):
|
|
|
108
108
|
num_components = len(cstr.segment[1].xrsiz)
|
|
109
109
|
else:
|
|
110
110
|
# try to get the image size from the IHDR box
|
|
111
|
-
jp2h =
|
|
112
|
-
ihdr =
|
|
111
|
+
jp2h = next(filter(lambda x: x.box_id == 'jp2h', self.box), None)
|
|
112
|
+
ihdr = next(filter(lambda x: x.box_id == 'ihdr', jp2h.box), None)
|
|
113
113
|
|
|
114
114
|
height, width = ihdr.height, ihdr.width
|
|
115
115
|
num_components = ihdr.num_components
|
|
@@ -189,10 +189,10 @@ class Jp2kr(Jp2kBox):
|
|
|
189
189
|
@layer.setter
|
|
190
190
|
def layer(self, layer):
|
|
191
191
|
# Set to the indicated value so long as it is valid.
|
|
192
|
-
cod =
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
192
|
+
cod = next(
|
|
193
|
+
filter(lambda x: x.marker_id == 'COD', self.codestream.segment),
|
|
194
|
+
None
|
|
195
|
+
)
|
|
196
196
|
if layer < 0 or layer >= cod.layers:
|
|
197
197
|
msg = f"Invalid layer number, must be in range [0, {cod.layers})."
|
|
198
198
|
raise ValueError(msg)
|
|
@@ -355,7 +355,13 @@ class Jp2kr(Jp2kBox):
|
|
|
355
355
|
# Don't bother trying to validate JPX.
|
|
356
356
|
return
|
|
357
357
|
|
|
358
|
-
jp2h =
|
|
358
|
+
jp2h = next(filter(lambda x: x.box_id == 'jp2h', self.box), None)
|
|
359
|
+
if jp2h is None:
|
|
360
|
+
msg = (
|
|
361
|
+
"No JP2 header box was located in the outermost jacket of "
|
|
362
|
+
"boxes."
|
|
363
|
+
)
|
|
364
|
+
raise InvalidJp2kError(msg)
|
|
359
365
|
|
|
360
366
|
# An IHDR box is required as the first child box of the JP2H box.
|
|
361
367
|
if jp2h.box[0].box_id != 'ihdr':
|
|
@@ -373,7 +379,7 @@ class Jp2kr(Jp2kBox):
|
|
|
373
379
|
"enumerated colorspace or a restricted ICC profile if the "
|
|
374
380
|
"file type box brand is 'jp2 '."
|
|
375
381
|
)
|
|
376
|
-
warnings.warn(msg,
|
|
382
|
+
warnings.warn(msg, InvalidJp2kWarning)
|
|
377
383
|
|
|
378
384
|
# We need to have one and only one JP2H box if we have a JP2 file.
|
|
379
385
|
num_jp2h_boxes = len([box for box in self.box if box.box_id == 'jp2h'])
|
|
@@ -382,7 +388,7 @@ class Jp2kr(Jp2kBox):
|
|
|
382
388
|
f"This file has {num_jp2h_boxes} JP2H boxes in the outermost "
|
|
383
389
|
"layer of boxes. There should only be one."
|
|
384
390
|
)
|
|
385
|
-
warnings.warn(msg)
|
|
391
|
+
warnings.warn(msg, InvalidJp2kWarning)
|
|
386
392
|
|
|
387
393
|
# We should have one and only one JP2C box if we have a JP2 file.
|
|
388
394
|
num_jp2c_boxes = len([box for box in self.box if box.box_id == 'jp2c'])
|
|
@@ -404,10 +410,10 @@ class Jp2kr(Jp2kBox):
|
|
|
404
410
|
ihdr = jp2h.box[0]
|
|
405
411
|
ihdr_dims = ihdr.height, ihdr.width, ihdr.num_components
|
|
406
412
|
|
|
407
|
-
siz =
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
413
|
+
siz = next(
|
|
414
|
+
filter(lambda x: x.marker_id == 'SIZ', self.codestream.segment),
|
|
415
|
+
None
|
|
416
|
+
)
|
|
411
417
|
|
|
412
418
|
siz_dims = (siz.ysiz, siz.xsiz, len(siz.bitdepth))
|
|
413
419
|
if ihdr_dims != siz_dims:
|
|
@@ -460,9 +466,9 @@ class Jp2kr(Jp2kBox):
|
|
|
460
466
|
if isinstance(pargs, tuple) and any(isinstance(x, int) for x in pargs):
|
|
461
467
|
# Replace the first such integer argument, replace it with a slice.
|
|
462
468
|
lst = list(pargs)
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
469
|
+
idx, _ = next(
|
|
470
|
+
filter(lambda x: isinstance(x[1], int), enumerate(lst)), None
|
|
471
|
+
)
|
|
466
472
|
lst[idx] = slice(pargs[idx], pargs[idx] + 1)
|
|
467
473
|
newindex = tuple(lst)
|
|
468
474
|
|
|
@@ -676,10 +682,13 @@ class Jp2kr(Jp2kBox):
|
|
|
676
682
|
# Must check the specified rlevel against the maximum.
|
|
677
683
|
if rlevel != 0:
|
|
678
684
|
# Must check the specified rlevel against the maximum.
|
|
679
|
-
cod_seg =
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
685
|
+
cod_seg = next(
|
|
686
|
+
filter(
|
|
687
|
+
lambda x: x.marker_id == 'COD',
|
|
688
|
+
self.codestream.segment
|
|
689
|
+
),
|
|
690
|
+
None
|
|
691
|
+
)
|
|
683
692
|
max_rlevel = cod_seg.num_res
|
|
684
693
|
if rlevel == -1:
|
|
685
694
|
# -1 is shorthand for the largest rlevel
|
|
@@ -889,25 +898,45 @@ class Jp2kr(Jp2kBox):
|
|
|
889
898
|
Vertical, Horizontal Subsampling: ((1, 1), (1, 1), (1, 1))
|
|
890
899
|
"""
|
|
891
900
|
with self.path.open('rb') as fptr:
|
|
901
|
+
|
|
902
|
+
# if it's just a raw codestream file, it's easy
|
|
892
903
|
if self._codec_format == opj2.CODEC_J2K:
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
904
|
+
return self._get_codestream(fptr, self.length, header_only)
|
|
905
|
+
|
|
906
|
+
# continue assuming JP2, must seek to the JP2C box and past its
|
|
907
|
+
# header
|
|
908
|
+
box = next(filter(lambda x: x.box_id == 'jp2c', self.box), None)
|
|
909
|
+
|
|
910
|
+
fptr.seek(box.offset)
|
|
911
|
+
read_buffer = fptr.read(8)
|
|
912
|
+
(box_length, _) = struct.unpack('>I4s', read_buffer)
|
|
913
|
+
if box_length == 0:
|
|
914
|
+
# The length of the box is presumed to last until the end
|
|
915
|
+
# of the file. Compute the effective length of the box.
|
|
916
|
+
box_length = self.path.stat().st_size - fptr.tell() + 8
|
|
917
|
+
elif box_length == 1:
|
|
918
|
+
# Seek past the XL field.
|
|
898
919
|
read_buffer = fptr.read(8)
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
codestream = Codestream(fptr, box_length - 8,
|
|
909
|
-
header_only=header_only)
|
|
920
|
+
box_length, = struct.unpack('>Q', read_buffer)
|
|
921
|
+
|
|
922
|
+
return self._get_codestream(fptr, box_length - 8, header_only)
|
|
923
|
+
|
|
924
|
+
def _get_codestream(self, fptr, length, header_only):
|
|
925
|
+
"""
|
|
926
|
+
Parsing errors can make for confusing errors sometimes, so catch any
|
|
927
|
+
such error and add context to it.
|
|
928
|
+
"""
|
|
910
929
|
|
|
930
|
+
try:
|
|
931
|
+
codestream = Codestream(fptr, length, header_only=header_only)
|
|
932
|
+
except Exception:
|
|
933
|
+
_, value, traceback = sys.exc_info()
|
|
934
|
+
msg = (
|
|
935
|
+
f'The file is invalid '
|
|
936
|
+
f'because the codestream could not be parsed: "{value}"'
|
|
937
|
+
)
|
|
938
|
+
raise InvalidJp2kError(msg).with_traceback(traceback)
|
|
939
|
+
else:
|
|
911
940
|
return codestream
|
|
912
941
|
|
|
913
942
|
def _validate_nonzero_image_size(self, nrows, ncols, component_index):
|
glymur/version.py
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|