diff --git a/docs/source/how_do_i.rst b/docs/source/how_do_i.rst index 5d11d67..8a62b32 100644 --- a/docs/source/how_do_i.rst +++ b/docs/source/how_do_i.rst @@ -14,27 +14,22 @@ retrieve a full resolution and first lower-resolution image :: >>> jp2file = glymur.data.nemo() # just a path to a JPEG2000 file >>> jp2 = glymur.Jp2k(jp2file) >>> fullres = jp2[:] - >>> print(fullres.shape) + >>> fullres.shape (1456, 2592, 3) >>> thumbnail = jp2[::2, ::2] - >>> print(thumbnail.shape) + >>> thumbnail.shape (728, 1296, 3) -The :py:meth:`read` method exposes many more options for other JPEG 2000 -features such as quality layers. - ... write images? ================= -So long as the image data can fit entirely into memory, array-style slicing may -also be used to write JPEG 2000 files. +It's pretty simple, just supply the image data as the 2nd argument to the Jp2k +constructor. >>> import glymur, numpy as np - >>> jp2 = glymur.Jp2k('zeros.jp2', mode='wb') - >>> jp2[:] = np.zeros((640, 480), dtype=np.uint8) + >>> data = np.zeros((640, 480), dtype=np.uint8) + >>> jp2 = glymur.Jp2k('zeros.jp2', data=data) -The :py:meth:`write` method exposes many more options for other JPEG 2000 -features. You should have OpenJPEG version 1.5 or more recent before writing -JPEG 2000 images. +You should have OpenJPEG version 1.5 or more recent before writing JPEG 2000 images. ... display metadata? ===================== @@ -354,15 +349,14 @@ image isn't square. :: >>> import numpy as np >>> import glymur >>> from glymur import Jp2k - >>> rgb = Jp2k(glymur.data.goodstuff()).read() + >>> rgb = Jp2k(glymur.data.goodstuff())[:] >>> lx, ly = rgb.shape[0:2] >>> X, Y = np.ogrid[0:lx, 0:ly] >>> mask = ly**2*(X - lx / 2) ** 2 + lx**2*(Y - ly / 2) ** 2 > (lx * ly / 2)**2 >>> alpha = 255 * np.ones((lx, ly, 1), dtype=np.uint8) >>> alpha[mask] = 0 >>> rgba = np.concatenate((rgb, alpha), axis=2) - >>> jp2 = Jp2k('tmp.jp2', 'wb') - >>> jp2[:] = rgba + >>> jp2 = Jp2k('tmp.jp2', data=rgba) Next we need to specify what types of channels we have. The first three channels are color channels, but we identify the fourth as @@ -465,8 +459,7 @@ http://photojournal.jpl.nasa.gov/tiff/PIA17145.tif info JPEG 2000:: >>> import skimage.io >>> image = skimage.io.imread('PIA17145.tif') >>> from glymur import Jp2k - >>> jp2 = Jp2k('PIA17145.jp2', 'wb') - >>> jp2[:] = image + >>> jp2 = Jp2k('PIA17145.jp2', data=image) Next you can extract the XMP metadata. diff --git a/docs/source/roadmap.rst b/docs/source/roadmap.rst index 503fbc4..f0d7017 100644 --- a/docs/source/roadmap.rst +++ b/docs/source/roadmap.rst @@ -1,12 +1,3 @@ -------------------------------------- -Platforms Tested (0.7.0 release only) -------------------------------------- - * Linux Mint 17 / Python 3.4.0 and 2.7.6 / OpenJPEG 2.1.0 and 1.3.0 - * MacOS 10.6.8 / MacPorts Python 3.4.1, 3.3.5,and 2.7.8 / OpenJPEG 2.1.0 - * CentOS 6.5 / Anaconda Python 3.4.1 / OpenJPEG 1.3.0 - * Fedora 20 i386 / Python 2.7.5 and 3.3.2 / OpenJPEG 1.5.1 - * Windows 7 32bit / Anaconda Python 2.7.6 and 3.4.1 / OpenJPEG 2.1.0 - ------------ Known Issues ------------ diff --git a/docs/source/whatsnew/0.7.rst b/docs/source/whatsnew/0.7.rst index 0a21d9b..3ed7715 100644 --- a/docs/source/whatsnew/0.7.rst +++ b/docs/source/whatsnew/0.7.rst @@ -2,10 +2,26 @@ Changes in glymur 0.7 ===================== +Changes in 0.7.3 +================= + + * added read support back for metadata only when the OpenJPEG library is + not installed + +Changes in 0.7.2 +================= + + * added ellipsis support in array-style slicing + +Changes in 0.7.1 +================= + + * fixed release notes regarding Python 3.4 + Changes in 0.7.0 ================= * implemented :py:meth:`__getitem__`, :py:meth:`__setitem__` support * added back windows support * box_id and longname are class attributes now instead of instance - attributes (see issue 248) + attributes diff --git a/docs/source/whatsnew/0.8.rst b/docs/source/whatsnew/0.8.rst new file mode 100644 index 0000000..f36b593 --- /dev/null +++ b/docs/source/whatsnew/0.8.rst @@ -0,0 +1,10 @@ +===================== +Changes in glymur 0.8 +===================== + +Changes in 0.8.0 +================= + + * Simplified writing images by moving data and options into the + constructor. This is backwards-incompatible with 0.7.x. + * Deprecated :py:meth:`read` method in favor of array-style slicing. diff --git a/docs/source/whatsnew/index.rst b/docs/source/whatsnew/index.rst index 2d69949..4569abd 100644 --- a/docs/source/whatsnew/index.rst +++ b/docs/source/whatsnew/index.rst @@ -8,6 +8,7 @@ These document the changes between minor (or major) versions of glymur. .. toctree:: - 0.5 - 0.6 + 0.8 0.7 + 0.6 + 0.5 diff --git a/glymur/jp2k.py b/glymur/jp2k.py index f36b75e..d7e04bb 100644 --- a/glymur/jp2k.py +++ b/glymur/jp2k.py @@ -37,16 +37,6 @@ from .jp2box import ( ) from .lib import openjpeg as opj, openjp2 as opj2, c as libc -JP2_IDS = ['colr', 'cdef', 'cmap', 'jp2c', 'ftyp', 'ihdr', 'jp2h', 'jP ', - 'pclr', 'res ', 'resc', 'resd', 'xml ', 'ulst', 'uinf', 'url ', - 'uuid'] -JPX_IDS = ['asoc', 'nlst'] - -_COLORSPACE_MAP = {'rgb': opj2.CLRSPC_SRGB, - 'gray': opj2.CLRSPC_GRAY, - 'grey': opj2.CLRSPC_GRAY, - 'ycc': opj2.CLRSPC_YCC} - class Jp2k(Jp2kBox): """JPEG 2000 file. @@ -54,34 +44,150 @@ class Jp2k(Jp2kBox): ---------- filename : str The path to the JPEG 2000 file. - mode : str - The mode used to open the file. box : sequence List of top-level boxes in the file. Each box may in turn contain its own list of boxes. Will be empty if the file consists only of a raw codestream. + shape : tuple + Size of the image. + + Properties + ---------- + ignore_pclr_cmap_cdef : bool + whether or not to ignore the pclr, cmap, or cdef boxes during any + color transformation, defaults to False. + layer : int + zero-based number of quality layer to decode + verbose : bool + whether or not to print informational messages produced by the + OpenJPEG library, defaults to false + + Examples + -------- + >>> import glymur + >>> jfile = glymur.data.nemo() + >>> jp2 = glymur.Jp2k(jfile) + >>> jp2.shape + (1456, 2592, 3) + >>> image = jp2[:] + >>> image.shape + (1456, 2592, 3) + + Read a lower resolution thumbnail. + + >>> thumbnail = jp2[::2, ::2] + >>> thumbnail.shape + (728, 1296, 3) """ - def __init__(self, filename, mode='rb'): + def __init__(self, filename, data=None, shape=None, **kwargs): """ + Only the filename parameter is required in order to read a JPEG 2000 + file. + Parameters ---------- filename : str or file - The path to JPEG 2000 file. - mode : str, optional - The mode used to open the file. + the path to JPEG 2000 file + image_data : ndarray, optional + image data to be written + shape : tuple + size of image data, only required when image_data is not provided + cbsize : tuple, optional + code block size (DY, DX) + cinema2k : int, optional + frames per second, either 24 or 48 + cinema4k : bool, optional + set to True to specify Cinema4K mode, defaults to false + colorspace : str, optional + either 'rgb' or 'gray' + cratios : iterable + compression ratios for successive layers + eph : bool, optional + if true, write SOP marker after each header packet + grid_offset : tuple, optional + offset (DY, DX) of the origin of the image in the reference grid + irreversible : bool, optional + if true, use the irreversible DWT 9-7 transform + mct : bool, optional + specifies usage of the multi component transform, if not + specified, defaults to True if the colorspace is RGB + modesw : int, optional + mode switch + 1 = BYPASS(LAZY) + 2 = RESET + 4 = RESTART(TERMALL) + 8 = VSC + 16 = ERTERM(SEGTERM) + 32 = SEGMARK(SEGSYM) + numres : int, optional + number of resolutions + prog : str, optional + progression order, one of "LRCP" "RLCP", "RPCL", "PCRL", "CPRL" + psnr : iterable, optional + different PSNR for successive layers + psizes : list, optional + list of precinct sizes, each precinct size tuple is defined in + (height x width) + sop : bool, optional + if true, write SOP marker before each packet + subsam : tuple, optional + subsampling factors (dy, dx) + tilesize : tuple, optional + numeric tuple specifying tile size in terms of (numrows, numcols), + not (X, Y) + verbose : bool, optional + print informational messages produced by the OpenJPEG library + """ Jp2kBox.__init__(self) self.filename = filename - self.mode = mode + self.box = [] self._codec_format = None self._colorspace = None - self._shape = None + self._layer = 0 + if data is not None: + self._shape = data.shape + else: + self._shape = shape + + self._ignore_pclr_cmap_cdef = False + self._verbose = False # Parse the file for JP2/JPX contents only if we are reading it. - if mode == 'rb': + if data is None and shape is None: self.parse() + elif data is not None: + self._write(data, **kwargs) + + @property + def ignore_pclr_cmap_cdef(self): + return self._ignore_pclr_cmap_cdef + + @ignore_pclr_cmap_cdef.setter + def ignore_pclr_cmap_cdef(self, ignore_pclr_cmap_cdef): + self._ignore_pclr_cmap_cdef = ignore_pclr_cmap_cdef + + @property + def layer(self): + return self._layer + + @layer.setter + def layer(self, layer): + if version.openjpeg_version_tuple[0] < 2: + msg = "Layer property not supported unless the version of OpenJPEG " + msg += "is 2.0 or higher." + raise RuntimeError(msg) + self._layer = layer + + @property + def verbose(self): + return self._verbose + + @verbose.setter + def verbose(self, verbose): + self._verbose = verbose @property def shape(self): @@ -371,79 +477,17 @@ class Jp2k(Jp2kBox): self._cparams = cparams - def write(self, img_array, verbose=False, **kwargs): + def _write(self, img_array, verbose=False, **kwargs): """Write image data to a JP2/JPX/J2k file. Intended usage of the various parameters follows that of OpenJPEG's opj_compress utility. This method can only be used to create JPEG 2000 images that can fit in memory. - - Parameters - ---------- - img_array : ndarray - Image data to be written to file. - cbsize : tuple, optional - Code block size (DY, DX). - cinema2k : int, optional - frames per second, either 24 or 48 - cinema4k : bool, optional - Set to True to specify Cinema4K mode, defaults to false. - colorspace : str, optional - Either 'rgb' or 'gray'. - cratios : iterable - Compression ratios for successive layers. - eph : bool, optional - If true, write SOP marker after each header packet. - grid_offset : tuple, optional - Offset (DY, DX) of the origin of the image in the reference grid. - irreversible : bool, optional - If true, use the irreversible DWT 9-7 transform. - mct : bool, optional - Specifies usage of the multi component transform. If not - specified, defaults to True if the colorspace is RGB. - modesw : int, optional - Mode switch. - 1 = BYPASS(LAZY) - 2 = RESET - 4 = RESTART(TERMALL) - 8 = VSC - 16 = ERTERM(SEGTERM) - 32 = SEGMARK(SEGSYM) - numres : int, optional - Number of resolutions. - prog : str, optional - Progression order, one of "LRCP" "RLCP", "RPCL", "PCRL", "CPRL". - psnr : iterable, optional - Different PSNR for successive layers. - psizes : list, optional - List of precinct sizes. Each precinct size tuple is defined in - (height x width). - sop : bool, optional - If true, write SOP marker before each packet. - subsam : tuple, optional - Subsampling factors (dy, dx). - tilesize : tuple, optional - Numeric tuple specifying tile size in terms of (numrows, numcols), - not (X, Y). - verbose : bool, optional - Print informational messages produced by the OpenJPEG library. - - Examples - -------- - >>> import glymur - >>> jfile = glymur.data.nemo() - >>> jp2 = glymur.Jp2k(jfile) - >>> data = jp2.read(rlevel=1) - >>> from tempfile import NamedTemporaryFile - >>> tfile = NamedTemporaryFile(suffix='.jp2', delete=False) - >>> j = Jp2k(tfile.name, mode='wb') - >>> j.write(data.astype(np.uint8)) """ if re.match("1.[0-4]", version.openjpeg_version) is not None: raise RuntimeError("You must have at least version 1.5 of OpenJPEG " "in order to write images.") - self._shape = img_array.shape self._determine_colorspace(**kwargs) self._populate_cparams(img_array, **kwargs) @@ -617,7 +661,12 @@ class Jp2k(Jp2kBox): # Turn the colorspace from a string to the enumerated value that # the library expects. - self._colorspace = _COLORSPACE_MAP[colorspace.lower()] + COLORSPACE_MAP = {'rgb': opj2.CLRSPC_SRGB, + 'gray': opj2.CLRSPC_GRAY, + 'grey': opj2.CLRSPC_GRAY, + 'ycc': opj2.CLRSPC_YCC} + + self._colorspace = COLORSPACE_MAP[colorspace.lower()] def _write_openjp2(self, img_array, verbose=False): @@ -640,7 +689,11 @@ class Jp2k(Jp2kBox): codec = opj2.create_compress(self._cparams.codec_fmt) stack.callback(opj2.destroy_codec, codec) - info_handler = _INFO_CALLBACK if verbose else None + if self._verbose or verbose: + info_handler = _INFO_CALLBACK + else: + info_handler = None + opj2.set_info_handler(codec, info_handler) opj2.set_warning_handler(codec, _WARNING_CALLBACK) opj2.set_error_handler(codec, _ERROR_CALLBACK) @@ -844,7 +897,7 @@ class Jp2k(Jp2kBox): # Case of jp2[:] = data, i.e. write the entire image. # # Should have a slice object where start = stop = step = None - self.write(data) + self._write(data) else: msg = "Partial write operations are currently not allowed." raise TypeError(msg) @@ -863,16 +916,16 @@ class Jp2k(Jp2kBox): # This retrieves a single row. row = pargs area = (row, 0, row + 1, numcols) - return self.read(area=area).squeeze() + return self._read(area=area).squeeze() if pargs is Ellipsis: # Case of jp2[...] - return self.read() + return self._read() if isinstance(pargs, slice): if pargs.start is None and pargs.stop is None and pargs.step is None: # Case of jp2[:] - return self.read() + return self._read() # Corner case of jp2[x] where x is a slice object with non-null # members. Just augment it with an ellipsis and let the code @@ -949,7 +1002,7 @@ class Jp2k(Jp2kBox): numrows if rows.stop is None else rows.stop, numcols if cols.stop is None else cols.stop ) - data = self.read(area=area, rlevel=rlevel) + data = self._read(area=area, rlevel=rlevel) if len(pargs) == 2: return data @@ -957,6 +1010,25 @@ class Jp2k(Jp2kBox): return data[:, :, bands] + def _read(self, **kwargs): + """Read a JPEG 2000 image. + + Returns + ------- + img_array : ndarray + The image data. + + Raises + ------ + IOError + If the image has differing subsample factors. + """ + if version.openjpeg_version_tuple[0] < 2: + img = self._read_openjpeg(**kwargs) + else: + img = self._read_openjp2(**kwargs) + return img + def read(self, **kwargs): """Read a JPEG 2000 image. @@ -973,9 +1045,6 @@ class Jp2k(Jp2kBox): (first_row, first_col, last_row, last_col) tile : int, optional Number of tile to decode. - ignore_pclr_cmap_cdef : bool - Whether or not to ignore the pclr, cmap, or cdef boxes during any - color transformation. Defaults to False. verbose : bool, optional Print informational messages produced by the OpenJPEG library. @@ -988,22 +1057,10 @@ class Jp2k(Jp2kBox): ------ IOError If the image has differing subsample factors. - - Examples - -------- - >>> import glymur - >>> jfile = glymur.data.nemo() - >>> jp = glymur.Jp2k(jfile) - >>> image = jp.read() - >>> image.shape - (1456, 2592, 3) - - Read the lowest resolution thumbnail. - - >>> thumbnail = jp.read(rlevel=-1) - >>> thumbnail.shape - (728, 1296, 3) """ + if 'ignore_pclr_cmap_cdef' in kwargs: + self.ignore_pclr_cmap_cdef = kwargs['ignore_pclr_cmap_cdef'] + warnings.warn("Use array-style slicing instead.", DeprecationWarning) if version.openjpeg_version_tuple[0] < 2: img = self._read_openjpeg(**kwargs) else: @@ -1022,8 +1079,7 @@ class Jp2k(Jp2kBox): msg += "the read_bands method instead." raise RuntimeError(msg) - def _read_openjpeg(self, rlevel=0, ignore_pclr_cmap_cdef=False, - verbose=False, area=None): + def _read_openjpeg(self, rlevel=0, verbose=False, area=None): """Read a JPEG 2000 image using libopenjpeg. Parameters @@ -1031,9 +1087,6 @@ class Jp2k(Jp2kBox): rlevel : int, optional Factor by which to rlevel output resolution. Use -1 to get the lowest resolution thumbnail. - ignore_pclr_cmap_cdef : bool - Whether or not to ignore the pclr, cmap, or cdef boxes during any - color transformation. Defaults to False. verbose : bool, optional Print informational messages produced by the OpenJPEG library. area : tuple, optional @@ -1052,7 +1105,7 @@ class Jp2k(Jp2kBox): """ self._subsampling_sanity_check() - self._populate_dparams(rlevel, ignore_pclr_cmap_cdef) + self._populate_dparams(rlevel) with ExitStack() as stack: try: @@ -1062,7 +1115,10 @@ class Jp2k(Jp2kBox): event_mgr = opj.EventMgrType() info_handler = ctypes.cast(_INFO_CALLBACK, ctypes.c_void_p) - event_mgr.info_handler = info_handler if verbose else None + if verbose or self._verbose: + event_mgr.info_handler = info_handler + else: + event_mgr.info_handler = None event_mgr.warning_handler = ctypes.cast(_WARNING_CALLBACK, ctypes.c_void_p) event_mgr.error_handler = ctypes.cast(_ERROR_CALLBACK, @@ -1105,8 +1161,7 @@ class Jp2k(Jp2kBox): return data - def _read_openjp2(self, rlevel=0, layer=0, area=None, tile=None, - verbose=False, ignore_pclr_cmap_cdef=False): + def _read_openjp2(self, rlevel=0, layer=None, area=None, tile=None, verbose=False): """Read a JPEG 2000 image using libopenjp2. Parameters @@ -1134,10 +1189,12 @@ class Jp2k(Jp2kBox): RuntimeError If the image has differing subsample factors. """ + if layer is not None: + self._layer = layer + self._subsampling_sanity_check() - self._populate_dparams(rlevel, ignore_pclr_cmap_cdef, - layer=layer, tile=tile, area=area) + self._populate_dparams(rlevel, tile=tile, area=area) with ExitStack() as stack: if re.match("2.1", version.openjpeg_version): @@ -1154,7 +1211,8 @@ class Jp2k(Jp2kBox): opj2.set_error_handler(codec, _ERROR_CALLBACK) opj2.set_warning_handler(codec, _WARNING_CALLBACK) - if verbose: + + if self._verbose or verbose: opj2.set_info_handler(codec, _INFO_CALLBACK) else: opj2.set_info_handler(codec, None) @@ -1181,14 +1239,11 @@ class Jp2k(Jp2kBox): return img_array - def _populate_dparams(self, rlevel, ignore_pclr_cmap_cdef, tile=None, - layer=None, area=None): + def _populate_dparams(self, rlevel, tile=None, area=None): """Populate decompression structure with appropriate input parameters. Parameters ---------- - layer : int - Number of quality layer to decode. rlevel : int Factor by which to rlevel output resolution. area : tuple @@ -1196,9 +1251,6 @@ class Jp2k(Jp2kBox): (first_row, first_col, last_row, last_col) tile : int Number of tile to decode. - ignore_pclr_cmap_cdef : bool - Whether or not to ignore the pclr, cmap, or cdef boxes during any - color transformation. Defaults to False. """ if opj2.OPENJP2 is not None: dparam = opj2.set_default_decoder_parameters() @@ -1211,10 +1263,13 @@ class Jp2k(Jp2kBox): infile += b'0' * nelts dparam.infile = infile + if self.ignore_pclr_cmap_cdef: + # Return raw codestream components. + dparam.flags |= 1 + dparam.decod_format = self._codec_format - if layer is not None: - dparam.cp_layer = layer + dparam.cp_layer = self._layer # Must check the specified rlevel against the maximum. if rlevel != 0: @@ -1245,13 +1300,13 @@ class Jp2k(Jp2kBox): dparam.tile_index = tile dparam.nb_tile_to_decode = 1 - if ignore_pclr_cmap_cdef is True: + if self.ignore_pclr_cmap_cdef: # Return raw codestream components. dparam.flags |= 1 self._dparams = dparam - def read_bands(self, rlevel=0, layer=0, area=None, tile=None, + def read_bands(self, rlevel=0, layer=None, area=None, tile=None, verbose=False, ignore_pclr_cmap_cdef=False): """Read a JPEG 2000 image. @@ -1297,8 +1352,10 @@ class Jp2k(Jp2kBox): "OpenJPEG installed before using this " "functionality.") - self._populate_dparams(rlevel, ignore_pclr_cmap_cdef, - layer=layer, tile=tile, area=area) + self.ignore_pclr_cmap_cdef = ignore_pclr_cmap_cdef + if layer is not None: + self._layer = layer + self._populate_dparams(rlevel, tile=tile, area=area) with ExitStack() as stack: if re.match("2.1", version.openjpeg_version): @@ -1710,6 +1767,8 @@ def _validate_singletons(boxes): if 'dtbl' in multiples: raise IOError('There can only be one dtbl box in a file.') +JPX_IDS = ['asoc', 'nlst'] + def _validate_jpx_brand(boxes, brand): """ If there is a JPX box then the brand must be 'jpx '. diff --git a/glymur/test/test_callbacks.py b/glymur/test/test_callbacks.py index ce3bb8c..c29f816 100644 --- a/glymur/test/test_callbacks.py +++ b/glymur/test/test_callbacks.py @@ -39,15 +39,28 @@ class TestCallbacks(unittest.TestCase): "Missing openjp2 library.") @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") - def test_info_callback_on_write(self): + def test_info_callback_on_write_backwards_compatibility(self): """Verify messages printed when writing an image in verbose mode.""" j = glymur.Jp2k(self.jp2file) with self.assertWarns(UserWarning): tiledata = j.read(tile=0) with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - j = glymur.Jp2k(tfile.name, 'wb') with patch('sys.stdout', new=StringIO()) as fake_out: - j.write(tiledata, verbose=True) + j = glymur.Jp2k(tfile.name, data=tiledata, verbose=True) + actual = fake_out.getvalue().strip() + expected = '[INFO] tile number 1 / 1' + self.assertEqual(actual, expected) + + @unittest.skipIf(glymur.version.openjpeg_version[0] != '2', + "Missing openjp2 library.") + @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") + def test_info_callback_on_write(self): + """Verify messages printed when writing an image in verbose mode.""" + j = glymur.Jp2k(self.jp2file) + tiledata = j[:] + with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: + with patch('sys.stdout', new=StringIO()) as fake_out: + jp2 = glymur.Jp2k(tfile.name, data=tiledata, verbose=True) actual = fake_out.getvalue().strip() expected = '[INFO] tile number 1 / 1' self.assertEqual(actual, expected) @@ -57,15 +70,16 @@ class TestCallbacks(unittest.TestCase): # Verify that we get the expected stdio output when our internal info # callback handler is enabled. - j = glymur.Jp2k(self.j2kfile) + jp2 = glymur.Jp2k(self.j2kfile) with patch('sys.stdout', new=StringIO()) as fake_out: - j.read(rlevel=1, verbose=True) + jp2.verbose = True + jp2[::2, ::2] actual = fake_out.getvalue().strip() if glymur.version.openjpeg_version[0] == '2': lines = ['[INFO] Start to read j2k main header (0).', '[INFO] Main header has been correctly decoded.', - '[INFO] No decoded area parameters, set the decoded area to the whole image', + '[INFO] Setting decoding area to 0,0,480,800', '[INFO] Header of tile 0 / 0 has been read.', '[INFO] Tile 1/1 has been decoded.', '[INFO] Image data has been updated with tile 1.'] diff --git a/glymur/test/test_codestream.py b/glymur/test/test_codestream.py deleted file mode 100644 index e520713..0000000 --- a/glymur/test/test_codestream.py +++ /dev/null @@ -1,149 +0,0 @@ -""" -Test suite for codestream parsing. -""" - -# unittest doesn't work well with R0904. -# pylint: disable=R0904 - -import os -import struct -import sys -import tempfile -import unittest - -from glymur import Jp2k -import glymur - -from .fixtures import opj_data_file, OPJ_DATA_ROOT - -class TestCodestream(unittest.TestCase): - """Test suite for unusual codestream cases.""" - - def setUp(self): - self.jp2file = glymur.data.nemo() - - def tearDown(self): - pass - - def test_siz_segment_ssiz_unsigned(self): - """ssiz attribute to be removed in future release""" - j = Jp2k(self.jp2file) - codestream = j.get_codestream() - - # The ssiz attribute was simply a tuple of raw bytes. - # The first 7 bits are interpreted as the bitdepth, the MSB determines - # whether or not it is signed. - self.assertEqual(codestream.segment[1].ssiz, (7, 7, 7)) - - -@unittest.skipIf(OPJ_DATA_ROOT is None, - "OPJ_DATA_ROOT environment variable not set") -class TestCodestreamOpjData(unittest.TestCase): - """Test suite for unusual codestream cases. Uses OPJ_DATA_ROOT""" - - def setUp(self): - self.jp2file = glymur.data.nemo() - - def tearDown(self): - pass - - @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") - def test_reserved_marker_segment(self): - """Reserved marker segments are ok.""" - - # Some marker segments were reserved in FCD15444-1. Since that - # standard is old, some of them may have come into use. - # - # Let's inject a reserved marker segment into a file that - # we know something about to make sure we can still parse it. - filename = os.path.join(OPJ_DATA_ROOT, 'input/conformance/p0_01.j2k') - with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - with open(filename, 'rb') as ifile: - # Everything up until the first QCD marker. - read_buffer = ifile.read(45) - tfile.write(read_buffer) - - # Write the new marker segment, 0xff6f = 65391 - read_buffer = struct.pack('>HHB', int(65391), int(3), int(0)) - tfile.write(read_buffer) - - # Get the rest of the input file. - read_buffer = ifile.read() - tfile.write(read_buffer) - tfile.flush() - - codestream = Jp2k(tfile.name).get_codestream() - - self.assertEqual(codestream.segment[2].marker_id, '0xff6f') - self.assertEqual(codestream.segment[2].length, 3) - self.assertEqual(codestream.segment[2].data, b'\x00') - - def test_psot_is_zero(self): - """Psot=0 in SOT is perfectly legal. Issue #78.""" - filename = os.path.join(OPJ_DATA_ROOT, - 'input/nonregression/123.j2c') - j = Jp2k(filename) - codestream = j.get_codestream(header_only=False) - - # The codestream is valid, so we should be able to get the entire - # codestream, so the last one is EOC. - self.assertEqual(codestream.segment[-1].marker_id, 'EOC') - - - def test_siz_segment_ssiz_signed(self): - """ssiz attribute to be removed in future release""" - filename = os.path.join(OPJ_DATA_ROOT, 'input/conformance/p0_03.j2k') - j = Jp2k(filename) - codestream = j.get_codestream() - - # The ssiz attribute was simply a tuple of raw bytes. - # The first 7 bits are interpreted as the bitdepth, the MSB determines - # whether or not it is signed. - self.assertEqual(codestream.segment[1].ssiz, (131,)) - - -class TestCodestreamRepr(unittest.TestCase): - - def setUp(self): - self.jp2file = glymur.data.nemo() - - def tearDown(self): - pass - - def test_soc(self): - """Test SOC segment repr""" - segment = glymur.codestream.SOCsegment() - newseg = eval(repr(segment)) - self.assertEqual(newseg.marker_id, 'SOC') - - def test_siz(self): - """Test SIZ segment repr""" - kwargs = {'rsiz': 0, - 'xysiz': (2592, 1456), - 'xyosiz': (0, 0), - 'xytsiz': (2592, 1456), - 'xytosiz': (0, 0), - 'Csiz': 3, - 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': ((1, 1, 1), (1, 1, 1))} - segment = glymur.codestream.SIZsegment(**kwargs) - newseg = eval(repr(segment)) - self.assertEqual(newseg.marker_id, 'SIZ') - self.assertEqual(newseg.xsiz, 2592) - self.assertEqual(newseg.ysiz, 1456) - self.assertEqual(newseg.xosiz, 0) - self.assertEqual(newseg.yosiz, 0) - self.assertEqual(newseg.xtsiz, 2592) - self.assertEqual(newseg.ytsiz, 1456) - self.assertEqual(newseg.xtosiz, 0) - self.assertEqual(newseg.ytosiz, 0) - - self.assertEqual(newseg.xrsiz, (1, 1, 1)) - self.assertEqual(newseg.yrsiz, (1, 1, 1)) - self.assertEqual(newseg.bitdepth, (8, 8, 8)) - self.assertEqual(newseg.signed, (False, False, False)) - - -if __name__ == "__main__": - unittest.main() diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py index 72daf17..9d1f9cf 100644 --- a/glymur/test/test_jp2box.py +++ b/glymur/test/test_jp2box.py @@ -54,16 +54,17 @@ class TestDataEntryURL(unittest.TestCase): def setUp(self): self.jp2file = glymur.data.nemo() + @unittest.skipIf(re.match("1.5|2", glymur.version.openjpeg_version) is None, + "Must have openjpeg 1.5 or higher to run") def test_wrap_greyscale(self): """A single component should be wrapped as GREYSCALE.""" j = Jp2k(self.jp2file) - data = j.read() + data = j[:] red = data[:, :, 0] # Write it back out as a raw codestream. with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile1: - j2k = glymur.Jp2k(tfile1.name, 'wb') - j2k.write(data[:, :, 0]) + j2k = glymur.Jp2k(tfile1.name, data=red) # Ok, now rewrap it as JP2. The colorspace should be GREYSCALE. with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile2: @@ -124,24 +125,21 @@ class TestChannelDefinition(unittest.TestCase): def setUpClass(cls): """Need a one_plane plane image for greyscale testing.""" j2k = Jp2k(glymur.data.goodstuff()) - data = j2k.read() + data = j2k[:] # Write the first component back out to file. with tempfile.NamedTemporaryFile(suffix=".j2k", delete=False) as tfile: - grey_j2k = Jp2k(tfile.name, 'wb') - grey_j2k.write(data[:, :, 0]) + grey_j2k = Jp2k(tfile.name, data=data[:, :, 0]) cls.one_plane = tfile.name # Write the first two components back out to file. with tempfile.NamedTemporaryFile(suffix=".j2k", delete=False) as tfile: - grey_j2k = Jp2k(tfile.name, 'wb') - grey_j2k.write(data[:, :, 0:1]) + grey_j2k = Jp2k(tfile.name, data=data[:, :, 0:1]) cls.two_planes = tfile.name # Write four components back out to file. with tempfile.NamedTemporaryFile(suffix=".j2k", delete=False) as tfile: - rgba_jp2 = Jp2k(tfile.name, 'wb') shape = (data.shape[0], data.shape[1], 1) alpha = np.zeros((shape), dtype=data.dtype) data4 = np.concatenate((data, alpha), axis=2) - rgba_jp2.write(data4) + rgba_jp2 = Jp2k(tfile.name, data=data4) cls.four_planes = tfile.name @classmethod diff --git a/glymur/test/test_jp2k.py b/glymur/test/test_jp2k.py index 9a9fb72..b903dda 100644 --- a/glymur/test/test_jp2k.py +++ b/glymur/test/test_jp2k.py @@ -67,12 +67,17 @@ class SliceProtocolBase(unittest.TestCase): def setUpClass(self): self.jp2 = Jp2k(glymur.data.nemo()) - self.jp2_data = self.jp2.read() + self.jp2_data = self.jp2[:] + self.jp2_data_r1 = self.jp2[::2, ::2] self.j2k = Jp2k(glymur.data.goodstuff()) - self.j2k_data = self.j2k.read() + self.j2k_data = self.j2k[:] + self.j2k_data_r1 = self.j2k[::2, ::2] + self.j2k_data_r5 = self.j2k[::32, ::32] +@unittest.skipIf(re.match("1.5|2", glymur.version.openjpeg_version) is None, + "Must have openjpeg 1.5 or higher to run") @unittest.skipIf(os.name == "nt", fixtures.WINDOWS_TMP_FILE_MSG) class TestSliceProtocolBaseWrite(SliceProtocolBase): @@ -80,9 +85,9 @@ class TestSliceProtocolBaseWrite(SliceProtocolBase): expected = self.j2k_data with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - j[...] = self.j2k_data - actual = j.read() + j = Jp2k(tfile.name, shape=expected.shape) + j[...] = expected + actual = j[:] np.testing.assert_array_equal(actual, expected) @@ -90,15 +95,14 @@ class TestSliceProtocolBaseWrite(SliceProtocolBase): expected = self.j2k_data with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - j[:] = self.j2k_data - actual = j.read() + j = Jp2k(tfile.name, data=self.j2k_data) + actual = j[:] np.testing.assert_array_equal(actual, expected) def test_cannot_write_with_non_default_single_slice(self): with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') + j = Jp2k(tfile.name, shape=self.j2k_data.shape) with self.assertRaises(TypeError): j[slice(None, 0)] = self.j2k_data with self.assertRaises(TypeError): @@ -110,31 +114,31 @@ class TestSliceProtocolBaseWrite(SliceProtocolBase): def test_cannot_write_a_row(self): with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') + j = Jp2k(tfile.name, shape=self.j2k_data.shape) with self.assertRaises(TypeError): j[5] = self.j2k_data def test_cannot_write_a_pixel(self): with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') + j = Jp2k(tfile.name, shape=self.j2k_data.shape) with self.assertRaises(TypeError): j[25, 35] = self.j2k_data[25, 35] def test_cannot_write_a_column(self): with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') + j = Jp2k(tfile.name, shape=self.j2k_data.shape) with self.assertRaises(TypeError): j[:, 25, :] = self.j2k_data[:, :25, :] def test_cannot_write_a_band(self): with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') + j = Jp2k(tfile.name, shape=self.j2k_data.shape) with self.assertRaises(TypeError): j[:, :, 0] = self.j2k_data[:, :, 0] def test_cannot_write_a_subarray(self): with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') + j = Jp2k(tfile.name, shape=self.j2k_data.shape) with self.assertRaises(TypeError): j[:25, :45, :] = self.j2k_data[:25, :25, :] @@ -167,9 +171,9 @@ class TestSliceProtocolRead(SliceProtocolBase): np.testing.assert_array_equal(actual, expected) def test_reduce_resolution_and_slice_in_third_dimension(self): - d = self.j2k[::2, ::2, 1:3] - all = self.j2k.read(rlevel=1) - np.testing.assert_array_equal(all[:,:,1:3], d) + actual = self.j2k[::2, ::2, 1:3] + expected = self.j2k_data_r1[:, :, 1:3] + np.testing.assert_array_equal(actual, expected) def test_retrieve_single_row(self): actual = self.jp2[0] @@ -186,71 +190,6 @@ class TestSliceProtocolRead(SliceProtocolBase): expected = self.jp2_data[20, 20, 2] np.testing.assert_array_equal(actual, expected) - def test_full_resolution_slicing_by_quarters_upper_left(self): - actual = self.jp2[:728, :1296] - expected = self.jp2_data[:728, :1296] - np.testing.assert_array_equal(actual, expected) - - def test_full_resolution_slicing_by_quarters_lower_left(self): - actual = self.jp2[728:, :1296] - expected = self.jp2_data[728:, :1296] - np.testing.assert_array_equal(actual, expected) - - def test_full_resolution_slicing_by_quarters_upper_right(self): - actual = self.jp2[:728, 1296:] - expected = self.jp2_data[:728, 1296:] - np.testing.assert_array_equal(actual, expected) - - def test_full_resolution_slicing_by_quarters_lower_right(self): - actual = self.jp2[728:, 1296:] - expected = self.jp2_data[728:, 1296:] - np.testing.assert_array_equal(actual, expected) - - def test_full_resolution_slicing_by_quarters_center(self): - actual = self.jp2[364:1092, 648:1942] - expected = self.jp2_data[364:1092, 648:1942] - np.testing.assert_array_equal(actual, expected) - - def test_full_resolution_slicing_by_halves_left(self): - actual = self.jp2[:, :1296] - expected = self.jp2_data[:, :1296] - np.testing.assert_array_equal(actual, expected) - - def test_full_resolution_slicing_by_right_half(self): - actual = self.jp2[:, 1296:] - expected = self.jp2_data[:, 1296:] - np.testing.assert_array_equal(actual, expected) - - def test_full_resolution_slicing_by_top_half(self): - actual = self.jp2[:728, :] - expected = self.jp2_data[:728, :] - np.testing.assert_array_equal(actual, expected) - - def test_full_resolution_slicing_by_bottom_half(self): - actual = self.jp2[728:, :] - expected = self.jp2_data[728:, :] - np.testing.assert_array_equal(actual, expected) - - def test_region_rlevel1(self): - actual = self.jp2[0:201:2, 0:201:2] - expected = self.jp2.read(area=(0, 0, 201, 201), rlevel=1) - np.testing.assert_array_equal(actual, expected) - - def test_region_rlevel1_slice_start_is_none(self): - actual = self.jp2[:201:2, :201:2] - expected = self.jp2.read(area=(0, 0, 201, 201), rlevel=1) - np.testing.assert_array_equal(actual, expected) - - def test_region_rlevel1_slice_stop_is_none(self): - actual = self.jp2[201::2, 201::2] - expected = self.jp2.read(area=(201, 201, 1456, 2592), rlevel=1) - np.testing.assert_array_equal(actual, expected) - - def test_region_rlevel1(self): - actual = self.jp2[0:202:2, 0:202:2] - expected = self.jp2.read(area=(0, 0, 202, 202), rlevel=1) - np.testing.assert_array_equal(actual, expected) - def test_ellipsis_full_read(self): actual = self.j2k[...] expected = self.j2k_data @@ -287,182 +226,18 @@ class TestSliceProtocolRead(SliceProtocolBase): expected = self.j2k_data[3:8, :,:] np.testing.assert_array_equal(actual, expected) - def test_slice_protocol_2d_reduce_resolution(self): - d = self.j2k[:] - self.assertEqual(d.shape, (800, 480, 3)) - - d = self.j2k[::1, ::1] - self.assertEqual(d.shape, (800, 480, 3)) - - d = self.j2k[::2, ::2] - self.assertEqual(d.shape, (400, 240, 3)) - - d = self.j2k[::4, ::4] - self.assertEqual(d.shape, (200, 120, 3)) - - d = self.j2k[::8, ::8] - self.assertEqual(d.shape, (100, 60, 3)) - - d = self.j2k[::16, ::16] - self.assertEqual(d.shape, (50, 30, 3)) - - d = self.j2k[::32, ::32] - self.assertEqual(d.shape, (25, 15, 3)) - + @unittest.skipIf(re.match("0|1", glymur.version.openjpeg_version), + "Must have openjpeg 2 or higher to run") def test_region_rlevel5(self): + """ + maximim rlevel + + There seems to be a difference between version of openjpeg, as + openjp2 produces an image of size (16, 13, 3) and openjpeg produced + (17, 12, 3). + """ actual = self.j2k[5:533:32, 27:423:32] - expected = self.j2k.read(area=(5, 27, 533, 423), rlevel=5) - np.testing.assert_array_equal(actual, expected) - -@unittest.skipIf(OPJ_DATA_ROOT is None, - "OPJ_DATA_ROOT environment variable not set") -class TestSliceProtocolOpjData(unittest.TestCase): - """ - Test slice protocol, i.e. when using [ ] to read image data. - These correspond to tests for the read method with the area parameter. - """ - @classmethod - def setUpClass(self): - - jfile = opj_data_file('input/conformance/p1_04.j2k') - self.j2k = Jp2k(jfile) - self.j2k_data = self.j2k.read() - self.j2k_half_data = self.j2k.read(rlevel=1) - self.j2k_quarter_data = self.j2k.read(rlevel=2) - - def test_NR_DEC_p1_04_j2k_43_decode(self): - actual = self.j2k[:1024, :1024] - expected = self.j2k_data - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_44_decode(self): - actual = self.j2k[640:768, 512:640] - expected = self.j2k_data[640:768, 512:640] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_45_decode(self): - actual = self.j2k[896:1024, 896:1024] - expected = self.j2k_data[896:1024, 896:1024] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_46_decode(self): - actual = self.j2k[500:800, 100:300] - expected = self.j2k_data[500:800, 100:300] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_47_decode(self): - actual = self.j2k[520:600, 260:360] - expected = self.j2k_data[520:600, 260:360] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_48_decode(self): - actual = self.j2k[520:660, 260:360] - expected = self.j2k_data[520:660, 260:360] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_49_decode(self): - actual = self.j2k[520:600, 360:400] - expected = self.j2k_data[520:600, 360:400] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_50_decode(self): - actual = self.j2k[:1024:4, :1024:4] - expected = self.j2k_quarter_data[:256, :256] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_51_decode(self): - actual = self.j2k[640:768:4, 512:640:4] - expected = self.j2k_quarter_data[160:192, 128:160] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_52_decode(self): - actual = self.j2k[896:1024:4, 896:1024:4] - expected = self.j2k_quarter_data[224:352, 224:352] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_53_decode(self): - actual = self.j2k[500:800:4, 100:300:4] - expected = self.j2k_quarter_data[125:200, 25:75] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_54_decode(self): - actual = self.j2k[520:600:4, 260:360:4] - expected = self.j2k_quarter_data[130:150, 65:90] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_55_decode(self): - actual = self.j2k[520:660:4, 260:360:4] - expected = self.j2k_quarter_data[130:165, 65:90] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_56_decode(self): - actual = self.j2k[520:600:4, 360:400:4] - expected = self.j2k_quarter_data[130:150, 90:100] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_06_j2k_75_decode(self): - # Image size would be 0 x 0. - with self.assertRaises((IOError, OSError)): - self.j2k[9:12:4, 9:12:4] - - def test_NR_DEC_p0_04_j2k_85_decode(self): - actual = self.j2k[:256, :256] - expected = self.j2k_data[:256, :256] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_86_decode(self): - actual = self.j2k[:128, 128:256] - expected = self.j2k_data[:128, 128:256] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_87_decode(self): - actual = self.j2k[10:200, 50:120] - expected = self.j2k_data[10:200, 50:120] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_88_decode(self): - actual = self.j2k[150:210, 10:190] - expected = self.j2k_data[150:210, 10:190] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_89_decode(self): - actual = self.j2k[80:150, 100:200] - expected = self.j2k_data[80:150, 100:200] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_90_decode(self): - actual = self.j2k[20:50, 150:200] - expected = self.j2k_data[20:50, 150:200] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_91_decode(self): - actual = self.j2k[:256:4, :256:4] - expected = self.j2k_quarter_data[0:64, 0:64] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_92_decode(self): - actual = self.j2k[:128:4, 128:256:4] - expected = self.j2k_quarter_data[:32, 32:64] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_93_decode(self): - actual = self.j2k[10:200:4, 50:120:4] - expected = self.j2k_quarter_data[3:50, 13:30] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_94_decode(self): - actual = self.j2k[150:210:4, 10:190:4] - expected = self.j2k_quarter_data[38:53, 3:48] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_95_decode(self): - actual = self.j2k[80:150:4, 100:200:4] - expected = self.j2k_quarter_data[20:38, 25:50] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_96_decode(self): - actual = self.j2k[20:50:4, 150:200:4] - expected = self.j2k_quarter_data[5:13, 38:50] + expected = self.j2k_data_r5[1:17, 1:14] np.testing.assert_array_equal(actual, expected) class TestJp2k(unittest.TestCase): @@ -476,6 +251,12 @@ class TestJp2k(unittest.TestCase): def tearDown(self): pass + @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) + def test_warn_if_using_read_method(self): + """Should warn if deprecated read method is called""" + with self.assertWarns(DeprecationWarning): + Jp2k(self.jp2file).read() + def test_shape_jp2(self): """verify shape attribute for JP2 file """ @@ -515,20 +296,21 @@ class TestJp2k(unittest.TestCase): jpx = Jp2k(self.jpxfile) self.assertEqual(jpx.shape, (1024, 1024, 3)) + @unittest.skipIf(re.match("0|1.[0-4]", glymur.version.openjpeg_version), + "Must have openjpeg 1.5 or higher to run") @unittest.skipIf(os.name == "nt", "Unexplained failure on windows") def test_irreversible(self): """Irreversible""" j = Jp2k(self.jp2file) - expdata = j.read() + expdata = j[:] with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j2 = Jp2k(tfile.name, 'wb') - j2.write(expdata, irreversible=True) + j2 = Jp2k(tfile.name, data=expdata, irreversible=True) codestream = j2.get_codestream() self.assertEqual(codestream.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) - actdata = j2.read() + actdata = j2[:] self.assertTrue(fixtures.mse(actdata[0], expdata[0]) < 0.38) @unittest.skipIf(re.match('1.[0-4]', openjpeg_version) is not None, @@ -538,8 +320,9 @@ class TestJp2k(unittest.TestCase): def test_no_cxform_pclr_jpx(self): """Indices for pclr jpxfile if no color transform""" j = Jp2k(self.jpxfile) - rgb = j.read() - idx = j.read(ignore_pclr_cmap_cdef=True) + rgb = j[:] + j.ignore_pclr_cmap_cdef = True + idx = j[:] nr, nc = 1024, 1024 self.assertEqual(rgb.shape, (nr, nc, 3)) self.assertEqual(idx.shape, (nr, nc)) @@ -560,14 +343,27 @@ class TestJp2k(unittest.TestCase): newjp2 = eval(repr(j)) self.assertEqual(newjp2.filename, self.j2kfile) - self.assertEqual(newjp2.mode, 'rb') self.assertEqual(len(newjp2.box), 0) - def test_rlevel_max(self): - """Verify that rlevel=-1 gets us the lowest resolution image""" + @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) + def test_rlevel_max_backwards_compatibility(self): + """ + Verify that rlevel=-1 gets us the lowest resolution image + + This is an old option only available via the read method, not via + array-style slicing. + """ j = Jp2k(self.j2kfile) - thumbnail1 = j.read(rlevel=-1) - thumbnail2 = j.read(rlevel=5) + if sys.hexversion < 0x03000000: + with warnings.catch_warnings(): + # Suppress a warning due to deprecated syntax + # Not as easy to verify the warning under python2. + warnings.simplefilter("ignore") + thumbnail1 = j.read(rlevel=-1) + else: + with self.assertWarns(DeprecationWarning): + thumbnail1 = j.read(rlevel=-1) + thumbnail2 = j[::32, ::32] np.testing.assert_array_equal(thumbnail1, thumbnail2) self.assertEqual(thumbnail1.shape, (25, 15, 3)) @@ -575,7 +371,7 @@ class TestJp2k(unittest.TestCase): """Should error out appropriately if reduce level too high""" j = Jp2k(self.jp2file) with self.assertRaises(IOError): - j.read(rlevel=6) + j[::64, ::64] def test_not_jpeg2000(self): """Should error out appropriately if not given a JPEG 2000 file.""" @@ -726,7 +522,7 @@ class TestJp2k(unittest.TestCase): """Just a very basic test that reading a JP2 file does not error out. """ j2k = Jp2k(self.jp2file) - j2k.read(rlevel=1) + j2k[::2, ::2] def test_basic_j2k(self): """This test is only useful when openjp2 is not available @@ -734,7 +530,7 @@ class TestJp2k(unittest.TestCase): working J2K test. """ j2k = Jp2k(self.j2kfile) - j2k.read() + j2k[:] def test_empty_box_with_j2k(self): """Verify that the list of boxes in a J2C/J2K file is present, but @@ -859,7 +655,7 @@ class TestJp2k(unittest.TestCase): """Read JPX codestream when jp2-compatible.""" # The file in question has multiple codestreams. jpx = Jp2k(self.jpxfile) - data = jpx.read() + data = jpx[:] self.assertEqual(data.shape, (1024, 1024, 3)) def test_read_bands_without_openjp2(self): @@ -886,32 +682,30 @@ class TestJp2k_write(unittest.TestCase): data = np.zeros((640, 480), dtype=np.uint8) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: with self.assertRaises(IOError): - j = Jp2k(tfile.name, 'wb') - j.write(data, cbsize=(16, 16), psizes=[(16, 16)]) + j = Jp2k(tfile.name, data=data, + cbsize=(16, 16), psizes=[(16, 16)]) def test_precinct_size_not_power_of_two(self): """must be power of two""" data = np.zeros((640, 480), dtype=np.uint8) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: with self.assertRaises(IOError): - j = Jp2k(tfile.name, 'wb') - j.write(data, cbsize=(16, 16), psizes=[(48, 48)]) + j = Jp2k(tfile.name, data=data, + cbsize=(16, 16), psizes=[(48, 48)]) def test_unsupported_int32(self): """Should raise a runtime error if trying to write int32""" data = np.zeros((128, 128), dtype=np.int32) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: with self.assertRaises(RuntimeError): - j = Jp2k(tfile.name, 'wb') - j.write(data) + j = Jp2k(tfile.name, data=data) def test_unsupported_uint32(self): """Should raise a runtime error if trying to write uint32""" data = np.zeros((128, 128), dtype=np.uint32) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: with self.assertRaises(RuntimeError): - j = Jp2k(tfile.name, 'wb') - j.write(data) + j = Jp2k(tfile.name, data=data) def test_write_with_version_too_early(self): """Should raise a runtime error if trying to write with version 1.3""" @@ -921,8 +715,7 @@ class TestJp2k_write(unittest.TestCase): with patch('glymur.version.openjpeg_version', new=version): with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: with self.assertRaises(RuntimeError): - j = Jp2k(tfile.name, 'wb') - j.write(data) + j = Jp2k(tfile.name, data=data) def test_cblkh_different_than_width(self): """Verify that we can set a code block size where height does not equal @@ -930,11 +723,8 @@ class TestJp2k_write(unittest.TestCase): """ data = np.zeros((128, 128), dtype=np.uint8) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - # The code block dimensions are given as rows x columns. - j.write(data, cbsize=(16, 32)) - + j = Jp2k(tfile.name, data=data, cbsize=(16, 32)) codestream = j.get_codestream() # Code block size is reported as XY in the codestream. @@ -943,59 +733,55 @@ class TestJp2k_write(unittest.TestCase): def test_too_many_dimensions(self): """OpenJP2 only allows 2D or 3D images.""" with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') with self.assertRaises(IOError): - data = np.zeros((128, 128, 2, 2), dtype=np.uint8) - j.write(data) + j = Jp2k(tfile.name, + data=np.zeros((128, 128, 2, 2), dtype=np.uint8)) def test_2d_rgb(self): """RGB must have at least 3 components.""" with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - j = Jp2k(tfile.name, 'wb') with self.assertRaises(IOError): - data = np.zeros((128, 128, 2), dtype=np.uint8) - j.write(data, colorspace='rgb') + j = Jp2k(tfile.name, + data=np.zeros((128, 128, 2), dtype=np.uint8), + colorspace='rgb') def test_colorspace_with_j2k(self): """Specifying a colorspace with J2K does not make sense""" with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') with self.assertRaises(IOError): - data = np.zeros((128, 128, 3), dtype=np.uint8) - j.write(data, colorspace='rgb') + j = Jp2k(tfile.name, + data=np.zeros((128, 128, 3), dtype=np.uint8), + colorspace='rgb') def test_specify_rgb(self): """specify RGB explicitly""" with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - j = Jp2k(tfile.name, 'wb') - data = np.zeros((128, 128, 3), dtype=np.uint8) - j.write(data, colorspace='rgb') + j = Jp2k(tfile.name, + data=np.zeros((128, 128, 3), dtype=np.uint8), + colorspace='rgb') self.assertEqual(j.box[2].box[1].colorspace, glymur.core.SRGB) def test_specify_gray(self): """test gray explicitly specified (that's GRAY, not GREY)""" with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - j = Jp2k(tfile.name, 'wb') data = np.zeros((128, 128), dtype=np.uint8) - j.write(data, colorspace='gray') + j = Jp2k(tfile.name, data=data, colorspace='gray') self.assertEqual(j.box[2].box[1].colorspace, glymur.core.GREYSCALE) def test_specify_grey(self): """test grey explicitly specified""" with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - j = Jp2k(tfile.name, 'wb') data = np.zeros((128, 128), dtype=np.uint8) - j.write(data, colorspace='grey') + j = Jp2k(tfile.name, data=data, colorspace='grey') self.assertEqual(j.box[2].box[1].colorspace, glymur.core.GREYSCALE) def test_grey_with_two_extra_comps(self): """should be able to write gray + two extra components""" with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - j = Jp2k(tfile.name, 'wb') data = np.zeros((128, 128, 3), dtype=np.uint8) - j.write(data, colorspace='gray') + j = Jp2k(tfile.name, data=data, colorspace='gray') self.assertEqual(j.box[2].box[0].height, 128) self.assertEqual(j.box[2].box[0].width, 128) self.assertEqual(j.box[2].box[0].num_components, 3) @@ -1005,29 +791,26 @@ class TestJp2k_write(unittest.TestCase): def test_specify_ycc(self): """Should reject YCC""" with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - j = Jp2k(tfile.name, 'wb') with self.assertRaises(IOError): data = np.zeros((128, 128, 3), dtype=np.uint8) - j.write(data, colorspace='ycc') + j = Jp2k(tfile.name, data=data, colorspace='ycc') def test_write_with_jp2_in_caps(self): """should be able to write with JP2 suffix.""" j2k = Jp2k(self.j2kfile) - expdata = j2k.read() + expdata = j2k[:] with tempfile.NamedTemporaryFile(suffix='.JP2') as tfile: - ofile = Jp2k(tfile.name, 'wb') - ofile.write(expdata) - actdata = ofile.read() + ofile = Jp2k(tfile.name, data=expdata) + actdata = ofile[:] np.testing.assert_array_equal(actdata, expdata) def test_write_srgb_without_mct(self): """should be able to write RGB without specifying mct""" j2k = Jp2k(self.j2kfile) - expdata = j2k.read() + expdata = j2k[:] with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - ofile = Jp2k(tfile.name, 'wb') - ofile.write(expdata, mct=False) - actdata = ofile.read() + ofile = Jp2k(tfile.name, data=expdata, mct=False) + actdata = ofile[:] np.testing.assert_array_equal(actdata, expdata) codestream = ofile.get_codestream() @@ -1036,21 +819,19 @@ class TestJp2k_write(unittest.TestCase): def test_write_grayscale_with_mct(self): """MCT usage makes no sense for grayscale images.""" j2k = Jp2k(self.j2kfile) - expdata = j2k.read() + expdata = j2k[:] with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - ofile = Jp2k(tfile.name, 'wb') with self.assertRaises(IOError): - ofile.write(expdata[:, :, 0], mct=True) + ofile = Jp2k(tfile.name, data=expdata[:, :, 0], mct=True) def test_write_cprl(self): """Must be able to write a CPRL progression order file""" # Issue 17 j = Jp2k(self.jp2file) - expdata = j.read(rlevel=1) + expdata = j[::2, ::2] with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - ofile = Jp2k(tfile.name, 'wb') - ofile.write(expdata, prog='CPRL') - actdata = ofile.read() + ofile = Jp2k(tfile.name, data=expdata, prog='CPRL') + actdata = ofile[:] np.testing.assert_array_equal(actdata, expdata) codestream = ofile.get_codestream() @@ -1072,16 +853,19 @@ class TestJp2k_1_x(unittest.TestCase): """ with patch('glymur.version.openjpeg_version_tuple', new=(1, 5, 0)): j2k = Jp2k(self.j2kfile) - with self.assertRaises(TypeError): - j2k.read(tile=0) + with warnings.catch_warnings(): + # The tile keyword is deprecated, so suppress the warning. + warnings.simplefilter('ignore') + with self.assertRaises(TypeError): + j2k.read(tile=0) def test_layer(self): """layer option not allowed for 1.x. """ with patch('glymur.version.openjpeg_version_tuple', new=(1, 5, 0)): j2k = Jp2k(self.j2kfile) - with self.assertRaises(TypeError): - j2k.read(layer=1) + with self.assertRaises(RuntimeError): + j2k.layer = 1 @unittest.skipIf(os.name == "nt", fixtures.WINDOWS_TMP_FILE_MSG) @@ -1092,10 +876,9 @@ class Test_2p0_official(unittest.TestCase): """Can only write 4 components on 2.0+, should error out otherwise.""" with patch('glymur.version.openjpeg_version', new="2.0.0"): with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - j = Jp2k(tfile.name, 'wb') data = np.zeros((128, 128, 4), dtype=np.uint8) with self.assertRaises(IOError): - j.write(data) + Jp2k(tfile.name, data=data) @unittest.skipIf(glymur.version.openjpeg_version_tuple[0] < 2, @@ -1115,32 +898,30 @@ class TestJp2k_2_0(unittest.TestCase): j = Jp2k(self.jp2file) with self.assertRaises(IOError): # Start corner must be >= 0 - j.read(area=(-1, -1, 1, 1)) + j[-1:1, -1:1] with self.assertRaises(IOError): # End corner must be > 0 - j.read(area=(10, 10, 0, 0)) + j[10:0, 10:0] with self.assertRaises(IOError): # End corner must be >= start corner - j.read(area=(10, 10, 8, 8)) + j[10:8, 10:8] @unittest.skipIf(os.name == "nt", fixtures.WINDOWS_TMP_FILE_MSG) def test_unrecognized_jp2_clrspace(self): """We only allow RGB and GRAYSCALE. Should error out with others""" with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - j = Jp2k(tfile.name, 'wb') + data = np.zeros((128, 128, 3), dtype=np.uint8) with self.assertRaises(IOError): - data = np.zeros((128, 128, 3), dtype=np.uint8) - j.write(data, colorspace='cmyk') + j = Jp2k(tfile.name, data=data, colorspace='cmyk') @unittest.skipIf(os.name == "nt", fixtures.WINDOWS_TMP_FILE_MSG) def test_asoc_label_box(self): """Test asoc and label box""" # Construct a fake file with an asoc and a label box, as # OpenJPEG doesn't have such a file. - data = Jp2k(self.jp2file).read(rlevel=1) + data = Jp2k(self.jp2file)[::2, ::2] with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - j = Jp2k(tfile.name, 'wb') - j.write(data) + j = Jp2k(tfile.name, data=data) with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile2: @@ -1198,9 +979,8 @@ class TestJp2k_2_1(unittest.TestCase): def test_grey_with_extra_component(self): """version 2.0 cannot write gray + extra""" with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - j = Jp2k(tfile.name, 'wb') data = np.zeros((128, 128, 2), dtype=np.uint8) - j.write(data) + j = Jp2k(tfile.name, data=data) self.assertEqual(j.box[2].box[0].height, 128) self.assertEqual(j.box[2].box[0].width, 128) self.assertEqual(j.box[2].box[0].num_components, 2) @@ -1211,9 +991,8 @@ class TestJp2k_2_1(unittest.TestCase): def test_rgb_with_extra_component(self): """v2.0+ should be able to write extra components""" with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - j = Jp2k(tfile.name, 'wb') data = np.zeros((128, 128, 4), dtype=np.uint8) - j.write(data) + j = Jp2k(tfile.name, data=data) self.assertEqual(j.box[2].box[0].height, 128) self.assertEqual(j.box[2].box[0].width, 128) self.assertEqual(j.box[2].box[0].num_components, 4) @@ -1238,11 +1017,9 @@ class TestJp2k_2_1(unittest.TestCase): tfile.write(data[offset+53:offset+55]) tfile.write(b'\x00') tfile.write(data[offset+57:offset+59]) - #tfile.write(data[3184:3186]) tfile.write(b'\x00') tfile.write(data[offset+59:]) - #tfile.write(data[3186:]) tfile.flush() with warnings.catch_warnings(): warnings.simplefilter('ignore') @@ -1252,10 +1029,10 @@ class TestJp2k_2_1(unittest.TestCase): :\sdx=1\sdy=0''', re.VERBOSE) if sys.hexversion < 0x03020000: with self.assertRaisesRegexp((IOError, OSError), regexp): - j.read(rlevel=1) + j[::2, ::2] else: with self.assertRaisesRegex((IOError, OSError), regexp): - j.read(rlevel=1) + j[::2, ::2] @unittest.skipIf(OPJ_DATA_ROOT is None, "OPJ_DATA_ROOT environment variable not set") @@ -1280,7 +1057,6 @@ class TestParsing(unittest.TestCase): with self.assertWarnsRegex(UserWarning, 'Invalid profile'): jp2 = Jp2k(filename) - #@unittest.skip('trouble is a brewing...') def test_main_header(self): """Verify that the main header is not loaded when parsing turned off.""" # The hidden _main_header attribute should show up after accessing it. @@ -1342,6 +1118,8 @@ class TestJp2kOpjDataRootWarnings(unittest.TestCase): class TestJp2kOpjDataRoot(unittest.TestCase): """These tests should be run by just about all configuration.""" + @unittest.skipIf(re.match("0|1.[0-4]", glymur.version.openjpeg_version), + "Must have openjpeg 1.5 or higher to run") @unittest.skipIf(os.name == "nt", fixtures.WINDOWS_TMP_FILE_MSG) def test_irreversible(self): """Irreversible""" @@ -1349,14 +1127,13 @@ class TestJp2kOpjDataRoot(unittest.TestCase): expdata = np.fromfile(filename, dtype=np.uint16) expdata.resize((2816, 2048)) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - j.write(expdata, irreversible=True) + j = Jp2k(tfile.name, data=expdata, irreversible=True) codestream = j.get_codestream() self.assertEqual(codestream.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) - actdata = j.read() + actdata = j[:] self.assertTrue(fixtures.mse(actdata, expdata) < 250) @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) @@ -1364,15 +1141,16 @@ class TestJp2kOpjDataRoot(unittest.TestCase): """Indices for pclr jpxfile if no color transform""" filename = opj_data_file('input/conformance/file9.jp2') with self.assertWarns(UserWarning): - j = Jp2k(filename) - rgb = j.read() - idx = j.read(ignore_pclr_cmap_cdef=True) + jp2 = Jp2k(filename) + rgb = jp2[:] + jp2.ignore_pclr_cmap_cdef = True + idx = jp2[:] self.assertEqual(rgb.shape, (512, 768, 3)) self.assertEqual(idx.shape, (512, 768)) # Should be able to manually reconstruct the RGB image from the palette # and indices. - palette = j.box[2].box[1].palette + palette = jp2.box[2].box[1].palette rgb_from_idx = np.zeros(rgb.shape, dtype=np.uint8) for r in np.arange(rgb.shape[0]): for c in np.arange(rgb.shape[1]): @@ -1388,7 +1166,7 @@ class TestJp2kOpjDataRoot(unittest.TestCase): filename = opj_data_file('input/conformance/p0_05.j2k') j = Jp2k(filename) with self.assertRaises(RuntimeError): - j.read() + j[:] @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) def test_no_cxform_cmap(self): @@ -1399,8 +1177,9 @@ class TestJp2kOpjDataRoot(unittest.TestCase): with self.assertWarns(UserWarning): # The file has a bad compatibility list entry. Not important here. j = Jp2k(filename) - ycbcr = j.read() - crcby = j.read(ignore_pclr_cmap_cdef=True) + ycbcr = j[:] + j.ignore_pclr_cmap_cdef = True + crcby = j[:] expected = np.zeros(ycbcr.shape, ycbcr.dtype) for k in range(crcby.shape[2]): @@ -1409,6 +1188,259 @@ class TestJp2kOpjDataRoot(unittest.TestCase): np.testing.assert_array_equal(ycbcr, expected) +class TestCodestream(unittest.TestCase): + """Test suite for unusual codestream cases.""" -if __name__ == "__main__": - unittest.main() + def setUp(self): + self.jp2file = glymur.data.nemo() + + def tearDown(self): + pass + + def test_siz_segment_ssiz_unsigned(self): + """ssiz attribute to be removed in future release""" + j = Jp2k(self.jp2file) + codestream = j.get_codestream() + + # The ssiz attribute was simply a tuple of raw bytes. + # The first 7 bits are interpreted as the bitdepth, the MSB determines + # whether or not it is signed. + self.assertEqual(codestream.segment[1].ssiz, (7, 7, 7)) + + +@unittest.skipIf(OPJ_DATA_ROOT is None, + "OPJ_DATA_ROOT environment variable not set") +class TestCodestreamOpjData(unittest.TestCase): + """Test suite for unusual codestream cases. Uses OPJ_DATA_ROOT""" + + def setUp(self): + self.jp2file = glymur.data.nemo() + + def tearDown(self): + pass + + @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") + def test_reserved_marker_segment(self): + """Reserved marker segments are ok.""" + + # Some marker segments were reserved in FCD15444-1. Since that + # standard is old, some of them may have come into use. + # + # Let's inject a reserved marker segment into a file that + # we know something about to make sure we can still parse it. + filename = os.path.join(OPJ_DATA_ROOT, 'input/conformance/p0_01.j2k') + with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: + with open(filename, 'rb') as ifile: + # Everything up until the first QCD marker. + read_buffer = ifile.read(45) + tfile.write(read_buffer) + + # Write the new marker segment, 0xff6f = 65391 + read_buffer = struct.pack('>HHB', int(65391), int(3), int(0)) + tfile.write(read_buffer) + + # Get the rest of the input file. + read_buffer = ifile.read() + tfile.write(read_buffer) + tfile.flush() + + codestream = Jp2k(tfile.name).get_codestream() + + self.assertEqual(codestream.segment[2].marker_id, '0xff6f') + self.assertEqual(codestream.segment[2].length, 3) + self.assertEqual(codestream.segment[2].data, b'\x00') + + def test_psot_is_zero(self): + """Psot=0 in SOT is perfectly legal. Issue #78.""" + filename = os.path.join(OPJ_DATA_ROOT, + 'input/nonregression/123.j2c') + j = Jp2k(filename) + codestream = j.get_codestream(header_only=False) + + # The codestream is valid, so we should be able to get the entire + # codestream, so the last one is EOC. + self.assertEqual(codestream.segment[-1].marker_id, 'EOC') + + + def test_siz_segment_ssiz_signed(self): + """ssiz attribute to be removed in future release""" + filename = os.path.join(OPJ_DATA_ROOT, 'input/conformance/p0_03.j2k') + j = Jp2k(filename) + codestream = j.get_codestream() + + # The ssiz attribute was simply a tuple of raw bytes. + # The first 7 bits are interpreted as the bitdepth, the MSB determines + # whether or not it is signed. + self.assertEqual(codestream.segment[1].ssiz, (131,)) + + +class TestCodestreamRepr(unittest.TestCase): + + def setUp(self): + self.jp2file = glymur.data.nemo() + + def tearDown(self): + pass + + def test_soc(self): + """Test SOC segment repr""" + segment = glymur.codestream.SOCsegment() + newseg = eval(repr(segment)) + self.assertEqual(newseg.marker_id, 'SOC') + + def test_siz(self): + """Test SIZ segment repr""" + kwargs = {'rsiz': 0, + 'xysiz': (2592, 1456), + 'xyosiz': (0, 0), + 'xytsiz': (2592, 1456), + 'xytosiz': (0, 0), + 'Csiz': 3, + 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': ((1, 1, 1), (1, 1, 1))} + segment = glymur.codestream.SIZsegment(**kwargs) + newseg = eval(repr(segment)) + self.assertEqual(newseg.marker_id, 'SIZ') + self.assertEqual(newseg.xsiz, 2592) + self.assertEqual(newseg.ysiz, 1456) + self.assertEqual(newseg.xosiz, 0) + self.assertEqual(newseg.yosiz, 0) + self.assertEqual(newseg.xtsiz, 2592) + self.assertEqual(newseg.ytsiz, 1456) + self.assertEqual(newseg.xtosiz, 0) + self.assertEqual(newseg.ytosiz, 0) + + self.assertEqual(newseg.xrsiz, (1, 1, 1)) + self.assertEqual(newseg.yrsiz, (1, 1, 1)) + self.assertEqual(newseg.bitdepth, (8, 8, 8)) + self.assertEqual(newseg.signed, (False, False, False)) + + +class TestCodestream(unittest.TestCase): + """Test suite for unusual codestream cases.""" + + def setUp(self): + self.jp2file = glymur.data.nemo() + + def tearDown(self): + pass + + def test_siz_segment_ssiz_unsigned(self): + """ssiz attribute to be removed in future release""" + j = Jp2k(self.jp2file) + codestream = j.get_codestream() + + # The ssiz attribute was simply a tuple of raw bytes. + # The first 7 bits are interpreted as the bitdepth, the MSB determines + # whether or not it is signed. + self.assertEqual(codestream.segment[1].ssiz, (7, 7, 7)) + + +@unittest.skipIf(OPJ_DATA_ROOT is None, + "OPJ_DATA_ROOT environment variable not set") +class TestCodestreamOpjData(unittest.TestCase): + """Test suite for unusual codestream cases. Uses OPJ_DATA_ROOT""" + + def setUp(self): + self.jp2file = glymur.data.nemo() + + def tearDown(self): + pass + + @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") + def test_reserved_marker_segment(self): + """Reserved marker segments are ok.""" + + # Some marker segments were reserved in FCD15444-1. Since that + # standard is old, some of them may have come into use. + # + # Let's inject a reserved marker segment into a file that + # we know something about to make sure we can still parse it. + filename = os.path.join(OPJ_DATA_ROOT, 'input/conformance/p0_01.j2k') + with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: + with open(filename, 'rb') as ifile: + # Everything up until the first QCD marker. + read_buffer = ifile.read(45) + tfile.write(read_buffer) + + # Write the new marker segment, 0xff6f = 65391 + read_buffer = struct.pack('>HHB', int(65391), int(3), int(0)) + tfile.write(read_buffer) + + # Get the rest of the input file. + read_buffer = ifile.read() + tfile.write(read_buffer) + tfile.flush() + + codestream = Jp2k(tfile.name).get_codestream() + + self.assertEqual(codestream.segment[2].marker_id, '0xff6f') + self.assertEqual(codestream.segment[2].length, 3) + self.assertEqual(codestream.segment[2].data, b'\x00') + + def test_psot_is_zero(self): + """Psot=0 in SOT is perfectly legal. Issue #78.""" + filename = os.path.join(OPJ_DATA_ROOT, + 'input/nonregression/123.j2c') + j = Jp2k(filename) + codestream = j.get_codestream(header_only=False) + + # The codestream is valid, so we should be able to get the entire + # codestream, so the last one is EOC. + self.assertEqual(codestream.segment[-1].marker_id, 'EOC') + + + def test_siz_segment_ssiz_signed(self): + """ssiz attribute to be removed in future release""" + filename = os.path.join(OPJ_DATA_ROOT, 'input/conformance/p0_03.j2k') + j = Jp2k(filename) + codestream = j.get_codestream() + + # The ssiz attribute was simply a tuple of raw bytes. + # The first 7 bits are interpreted as the bitdepth, the MSB determines + # whether or not it is signed. + self.assertEqual(codestream.segment[1].ssiz, (131,)) + + +class TestCodestreamRepr(unittest.TestCase): + + def setUp(self): + self.jp2file = glymur.data.nemo() + + def tearDown(self): + pass + + def test_soc(self): + """Test SOC segment repr""" + segment = glymur.codestream.SOCsegment() + newseg = eval(repr(segment)) + self.assertEqual(newseg.marker_id, 'SOC') + + def test_siz(self): + """Test SIZ segment repr""" + kwargs = {'rsiz': 0, + 'xysiz': (2592, 1456), + 'xyosiz': (0, 0), + 'xytsiz': (2592, 1456), + 'xytosiz': (0, 0), + 'Csiz': 3, + 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': ((1, 1, 1), (1, 1, 1))} + segment = glymur.codestream.SIZsegment(**kwargs) + newseg = eval(repr(segment)) + self.assertEqual(newseg.marker_id, 'SIZ') + self.assertEqual(newseg.xsiz, 2592) + self.assertEqual(newseg.ysiz, 1456) + self.assertEqual(newseg.xosiz, 0) + self.assertEqual(newseg.yosiz, 0) + self.assertEqual(newseg.xtsiz, 2592) + self.assertEqual(newseg.ytsiz, 1456) + self.assertEqual(newseg.xtosiz, 0) + self.assertEqual(newseg.ytosiz, 0) + + self.assertEqual(newseg.xrsiz, (1, 1, 1)) + self.assertEqual(newseg.yrsiz, (1, 1, 1)) + self.assertEqual(newseg.bitdepth, (8, 8, 8)) + self.assertEqual(newseg.signed, (False, False, False)) diff --git a/glymur/test/test_opj_suite.py b/glymur/test/test_opj_suite.py index a033aae..cf44eaa 100644 --- a/glymur/test/test_opj_suite.py +++ b/glymur/test/test_opj_suite.py @@ -30,6 +30,7 @@ suite. import re import sys import unittest +import warnings import numpy as np @@ -57,7 +58,7 @@ class TestSuite(unittest.TestCase): def test_ETS_C1P0_p0_01_j2k(self): jfile = opj_data_file('input/conformance/p0_01.j2k') jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) + jpdata = jp2k[:] pgxfile = opj_data_file('baseline/conformance/c1p0_01_0.pgx') pgxdata = read_pgx(pgxfile) @@ -67,7 +68,7 @@ class TestSuite(unittest.TestCase): def test_ETS_C1P0_p0_03_j2k(self): jfile = opj_data_file('input/conformance/p0_03.j2k') jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) + jpdata = jp2k[:] pgxfile = opj_data_file('baseline/conformance/c1p0_03_0.pgx') pgxdata = read_pgx(pgxfile) @@ -77,7 +78,7 @@ class TestSuite(unittest.TestCase): def test_ETS_C1P0_p0_04_j2k(self): jfile = opj_data_file('input/conformance/p0_04.j2k') jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) + jpdata = jp2k[:] pgxfile = opj_data_file('baseline/conformance/c1p0_04_0.pgx') pgxdata = read_pgx(pgxfile) @@ -97,7 +98,7 @@ class TestSuite(unittest.TestCase): def test_ETS_C1P0_p0_08_j2k(self): jfile = opj_data_file('input/conformance/p0_08.j2k') jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=1) + jpdata = jp2k[::2, ::2] pgxfile = opj_data_file('baseline/conformance/c1p0_08_0.pgx') pgxdata = read_pgx(pgxfile) @@ -114,7 +115,7 @@ class TestSuite(unittest.TestCase): def test_ETS_C1P0_p0_09_j2k(self): jfile = opj_data_file('input/conformance/p0_09.j2k') jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) + jpdata = jp2k[:] pgxfile = opj_data_file('baseline/conformance/c1p0_09_0.pgx') pgxdata = read_pgx(pgxfile) @@ -123,7 +124,7 @@ class TestSuite(unittest.TestCase): def test_ETS_C1P0_p0_11_j2k(self): jfile = opj_data_file('input/conformance/p0_11.j2k') jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) + jpdata = jp2k[:] pgxfile = opj_data_file('baseline/conformance/c1p0_11_0.pgx') pgxdata = read_pgx(pgxfile) @@ -132,7 +133,7 @@ class TestSuite(unittest.TestCase): def test_ETS_C1P0_p0_14_j2k(self): jfile = opj_data_file('input/conformance/p0_14.j2k') jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) + jpdata = jp2k[:] pgxfile = opj_data_file('baseline/conformance/c1p0_14_0.pgx') pgxdata = read_pgx(pgxfile) @@ -149,7 +150,7 @@ class TestSuite(unittest.TestCase): def test_ETS_C1P0_p0_15_j2k(self): jfile = opj_data_file('input/conformance/p0_15.j2k') jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) + jpdata = jp2k[:] pgxfile = opj_data_file('baseline/conformance/c1p0_15_0.pgx') pgxdata = read_pgx(pgxfile) @@ -158,7 +159,7 @@ class TestSuite(unittest.TestCase): def test_ETS_C1P0_p0_16_j2k(self): jfile = opj_data_file('input/conformance/p0_16.j2k') jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) + jpdata = jp2k[:] pgxfile = opj_data_file('baseline/conformance/c1p0_16_0.pgx') pgxdata = read_pgx(pgxfile) @@ -167,7 +168,7 @@ class TestSuite(unittest.TestCase): def test_ETS_C1P1_p1_01_j2k(self): jfile = opj_data_file('input/conformance/p1_01.j2k') jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) + jpdata = jp2k[:] pgxfile = opj_data_file('baseline/conformance/c1p1_01_0.pgx') pgxdata = read_pgx(pgxfile) @@ -176,7 +177,7 @@ class TestSuite(unittest.TestCase): def test_ETS_C1P1_p1_02_j2k(self): jfile = opj_data_file('input/conformance/p1_02.j2k') jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) + jpdata = jp2k[:] pgxfile = opj_data_file('baseline/conformance/c1p1_02_0.pgx') pgxdata = read_pgx(pgxfile) @@ -196,7 +197,7 @@ class TestSuite(unittest.TestCase): def test_ETS_C1P1_p1_04_j2k(self): jfile = opj_data_file('input/conformance/p1_04.j2k') jp2k = Jp2k(jfile) - jpdata = jp2k.read() + jpdata = jp2k[:] pgxfile = opj_data_file('baseline/conformance/c1p1_04_0.pgx') pgxdata = read_pgx(pgxfile) @@ -206,95 +207,95 @@ class TestSuite(unittest.TestCase): def test_NR_DEC_Bretagne2_j2k_1_decode(self): jfile = opj_data_file('input/nonregression/Bretagne2.j2k') jp2 = Jp2k(jfile) - jp2.read() + jp2[:] self.assertTrue(True) def test_NR_DEC__00042_j2k_2_decode(self): jfile = opj_data_file('input/nonregression/_00042.j2k') jp2 = Jp2k(jfile) - jp2.read() + jp2[:] self.assertTrue(True) def test_NR_DEC_buxI_j2k_9_decode(self): jfile = opj_data_file('input/nonregression/buxI.j2k') - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_buxR_j2k_10_decode(self): jfile = opj_data_file('input/nonregression/buxR.j2k') - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_Cannotreaddatawithnosizeknown_j2k_11_decode(self): relpath = 'input/nonregression/Cannotreaddatawithnosizeknown.j2k' jfile = opj_data_file(relpath) - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_cthead1_j2k_12_decode(self): jfile = opj_data_file('input/nonregression/cthead1.j2k') - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_CT_Phillips_JPEG2K_Decompr_Problem_j2k_13_decode(self): relpath = 'input/nonregression/CT_Phillips_JPEG2K_Decompr_Problem.j2k' jfile = opj_data_file(relpath) - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_j2k32_j2k_15_decode(self): jfile = opj_data_file('input/nonregression/j2k32.j2k') - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_MarkerIsNotCompliant_j2k_17_decode(self): jfile = opj_data_file('input/nonregression/MarkerIsNotCompliant.j2k') - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_Marrin_jp2_18_decode(self): jfile = opj_data_file('input/nonregression/Marrin.jp2') - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_movie_00000_j2k_20_decode(self): jfile = opj_data_file('input/nonregression/movie_00000.j2k') - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_movie_00001_j2k_21_decode(self): jfile = opj_data_file('input/nonregression/movie_00001.j2k') - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_movie_00002_j2k_22_decode(self): jfile = opj_data_file('input/nonregression/movie_00002.j2k') - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_orb_blue_lin_j2k_j2k_23_decode(self): jfile = opj_data_file('input/nonregression/orb-blue10-lin-j2k.j2k') - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_orb_blue_win_j2k_j2k_24_decode(self): jfile = opj_data_file('input/nonregression/orb-blue10-win-j2k.j2k') - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_relax_jp2_27_decode(self): jfile = opj_data_file('input/nonregression/relax.jp2') - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_test_lossless_j2k_28_decode(self): jfile = opj_data_file('input/nonregression/test_lossless.j2k') - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_pacs_ge_j2k_30_decode(self): jfile = opj_data_file('input/nonregression/pacs.ge.j2k') - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) @@ -317,14 +318,14 @@ class TestSuiteWarns(MetadataBase): with self.assertWarns(UserWarning): # Bad compatibility list item. jp2k = Jp2k(jfile) - jpdata = jp2k.read() + jpdata = jp2k[:] self.assertEqual(jpdata.shape, (512, 768, 3)) def test_ETS_JP2_file2(self): jfile = opj_data_file('input/conformance/file2.jp2') with self.assertWarns(UserWarning): jp2k = Jp2k(jfile) - jpdata = jp2k.read() + jpdata = jp2k[:] self.assertEqual(jpdata.shape, (640, 480, 3)) @unittest.skipIf(glymur.version.openjpeg_version_tuple[0] < 2, @@ -342,7 +343,7 @@ class TestSuiteWarns(MetadataBase): jfile = opj_data_file('input/conformance/file4.jp2') with self.assertWarns(UserWarning): jp2k = Jp2k(jfile) - jpdata = jp2k.read() + jpdata = jp2k[:] self.assertEqual(jpdata.shape, (512, 768)) def test_ETS_JP2_file5(self): @@ -351,35 +352,35 @@ class TestSuiteWarns(MetadataBase): # There's a warning for an unknown compatibility entry. # Ignore it here. jp2k = Jp2k(jfile) - jpdata = jp2k.read() + jpdata = jp2k[:] self.assertEqual(jpdata.shape, (512, 768, 3)) def test_ETS_JP2_file6(self): jfile = opj_data_file('input/conformance/file6.jp2') with self.assertWarns(UserWarning): jp2k = Jp2k(jfile) - jpdata = jp2k.read() + jpdata = jp2k[:] self.assertEqual(jpdata.shape, (512, 768)) def test_ETS_JP2_file7(self): jfile = opj_data_file('input/conformance/file7.jp2') with self.assertWarns(UserWarning): jp2k = Jp2k(jfile) - jpdata = jp2k.read() + jpdata = jp2k[:] self.assertEqual(jpdata.shape, (640, 480, 3)) def test_ETS_JP2_file8(self): jfile = opj_data_file('input/conformance/file8.jp2') with self.assertWarns(UserWarning): jp2k = Jp2k(jfile) - jpdata = jp2k.read() + jpdata = jp2k[:] self.assertEqual(jpdata.shape, (400, 700)) def test_ETS_JP2_file9(self): jfile = opj_data_file('input/conformance/file9.jp2') with self.assertWarns(UserWarning): jp2k = Jp2k(jfile) - jpdata = jp2k.read() + jpdata = jp2k[:] self.assertEqual(jpdata.shape, (512, 768, 3)) def test_NR_broken_jp2_dump(self): @@ -469,13 +470,13 @@ class TestSuiteWarns(MetadataBase): jfile = opj_data_file('input/nonregression/orb-blue10-lin-jp2.jp2') with self.assertWarns(UserWarning): # This file has an invalid ICC profile - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) def test_NR_DEC_orb_blue_win_jp2_26_decode(self): jfile = opj_data_file('input/nonregression/orb-blue10-win-jp2.jp2') with self.assertWarns(UserWarning): - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) @@ -590,7 +591,7 @@ class TestSuite2point0(unittest.TestCase): def test_ETS_C1P0_p0_10_j2k(self): jfile = opj_data_file('input/conformance/p0_10.j2k') jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) + jpdata = jp2k[:] pgxfile = opj_data_file('baseline/conformance/c1p0_10_0.pgx') pgxdata = read_pgx(pgxfile) @@ -611,7 +612,7 @@ class TestSuite2point0(unittest.TestCase): with self.assertRaises(IOError): with self.assertWarns(UserWarning): # Invalid marker ID. - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) @@ -620,7 +621,7 @@ class TestSuite2point0(unittest.TestCase): with self.assertRaises(IOError): with self.assertWarns(UserWarning): # invalid number of subbands, bad marker ID - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) @@ -632,11 +633,343 @@ class TestSuite2point0(unittest.TestCase): if glymur.version.openjpeg_version_tuple[0] < 2: with self.assertWarns(UserWarning): # Incorrect warning issued about tile parts. - Jp2k(jfile).read() + Jp2k(jfile)[:] else: - Jp2k(jfile).read() + Jp2k(jfile)[:] self.assertTrue(True) -if __name__ == "__main__": - unittest.main() +@unittest.skipIf(OPJ_DATA_ROOT is None, + "OPJ_DATA_ROOT environment variable not set") +@unittest.skipIf(re.match(r'''(1|2.0.0)''', + glymur.version.openjpeg_version) is not None, + "Only supported in 2.0.1 or higher") +class TestSuite2point1(unittest.TestCase): + """Runs tests introduced in version 2.0+ or that pass only in 2.0+""" + + def setUp(self): + pass + + def tearDown(self): + pass + + @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) + def test_NR_DEC_text_GBR_jp2_29_decode(self): + jfile = opj_data_file('input/nonregression/text_GBR.jp2') + with self.assertWarns(UserWarning): + # brand is 'jp2 ', but has any icc profile. + jp2 = Jp2k(jfile) + jp2[:] + self.assertTrue(True) + + def test_NR_DEC_kodak_2layers_lrcp_j2c_31_decode(self): + jfile = opj_data_file('input/nonregression/kodak_2layers_lrcp.j2c') + Jp2k(jfile)[:] + self.assertTrue(True) + + def test_NR_DEC_kodak_2layers_lrcp_j2c_32_decode(self): + jfile = opj_data_file('input/nonregression/kodak_2layers_lrcp.j2c') + Jp2k(jfile)[::4, ::4] + self.assertTrue(True) + + def test_NR_DEC_issue104_jpxstream_jp2_33_decode(self): + jfile = opj_data_file('input/nonregression/issue104_jpxstream.jp2') + Jp2k(jfile)[:] + self.assertTrue(True) + + def test_NR_DEC_mem_b2b86b74_2753_jp2_35_decode(self): + jfile = opj_data_file('input/nonregression/mem-b2b86b74-2753.jp2') + Jp2k(jfile)[:] + self.assertTrue(True) + + @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) + def test_NR_DEC_gdal_fuzzer_unchecked_num_resolutions_jp2_36_decode(self): + f = 'input/nonregression/gdal_fuzzer_unchecked_numresolutions.jp2' + jfile = opj_data_file(f) + with self.assertWarns(UserWarning): + # Invalid number of resolutions. + j = Jp2k(jfile) + with self.assertRaises(IOError): + j[:] + + @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) + def test_NR_DEC_gdal_fuzzer_check_number_of_tiles_jp2_38_decode(self): + relpath = 'input/nonregression/gdal_fuzzer_check_number_of_tiles.jp2' + jfile = opj_data_file(relpath) + with self.assertWarns(UserWarning): + # Invalid number of tiles. + j = Jp2k(jfile) + with self.assertRaises(IOError): + j[:] + + @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) + def test_NR_DEC_gdal_fuzzer_check_comp_dx_dy_jp2_39_decode(self): + relpath = 'input/nonregression/gdal_fuzzer_check_comp_dx_dy.jp2' + jfile = opj_data_file(relpath) + with self.assertWarns(UserWarning): + # Invalid subsampling value + with self.assertRaises(IOError): + Jp2k(jfile)[:] + + def test_NR_DEC_file_409752_jp2_40_decode(self): + jfile = opj_data_file('input/nonregression/file409752.jp2') + with self.assertRaises(RuntimeError): + Jp2k(jfile)[:] + + def test_NR_DEC_issue206_image_000_jp2_42_decode(self): + jfile = opj_data_file('input/nonregression/issue206_image-000.jp2') + Jp2k(jfile)[:] + self.assertTrue(True) + + def test_NR_DEC_p1_04_j2k_57_decode(self): + jfile = opj_data_file('input/conformance/p1_04.j2k') + jp2k = Jp2k(jfile) + tdata = jp2k[896:1024, 896:1024] # last tile + odata = jp2k[:] + np.testing.assert_array_equal(tdata, odata[896:1024, 896:1024]) + + @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) + def test_NR_DEC_p1_04_j2k_57_decode_0p7_backwards_compatibility(self): + """ + 0.7.x usage deprecated + """ + jfile = opj_data_file('input/conformance/p1_04.j2k') + jp2k = Jp2k(jfile) + if sys.hexversion < 0x03000000: + with warnings.catch_warnings(): + # Suppress a warning due to deprecated syntax + warnings.simplefilter("ignore") + tdata = jp2k.read(tile=63) # last tile + else: + with self.assertWarns(DeprecationWarning): + tdata = jp2k.read(tile=63) # last tile + odata = jp2k[:] + np.testing.assert_array_equal(tdata, odata[896:1024, 896:1024]) + + @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) + def test_NR_DEC_p1_04_j2k_58_decode_0p7_backwards_compatibility(self): + """ + 0.7.x usage deprecated + """ + jfile = opj_data_file('input/conformance/p1_04.j2k') + jp2k = Jp2k(jfile) + if sys.hexversion < 0x03000000: + with warnings.catch_warnings(): + # Suppress a warning due to deprecated syntax + tdata = jp2k.read(tile=63, rlevel=2) # last tile + else: + with self.assertWarns(DeprecationWarning): + tdata = jp2k.read(tile=63, rlevel=2) # last tile + odata = jp2k[::4, ::4] + np.testing.assert_array_equal(tdata, odata[224:256, 224:256]) + + def test_NR_DEC_p1_04_j2k_58_decode(self): + jfile = opj_data_file('input/conformance/p1_04.j2k') + jp2k = Jp2k(jfile) + tdata = jp2k[896:1024:4, 896:1024:4] # last tile + odata = jp2k[::4, ::4] + np.testing.assert_array_equal(tdata, odata[224:256, 224:256]) + + def test_NR_DEC_p1_04_j2k_59_decode(self): + jfile = opj_data_file('input/conformance/p1_04.j2k') + jp2k = Jp2k(jfile) + tdata = jp2k[128:256, 512:640] # 2nd row, 5th column + odata = jp2k[:] + np.testing.assert_array_equal(tdata, odata[128:256, 512:640]) + + def test_NR_DEC_p1_04_j2k_60_decode(self): + jfile = opj_data_file('input/conformance/p1_04.j2k') + jp2k = Jp2k(jfile) + tdata = jp2k[128:256:2, 512:640:2] # 2nd row, 5th column + odata = jp2k[::2, ::2] + np.testing.assert_array_equal(tdata, odata[64:128, 256:320]) + + @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) + def test_NR_DEC_jp2_36_decode(self): + lst = ('input', + 'nonregression', + 'gdal_fuzzer_assert_in_opj_j2k_read_SQcd_SQcc.patch.jp2') + jfile = opj_data_file('/'.join(lst)) + with self.assertWarns(UserWarning): + # Invalid component number. + j = Jp2k(jfile) + with self.assertRaises(IOError): + j[:] + +@unittest.skipIf(OPJ_DATA_ROOT is None, + "OPJ_DATA_ROOT environment variable not set") +@unittest.skipIf(re.match(r'''(1|2.0.0)''', + glymur.version.openjpeg_version) is not None, + "Only supported in 2.0.1 or higher") +class TestReadArea(unittest.TestCase): + """ + Runs tests introduced in version 2.0+ or that pass only in 2.0+ + + Specifically for read method with area parameter. + """ + @classmethod + def setUpClass(self): + + jfile = opj_data_file('input/conformance/p1_04.j2k') + self.j2k = Jp2k(jfile) + self.j2k_data = self.j2k[:] + self.j2k_half_data = self.j2k[::2, ::2] + self.j2k_quarter_data = self.j2k[::4, ::4] + + jfile = opj_data_file('input/conformance/p1_06.j2k') + self.j2k_p1_06 = Jp2k(jfile) + + def test_NR_DEC_p1_04_j2k_43_decode(self): + actual = self.j2k[:1024, :1024] + expected = self.j2k_data + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p1_04_j2k_44_decode(self): + actual = self.j2k[640:768, 512:640] + expected = self.j2k_data[640:768, 512:640] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p1_04_j2k_45_decode(self): + actual = self.j2k[896:1024, 896:1024] + expected = self.j2k_data[896:1024, 896:1024] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p1_04_j2k_46_decode(self): + actual = self.j2k[500:800, 100:300] + expected = self.j2k_data[500:800, 100:300] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p1_04_j2k_47_decode(self): + actual = self.j2k[520:600, 260:360] + expected = self.j2k_data[520:600, 260:360] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p1_04_j2k_48_decode(self): + actual = self.j2k[520:660, 260:360] + expected = self.j2k_data[520:660, 260:360] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p1_04_j2k_49_decode(self): + actual = self.j2k[520:600, 360:400] + expected = self.j2k_data[520:600, 360:400] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p1_04_j2k_50_decode(self): + actual = self.j2k[:1024:4, :1024:4] + expected = self.j2k_quarter_data + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p1_04_j2k_51_decode(self): + actual = self.j2k[640:768:4, 512:640:4] + expected = self.j2k_quarter_data[160:192, 128:160] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p1_04_j2k_52_decode(self): + actual = self.j2k[896:1024:4, 896:1024:4] + expected = self.j2k_quarter_data[224:352, 224:352] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p1_04_j2k_53_decode(self): + actual = self.j2k[500:800:4, 100:300:4] + expected = self.j2k_quarter_data[125:200, 25:75] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p1_04_j2k_54_decode(self): + actual = self.j2k[520:600:4, 260:360:4] + expected = self.j2k_quarter_data[130:150, 65:90] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p1_04_j2k_55_decode(self): + actual = self.j2k[520:660:4, 260:360:4] + expected = self.j2k_quarter_data[130:165, 65:90] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p1_04_j2k_56_decode(self): + actual = self.j2k[520:600:4, 360:400:4] + expected = self.j2k_quarter_data[130:150, 90:100] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p1_06_j2k_70_decode(self): + actual = self.j2k_p1_06[9:12:2, 9:12:2] + self.assertEqual(actual.shape, (1, 1, 3)) + + def test_NR_DEC_p1_06_j2k_71_decode(self): + actual = self.j2k_p1_06[10:12:2, 4:10:2] + self.assertEqual(actual.shape, (1, 3, 3)) + + def test_NR_DEC_p1_06_j2k_72_decode(self): + ssdata = self.j2k_p1_06[3:9:2, 3:9:2] + self.assertEqual(ssdata.shape, (3, 3, 3)) + + def test_NR_DEC_p1_06_j2k_73_decode(self): + ssdata = self.j2k_p1_06[4:7:2, 4:7:2] + self.assertEqual(ssdata.shape, (2, 2, 3)) + + def test_NR_DEC_p1_06_j2k_74_decode(self): + ssdata = self.j2k_p1_06[4:5:2, 4:5:2] + self.assertEqual(ssdata.shape, (1, 1, 3)) + + def test_NR_DEC_p1_06_j2k_75_decode(self): + # Image size would be 0 x 0. + with self.assertRaises((IOError, OSError)): + self.j2k_p1_06[9:12:4, 9:12:4] + + def test_NR_DEC_p0_04_j2k_85_decode(self): + actual = self.j2k[:256, :256] + expected = self.j2k_data[:256, :256] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p0_04_j2k_86_decode(self): + actual = self.j2k[:128, 128:256] + expected = self.j2k_data[:128, 128:256] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p0_04_j2k_87_decode(self): + actual = self.j2k[10:200, 50:120] + expected = self.j2k_data[10:200, 50:120] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p0_04_j2k_88_decode(self): + actual = self.j2k[150:210, 10:190] + expected = self.j2k_data[150:210, 10:190] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p0_04_j2k_89_decode(self): + actual = self.j2k[80:150, 100:200] + expected = self.j2k_data[80:150, 100:200] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p0_04_j2k_90_decode(self): + actual = self.j2k[20:50, 150:200] + expected = self.j2k_data[20:50, 150:200] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p0_04_j2k_91_decode(self): + actual = self.j2k[:256:4, :256:4] + expected = self.j2k_quarter_data[0:64, 0:64] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p0_04_j2k_92_decode(self): + actual = self.j2k[:128:4, 128:256:4] + expected = self.j2k_quarter_data[:32, 32:64] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p0_04_j2k_93_decode(self): + actual = self.j2k[10:200:4, 50:120:4] + expected = self.j2k_quarter_data[3:50, 13:30] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p0_04_j2k_94_decode(self): + actual = self.j2k[150:210:4, 10:190:4] + expected = self.j2k_quarter_data[38:53, 3:48] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p0_04_j2k_95_decode(self): + actual = self.j2k[80:150:4, 100:200:4] + expected = self.j2k_quarter_data[20:38, 25:50] + np.testing.assert_array_equal(actual, expected) + + def test_NR_DEC_p0_04_j2k_96_decode(self): + actual = self.j2k[20:50:4, 150:200:4] + expected = self.j2k_quarter_data[5:13, 38:50] + np.testing.assert_array_equal(actual, expected) diff --git a/glymur/test/test_opj_suite_2p1.py b/glymur/test/test_opj_suite_2p1.py deleted file mode 100644 index addc48b..0000000 --- a/glymur/test/test_opj_suite_2p1.py +++ /dev/null @@ -1,342 +0,0 @@ -""" -The tests defined here roughly correspond to what is in the OpenJPEG test -suite. -""" - -# Some test names correspond with openjpeg tests. Long names are ok in this -# case. -# pylint: disable=C0103 - -# All of these tests correspond to tests in openjpeg, so no docstring is really -# needed. -# pylint: disable=C0111 - -# This module is very long, cannot be helped. -# pylint: disable=C0302 - -# unittest fools pylint with "too many public methods" -# pylint: disable=R0904 - -# Some tests use numpy test infrastructure, which means the tests never -# reference "self", so pylint claims it should be a function. No, no, no. -# pylint: disable=R0201 - -# Many tests are pretty long and that can't be helped. -# pylint: disable=R0915 - -# asserWarns introduced in python 3.2 (python2.7/pylint issue) -# pylint: disable=E1101 - -import re -import sys -import unittest - -import numpy as np - -from glymur import Jp2k -import glymur - -from .fixtures import OPJ_DATA_ROOT -from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG -from .fixtures import mse, peak_tolerance, read_pgx, opj_data_file - - -@unittest.skipIf(OPJ_DATA_ROOT is None, - "OPJ_DATA_ROOT environment variable not set") -@unittest.skipIf(re.match(r'''(1|2.0.0)''', - glymur.version.openjpeg_version) is not None, - "Only supported in 2.0.1 or higher") -class TestSuite2point1(unittest.TestCase): - """Runs tests introduced in version 2.0+ or that pass only in 2.0+""" - - def setUp(self): - pass - - def tearDown(self): - pass - - @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) - def test_NR_DEC_text_GBR_jp2_29_decode(self): - jfile = opj_data_file('input/nonregression/text_GBR.jp2') - with self.assertWarns(UserWarning): - # brand is 'jp2 ', but has any icc profile. - jp2 = Jp2k(jfile) - jp2.read() - self.assertTrue(True) - - def test_NR_DEC_kodak_2layers_lrcp_j2c_31_decode(self): - jfile = opj_data_file('input/nonregression/kodak_2layers_lrcp.j2c') - Jp2k(jfile).read() - self.assertTrue(True) - - def test_NR_DEC_kodak_2layers_lrcp_j2c_32_decode(self): - jfile = opj_data_file('input/nonregression/kodak_2layers_lrcp.j2c') - Jp2k(jfile).read(layer=2) - self.assertTrue(True) - - def test_NR_DEC_issue104_jpxstream_jp2_33_decode(self): - jfile = opj_data_file('input/nonregression/issue104_jpxstream.jp2') - Jp2k(jfile).read() - self.assertTrue(True) - - def test_NR_DEC_mem_b2b86b74_2753_jp2_35_decode(self): - jfile = opj_data_file('input/nonregression/mem-b2b86b74-2753.jp2') - Jp2k(jfile).read() - self.assertTrue(True) - - @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) - def test_NR_DEC_gdal_fuzzer_unchecked_num_resolutions_jp2_36_decode(self): - f = 'input/nonregression/gdal_fuzzer_unchecked_numresolutions.jp2' - jfile = opj_data_file(f) - with self.assertWarns(UserWarning): - # Invalid number of resolutions. - j = Jp2k(jfile) - with self.assertRaises(IOError): - j.read() - - @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) - def test_NR_DEC_gdal_fuzzer_check_number_of_tiles_jp2_38_decode(self): - relpath = 'input/nonregression/gdal_fuzzer_check_number_of_tiles.jp2' - jfile = opj_data_file(relpath) - with self.assertWarns(UserWarning): - # Invalid number of tiles. - j = Jp2k(jfile) - with self.assertRaises(IOError): - j.read() - - @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) - def test_NR_DEC_gdal_fuzzer_check_comp_dx_dy_jp2_39_decode(self): - relpath = 'input/nonregression/gdal_fuzzer_check_comp_dx_dy.jp2' - jfile = opj_data_file(relpath) - with self.assertWarns(UserWarning): - # Invalid subsampling value - with self.assertRaises(IOError): - Jp2k(jfile).read() - - def test_NR_DEC_file_409752_jp2_40_decode(self): - jfile = opj_data_file('input/nonregression/file409752.jp2') - with self.assertRaises(RuntimeError): - Jp2k(jfile).read() - - def test_NR_DEC_issue206_image_000_jp2_42_decode(self): - jfile = opj_data_file('input/nonregression/issue206_image-000.jp2') - Jp2k(jfile).read() - self.assertTrue(True) - - def test_NR_DEC_p1_04_j2k_57_decode(self): - jfile = opj_data_file('input/conformance/p1_04.j2k') - jp2k = Jp2k(jfile) - tdata = jp2k.read(tile=63) # last tile - odata = jp2k.read() - np.testing.assert_array_equal(tdata, odata[896:1024, 896:1024]) - - def test_NR_DEC_p1_04_j2k_58_decode(self): - jfile = opj_data_file('input/conformance/p1_04.j2k') - jp2k = Jp2k(jfile) - tdata = jp2k.read(tile=63, rlevel=2) # last tile - odata = jp2k.read(rlevel=2) - np.testing.assert_array_equal(tdata, odata[224:256, 224:256]) - - def test_NR_DEC_p1_04_j2k_59_decode(self): - jfile = opj_data_file('input/conformance/p1_04.j2k') - jp2k = Jp2k(jfile) - tdata = jp2k.read(tile=12) # 2nd row, 5th column - odata = jp2k.read() - np.testing.assert_array_equal(tdata, odata[128:256, 512:640]) - - def test_NR_DEC_p1_04_j2k_60_decode(self): - jfile = opj_data_file('input/conformance/p1_04.j2k') - jp2k = Jp2k(jfile) - tdata = jp2k.read(tile=12, rlevel=1) # 2nd row, 5th column - odata = jp2k.read(rlevel=1) - np.testing.assert_array_equal(tdata, odata[64:128, 256:320]) - - @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) - def test_NR_DEC_jp2_36_decode(self): - lst = ('input', - 'nonregression', - 'gdal_fuzzer_assert_in_opj_j2k_read_SQcd_SQcc.patch.jp2') - jfile = opj_data_file('/'.join(lst)) - with self.assertWarns(UserWarning): - # Invalid component number. - j = Jp2k(jfile) - with self.assertRaises(IOError): - j.read() - -@unittest.skipIf(OPJ_DATA_ROOT is None, - "OPJ_DATA_ROOT environment variable not set") -@unittest.skipIf(re.match(r'''(1|2.0.0)''', - glymur.version.openjpeg_version) is not None, - "Only supported in 2.0.1 or higher") -class TestReadArea(unittest.TestCase): - """ - Runs tests introduced in version 2.0+ or that pass only in 2.0+ - - Specifically for read method with area parameter. - """ - @classmethod - def setUpClass(self): - - jfile = opj_data_file('input/conformance/p1_04.j2k') - self.j2k = Jp2k(jfile) - self.j2k_data = self.j2k.read() - self.j2k_half_data = self.j2k.read(rlevel=1) - self.j2k_quarter_data = self.j2k.read(rlevel=2) - - jfile = opj_data_file('input/conformance/p1_06.j2k') - self.j2k_p1_06 = Jp2k(jfile) - - def test_NR_DEC_p1_04_j2k_43_decode(self): - actual = self.j2k.read(area=(0, 0, 1024, 1024)) - expected = self.j2k_data - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_44_decode(self): - actual = self.j2k.read(area=(640, 512, 768, 640)) - expected = self.j2k_data[640:768, 512:640] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_45_decode(self): - actual = self.j2k.read(area=(896, 896, 1024, 1024)) - expected = self.j2k_data[896:1024, 896:1024] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_46_decode(self): - actual = self.j2k.read(area=(500, 100, 800, 300)) - expected = self.j2k_data[500:800, 100:300] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_47_decode(self): - actual = self.j2k.read(area=(520, 260, 600, 360)) - expected = self.j2k_data[520:600, 260:360] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_48_decode(self): - actual = self.j2k.read(area=(520, 260, 660, 360)) - expected = self.j2k_data[520:660, 260:360] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_49_decode(self): - actual = self.j2k.read(area=(520, 360, 600, 400)) - expected = self.j2k_data[520:600, 360:400] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_50_decode(self): - actual = self.j2k.read(area=(0, 0, 1024, 1024), rlevel=2) - expected = self.j2k_quarter_data - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_51_decode(self): - actual = self.j2k.read(area=(640, 512, 768, 640), rlevel=2) - expected = self.j2k_quarter_data[160:192, 128:160] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_52_decode(self): - actual = self.j2k.read(area=(896, 896, 1024, 1024), rlevel=2) - expected = self.j2k_quarter_data[224:352, 224:352] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_53_decode(self): - actual = self.j2k.read(area=(500, 100, 800, 300), rlevel=2) - expected = self.j2k_quarter_data[125:200, 25:75] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_54_decode(self): - actual = self.j2k.read(area=(520, 260, 600, 360), rlevel=2) - expected = self.j2k_quarter_data[130:150, 65:90] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_55_decode(self): - actual = self.j2k.read(area=(520, 260, 660, 360), rlevel=2) - expected = self.j2k_quarter_data[130:165, 65:90] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_04_j2k_56_decode(self): - actual = self.j2k.read(area=(520, 360, 600, 400), rlevel=2) - expected = self.j2k_quarter_data[130:150, 90:100] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p1_06_j2k_70_decode(self): - actual = self.j2k_p1_06.read(area=(9, 9, 12, 12), rlevel=1) - self.assertEqual(actual.shape, (1, 1, 3)) - - def test_NR_DEC_p1_06_j2k_71_decode(self): - actual = self.j2k_p1_06.read(area=(10, 4, 12, 10), rlevel=1) - self.assertEqual(actual.shape, (1, 3, 3)) - - def test_NR_DEC_p1_06_j2k_72_decode(self): - ssdata = self.j2k_p1_06.read(area=(3, 3, 9, 9), rlevel=1) - self.assertEqual(ssdata.shape, (3, 3, 3)) - - def test_NR_DEC_p1_06_j2k_73_decode(self): - ssdata = self.j2k_p1_06.read(area=(4, 4, 7, 7), rlevel=1) - self.assertEqual(ssdata.shape, (2, 2, 3)) - - def test_NR_DEC_p1_06_j2k_74_decode(self): - ssdata = self.j2k_p1_06.read(area=(4, 4, 5, 5), rlevel=1) - self.assertEqual(ssdata.shape, (1, 1, 3)) - - def test_NR_DEC_p1_06_j2k_75_decode(self): - # Image size would be 0 x 0. - with self.assertRaises((IOError, OSError)): - self.j2k_p1_06.read(area=(9, 9, 12, 12), rlevel=2) - - def test_NR_DEC_p0_04_j2k_85_decode(self): - actual = self.j2k.read(area=(0, 0, 256, 256)) - expected = self.j2k_data[:256, :256] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_86_decode(self): - actual = self.j2k.read(area=(0, 128, 128, 256)) - expected = self.j2k_data[:128, 128:256] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_87_decode(self): - actual = self.j2k.read(area=(10, 50, 200, 120)) - expected = self.j2k_data[10:200, 50:120] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_88_decode(self): - actual = self.j2k.read(area=(150, 10, 210, 190)) - expected = self.j2k_data[150:210, 10:190] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_89_decode(self): - actual = self.j2k.read(area=(80, 100, 150, 200)) - expected = self.j2k_data[80:150, 100:200] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_90_decode(self): - actual = self.j2k.read(area=(20, 150, 50, 200)) - expected = self.j2k_data[20:50, 150:200] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_91_decode(self): - actual = self.j2k.read(area=(0, 0, 256, 256), rlevel=2) - expected = self.j2k_quarter_data[0:64, 0:64] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_92_decode(self): - actual = self.j2k.read(area=(0, 128, 128, 256), rlevel=2) - expected = self.j2k_quarter_data[:32, 32:64] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_93_decode(self): - actual = self.j2k.read(area=(10, 50, 200, 120), rlevel=2) - expected = self.j2k_quarter_data[3:50, 13:30] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_94_decode(self): - actual = self.j2k.read(area=(150, 10, 210, 190), rlevel=2) - expected = self.j2k_quarter_data[38:53, 3:48] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_95_decode(self): - actual = self.j2k.read(area=(80, 100, 150, 200), rlevel=2) - expected = self.j2k_quarter_data[20:38, 25:50] - np.testing.assert_array_equal(actual, expected) - - def test_NR_DEC_p0_04_j2k_96_decode(self): - actual = self.j2k.read(area=(20, 150, 50, 200), rlevel=2) - expected = self.j2k_quarter_data[5:13, 38:50] - np.testing.assert_array_equal(actual, expected) diff --git a/glymur/test/test_opj_suite_dump.py b/glymur/test/test_opj_suite_dump.py index 8201c9f..ee1838b 100644 --- a/glymur/test/test_opj_suite_dump.py +++ b/glymur/test/test_opj_suite_dump.py @@ -2847,8 +2847,7 @@ class TestSuiteWarns(MetadataBase): relpath = 'input/nonregression/issue188_beach_64bitsbox.jp2' jfile = opj_data_file(relpath) with self.assertWarns(UserWarning): - j = Jp2k(jfile) - d = j.read() + d = Jp2k(jfile)[:] self.assertTrue(True) def test_NR_broken4_jp2_dump(self): diff --git a/glymur/test/test_opj_suite_neg.py b/glymur/test/test_opj_suite_neg.py index 058be42..c7e31e5 100644 --- a/glymur/test/test_opj_suite_neg.py +++ b/glymur/test/test_opj_suite_neg.py @@ -24,6 +24,7 @@ from .fixtures import OPJ_DATA_ROOT, opj_data_file, read_image from .fixtures import NO_READ_BACKEND, NO_READ_BACKEND_MSG from .fixtures import NO_SKIMAGE_FREEIMAGE_SUPPORT from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG +from . import fixtures from glymur import Jp2k import glymur @@ -31,7 +32,7 @@ import glymur @unittest.skipIf(OPJ_DATA_ROOT is None, "OPJ_OPJ_DATA_ROOT environment variable not set") -class TestSuiteNegative(unittest.TestCase): +class TestSuiteNegativeRead(unittest.TestCase): """Test suite for certain negative tests from openjpeg suite.""" def setUp(self): @@ -41,33 +42,6 @@ class TestSuiteNegative(unittest.TestCase): def tearDown(self): pass - - @unittest.skipIf(NO_SKIMAGE_FREEIMAGE_SUPPORT, - "Cannot read input image without scikit-image/freeimage") - @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") - def test_cinema2K_bad_frame_rate(self): - """Cinema2k frame rate must be either 24 or 48.""" - relfile = 'input/nonregression/X_5_2K_24_235_CBR_STEM24_000.tif' - infile = opj_data_file(relfile) - data = skimage.io.imread(infile) - with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - with self.assertRaises(IOError): - j.write(data, cinema2k=36) - - - @unittest.skipIf(NO_READ_BACKEND, NO_READ_BACKEND_MSG) - @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") - def test_psnr_with_cratios(self): - """Using psnr with cratios options is not allowed.""" - # Not an OpenJPEG test, but close. - infile = opj_data_file('input/nonregression/Bretagne1.ppm') - data = read_image(infile) - with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - with self.assertRaises(IOError): - j.write(data, psnr=[30, 35, 40], cratios=[2, 3, 4]) - def test_nr_marker_not_compliant(self): """non-compliant marker, should still be able to read""" relpath = 'input/nonregression/MarkerIsNotCompliant.j2k' @@ -98,56 +72,84 @@ class TestSuiteNegative(unittest.TestCase): jp2k.get_codestream(header_only=False) self.assertTrue(True) - @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") + +@unittest.skipIf(re.match("1.5|2", glymur.version.openjpeg_version) is None, + "Must have openjpeg 1.5 or higher to run") +@unittest.skipIf(os.name == "nt", fixtures.WINDOWS_TMP_FILE_MSG) +@unittest.skipIf(OPJ_DATA_ROOT is None, + "OPJ_OPJ_DATA_ROOT environment variable not set") +class TestSuiteNegativeWrite(unittest.TestCase): + """Test suite for certain negative tests from openjpeg suite.""" + + def setUp(self): + self.jp2file = glymur.data.nemo() + self.j2kfile = glymur.data.goodstuff() + + def tearDown(self): + pass + + + @unittest.skipIf(NO_SKIMAGE_FREEIMAGE_SUPPORT, + "Cannot read input image without scikit-image/freeimage") + def test_cinema2K_bad_frame_rate(self): + """Cinema2k frame rate must be either 24 or 48.""" + relfile = 'input/nonregression/X_5_2K_24_235_CBR_STEM24_000.tif' + infile = opj_data_file(relfile) + data = skimage.io.imread(infile) + with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: + with self.assertRaises(IOError): + j = Jp2k(tfile.name, data=data, cinema2k=36) + + + @unittest.skipIf(NO_READ_BACKEND, NO_READ_BACKEND_MSG) + def test_psnr_with_cratios(self): + """Using psnr with cratios options is not allowed.""" + # Not an OpenJPEG test, but close. + infile = opj_data_file('input/nonregression/Bretagne1.ppm') + data = read_image(infile) + with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: + with self.assertRaises(IOError): + j = Jp2k(tfile.name, + data=data, psnr=[30, 35, 40], cratios=[2, 3, 4]) + def test_code_block_dimensions(self): """don't allow extreme codeblock sizes""" # opj_compress doesn't allow the dimensions of a codeblock # to be too small or too big, so neither will we. data = np.zeros((256, 256), dtype=np.uint8) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - # opj_compress doesn't allow code block area to exceed 4096. with self.assertRaises(IOError): - j.write(data, cbsize=(256, 256)) + j = Jp2k(tfile.name, data=data, cbsize=(256, 256)) # opj_compress doesn't allow either dimension to be less than 4. with self.assertRaises(IOError): - j.write(data, cbsize=(2048, 2)) + j = Jp2k(tfile.name, data=data, cbsize=(2048, 2)) with self.assertRaises(IOError): - j.write(data, cbsize=(2, 2048)) + j = Jp2k(tfile.name, data=data, cbsize=(2, 2048)) - @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") def test_precinct_size_not_p2(self): """precinct sizes should be powers of two.""" ifile = Jp2k(self.j2kfile) - data = ifile.read(rlevel=2) + data = ifile[::4, ::4] with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - ofile = Jp2k(tfile.name, 'wb') with self.assertRaises(IOError): - ofile.write(data, psizes=[(13, 13)]) + ofile = Jp2k(tfile.name, data=data, psizes=[(13, 13)]) - @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") def test_cblk_size_not_power_of_two(self): """code block sizes should be powers of two.""" ifile = Jp2k(self.j2kfile) - data = ifile.read(rlevel=2) + data = ifile[::4, ::4] with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - ofile = Jp2k(tfile.name, 'wb') with self.assertRaises(IOError): - ofile.write(data, cbsize=(13, 12)) + ofile = Jp2k(tfile.name, data=data, cbsize=(13, 12)) - @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") def test_cblk_size_precinct_size(self): """code block sizes should never exceed half that of precinct size.""" ifile = Jp2k(self.j2kfile) - data = ifile.read(rlevel=2) + data = ifile[::4, ::4] with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - ofile = Jp2k(tfile.name, 'wb') with self.assertRaises(IOError): - ofile.write(data, - cbsize=(64, 64), - psizes=[(64, 64)]) + ofile = Jp2k(tfile.name, + data=data, cbsize=(64, 64), psizes=[(64, 64)]) -if __name__ == "__main__": - unittest.main() diff --git a/glymur/test/test_opj_suite_write.py b/glymur/test/test_opj_suite_write.py index 8be1cef..ecb7a7d 100644 --- a/glymur/test/test_opj_suite_write.py +++ b/glymur/test/test_opj_suite_write.py @@ -87,9 +87,9 @@ class WriteCinema(CinemaBase): infile = opj_data_file(relfile) data = skimage.io.imread(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') with self.assertRaises(IOError): - j.write(data, cinema2k=48, cratios=[200, 100, 50]) + j = Jp2k(tfile.name, data=data, + cinema2k=48, cratios=[200, 100, 50]) def test_cinema4K_with_others(self): """Can't specify cinema4k with any other options.""" @@ -97,9 +97,9 @@ class WriteCinema(CinemaBase): infile = opj_data_file(relfile) data = skimage.io.imread(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') with self.assertRaises(IOError): - j.write(data, cinema4k=True, cratios=[200, 100, 50]) + j = Jp2k(tfile.name, data=data, + cinema4k=True, cratios=[200, 100, 50]) @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) @@ -123,10 +123,9 @@ class WriteCinemaWarns(CinemaBase): infile = opj_data_file(relfile) data = skimage.io.imread(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') regex = 'OpenJPEG library warning:.*' with self.assertWarnsRegex(UserWarning, re.compile(regex)): - j.write(data, cinema4k=True) + j = Jp2k(tfile.name, data=data, cinema4k=True) codestream = j.get_codestream() self.check_cinema4k_codestream(codestream, (4096, 2160)) @@ -136,9 +135,8 @@ class WriteCinemaWarns(CinemaBase): infile = opj_data_file(relfile) data = skimage.io.imread(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') with self.assertWarnsRegex(UserWarning, 'OpenJPEG library warning'): - j.write(data, cinema2k=48) + j = Jp2k(tfile.name, data=data, cinema2k=48) codestream = j.get_codestream() self.check_cinema2k_codestream(codestream, (2048, 857)) @@ -148,9 +146,8 @@ class WriteCinemaWarns(CinemaBase): infile = opj_data_file(relfile) data = skimage.io.imread(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') with self.assertWarnsRegex(UserWarning, 'OpenJPEG library warning'): - j.write(data, cinema2k=48) + j = Jp2k(tfile.name, data=data, cinema2k=48) codestream = j.get_codestream() self.check_cinema2k_codestream(codestream, (2048, 1080)) @@ -160,9 +157,8 @@ class WriteCinemaWarns(CinemaBase): infile = opj_data_file(relfile) data = skimage.io.imread(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') with self.assertWarnsRegex(UserWarning, 'OpenJPEG library warning'): - j.write(data, cinema2k=24) + j = Jp2k(tfile.name, data=data, cinema2k=24) codestream = j.get_codestream() self.check_cinema2k_codestream(codestream, (2048, 1080)) @@ -172,11 +168,10 @@ class WriteCinemaWarns(CinemaBase): infile = opj_data_file(relfile) data = skimage.io.imread(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') with self.assertWarnsRegex(UserWarning, 'OpenJPEG library warning'): # OpenJPEG library warning: The desired maximum codestream # size has limited at least one of the desired quality layers - j.write(data, cinema2k=24) + j = Jp2k(tfile.name, data=data, cinema2k=24) codestream = j.get_codestream() self.check_cinema2k_codestream(codestream, (2048, 857)) @@ -186,12 +181,11 @@ class WriteCinemaWarns(CinemaBase): infile = opj_data_file(relfile) data = skimage.io.imread(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') regex = 'OpenJPEG library warning' with self.assertWarnsRegex(UserWarning, regex): # OpenJPEG library warning: The desired maximum codestream # size has limited at least one of the desired quality layers - j.write(data, cinema2k=48) + j = Jp2k(tfile.name, data=data, cinema2k=48) codestream = j.get_codestream() self.check_cinema2k_codestream(codestream, (1998, 1080)) @@ -221,9 +215,8 @@ class TestNegative2pointzero(unittest.TestCase): for version in versions: with patch('glymur.version.openjpeg_version', new=version): with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') with self.assertRaises(IOError): - j.write(data, cinema2k=48) + j = Jp2k(tfile.name, data=data, cinema2k=48) @unittest.skipIf(re.match(r'''1.[0-4]''', openjpeg_version) is not None, @@ -249,8 +242,7 @@ class TestSuiteWrite(fixtures.MetadataBase): expdata = np.fromfile(filename, dtype=np.uint16) expdata.resize((2816, 2048)) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - j.write(expdata, irreversible=True) + j = Jp2k(tfile.name, data=expdata, irreversible=True) codestream = j.get_codestream() self.assertEqual(codestream.segment[2].spcod[8], @@ -262,8 +254,7 @@ class TestSuiteWrite(fixtures.MetadataBase): infile = opj_data_file('input/nonregression/Bretagne1.ppm') data = read_image(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - j.write(data, cratios=[200, 100, 50]) + j = Jp2k(tfile.name, data=data, cratios=[200, 100, 50]) # Should be three layers. c = j.get_codestream() @@ -294,8 +285,7 @@ class TestSuiteWrite(fixtures.MetadataBase): infile = opj_data_file('input/nonregression/Bretagne1.ppm') data = read_image(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - j.write(data, psnr=[30, 35, 40], numres=2) + j = Jp2k(tfile.name, data=data, psnr=[30, 35, 40], numres=2) # Should be three layers. codestream = j.get_codestream() @@ -326,9 +316,9 @@ class TestSuiteWrite(fixtures.MetadataBase): infile = opj_data_file('input/nonregression/Bretagne1.ppm') data = read_image(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - j.write(data, psnr=[30, 35, 40], cbsize=(16, 16), - psizes=[(64, 64)]) + j = Jp2k(tfile.name, + data=data, + psnr=[30, 35, 40], cbsize=(16, 16), psizes=[(64, 64)]) # Should be three layers. codestream = j.get_codestream() @@ -361,8 +351,8 @@ class TestSuiteWrite(fixtures.MetadataBase): infile = opj_data_file('input/nonregression/Bretagne2.ppm') data = read_image(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - j.write(data, + j = Jp2k(tfile.name, + data=data, psizes=[(128, 128)] * 3, cratios=[100, 20, 2], tilesize=(480, 640), @@ -398,8 +388,7 @@ class TestSuiteWrite(fixtures.MetadataBase): infile = opj_data_file('input/nonregression/Bretagne2.ppm') data = read_image(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - j.write(data, tilesize=(127, 127), prog="PCRL") + j = Jp2k(tfile.name, data=data, tilesize=(127, 127), prog="PCRL") codestream = j.get_codestream() @@ -429,8 +418,7 @@ class TestSuiteWrite(fixtures.MetadataBase): infile = opj_data_file('input/nonregression/Bretagne2.ppm') data = read_image(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - j.write(data, subsam=(2, 2), sop=True) + j = Jp2k(tfile.name, data=data, subsam=(2, 2), sop=True) codestream = j.get_codestream(header_only=False) @@ -465,8 +453,7 @@ class TestSuiteWrite(fixtures.MetadataBase): infile = opj_data_file('input/nonregression/Bretagne2.ppm') data = read_image(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - j.write(data, modesw=38, eph=True) + j = Jp2k(tfile.name, data=data, modesw=38, eph=True) codestream = j.get_codestream(header_only=False) @@ -500,8 +487,8 @@ class TestSuiteWrite(fixtures.MetadataBase): infile = opj_data_file('input/nonregression/Bretagne2.ppm') data = read_image(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - j.write(data, grid_offset=[300, 150], cratios=[800]) + j = Jp2k(tfile.name, + data=data, grid_offset=[300, 150], cratios=[800]) codestream = j.get_codestream(header_only=False) @@ -531,8 +518,7 @@ class TestSuiteWrite(fixtures.MetadataBase): infile = opj_data_file('input/nonregression/Cevennes1.bmp') data = read_image(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - j.write(data, cratios=[800]) + j = Jp2k(tfile.name, data=data, cratios=[800]) codestream = j.get_codestream(header_only=False) @@ -562,8 +548,7 @@ class TestSuiteWrite(fixtures.MetadataBase): infile = opj_data_file('input/nonregression/Cevennes2.ppm') data = read_image(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - j.write(data, cratios=[50]) + j = Jp2k(tfile.name, data=data, cratios=[50]) codestream = j.get_codestream(header_only=False) @@ -592,8 +577,8 @@ class TestSuiteWrite(fixtures.MetadataBase): """NR-ENC-Rome.bmp-11-encode""" data = read_image(opj_data_file('input/nonregression/Rome.bmp')) with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - jp2 = Jp2k(tfile.name, 'wb') - jp2.write(data, psnr=[30, 35, 50], prog='LRCP', numres=3) + jp2 = Jp2k(tfile.name, + data=data, psnr=[30, 35, 50], prog='LRCP', numres=3) ids = [box.box_id for box in jp2.box] self.assertEqual(ids, ['jP ', 'ftyp', 'jp2h', 'jp2c']) @@ -658,8 +643,7 @@ class TestSuiteWrite(fixtures.MetadataBase): infile = opj_data_file('input/nonregression/random-issue-0005.tif') data = read_image(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, 'wb') - j.write(data) + j = Jp2k(tfile.name, data=data) codestream = j.get_codestream(header_only=False) diff --git a/glymur/test/test_printing.py b/glymur/test/test_printing.py index 7a5f9b9..5eedfe5 100644 --- a/glymur/test/test_printing.py +++ b/glymur/test/test_printing.py @@ -107,14 +107,15 @@ class TestPrinting(unittest.TestCase): with self.assertRaises(TypeError): glymur.set_printoptions(hi='low') + @unittest.skipIf(re.match("1.5|2", glymur.version.openjpeg_version) is None, + "Must have openjpeg 1.5 or higher to run") def test_asoc_label_box(self): """verify printing of asoc, label boxes""" # Construct a fake file with an asoc and a label box, as # OpenJPEG doesn't have such a file. - data = glymur.Jp2k(self.jp2file).read(rlevel=1) + data = glymur.Jp2k(self.jp2file)[::2, ::2] with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - j = glymur.Jp2k(tfile.name, 'wb') - j.write(data) + j = glymur.Jp2k(tfile.name, data=data) with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile2: