From 0e370f5882286271e4160070e4aba5b612f7eca8 Mon Sep 17 00:00:00 2001 From: jevans Date: Wed, 2 Apr 2014 20:49:17 -0400 Subject: [PATCH] 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,