From c01079d677aaca06ef9fb5f6cf46143aa4d5ccac Mon Sep 17 00:00:00 2001 From: John Evans Date: Sun, 2 Mar 2014 07:58:48 -0500 Subject: [PATCH 01/10] Refactored filetype box to use struct.unpack_from. #130 --- glymur/jp2box.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index 5a0febf..0f710c9 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -994,7 +994,7 @@ class DataReferenceBox(Jp2kBox): @staticmethod def parse(fptr, offset, length): - """Parse Label box. + """Parse data reference box. Parameters ---------- @@ -1124,19 +1124,17 @@ class FileTypeBox(Jp2kBox): ------- FileTypeBox instance """ - # Read the brand, minor version. - read_buffer = fptr.read(8) - (brand, minor_version) = struct.unpack('>4sI', read_buffer) + read_buffer = fptr.read(length - 8) + # Extract the brand, minor version. + (brand, minor_version) = struct.unpack_from('>4sI', read_buffer, 0) if sys.hexversion >= 0x030000: brand = brand.decode('utf-8') - # Read the compatibility list. Each entry has 4 bytes. - current_pos = fptr.tell() - num_bytes = (offset + length - current_pos) / 4 - read_buffer = fptr.read(int(num_bytes) * 4) + # Extract the compatibility list. Each entry has 4 bytes. + num_entries = int((length - 16)/ 4) compatibility_list = [] - for j in range(int(num_bytes)): - entry, = struct.unpack('>4s', read_buffer[4*j:4*(j+1)]) + for j in range(int(num_entries)): + entry, = struct.unpack_from('>4s', read_buffer, 8 + j * 4) if sys.hexversion >= 0x03000000: entry = entry.decode('utf-8') compatibility_list.append(entry) From bf0d94e65b1f8463bb2eb5baab111bfb130d33a6 Mon Sep 17 00:00:00 2001 From: jevans Date: Mon, 3 Mar 2014 20:49:00 -0500 Subject: [PATCH 02/10] colr, flst, and pclr box. #130 The pclr box is the problematic one. If the box length is wrong, then it's hard to reliably parse when reading just one raw buffer. --- glymur/jp2box.py | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index b440cf6..a06d87d 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -401,28 +401,30 @@ class ColourSpecificationBox(Jp2kBox): ------- ColourSpecificationBox instance """ + num_bytes = offset + length - fptr.tell() + read_buffer = fptr.read(num_bytes) # Read the brand, minor version. - read_buffer = fptr.read(3) - (method, precedence, approximation) = struct.unpack('>BBB', - read_buffer) + (method, precedence, approximation) = struct.unpack_from('>BBB', + read_buffer, + 0) if method == 1: # enumerated colour space - read_buffer = fptr.read(4) - colorspace, = struct.unpack('>I', read_buffer) + colorspace, = struct.unpack_from('>I', read_buffer, 3) icc_profile = None else: # ICC profile colorspace = None - numbytes = offset + length - fptr.tell() - if numbytes < 128: + if num_bytes < 131: + # If the number of bytes is less than 128 + 3, then there + # cannot possibly be enough for an ICC profile. msg = "ICC profile header is corrupt, length is " msg += "only {0} instead of 128." - warnings.warn(msg.format(numbytes), UserWarning) + warnings.warn(msg.format(num_bytes - 3), UserWarning) icc_profile = None else: - profile = _ICCProfile(fptr.read(numbytes)) + profile = _ICCProfile(read_buffer[3:]) icc_profile = profile.header box = ColourSpecificationBox(method=method, @@ -1245,7 +1247,7 @@ class FragmentListBox(Jp2kBox): @staticmethod def parse(fptr, offset, length): - """Parse JPX free box. + """Parse JPX fragment list box. Parameters ---------- @@ -1260,11 +1262,13 @@ class FragmentListBox(Jp2kBox): ------- FragmentListBox instance """ - read_buffer = fptr.read(2) - num_fragments, = struct.unpack('>H', read_buffer) + num_bytes = offset + length - fptr.tell() + read_buffer = fptr.read(num_bytes) + num_fragments, = struct.unpack_from('>H', read_buffer, offset=0) - read_buffer = fptr.read(num_fragments * 14) - lst = struct.unpack('>' + 'QIH' * num_fragments, read_buffer) + lst = struct.unpack_from('>' + 'QIH' * num_fragments, + read_buffer, + offset=2) frag_offset = lst[0::3] frag_len = lst[1::3] data_reference = lst[2::3] @@ -1826,13 +1830,12 @@ class PaletteBox(Jp2kBox): ------- PaletteBox instance """ - # Get the size of the palette. - read_buffer = fptr.read(3) - (num_entries, num_columns) = struct.unpack('>HB', read_buffer) + num_bytes = offset + length - fptr.tell() + read_buffer = fptr.read(num_bytes) + (nrows, ncols) = struct.unpack_from('>HB', read_buffer, offset=0) # Need to determine bps and signed or not - read_buffer = fptr.read(num_columns) - data = struct.unpack('>' + 'B' * num_columns, read_buffer) + data = struct.unpack_from('>' + 'B' * ncols, read_buffer, offset=3) bps = [((x & 0x7f) + 1) for x in data] signed = [((x & 0x80) > 1) for x in data] @@ -1849,11 +1852,10 @@ class PaletteBox(Jp2kBox): # That means a list comprehension does this in one shot. row_nbytes = sum([int(math.ceil(x/8.0)) for x in bps]) - read_buffer = fptr.read(num_entries * row_nbytes) - palette = np.zeros((num_entries, num_columns), dtype=np.int32) - for j in range(num_entries): + palette = np.zeros((nrows, ncols), dtype=np.int32) + for j in range(nrows): palette[j] = struct.unpack_from(fmt, read_buffer, - offset=j * row_nbytes) + offset=j * row_nbytes + 3 + ncols) return PaletteBox(palette, bps, signed, length=length, offset=offset) From 63d203796b8d1cd981a5e2585450f4cc12ffd97b Mon Sep 17 00:00:00 2001 From: John Evans Date: Wed, 2 Apr 2014 12:21:56 -0400 Subject: [PATCH 03/10] Use memoryview instead of np.getbuffer. #210 np.getbuffer is not available in python3. --- glymur/jp2box.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index f62567d..92c94ba 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -1885,11 +1885,11 @@ class PaletteBox(Jp2kBox): if all(b == bps[0] for b in bps): # All components are the same. Writing is straightforward. if self.bits_per_component[0] <= 8: - write_buffer = np.getbuffer(self.palette.astype(np.uint8)) + write_buffer = memoryview(self.palette.astype(np.uint8)) elif self.bits_per_component[0] <= 16: - write_buffer = np.getbuffer(self.palette.astype(np.uint16)) + write_buffer = memoryview(self.palette.astype(np.uint16)) elif self.bits_per_component[0] <= 32: - write_buffer = np.getbuffer(self.palette.astype(np.uint32)) + write_buffer = memoryview(self.palette.astype(np.uint32)) fptr.write(write_buffer) else: # Not all the components are the same. More general, but much rarer From 0e370f5882286271e4160070e4aba5b612f7eca8 Mon Sep 17 00:00:00 2001 From: jevans Date: Wed, 2 Apr 2014 20:49:17 -0400 Subject: [PATCH 04/10] Refactoring, lint cleanup. --- glymur/jp2box.py | 64 ++++++++++++++++++++++++++---------------------- glymur/jp2k.py | 64 ++++++++++++++++++++---------------------------- 2 files changed, 62 insertions(+), 66 deletions(-) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index 92c94ba..2dd30d0 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -43,7 +43,7 @@ _METHOD_DISPLAY = { ANY_ICC_PROFILE: 'any ICC profile', VENDOR_COLOR_METHOD: 'vendor color method'} -_factory = lambda x: '{0} (invalid)'.format(x) +_factory = lambda x: '{0} (invalid)'.format(x) _APPROX_DISPLAY = _Keydefaultdict(_factory, {1: 'accurately represents correct colorspace definition', 2: 'approximates correct colorspace definition, exceptional quality', @@ -125,7 +125,7 @@ class Jp2kBox(object): String to be indented. indent_level : str Number of spaces of indentation to add. - + Returns ------- indented_string : str @@ -407,15 +407,16 @@ class ColourSpecificationBox(Jp2kBox): ------- ColourSpecificationBox instance """ + num_bytes = offset + length - fptr.tell() + read_buffer = fptr.read(num_bytes) # Read the brand, minor version. - read_buffer = fptr.read(3) - (method, precedence, approximation) = struct.unpack('>BBB', - read_buffer) + (method, precedence, approximation) = struct.unpack_from('>BBB', + read_buffer, + offset=0) if method == 1: # enumerated colour space - read_buffer = fptr.read(4) - colorspace, = struct.unpack('>I', read_buffer) + colorspace, = struct.unpack_from('>I', read_buffer, offset=3) if colorspace not in _COLORSPACE_MAP_DISPLAY.keys(): msg = "Unrecognized colorspace: {0}".format(colorspace) warnings.warn(msg) @@ -424,14 +425,13 @@ class ColourSpecificationBox(Jp2kBox): else: # ICC profile colorspace = None - numbytes = offset + length - fptr.tell() - if numbytes < 128: + if (num_bytes - 3) < 128: msg = "ICC profile header is corrupt, length is " msg += "only {0} instead of 128." - warnings.warn(msg.format(numbytes), UserWarning) + warnings.warn(msg.format(num_bytes - 3), UserWarning) icc_profile = None else: - profile = _ICCProfile(fptr.read(numbytes)) + profile = _ICCProfile(read_buffer[3:]) icc_profile = profile.header return cls(method=method, @@ -659,12 +659,14 @@ class ChannelDefinitionBox(Jp2kBox): ------- ComponentDefinitionBox instance """ - # Read the number of components. - read_buffer = fptr.read(2) - num_components, = struct.unpack('>H', read_buffer) + num_bytes = offset + length - fptr.tell() + read_buffer = fptr.read(num_bytes) - read_buffer = fptr.read(num_components * 6) - data = struct.unpack('>' + 'HHH' * num_components, read_buffer) + # Read the number of components. + num_components, = struct.unpack_from('>H', read_buffer) + + data = struct.unpack_from('>' + 'HHH' * num_components, read_buffer, + offset=2) index = data[0:num_components * 6:3] channel_type = data[1:num_components * 6:3] association = data[2:num_components * 6:3] @@ -1234,19 +1236,21 @@ class FileTypeBox(Jp2kBox): ------- FileTypeBox instance """ + current_pos = fptr.tell() + num_bytes = (offset + length - current_pos) + read_buffer = fptr.read(num_bytes) + # Read the brand, minor version. - read_buffer = fptr.read(8) - (brand, minor_version) = struct.unpack('>4sI', read_buffer) + (brand, minor_version) = struct.unpack_from('>4sI', read_buffer, + offset=0) if sys.hexversion >= 0x030000: brand = brand.decode('utf-8') # Read the compatibility list. Each entry has 4 bytes. - current_pos = fptr.tell() - num_bytes = (offset + length - current_pos) / 4 - read_buffer = fptr.read(int(num_bytes) * 4) compatibility_list = [] - for j in range(int(num_bytes)): - entry, = struct.unpack('>4s', read_buffer[4*j:4*(j+1)]) + num_entries = int((offset + length - current_pos - 8) / 4) + for j in range(num_entries): + entry, = struct.unpack_from('>4s', read_buffer, offset=8 + (4 * j)) if sys.hexversion >= 0x03000000: entry = entry.decode('utf-8') compatibility_list.append(entry) @@ -1942,7 +1946,7 @@ class PaletteBox(Jp2kBox): elif bps[0] <= 32: nbytes_per_row = 3 * num_columns dtype = np.uint32 - + read_buffer = fptr.read(num_entries * nbytes_per_row) palette = np.frombuffer(read_buffer, dtype=dtype) palette = np.reshape(palette, (num_entries, num_columns)) @@ -2828,13 +2832,15 @@ class UUIDListBox(Jp2kBox): ------- UUIDListBox instance """ - read_buffer = fptr.read(2) - num_uuids, = struct.unpack('>H', read_buffer) + num_bytes = offset + length - fptr.tell() + read_buffer = fptr.read(num_bytes) + + num_uuids, = struct.unpack_from('>H', read_buffer) ulst = [] - for _ in range(num_uuids): - read_buffer = fptr.read(16) - ulst.append(uuid.UUID(bytes=read_buffer)) + for j in range(num_uuids): + uuid_buffer = read_buffer[2 + j * 16 : 2 + (j + 1) * 16] + ulst.append(uuid.UUID(bytes=uuid_buffer)) return cls(ulst, length=length, offset=offset) diff --git a/glymur/jp2k.py b/glymur/jp2k.py index 971c82d..dee6700 100644 --- a/glymur/jp2k.py +++ b/glymur/jp2k.py @@ -691,7 +691,7 @@ class Jp2k(Jp2kBox): msg = "Unable to locate the specified codestream." raise IOError(msg) if L == 0: - # The length of the box is presumed to last until the end of + # The length of the box is presumed to last until the end of # the file. Compute the effective length of the box. L = os.path.getsize(ifile.name) - ifile.tell() + 8 @@ -833,38 +833,13 @@ class Jp2k(Jp2kBox): """ self._subsampling_sanity_check() - # Must check the specified rlevel against the maximum. - if rlevel != 0: - # Must check the specified rlevel against the maximum. - codestream = self.get_codestream() - max_rlevel = codestream.segment[2].spcod[4] - if rlevel == -1: - # -1 is shorthand for the largest rlevel - rlevel = max_rlevel - elif rlevel < -1 or rlevel > max_rlevel: - msg = "rlevel must be in the range [-1, {0}] for this image." - msg = msg.format(max_rlevel) - raise IOError(msg) + dparameters = self._populate_dparam(rlevel, ignore_pclr_cmap_cdef) with ExitStack() as stack: try: - # Set decoding parameters. - # TODO: look to refactor, use _populate_dparam - dparameters = opj.DecompressionParametersType() - opj.set_default_decoder_parameters(ctypes.byref(dparameters)) - - if ignore_pclr_cmap_cdef is True: - # Return raw codestream components. - dparameters.flags |= 1 - dparameters.cp_reduce = rlevel dparameters.decod_format = self._codec_format - infile = self.filename.encode() - nelts = opj.PATH_LEN - len(infile) - infile += b'0' * nelts - dparameters.infile = infile - dinfo = opj.create_decompress(dparameters.decod_format) event_mgr = opj.EventMgrType() @@ -931,8 +906,8 @@ class Jp2k(Jp2kBox): """ self._subsampling_sanity_check() - dparam = self._populate_dparam(layer, rlevel, area, tile, - ignore_pclr_cmap_cdef) + dparam = self._populate_dparam(rlevel, ignore_pclr_cmap_cdef, + layer=layer, tile=tile, area=area) with ExitStack() as stack: if hasattr(opj2.OPENJP2, @@ -976,8 +951,8 @@ class Jp2k(Jp2kBox): return img_array - def _populate_dparam(self, layer, rlevel, area, tile, - ignore_pclr_cmap_cdef): + def _populate_dparam(self, rlevel, ignore_pclr_cmap_cdef, tile=None, + layer=None, area=None): """Populate decompression structure with appropriate input parameters. Parameters @@ -1000,7 +975,11 @@ class Jp2k(Jp2kBox): dparam : DecompressionParametersType (ctypes) Corresponds to openjp2 decompression parameters structure. """ - dparam = opj2.set_default_decoder_parameters() + if opj2.OPENJP2 is not None: + dparam = opj2.set_default_decoder_parameters() + else: + dparam = opj.DecompressionParametersType() + opj.set_default_decoder_parameters(ctypes.byref(dparam)) infile = self.filename.encode() nelts = opj2.PATH_LEN - len(infile) @@ -1009,12 +988,22 @@ class Jp2k(Jp2kBox): dparam.decod_format = self._codec_format - dparam.cp_layer = layer + if layer is not None: + dparam.cp_layer = layer - if rlevel == -1: - # Get the lowest resolution thumbnail. + # Must check the specified rlevel against the maximum. + if rlevel != 0: + # Must check the specified rlevel against the maximum. codestream = self.get_codestream() - rlevel = codestream.segment[2].spcod[4] + max_rlevel = codestream.segment[2].spcod[4] + if rlevel == -1: + # -1 is shorthand for the largest rlevel + rlevel = max_rlevel + elif rlevel < -1 or rlevel > max_rlevel: + msg = "rlevel must be in the range [-1, {0}] for this image." + msg = msg.format(max_rlevel) + raise IOError(msg) + dparam.cp_reduce = rlevel if area is not None: @@ -1088,7 +1077,8 @@ class Jp2k(Jp2kBox): "of OpenJP2 installed before using " "this functionality.") - dparam = self._populate_dparam(layer, rlevel, area, tile, ignore_pclr_cmap_cdef) + dparam = self._populate_dparam(rlevel, ignore_pclr_cmap_cdef, + layer=layer, tile=tile, area=area) with ExitStack() as stack: if hasattr(opj2.OPENJP2, From 7ebe4ff59eccd2cde91cd9f89c997bf9ffe54ffe Mon Sep 17 00:00:00 2001 From: jevans Date: Wed, 2 Apr 2014 21:30:01 -0400 Subject: [PATCH 05/10] Fixed rlevel assignment issue causing segfault in 1.5. Segfault introduced in 0e370f5882286271e4160070e4aba5b612f7eca8 --- glymur/jp2k.py | 1 - 1 file changed, 1 deletion(-) diff --git a/glymur/jp2k.py b/glymur/jp2k.py index dee6700..8110c50 100644 --- a/glymur/jp2k.py +++ b/glymur/jp2k.py @@ -837,7 +837,6 @@ class Jp2k(Jp2kBox): with ExitStack() as stack: try: - dparameters.cp_reduce = rlevel dparameters.decod_format = self._codec_format dinfo = opj.create_decompress(dparameters.decod_format) From 576571fa8511ecb1e5e94d738467faa738405fe7 Mon Sep 17 00:00:00 2001 From: John Evans Date: Thu, 3 Apr 2014 07:09:34 -0400 Subject: [PATCH 06/10] Streamlined SIZ parsing. #130 --- glymur/codestream.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/glymur/codestream.py b/glymur/codestream.py index 2f9d37a..544b8a2 100644 --- a/glymur/codestream.py +++ b/glymur/codestream.py @@ -670,8 +670,8 @@ class Codestream(object): read_buffer = fptr.read(2) length, = struct.unpack('>H', read_buffer) - xy_buffer = fptr.read(36) - data = struct.unpack('>HIIIIIIIIH', xy_buffer) + read_buffer = fptr.read(length - 2) + data = struct.unpack_from('>HIIIIIIIIH', read_buffer) rsiz = data[0] if rsiz not in _KNOWN_PROFILES: @@ -685,9 +685,8 @@ class Codestream(object): # Csiz is the number of components Csiz = data[9] - component_buffer = fptr.read(Csiz * 3) - data = struct.unpack('>' + 'B' * len(component_buffer), - component_buffer) + data = struct.unpack_from('>' + 'B' * (length - 36 - 2), + read_buffer, offset=36) bitdepth = tuple(((x & 0x7f) + 1) for x in data[0::3]) signed = tuple(((x & 0x80) > 0) for x in data[0::3]) From 4e19e688a0704f05c6916f6559a5eaa4c6d8d19a Mon Sep 17 00:00:00 2001 From: jevans Date: Thu, 3 Apr 2014 22:52:11 -0400 Subject: [PATCH 07/10] Variable renaming. #130 --- glymur/jp2box.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index 701483f..22ef99d 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -1922,13 +1922,11 @@ class PaletteBox(Jp2kBox): ------- PaletteBox instance """ - num_bytes = offset + length - fptr.tell() - read_buffer = fptr.read(num_bytes) - (nrows, ncols) = struct.unpack_from('>HB', read_buffer, offset=0) + read_buffer = fptr.read(3) + (nrows, ncols) = struct.unpack('>HB', read_buffer) - # Need to determine bps and signed or not - read_buffer = fptr.read(num_columns) - bps_signed = struct.unpack('>' + 'B' * num_columns, read_buffer) + read_buffer = fptr.read(ncols) + bps_signed = struct.unpack('>' + 'B' * ncols, read_buffer) bps = [((x & 0x7f) + 1) for x in bps_signed] signed = [((x & 0x80) > 1) for x in bps_signed] @@ -1936,18 +1934,18 @@ class PaletteBox(Jp2kBox): # Ok the palette has the same datatype for all columns. We should # be able to efficiently read it. if bps[0] <= 8: - nbytes_per_row = num_columns + nbytes_per_row = ncols dtype = np.uint8 elif bps[0] <= 16: - nbytes_per_row = 2 * num_columns + nbytes_per_row = 2 * ncols dtype = np.uint16 elif bps[0] <= 32: - nbytes_per_row = 3 * num_columns + nbytes_per_row = 3 * ncols dtype = np.uint32 - read_buffer = fptr.read(num_entries * nbytes_per_row) + read_buffer = fptr.read(nrows * nbytes_per_row) palette = np.frombuffer(read_buffer, dtype=dtype) - palette = np.reshape(palette, (num_entries, num_columns)) + palette = np.reshape(palette, (nrows, ncols)) else: # General case where the columns may not be the same width. @@ -1964,9 +1962,9 @@ class PaletteBox(Jp2kBox): # That means a list comprehension does this in one shot. row_nbytes = sum([int(math.ceil(x/8.0)) for x in bps]) - read_buffer = fptr.read(num_entries * row_nbytes) - palette = np.zeros((num_entries, num_columns), dtype=np.int32) - for j in range(num_entries): + read_buffer = fptr.read(nrows * row_nbytes) + palette = np.zeros((nrows, ncols), dtype=np.int32) + for j in range(nrows): palette[j] = struct.unpack_from(fmt, read_buffer, offset=j * row_nbytes) From 828abe942ac4f2ebbac27c9e8339fa42e36870e6 Mon Sep 17 00:00:00 2001 From: jevans Date: Thu, 3 Apr 2014 22:53:52 -0400 Subject: [PATCH 08/10] Removed one read statement, using struct.unpack_from. #130 --- glymur/codestream.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/glymur/codestream.py b/glymur/codestream.py index 544b8a2..2a257ed 100644 --- a/glymur/codestream.py +++ b/glymur/codestream.py @@ -380,13 +380,13 @@ class Codestream(object): COD segment instance. """ offset = fptr.tell() - 2 - offset = fptr.tell() - 2 - read_buffer = fptr.read(3) - length, scod = struct.unpack('>HB', read_buffer) + read_buffer = fptr.read(2) + length, = struct.unpack('>H', read_buffer) - numbytes = offset + 2 + length - fptr.tell() - spcod = fptr.read(numbytes) + read_buffer = fptr.read(length - 2) + scod, = struct.unpack_from('>B', read_buffer, offset=0) + spcod = read_buffer[1:] spcod = np.frombuffer(spcod, dtype=np.uint8) if spcod[0] not in [LRCP, RLCP, RPCL, PCRL, CPRL]: msg = "Invalid progression order in COD segment: {0}." From 3dbaf9f458579ef10facac922aedc77566a67916 Mon Sep 17 00:00:00 2001 From: John Evans Date: Fri, 4 Apr 2014 07:11:43 -0400 Subject: [PATCH 09/10] Refactored QCC segment parsing. #130 --- glymur/codestream.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/glymur/codestream.py b/glymur/codestream.py index 2a257ed..fb9917c 100644 --- a/glymur/codestream.py +++ b/glymur/codestream.py @@ -583,22 +583,21 @@ class Codestream(object): read_buffer = fptr.read(2) length, = struct.unpack('>H', read_buffer) + read_buffer = fptr.read(length - 2) if self._csiz > 256: - read_buffer = fptr.read(3) fmt = '>HB' - mantissa_exponent_buffer_length = length - 5 + mantissa_exponent_offset = 3 else: - read_buffer = fptr.read(2) fmt = '>BB' - mantissa_exponent_buffer_length = length - 4 - cqcc, sqcc = struct.unpack(fmt, read_buffer) + mantissa_exponent_offset = 2 + cqcc, sqcc = struct.unpack_from(fmt, read_buffer) if cqcc >= self._csiz: msg = "Invalid component number ({0}), " msg += "number of components is only {1}." msg = msg.format(cqcc, self._csiz) warnings.warn(msg) - spqcc = fptr.read(mantissa_exponent_buffer_length) + spqcc = read_buffer[mantissa_exponent_offset:] return QCCsegment(cqcc, sqcc, spqcc, length, offset) From 2dc4e8400e81479c0b54ad18b7d40b55bbac2198 Mon Sep 17 00:00:00 2001 From: John Evans Date: Fri, 4 Apr 2014 12:17:58 -0400 Subject: [PATCH 10/10] Refactored the TLM segment. #130 --- glymur/codestream.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/glymur/codestream.py b/glymur/codestream.py index fb9917c..6830fab 100644 --- a/glymur/codestream.py +++ b/glymur/codestream.py @@ -802,8 +802,8 @@ class Codestream(object): read_buffer = fptr.read(2) length, = struct.unpack('>H', read_buffer) - read_buffer = fptr.read(2) - ztlm, stlm = struct.unpack('>BB', read_buffer) + read_buffer = fptr.read(length - 2) + ztlm, stlm = struct.unpack_from('>BB', read_buffer) ttlm_st = (stlm >> 4) & 0x3 ptlm_sp = (stlm >> 6) & 0x1 @@ -813,7 +813,6 @@ class Codestream(object): else: ntiles = nbytes / (ttlm_st + (ptlm_sp + 1) * 2) - read_buffer = fptr.read(nbytes) if ttlm_st == 0: ttlm = None fmt = '' @@ -827,7 +826,8 @@ class Codestream(object): else: fmt += 'I' - data = struct.unpack('>' + fmt * int(ntiles), read_buffer) + data = struct.unpack_from('>' + fmt * int(ntiles), read_buffer, + offset=2) if ttlm_st == 0: ttlm = None ptlm = data