diff -Nru glymur-0.9.6/appveyor.yml glymur-0.9.7/appveyor.yml --- glymur-0.9.6/appveyor.yml 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/appveyor.yml 2021-12-27 23:53:21.000000000 +0000 @@ -30,6 +30,12 @@ CONDA_PY: "39" CONDA_NPY: "21" + - CONDA_ROOT: "C:\\Miniconda3_64" + PYTHON_VERSION: "3.10" + PYTHON_ARCH: "64" + CONDA_PY: "310" + CONDA_NPY: "21" + # We always use a 64-bit machine, but can build x86 distributions # with the PYTHON_ARCH variable (which is used by CMD_IN_ENV). platform: @@ -73,7 +79,7 @@ - cmd: echo "installing requirements from %REQ% - done" # build em using the local source checkout in the correct windows env - - cmd: '%CMD_IN_ENV% python setup.py install' + - cmd: '%CMD_IN_ENV% python -m pip install -e .' test_script: # tests @@ -82,4 +88,4 @@ - cmd: cd c:\projects\glymur - ls -ltr - cmd: python -c "import sys; print(sys.executable)" - - cmd: c:\miniconda3_64\envs\glymur\python -m unittest discover -v + - cmd: c:\miniconda3_64\envs\glymur\Scripts\pytest -n 2 -x diff -Nru glymur-0.9.6/CHANGES.txt glymur-0.9.7/CHANGES.txt --- glymur-0.9.6/CHANGES.txt 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/CHANGES.txt 2021-12-27 23:53:21.000000000 +0000 @@ -1,3 +1,8 @@ +December 27, 2021 - v0.9.7 + Remove distutils in favor of setuptools + Add recognition of IMF profiles + Add ndim, dtype properties + November 04, 2021 - v0.9.6 Fix tiff support on windows. Update doc support for python 3.10. diff -Nru glymur-0.9.6/ci/travis-310.yaml glymur-0.9.7/ci/travis-310.yaml --- glymur-0.9.6/ci/travis-310.yaml 1970-01-01 00:00:00.000000000 +0000 +++ glymur-0.9.7/ci/travis-310.yaml 2021-12-27 23:53:21.000000000 +0000 @@ -0,0 +1,11 @@ +name: glymur +channels: + - conda-forge +dependencies: + - python=3.10.* + - gdal + - lxml + - numpy + - openjpeg + - libtiff + - pytest-xdist diff -Nru glymur-0.9.6/ci/travis-37.yaml glymur-0.9.7/ci/travis-37.yaml --- glymur-0.9.6/ci/travis-37.yaml 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/ci/travis-37.yaml 2021-12-27 23:53:21.000000000 +0000 @@ -9,3 +9,4 @@ - openjpeg - scikit-image - libtiff + - pytest-xdist diff -Nru glymur-0.9.6/ci/travis-38.yaml glymur-0.9.7/ci/travis-38.yaml --- glymur-0.9.6/ci/travis-38.yaml 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/ci/travis-38.yaml 2021-12-27 23:53:21.000000000 +0000 @@ -9,4 +9,5 @@ - openjpeg - scikit-image - libtiff + - pytest-xdist diff -Nru glymur-0.9.6/ci/travis-39.yaml glymur-0.9.7/ci/travis-39.yaml --- glymur-0.9.6/ci/travis-39.yaml 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/ci/travis-39.yaml 2021-12-27 23:53:21.000000000 +0000 @@ -1,6 +1,6 @@ name: glymur channels: - - conda-forge + - default dependencies: - python=3.9.* - gdal @@ -9,3 +9,4 @@ - openjpeg - scikit-image - libtiff + - pytest-xdist diff -Nru glymur-0.9.6/debian/changelog glymur-0.9.7/debian/changelog --- glymur-0.9.6/debian/changelog 2021-11-07 12:21:22.000000000 +0000 +++ glymur-0.9.7/debian/changelog 2021-12-30 09:18:54.000000000 +0000 @@ -1,3 +1,23 @@ +glymur (0.9.7-2) unstable; urgency=medium + + [ Bas Couwenberg ] + * Update build dependencies for pybuild-plugin-pyproject. + + [ Antonio Valentino ] + * debian/control: + - add missing (build) dependency on python3-packaging. + + -- Antonio Valentino Thu, 30 Dec 2021 09:18:54 +0000 + +glymur (0.9.7-1) unstable; urgency=medium + + * New upstream release. + * debian/control: + - drop dependency on pkg-resources, no longer needed + - use dh-python-pep517 instead of the standard dh-python. + + -- Antonio Valentino Wed, 29 Dec 2021 08:58:12 +0000 + glymur (0.9.6-1) unstable; urgency=medium [ Bas Couwenberg ] diff -Nru glymur-0.9.6/debian/control glymur-0.9.7/debian/control --- glymur-0.9.6/debian/control 2021-11-07 12:21:22.000000000 +0000 +++ glymur-0.9.7/debian/control 2021-12-30 09:18:54.000000000 +0000 @@ -9,10 +9,11 @@ dh-python, libopenjp2-7, procps, + pybuild-plugin-pyproject, python3-all, python3-lxml, python3-numpy, - python3-pkg-resources, + python3-packaging, python3-setuptools, python3-skimage Standards-Version: 4.6.0 @@ -24,7 +25,7 @@ Architecture: all Depends: libopenjp2-7, python3-numpy, - python3-pkg-resources, + python3-packaging, ${python3:Depends}, ${misc:Depends} Recommends: python3-lxml diff -Nru glymur-0.9.6/docs/source/conf.py glymur-0.9.7/docs/source/conf.py --- glymur-0.9.6/docs/source/conf.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/docs/source/conf.py 2021-12-27 23:53:21.000000000 +0000 @@ -78,7 +78,7 @@ # The short X.Y version. version = '0.9' # The full version, including alpha/beta/rc tags. -release = '0.9.6' +release = '0.9.7' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff -Nru glymur-0.9.6/docs/source/whatsnew/0.9.rst glymur-0.9.7/docs/source/whatsnew/0.9.rst --- glymur-0.9.6/docs/source/whatsnew/0.9.rst 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/docs/source/whatsnew/0.9.rst 2021-12-27 23:53:21.000000000 +0000 @@ -3,6 +3,14 @@ ##################### **************** +Changes in 0.9.7 +**************** + + Remove distutils in favor of setuptools. + Add recognition of IMF profiles. + Add ndim, dtype properties. + +**************** Changes in 0.9.6 **************** @@ -15,6 +23,7 @@ * Add support for generation of PLT markers. * Add support for converting TIFFs to JPEG 2000. + * Add recognition of additional IMF profiles. **************** Changes in 0.9.4 diff -Nru glymur-0.9.6/glymur/codestream.py glymur-0.9.7/glymur/codestream.py --- glymur-0.9.6/glymur/codestream.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/glymur/codestream.py 2021-12-27 23:53:21.000000000 +0000 @@ -39,17 +39,84 @@ _PROFILE_3 = 3 _PROFILE_4 = 4 -_KNOWN_PROFILES = [_NO_PROFILE, _PROFILE_0, _PROFILE_1, _PROFILE_3, _PROFILE_4] +# no profile, conform to 15444-1 +_PROFILE_NONE = 0x0000 + +# Profile 0 as described in 15444-1,Table A.45 +_PROFILE_0 = 0x0001 + +# Profile 1 as described in 15444-1,Table A.45 +_PROFILE_1 = 0x0002 + +# At least 1 extension defined in 15444-2 (Part-2) +_PROFILE_PART2 = 0x8000 + +# 2K cinema profile defined in 15444-1 AMD1 +_PROFILE_CINEMA_2K = 0x0003 + +# 4K cinema profile defined in 15444-1 AMD1 +_PROFILE_CINEMA_4K = 0x0004 + +# Scalable 2K cinema profile defined in 15444-1 AMD2 +_PROFILE_CINEMA_S2K = 0x0005 + +# Scalable 4K cinema profile defined in 15444-1 AMD2 +_PROFILE_CINEMA_S4K = 0x0006 + +# Long term storage cinema profile defined in 15444-1 AMD2 +_PROFILE_CINEMA_LTS = 0x0007 + +# Single Tile Broadcast profile defined in 15444-1 AMD3 +_PROFILE_BC_SINGLE = 0x0100 + +# Multi Tile Broadcast profile defined in 15444-1 AMD3 +_PROFILE_BC_MULTI = 0x0200 + +# Multi Tile Reversible Broadcast profile defined in 15444-1 AMD3 +_PROFILE_BC_MULTI_R = 0x0300 + +# 2K Single Tile Lossy IMF profile defined in 15444-1 AMD 8 +_PROFILE_IMF_2K = 0x0400 + +# 4K Single Tile Lossy IMF profile defined in 15444-1 AMD 8 +_PROFILE_IMF_4K = 0x0500 + +# 8K Single Tile Lossy IMF profile defined in 15444-1 AMD 8 +_PROFILE_IMF_8K = 0x0600 + +# 2K Single/Multi Tile Reversible IMF profile defined in 15444-1 AMD 8 +_PROFILE_IMF_2K_R = 0x0700 + +# 4K Single/Multi Tile Reversible IMF profile defined in 15444-1 AMD 8 +_PROFILE_IMF_4K_R = 0x0800 + +# 8K Single/Multi Tile Reversible IMF profile defined in 15444-1 AMD 8 +_PROFILE_IMF_8K_R = 0x0900 # How to display the codestream profile. _CAPABILITIES_DISPLAY = { - _NO_PROFILE: 'no profile', + _PROFILE_NONE: 'no profile', _PROFILE_0: '0', _PROFILE_1: '1', - _PROFILE_3: 'Cinema 2K', - _PROFILE_4: 'Cinema 4K', + _PROFILE_PART2: 'at least 1 extension defined in 15444-2 (Part-2)', + _PROFILE_CINEMA_2K: '2K cinema', + _PROFILE_CINEMA_4K: '4K cinema', + _PROFILE_CINEMA_S2K: 'scalable 2K cinema', + _PROFILE_CINEMA_S4K: 'scalable 4K cinema', + _PROFILE_CINEMA_LTS: 'long term storage cinema', + _PROFILE_BC_SINGLE: 'single tile broadcast', + _PROFILE_BC_MULTI: 'multi tile broadcast', + _PROFILE_BC_MULTI_R: 'multi tile reversible broadcast', + _PROFILE_IMF_2K: '2K single tile lossy IMF', + _PROFILE_IMF_4K: '4K single tile lossy IMF', + _PROFILE_IMF_8K: '8K single tile lossy IMF', + _PROFILE_IMF_2K_R: '2K single/multi tile reversible IMF', + _PROFILE_IMF_4K_R: '4K single/multi tile reversible IMF', + _PROFILE_IMF_8K_R: '8K single/multi tile reversible IMF', } +_KNOWN_PROFILES = _CAPABILITIES_DISPLAY.keys() + class Codestream(object): """Container for codestream information. diff -Nru glymur-0.9.6/glymur/jp2k.py glymur-0.9.7/glymur/jp2k.py --- glymur-0.9.6/glymur/jp2k.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/glymur/jp2k.py 2021-12-27 23:53:21.000000000 +0000 @@ -191,6 +191,8 @@ self._tilesize = tilesize self._shape = None + self._ndim = None + self._dtype = None self._ignore_pclr_cmap_cdef = False self._verbose = verbose @@ -370,6 +372,45 @@ self._layer = layer @property + def dtype(self): + """ + Datatype of the image elements. + """ + if self._dtype is None: + c = self.get_codestream() + bps0 = c.segment[1].bitdepth[0] + sgnd0 = c.segment[1].signed[0] + + if ( + all(bitdepth == bps0 for bitdepth in c.segment[1].bitdepth) + and all(signed == sgnd0 for signed in c.segment[1].signed) + ): + if bps0 <= 8: + self._dtype = np.int8 if sgnd0 else np.uint8 + else: + self._dtype = np.int16 if sgnd0 else np.uint16 + else: + msg = ( + "The dtype property is only valid when all components " + "have the same bitdepth and sign. " + "\n\n" + f"{c.segment[1]}" + ) + raise TypeError(msg) + + return self._dtype + + @property + def ndim(self): + """ + Number of image dimensions. + """ + if self._ndim is None: + self._ndim = len(self.shape) + + return self._ndim + + @property def codestream(self): if self._codestream is None: self._codestream = self.get_codestream(header_only=True) diff -Nru glymur-0.9.6/glymur/lib/tiff.py glymur-0.9.7/glymur/lib/tiff.py --- glymur-0.9.6/glymur/lib/tiff.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/glymur/lib/tiff.py 2021-12-27 23:53:21.000000000 +0000 @@ -3,6 +3,7 @@ from enum import IntEnum import os import queue +import re import warnings # 3rd party library imports @@ -582,8 +583,7 @@ # libtiff not installed return '0.0.0' - v = _LIBTIFF.TIFFGetVersion() - v = v.decode('utf-8') + v = _LIBTIFF.TIFFGetVersion().decode('utf-8') # v would be something like # @@ -592,8 +592,8 @@ # Copyright (c) 1991-1996 Silicon Graphics, Inc. # # All we want is the '4.3.0' - version = v.splitlines()[0].split()[2] - return version + m = re.search(r'(?P\d+\.\d+\.\d+)', v) + return m.group('version') def open(filename, mode='r'): diff -Nru glymur-0.9.6/glymur/version.py glymur-0.9.7/glymur/version.py --- glymur-0.9.6/glymur/version.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/glymur/version.py 2021-12-27 23:53:21.000000000 +0000 @@ -12,7 +12,7 @@ import sys # Third party library imports ... -from distutils.version import LooseVersion +from packaging.version import parse import numpy as np # Local imports ... @@ -21,15 +21,14 @@ # Do not change the format of this next line! Doing so risks breaking # setup.py -version = "0.9.6" -_sv = LooseVersion(version) -version_tuple = _sv.version +version = "0.9.7" + +version_tuple = parse(version).release openjpeg_version = opj2.version() -tiff_version = tiff.getVersion() +openjpeg_version_tuple = parse(openjpeg_version).release -_sv = LooseVersion(openjpeg_version) -openjpeg_version_tuple = _sv.version +tiff_version = tiff.getVersion() __doc__ = f"""\ This is glymur **{version}** diff -Nru glymur-0.9.6/pyproject.toml glymur-0.9.7/pyproject.toml --- glymur-0.9.6/pyproject.toml 1970-01-01 00:00:00.000000000 +0000 +++ glymur-0.9.7/pyproject.toml 2021-12-27 23:53:21.000000000 +0000 @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" diff -Nru glymur-0.9.6/setup.cfg glymur-0.9.7/setup.cfg --- glymur-0.9.6/setup.cfg 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/setup.cfg 2021-12-27 23:53:21.000000000 +0000 @@ -1,13 +1,44 @@ -[flake8] -exclude = build -ignore = E402,W503 -[nosetests] -# std library unit testing uses "load_tests" to hook into -# doctests, but nose doesn't like it. -exclude=load_tests -with-coverage=1 -cover-erase=1 -cover-html=1 -cover-html-dir=cover -cover-tests=1 -cover-package=glymur,tests +[metadata] +name = glymur +version = 0.9.7 +author = 'John Evans' +author_email = 'john.g.evans.ne@gmail.com' +license = 'MIT' +long_description_content_type = 'text/markdown', +long_description = + **glymur** contains a Python interface to the OpenJPEG library which + allows one to read and write JPEG 2000 files. + +url = 'https://github.com/quintusdias/glymur' +classifiers = + Programming Language :: Python" + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Programming Language :: Python :: Implementation :: CPython + License :: OSI Approved :: MIT License + Intended Audience :: Science/Research + Operating System :: OS Independent + Topic :: Scientific/Engineering + +[options] +packages = find: +install_requires = + numpy + lxml + setuptools +python_requires = >=3.7 +include_package_data = True +zip_safe = False + +[options.entry_points] +console_scripts = + jp2dump = glymur.command_line:main + tiff2jp2 = glymur.command_line:tiff2jp2 + +[options.package_data] +glymur = + data/*.jp2 + data/*.jpx + data/*.j2k diff -Nru glymur-0.9.6/setup.py glymur-0.9.7/setup.py --- glymur-0.9.6/setup.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/setup.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -# Standard library imports ... -import pathlib -import re - -# Third party library imports ... -from setuptools import setup - -kwargs = { - 'name': 'Glymur', - 'description': 'Tools for accessing JPEG2000 files', - 'long_description': open('README.md').read(), - 'author': 'John Evans', - 'author_email': 'john.g.evans.ne@gmail.com', - 'url': 'https://github.com/quintusdias/glymur', - 'packages': ['glymur', 'glymur.data', 'glymur.lib', 'tests'], - 'package_data': {'glymur': ['data/*.jp2', 'data/*.j2k', 'data/*.jpx']}, - 'entry_points': { - 'console_scripts': [ - 'jp2dump=glymur.command_line:main', - 'tiff2jp2=glymur.command_line:tiff2jp2' - ], - }, - 'license': 'MIT', - 'test_suite': 'glymur.test', - 'install_requires': ['lxml', 'numpy', 'setuptools'], -} - -kwargs['classifiers'] = [ - "Programming Language :: Python", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: Implementation :: CPython", - "License :: OSI Approved :: MIT License", - "Development Status :: 5 - Production/Stable", - "Operating System :: MacOS", - "Operating System :: POSIX :: Linux", - "Operating System :: Microsoft :: Windows :: Windows XP", - "Intended Audience :: Science/Research", - "Intended Audience :: Information Technology", - "Topic :: Software Development :: Libraries :: Python Modules" -] - -# Get the version string. Cannot do this by importing glymur! -p = pathlib.Path('glymur') / 'version.py' -contents = p.read_text() -pattern = r'''version\s=\s"(?P\d*.\d*.\d*.*)"\s''' -match = re.search(pattern, contents) -kwargs['version'] = match.group('version') - -setup(**kwargs) Binary files /tmp/tmpa4u969fn/j2Yu6DRkhw/glymur-0.9.6/tests/data/0220000800/uuid.dat and /tmp/tmpa4u969fn/5Alf5OzJus/glymur-0.9.7/tests/data/0220000800/uuid.dat differ Binary files /tmp/tmpa4u969fn/j2Yu6DRkhw/glymur-0.9.6/tests/data/0220000800_uuid.dat and /tmp/tmpa4u969fn/5Alf5OzJus/glymur-0.9.7/tests/data/0220000800_uuid.dat differ Binary files /tmp/tmpa4u969fn/j2Yu6DRkhw/glymur-0.9.6/tests/data/issue982.j2k and /tmp/tmpa4u969fn/5Alf5OzJus/glymur-0.9.7/tests/data/issue982.j2k differ Binary files /tmp/tmpa4u969fn/j2Yu6DRkhw/glymur-0.9.6/tests/data/uint16.j2k and /tmp/tmpa4u969fn/5Alf5OzJus/glymur-0.9.7/tests/data/uint16.j2k differ diff -Nru glymur-0.9.6/tests/fixtures.py glymur-0.9.7/tests/fixtures.py --- glymur-0.9.6/tests/fixtures.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/tests/fixtures.py 2021-12-27 23:53:21.000000000 +0000 @@ -13,6 +13,15 @@ _HAVE_GDAL = True except ModuleNotFoundError: _HAVE_GDAL = False +try: + import skimage.data # noqa : F401 + import skimage.io # noqa : F401 + import skimage.metrics # noqa : F401 + HAVE_SCIKIT_IMAGE = True + HAVE_SCIKIT_IMAGE_MSG = None +except ModuleNotFoundError: + HAVE_SCIKIT_IMAGE = False + HAVE_SCIKIT_IMAGE_MSG = 'scikit-image not available' import numpy as np # Local imports @@ -37,6 +46,7 @@ TIFF_NOT_AVAILABLE = False TIFF_NOT_AVAILABLE_MSG = None + class TestCommon(unittest.TestCase): """ Common setup for many if not all tests. diff -Nru glymur-0.9.6/tests/test_callbacks.py glymur-0.9.7/tests/test_callbacks.py --- glymur-0.9.6/tests/test_callbacks.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/tests/test_callbacks.py 2021-12-27 23:53:21.000000000 +0000 @@ -7,16 +7,14 @@ import unittest from unittest.mock import patch -# 3rd party library imports -import skimage.data - # Local imports ... import glymur from . import fixtures -@unittest.skipIf(fixtures.OPENJPEG_NOT_AVAILABLE, - fixtures.OPENJPEG_NOT_AVAILABLE_MSG) +@unittest.skipIf( + fixtures.OPENJPEG_NOT_AVAILABLE, fixtures.OPENJPEG_NOT_AVAILABLE_MSG +) class TestSuite(fixtures.TestCommon): """Test suite for callbacks.""" @@ -70,6 +68,9 @@ self.assertIn('[INFO]', actual) + @unittest.skipIf( + not fixtures.HAVE_SCIKIT_IMAGE, fixtures.HAVE_SCIKIT_IMAGE_MSG + ) def test_info_callbacks_on_writing_tiles(self): """ SCENARIO: the verbose attribute is set to True @@ -77,7 +78,7 @@ EXPECTED RESULT: The info callback handler should be enabled. There should be [INFO] output present in sys.stdout. """ - jp2_data = skimage.data.moon() + jp2_data = fixtures.skimage.data.moon() shape = jp2_data.shape[0] * 3, jp2_data.shape[1] * 2 tilesize = (jp2_data.shape[0], jp2_data.shape[1]) diff -Nru glymur-0.9.6/tests/test_cinema.py glymur-0.9.7/tests/test_cinema.py --- glymur-0.9.6/tests/test_cinema.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/tests/test_cinema.py 2021-12-27 23:53:21.000000000 +0000 @@ -30,27 +30,40 @@ def check_cinema4k_codestream(self, codestream, image_size): - kwargs = {'rsiz': 4, 'xysiz': image_size, 'xyosiz': (0, 0), - 'xytsiz': image_size, 'xytosiz': (0, 0), - 'bitdepth': (12, 12, 12), 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + kwargs = { + 'rsiz': 4, + 'xysiz': image_size, + 'xyosiz': (0, 0), + 'xytsiz': image_size, + 'xytosiz': (0, 0), + 'bitdepth': (12, 12, 12), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)] + } self.verifySizSegment(codestream.segment[1], SIZsegment(**kwargs)) self.verify_cinema_cod(codestream.segment[2]) def check_cinema2k_codestream(self, codestream, image_size): - kwargs = {'rsiz': 3, 'xysiz': image_size, 'xyosiz': (0, 0), - 'xytsiz': image_size, 'xytosiz': (0, 0), - 'bitdepth': (12, 12, 12), 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + kwargs = { + 'rsiz': 3, + 'xysiz': image_size, + 'xyosiz': (0, 0), + 'xytsiz': image_size, + 'xytosiz': (0, 0), + 'bitdepth': (12, 12, 12), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)] + } self.verifySizSegment(codestream.segment[1], SIZsegment(**kwargs)) self.verify_cinema_cod(codestream.segment[2]) -@unittest.skipIf(fixtures.OPENJPEG_NOT_AVAILABLE, - fixtures.OPENJPEG_NOT_AVAILABLE_MSG) +@unittest.skipIf( + fixtures.OPENJPEG_NOT_AVAILABLE, fixtures.OPENJPEG_NOT_AVAILABLE_MSG +) class WriteCinema(CinemaBase): @classmethod diff -Nru glymur-0.9.6/tests/test_codestream.py glymur-0.9.7/tests/test_codestream.py --- glymur-0.9.6/tests/test_codestream.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/tests/test_codestream.py 2021-12-27 23:53:21.000000000 +0000 @@ -112,15 +112,17 @@ 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))} + 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') diff -Nru glymur-0.9.6/tests/test_colour_specification_box.py glymur-0.9.7/tests/test_colour_specification_box.py --- glymur-0.9.6/tests/test_colour_specification_box.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/tests/test_colour_specification_box.py 2021-12-27 23:53:21.000000000 +0000 @@ -42,8 +42,11 @@ self.ftyp = FileTypeBox() self.jp2h = JP2HeaderBox() self.jp2c = ContiguousCodestreamBox() - self.ihdr = ImageHeaderBox(height=height, width=width, - num_components=num_components) + self.ihdr = ImageHeaderBox( + height=height, + width=width, + num_components=num_components + ) self.icc_profile = ir.read_binary(data, 'sgray.icc') @@ -190,20 +193,28 @@ self.assertEqual(box.icc_profile_header['Size'], 1328) self.assertEqual(box.icc_profile_header['Color Space'], 'RGB') self.assertEqual(box.icc_profile_header['Connection Space'], 'XYZ') - self.assertEqual(box.icc_profile_header['Datetime'], - datetime(2009, 2, 25, 11, 26, 11)) + self.assertEqual( + box.icc_profile_header['Datetime'], + datetime(2009, 2, 25, 11, 26, 11) + ) self.assertEqual(box.icc_profile_header['File Signature'], 'acsp') self.assertEqual(box.icc_profile_header['Platform'], 'APPL') - self.assertEqual(box.icc_profile_header['Flags'], - 'not embedded, can be used independently') + self.assertEqual( + box.icc_profile_header['Flags'], + 'not embedded, can be used independently' + ) self.assertEqual(box.icc_profile_header['Device Manufacturer'], 'appl') self.assertEqual(box.icc_profile_header['Device Model'], '') - self.assertEqual(box.icc_profile_header['Device Attributes'], - ('reflective, glossy, positive media polarity, ' - 'color media')) - self.assertEqual(box.icc_profile_header['Rendering Intent'], - 'perceptual') - np.testing.assert_almost_equal(box.icc_profile_header['Illuminant'], - np.array([0.9642023, 1.0, 0.824905]), - decimal=6) + self.assertEqual( + box.icc_profile_header['Device Attributes'], + 'reflective, glossy, positive media polarity, color media' + ) + self.assertEqual( + box.icc_profile_header['Rendering Intent'], 'perceptual' + ) + np.testing.assert_almost_equal( + box.icc_profile_header['Illuminant'], + np.array([0.9642023, 1.0, 0.824905]), + decimal=6 + ) self.assertEqual(box.icc_profile_header['Creator'], 'appl') diff -Nru glymur-0.9.6/tests/test_jp2box_jpx.py glymur-0.9.7/tests/test_jp2box_jpx.py --- glymur-0.9.6/tests/test_jp2box_jpx.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/tests/test_jp2box_jpx.py 2021-12-27 23:53:21.000000000 +0000 @@ -69,9 +69,11 @@ dr_idx.append(1) # Make the url box for this codestream. - url1 = DataEntryURLBox(0, - [0, 0, 0], - f'file://{self.temp_jp2_filename}') + url1 = DataEntryURLBox( + 0, + [0, 0, 0], + f'file://{self.temp_jp2_filename}' + ) url1_name_len = len(url1.url) + 1 # Wrap our own J2K file as a JP2 file. @@ -87,10 +89,13 @@ # Make the url box for this codestream. url2 = DataEntryURLBox(0, [0, 0, 0], 'file://{file2}') - boxes = [JPEG2000SignatureBox(), - FileTypeBox(brand='jpx ', - compatibility_list=['jpx ', 'jp2 ', 'jpxb']), - jp2h] + boxes = [ + JPEG2000SignatureBox(), + FileTypeBox( + brand='jpx ', compatibility_list=['jpx ', 'jp2 ', 'jpxb'] + ), + jp2h + ] with open(self.temp_jpx_filename, mode='wb') as tjpx: for box in boxes: box.write(tjpx) @@ -106,8 +111,9 @@ jpx_no_jp2c = Jp2k(tjpx.name) jpx_boxes = [box.box_id for box in jpx_no_jp2c.box] - self.assertEqual(jpx_boxes, ['jP ', 'ftyp', 'jp2h', - 'ftbl', 'dtbl']) + self.assertEqual( + jpx_boxes, ['jP ', 'ftyp', 'jp2h', 'ftbl', 'dtbl'] + ) self.assertEqual(jpx_no_jp2c.box[4].DR[0].offset, 141) offset = 141 + 8 + 4 + url1_name_len @@ -615,14 +621,23 @@ struct.pack_into('>H', rreq_buffer, 15, 11) standard_flags = [5, 42, 45, 2, 18, 19, 1, 8, 12, 31, 20] - standard_masks = [8388608, 4194304, 2097152, 1048576, 524288, 262144, - 131072, 65536, 32768, 16384, 8192] + standard_masks = [ + 8388608, 4194304, 2097152, 1048576, 524288, 262144, 131072, 65536, + 32768, 16384, 8192 + ] for j in range(len(standard_flags)): - mask = (standard_masks[j] >> 16, - standard_masks[j] & 0x0000ffff >> 8, - standard_masks[j] & 0x000000ff) - struct.pack_into('>HBBB', rreq_buffer, 17 + j * 5, - standard_flags[j], *mask) + mask = ( + standard_masks[j] >> 16, + standard_masks[j] & 0x0000ffff >> 8, + standard_masks[j] & 0x000000ff + ) + struct.pack_into( + '>HBBB', + rreq_buffer, + 17 + j * 5, + standard_flags[j], + *mask + ) # num vendor features: 0 struct.pack_into('>H', rreq_buffer, 72, 0) diff -Nru glymur-0.9.6/tests/test_jp2box.py glymur-0.9.7/tests/test_jp2box.py --- glymur-0.9.6/tests/test_jp2box.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/tests/test_jp2box.py 2021-12-27 23:53:21.000000000 +0000 @@ -65,8 +65,7 @@ file2 = self.test_dir_path / 'file2.jp2' jp2 = j2k.wrap(file2) - self.assertEqual(jp2.box[2].box[1].colorspace, - glymur.core.GREYSCALE) + self.assertEqual(jp2.box[2].box[1].colorspace, glymur.core.GREYSCALE) def test_basic_url(self): """Just your most basic URL box.""" @@ -105,8 +104,9 @@ with open(tfile.name, 'rb') as fptr: fptr.seek(jp22.box[-1].offset + 4 + 4 + 1 + 3) - nbytes = (jp22.box[-1].offset - + jp22.box[-1].length - fptr.tell()) + nbytes = ( + jp22.box[-1].offset + jp22.box[-1].length - fptr.tell() + ) read_buffer = fptr.read(nbytes) read_url = read_buffer.decode('utf-8') self.assertEqual(url + chr(0), read_url) @@ -156,14 +156,18 @@ self.ftyp = FileTypeBox() self.jp2h = JP2HeaderBox() self.jp2c = ContiguousCodestreamBox() - self.ihdr = ImageHeaderBox(height=height, width=width, - num_components=num_components) - self.ihdr1 = ImageHeaderBox(height=height, width=width, - num_components=1) - self.ihdr2 = ImageHeaderBox(height=height, width=width, - num_components=2) - self.ihdr4 = ImageHeaderBox(height=height, width=width, - num_components=4) + self.ihdr = ImageHeaderBox( + height=height, width=width, num_components=num_components + ) + self.ihdr1 = ImageHeaderBox( + height=height, width=width, num_components=1 + ) + self.ihdr2 = ImageHeaderBox( + height=height, width=width, num_components=2 + ) + self.ihdr4 = ImageHeaderBox( + height=height, width=width, num_components=4 + ) self.colr_rgb = ColourSpecificationBox(colorspace=SRGB) self.colr_gr = ColourSpecificationBox(colorspace=GREYSCALE) @@ -177,9 +181,11 @@ j2k = Jp2k(self.j2kfile) channel_type = [COLOR, COLOR, COLOR] association = [RED, GREEN, BLUE] - cdef = glymur.jp2box.ChannelDefinitionBox(index=[0, 1, 2], - channel_type=channel_type, - association=association) + cdef = glymur.jp2box.ChannelDefinitionBox( + index=[0, 1, 2], + channel_type=channel_type, + association=association + ) boxes = [self.ihdr, self.colr_rgb, cdef] self.jp2h.box = boxes boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c] @@ -191,18 +197,21 @@ boxes = [box.box_id for box in jp2h.box] self.assertEqual(boxes, ['ihdr', 'colr', 'cdef']) self.assertEqual(jp2h.box[2].index, (0, 1, 2)) - self.assertEqual(jp2h.box[2].channel_type, - (COLOR, COLOR, COLOR)) - self.assertEqual(jp2h.box[2].association, - (RED, GREEN, BLUE)) + self.assertEqual( + jp2h.box[2].channel_type, (COLOR, COLOR, COLOR) + ) + self.assertEqual( + jp2h.box[2].association, (RED, GREEN, BLUE) + ) def test_rgb(self): """Just regular RGB, but don't supply the optional index.""" j2k = Jp2k(self.j2kfile) channel_type = [COLOR, COLOR, COLOR] association = [RED, GREEN, BLUE] - cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type, - association=association) + cdef = glymur.jp2box.ChannelDefinitionBox( + channel_type=channel_type, association=association + ) boxes = [self.ihdr, self.colr_rgb, cdef] self.jp2h.box = boxes boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c] @@ -214,18 +223,21 @@ boxes = [box.box_id for box in jp2h.box] self.assertEqual(boxes, ['ihdr', 'colr', 'cdef']) self.assertEqual(jp2h.box[2].index, (0, 1, 2)) - self.assertEqual(jp2h.box[2].channel_type, - (COLOR, COLOR, COLOR)) - self.assertEqual(jp2h.box[2].association, - (RED, GREEN, BLUE)) + self.assertEqual( + jp2h.box[2].channel_type, (COLOR, COLOR, COLOR) + ) + self.assertEqual( + jp2h.box[2].association, (RED, GREEN, BLUE) + ) def test_rgba(self): """Just regular RGBA.""" j2k = Jp2k(self.four_planes) channel_type = (COLOR, COLOR, COLOR, OPACITY) association = (RED, GREEN, BLUE, WHOLE_IMAGE) - cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type, - association=association) + cdef = glymur.jp2box.ChannelDefinitionBox( + channel_type=channel_type, association=association + ) boxes = [self.ihdr4, self.colr_rgb, cdef] self.jp2h.box = boxes boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c] @@ -246,8 +258,9 @@ j2k = Jp2k(self.four_planes) channel_type = (COLOR, COLOR, OPACITY, OPACITY) association = (RED, GREEN, BLUE, WHOLE_IMAGE) - cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type, - association=association) + cdef = glymur.jp2box.ChannelDefinitionBox( + channel_type=channel_type, association=association + ) boxes = [self.ihdr, self.colr_rgb, cdef] self.jp2h.box = boxes boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c] @@ -260,8 +273,9 @@ j2k = Jp2k(self.one_plane) channel_type = (COLOR,) association = (GREY,) - cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type, - association=association) + cdef = glymur.jp2box.ChannelDefinitionBox( + channel_type=channel_type, association=association + ) boxes = [self.ihdr1, self.colr_gr, cdef] self.jp2h.box = boxes boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c] @@ -281,8 +295,9 @@ j2k = Jp2k(self.two_planes) channel_type = (COLOR, OPACITY) association = (GREY, WHOLE_IMAGE) - cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type, - association=association) + cdef = glymur.jp2box.ChannelDefinitionBox( + channel_type=channel_type, association=association + ) boxes = [self.ihdr2, self.colr_gr, cdef] self.jp2h.box = boxes boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c] @@ -305,8 +320,9 @@ association = (GREY, WHOLE_IMAGE) # This cdef box - cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type, - association=association) + cdef = glymur.jp2box.ChannelDefinitionBox( + channel_type=channel_type, association=association + ) boxes = [self.ihdr, self.colr_gr, cdef] self.jp2h.box = boxes boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c] @@ -320,8 +336,9 @@ channel_type = (COLOR, COLOR, COLOR) association = (RED, GREEN, BLUE) - cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type, - association=association) + cdef = glymur.jp2box.ChannelDefinitionBox( + channel_type=channel_type, association=association + ) boxes = [self.ihdr, cdef, self.colr_rgb, cdef] self.jp2h.box = boxes @@ -340,8 +357,9 @@ channel_type = (COLOR, COLOR, COLOR) association = (RED, GREEN, BLUE) - cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type, - association=association) + cdef = glymur.jp2box.ChannelDefinitionBox( + channel_type=channel_type, association=association + ) boxes = [self.jp2b, self.ftyp, self.jp2h, cdef, self.jp2c] @@ -408,8 +426,9 @@ palette = np.array([[255, 0, 255], [0, 255, 0]], dtype=np.uint16) bps = (8, 16, 8) signed = (False, False, False) - pclr = glymur.jp2box.PaletteBox(palette, bits_per_component=bps, - signed=signed) + pclr = glymur.jp2box.PaletteBox( + palette, bits_per_component=bps, signed=signed + ) with open(self.temp_jp2_filename, mode='wb') as tfile: with self.assertRaises(InvalidJp2kError): pclr.write(tfile) @@ -464,8 +483,10 @@ box_ids = [box.box_id for box in jp2.box] expected = ['jP ', 'ftyp', 'jp2h', 'uuid', 'jp2c', 'xml '] self.assertEqual(box_ids, expected) - self.assertEqual(ET.tostring(jp2.box[-1].xml.getroot()), - b'0') + self.assertEqual( + ET.tostring(jp2.box[-1].xml.getroot()), + b'0' + ) def test_only_jp2_allowed_to_append(self): """Only JP2 files are allowed to be appended.""" @@ -514,8 +535,10 @@ box_ids = [box.box_id for box in jp2.box] expected = ['jP ', 'ftyp', 'jp2h', 'uuid', 'jp2c', 'xml '] self.assertEqual(box_ids, expected) - self.assertEqual(ET.tostring(jp2.box[-1].xml.getroot()), - b'0') + self.assertEqual( + ET.tostring(jp2.box[-1].xml.getroot()), + b'0' + ) def test_append_allowable_boxes(self): """Only XML boxes are allowed to be appended.""" @@ -677,18 +700,22 @@ def test_default_layout_with_boxes(self): """basic test for rewrapping a jp2 file, boxes specified""" j2k = Jp2k(self.j2kfile) - boxes = [JPEG2000SignatureBox(), - FileTypeBox(), - JP2HeaderBox(), - ContiguousCodestreamBox()] + boxes = [ + JPEG2000SignatureBox(), + FileTypeBox(), + JP2HeaderBox(), + ContiguousCodestreamBox() + ] codestream = j2k.get_codestream() height = codestream.segment[1].ysiz width = codestream.segment[1].xsiz num_components = len(codestream.segment[1].xrsiz) - boxes[2].box = [ImageHeaderBox(height=height, - width=width, - num_components=num_components), - ColourSpecificationBox(colorspace=glymur.core.SRGB)] + boxes[2].box = [ + ImageHeaderBox( + height=height, width=width, num_components=num_components + ), + ColourSpecificationBox(colorspace=glymur.core.SRGB) + ] with open(self.temp_jp2_filename, mode='wb') as tfile: j2k.wrap(tfile.name, boxes=boxes) self.verify_wrapped_raw(tfile.name) @@ -696,18 +723,22 @@ def test_ihdr_not_first_in_jp2h(self): """The specification says that ihdr must be the first box in jp2h.""" j2k = Jp2k(self.j2kfile) - boxes = [JPEG2000SignatureBox(), - FileTypeBox(), - JP2HeaderBox(), - ContiguousCodestreamBox()] + boxes = [ + JPEG2000SignatureBox(), + FileTypeBox(), + JP2HeaderBox(), + ContiguousCodestreamBox() + ] codestream = j2k.get_codestream() height = codestream.segment[1].ysiz width = codestream.segment[1].xsiz num_components = len(codestream.segment[1].xrsiz) - boxes[2].box = [ColourSpecificationBox(colorspace=glymur.core.SRGB), - ImageHeaderBox(height=height, - width=width, - num_components=num_components)] + boxes[2].box = [ + ColourSpecificationBox(colorspace=glymur.core.SRGB), + ImageHeaderBox( + height=height, width=width, num_components=num_components + ) + ] with open(self.temp_jp2_filename, mode='wb') as tfile: with self.assertRaises(RuntimeError): j2k.wrap(tfile.name, boxes=boxes) @@ -725,8 +756,9 @@ jp2h = JP2HeaderBox() jp2c = ContiguousCodestreamBox() colr = ColourSpecificationBox(colorspace=glymur.core.SRGB) - ihdr = ImageHeaderBox(height=height, width=width, - num_components=num_components) + ihdr = ImageHeaderBox( + height=height, width=width, num_components=num_components + ) jp2h.box = [ihdr, colr] boxes = [ftyp, jp2b, jp2h, jp2c] with open(self.temp_jp2_filename, mode='wb') as tfile: @@ -737,9 +769,9 @@ """A palette box must reside in a JP2 header box.""" palette = np.array([[255, 0, 255], [0, 255, 0]], dtype=np.int32) bps = (8, 8, 8) - pclr = glymur.jp2box.PaletteBox(palette=palette, - bits_per_component=bps, - signed=(True, False, True)) + pclr = glymur.jp2box.PaletteBox( + palette=palette, bits_per_component=bps, signed=(True, False, True) + ) j2k = Jp2k(self.j2kfile) codestream = j2k.get_codestream() @@ -752,8 +784,9 @@ jp2h = JP2HeaderBox() jp2c = ContiguousCodestreamBox() colr = ColourSpecificationBox(colorspace=glymur.core.SRGB) - ihdr = ImageHeaderBox(height=height, width=width, - num_components=num_components) + ihdr = ImageHeaderBox( + height=height, width=width, num_components=num_components + ) jp2h.box = [ihdr, colr] boxes = [jp2b, ftyp, jp2h, jp2c, pclr] with open(self.temp_jp2_filename, mode='wb') as tfile: @@ -773,8 +806,9 @@ jp2h = JP2HeaderBox() jp2c = ContiguousCodestreamBox() colr = ColourSpecificationBox(colorspace=glymur.core.SRGB) - ihdr = ImageHeaderBox(height=height, width=width, - num_components=num_components) + ihdr = ImageHeaderBox( + height=height, width=width, num_components=num_components + ) jp2h.box = [ihdr, colr] boxes = [jp2b, ftyp, jp2c, jp2h] with open(self.temp_jp2_filename, mode='wb') as tfile: @@ -792,8 +826,9 @@ jp2k = JPEG2000SignatureBox() ftyp = FileTypeBox() jp2h = JP2HeaderBox() - ihdr = ImageHeaderBox(height=height, width=width, - num_components=num_components) + ihdr = ImageHeaderBox( + height=height, width=width, num_components=num_components + ) jp2h.box = [ihdr] boxes = [jp2k, ftyp, jp2h] with open(self.temp_jp2_filename, mode='wb') as tfile: @@ -804,8 +839,12 @@ """A JPX file rewrapped with plain jpch is not allowed.""" with open(self.temp_jp2_filename, mode='wb') as tfile1: jpx = Jp2k(self.jpxfile) - boxes = [jpx.box[0], jpx.box[1], jpx.box[2], - glymur.jp2box.ContiguousCodestreamBox()] + boxes = [ + jpx.box[0], + jpx.box[1], + jpx.box[2], + glymur.jp2box.ContiguousCodestreamBox() + ] with self.assertRaises(RuntimeError): jpx.wrap(tfile1.name, boxes=boxes) @@ -850,8 +889,9 @@ """Rewrap a jpx file.""" with open(self.temp_jp2_filename, mode='wb') as tfile1: jpx = Jp2k(self.jpxfile) - idx = (list(range(5)) - + list(range(9, 12)) + list(range(6, 9))) + [12] + idx = ( + list(range(5)) + list(range(9, 12)) + list(range(6, 9)) + ) + [12] boxes = [jpx.box[j] for j in idx] jpx2 = jpx.wrap(tfile1.name, boxes=boxes) exp_ids = [box.box_id for box in boxes] @@ -928,8 +968,9 @@ def test_default_ihdr(self): """Should be able to instantiate an image header box.""" - ihdr = glymur.jp2box.ImageHeaderBox(height=512, width=256, - num_components=3) + ihdr = glymur.jp2box.ImageHeaderBox( + height=512, width=256, num_components=3 + ) self.assertEqual(ihdr.height, 512) self.assertEqual(ihdr.width, 256) self.assertEqual(ihdr.num_components, 3) @@ -940,8 +981,10 @@ def test_default_jp2headerbox(self): """Should be able to set jp2h boxes.""" box = JP2HeaderBox() - box.box = [ImageHeaderBox(height=512, width=256), - ColourSpecificationBox(colorspace=glymur.core.GREYSCALE)] + box.box = [ + ImageHeaderBox(height=512, width=256), + ColourSpecificationBox(colorspace=glymur.core.GREYSCALE) + ] self.assertTrue(True) def test_default_ccodestreambox(self): @@ -955,8 +998,9 @@ main_header_offset is an attribute of the ContiguousCodesStream box """ j = Jp2k(self.jpxfile) - self.assertEqual(j.box[5].main_header_offset, - j.box[5].offset + 8) + self.assertEqual( + j.box[5].main_header_offset, j.box[5].offset + 8 + ) class TestRepr(MetadataBase): @@ -1067,9 +1111,11 @@ """Verify __repr__ method on cdef box.""" channel_type = [COLOR, COLOR, COLOR] association = [RED, GREEN, BLUE] - cdef = glymur.jp2box.ChannelDefinitionBox(index=[0, 1, 2], - channel_type=channel_type, - association=association) + cdef = glymur.jp2box.ChannelDefinitionBox( + index=[0, 1, 2], + channel_type=channel_type, + association=association + ) newbox = eval(repr(cdef)) self.assertEqual(newbox.index, (0, 1, 2)) self.assertEqual(newbox.channel_type, (COLOR, COLOR, COLOR)) @@ -1122,9 +1168,11 @@ def test_componentmapping_box(self): """Verify __repr__ method on cmap box.""" - cmap = glymur.jp2box.ComponentMappingBox(component_index=(0, 0, 0), - mapping_type=(1, 1, 1), - palette_index=(0, 1, 2)) + cmap = glymur.jp2box.ComponentMappingBox( + component_index=(0, 0, 0), + mapping_type=(1, 1, 1), + palette_index=(0, 1, 2) + ) newbox = eval(repr(cmap)) self.assertEqual(newbox.box_id, 'cmap') self.assertEqual(newbox.component_index, (0, 0, 0)) @@ -1188,8 +1236,11 @@ """Verify Palette box repr.""" palette = np.array([[255, 0, 1000], [0, 255, 0]], dtype=np.int32) bps = (8, 8, 16) - box = glymur.jp2box.PaletteBox(palette=palette, bits_per_component=bps, - signed=(True, False, True)) + box = glymur.jp2box.PaletteBox( + palette=palette, + bits_per_component=bps, + signed=(True, False, True) + ) # Test will fail unless addition imports from numpy are done. from numpy import array, int32 # noqa: F401 @@ -1213,11 +1264,14 @@ def test_readerrequirements_box(self): """Verify rreq repr method.""" - box = glymur.jp2box.ReaderRequirementsBox(fuam=160, dcm=192, - standard_flag=(5, 61, 43), - standard_mask=(128, 96, 64), - vendor_feature=[], - vendor_mask=[]) + box = glymur.jp2box.ReaderRequirementsBox( + fuam=160, + dcm=192, + standard_flag=(5, 61, 43), + standard_mask=(128, 96, 64), + vendor_feature=[], + vendor_mask=[] + ) newbox = eval(repr(box)) self.assertEqual(box.fuam, newbox.fuam) self.assertEqual(box.dcm, newbox.dcm) @@ -1235,11 +1289,11 @@ # Since the raw_data parameter is a sequence of bytes which could be # quite long, don't bother trying to make it conform to eval(repr()). pattern = r""" - glymur.jp2box.UUIDBox\( - UUID\('00000000-0000-0000-0000-000000000000'\),\s - raw_data= - \) - """ + glymur.jp2box.UUIDBox\( + UUID\('00000000-0000-0000-0000-000000000000'\),\s + raw_data= + \) + """ regex = re.compile(pattern, re.VERBOSE) self.assertRegex(repr(box), regex) @@ -1252,11 +1306,11 @@ # Since the raw_data parameter is a sequence of bytes which could be # quite long, don't bother trying to make it conform to eval(repr()). pattern = r""" - glymur.jp2box.UUIDBox\( - UUID\('be7acfcb-97a9-42e8-9c71-999491e3afac'\),\s - raw_data= - \) - """ + glymur.jp2box.UUIDBox\( + UUID\('be7acfcb-97a9-42e8-9c71-999491e3afac'\),\s + raw_data= + \) + """ regex = re.compile(pattern, re.VERBOSE) self.assertRegex(repr(box), regex) @@ -1268,10 +1322,10 @@ # Difficult to eval(repr()) this, so just match the general pattern. pattern = r""" - glymur.jp2box.ContiguousCodeStreamBox\( - codestream= - \) - """ + glymur.jp2box.ContiguousCodeStreamBox\( + codestream= + \) + """ regex = re.compile(pattern, re.VERBOSE) self.assertRegex(repr(box), regex) diff -Nru glymur-0.9.6/tests/test_jp2box_uuid.py glymur-0.9.7/tests/test_jp2box_uuid.py --- glymur-0.9.6/tests/test_jp2box_uuid.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/tests/test_jp2box_uuid.py 2021-12-27 23:53:21.000000000 +0000 @@ -203,7 +203,7 @@ EXPECTED RESULT: Should not error out. """ - box_data = ir.read_binary('tests.data.0220000800', 'uuid.dat') + box_data = ir.read_binary('tests.data', '0220000800_uuid.dat') bf = io.BytesIO(box_data) bf.seek(8) box = UUIDBox.parse(bf, 0, 703) diff -Nru glymur-0.9.6/tests/test_jp2k.py glymur-0.9.7/tests/test_jp2k.py --- glymur-0.9.6/tests/test_jp2k.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/tests/test_jp2k.py 2021-12-27 23:53:21.000000000 +0000 @@ -20,12 +20,6 @@ # Third party library imports ... from lxml import etree as ET import numpy as np -try: - import skimage.data - import skimage.metrics - _HAVE_SCIKIT_IMAGE = True -except ModuleNotFoundError: - _HAVE_SCIKIT_IMAGE = False # Local imports import glymur @@ -49,8 +43,9 @@ # Can't do it on windows, temporary file issue. return tests if glymur.lib.openjp2.OPENJP2 is not None: - tests.addTests(doctest.DocTestSuite('glymur.jp2k', - tearDown=docTearDown)) + tests.addTests( + doctest.DocTestSuite('glymur.jp2k', tearDown=docTearDown) + ) return tests @@ -64,6 +59,74 @@ super(TestJp2k, self).setUp() glymur.reset_option('all') + def test_dtype_jp2(self): + """ + Scenario: An RGB image is read from a JP2 file. + + Expected response: the dtype property is np.uint8 + """ + j = Jp2k(self.jp2file) + self.assertEqual(j.dtype, np.uint8) + + def test_dtype_j2k_uint16(self): + """ + Scenario: A uint16 monochrome image is read from a J2K file. + + Expected response: the dtype property is np.uint16 + """ + with ir.path('tests.data', 'uint16.j2k') as path: + j = Jp2k(path) + self.assertEqual(j.dtype, np.uint16) + + def test_dtype_prec4_signd1(self): + """ + Scenario: A 4-bit signed image is read from a J2k file. + + Expected response: the dtype property is np.int8 + """ + with ir.path('tests.data', 'p0_03.j2k') as path: + j = Jp2k(path) + self.assertEqual(j.dtype, np.int8) + + def test_dtype_inconsistent_bitdetph(self): + """ + Scenario: The image has different bitdepths in different components. + + Expected response: TypeError when accessing the dtype property. + """ + with ir.path('tests.data', 'issue982.j2k') as path: + j = Jp2k(path) + with self.assertRaises(TypeError): + j.dtype + + def test_ndims_jp2(self): + """ + Scenario: An RGB image is read from a JP2 file. + + Expected response: the ndim attribute/property is 3 + """ + j = Jp2k(self.jp2file) + self.assertEqual(j.ndim, 3) + + def test_ndims_j2k(self): + """ + Scenario: An RGB image is read from a raw codestream. + + Expected response: the ndim attribute/property is 3 + """ + j = Jp2k(self.j2kfile) + self.assertEqual(j.ndim, 3) + + def test_ndims_monochrome_j2k(self): + """ + Scenario: An monochrome image is read from a raw codestream. + + Expected response: the ndim attribute/property is 2 + """ + with ir.path('tests.data', 'p0_02.j2k') as path: + j = Jp2k(path) + self.assertEqual(j.ndim, 2) + def test_read_bands_unequal_subsampling(self): """ SCENARIO: The read_bands method is used on an image with unequal @@ -152,8 +215,9 @@ channel_type = [COLOR, COLOR, COLOR] association = [BLUE, GREEN, RED] - cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type, - association=association) + cdef = glymur.jp2box.ChannelDefinitionBox( + channel_type=channel_type, association=association + ) jp2h.box.append(cdef) boxes.append(jp2h) @@ -254,8 +318,10 @@ j2 = Jp2k(self.temp_j2k_filename, data=expdata, irreversible=True) codestream = j2.get_codestream() - self.assertEqual(codestream.segment[2].xform, - glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) + self.assertEqual( + codestream.segment[2].xform, + glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE + ) actdata = j2[:] self.assertTrue(fixtures.mse(actdata[0], expdata[0]) < 0.38) @@ -302,6 +368,9 @@ with self.assertRaises(FileNotFoundError): j[:] + @unittest.skipIf( + not fixtures.HAVE_SCIKIT_IMAGE, fixtures.HAVE_SCIKIT_IMAGE_MSG + ) def test_write_to_a_file_using_context_manager(self): """ SCENARIO: Write to a file using a context manager, read the data back @@ -309,7 +378,7 @@ EXPECTED RESULT: the data matches """ - expected = skimage.data.astronaut() + expected = fixtures.skimage.data.astronaut() j1 = Jp2k(self.temp_jp2_filename) j1[:] = expected @@ -605,18 +674,20 @@ # Write the ULST box. # Length is 26, 1 UUID, hard code that UUID as zeros. ulst_len = 26 - write_buffer = struct.pack('>I4sHIIII', ulst_len, b'ulst', - int(1), int(0), int(0), int(0), - int(0)) + write_buffer = struct.pack( + '>I4sHIIII', + ulst_len, b'ulst', int(1), int(0), int(0), int(0), int(0) + ) tfile.write(write_buffer) # Write the URL box. # Length is 16, version is one byte, flag is 3 bytes, url # is the rest. url_box_len = 16 - write_buffer = struct.pack('>I4sBBBB', - url_box_len, b'url ', - int(0), int(0), int(0), int(0)) + write_buffer = struct.pack( + '>I4sBBBB', + url_box_len, b'url ', int(0), int(0), int(0), int(0) + ) tfile.write(write_buffer) write_buffer = struct.pack('>ssss', b'a', b'b', b'c', b'd') tfile.write(write_buffer) @@ -840,9 +911,11 @@ 'color media')) self.assertEqual(profile['Rendering Intent'], 'perceptual') - np.testing.assert_almost_equal(profile['Illuminant'], - (0.964203, 1.000000, 0.824905), - decimal=6) + np.testing.assert_almost_equal( + profile['Illuminant'], + (0.964203, 1.000000, 0.824905), + decimal=6 + ) self.assertEqual(profile['Creator'], 'JPEG') @@ -1073,7 +1146,9 @@ with self.assertRaises(InvalidJp2kError): Jp2k(tfile.name, data=np.zeros((0, 256), dtype=np.uint8)) - @unittest.skipIf(not _HAVE_SCIKIT_IMAGE, "No scikit-image found") + @unittest.skipIf( + not fixtures.HAVE_SCIKIT_IMAGE, fixtures.HAVE_SCIKIT_IMAGE_MSG + ) def test_psnr_zero_value_not_last(self): """ SCENARIO: The PSNR keyword argument has a zero value, but it is not @@ -1082,12 +1157,15 @@ EXPECTED RESULT: RuntimeError """ kwargs = { - 'data': skimage.data.camera(), + 'data': fixtures.skimage.data.camera(), 'psnr': [0, 35, 40, 30], } with self.assertRaises(RuntimeError): Jp2k(self.temp_jp2_filename, **kwargs) + @unittest.skipIf( + not fixtures.HAVE_SCIKIT_IMAGE, fixtures.HAVE_SCIKIT_IMAGE_MSG + ) def test_plt_yes(self): """ SCENARIO: Use the plt keyword. @@ -1095,7 +1173,7 @@ EXPECTED RESULT: Plt segment is detected. """ kwargs = { - 'data': skimage.data.camera(), + 'data': fixtures.skimage.data.camera(), 'plt': True } j = Jp2k(self.temp_jp2_filename, **kwargs) @@ -1108,6 +1186,9 @@ ) self.assertTrue(at_least_one_plt) + @unittest.skipIf( + not fixtures.HAVE_SCIKIT_IMAGE, fixtures.HAVE_SCIKIT_IMAGE_MSG + ) def test_plt_no(self): """ SCENARIO: Use the plt keyword set to false. @@ -1115,7 +1196,7 @@ EXPECTED RESULT: Plt segment is not detected. """ kwargs = { - 'data': skimage.data.camera(), + 'data': fixtures.skimage.data.camera(), 'plt': False } j = Jp2k(self.temp_jp2_filename, **kwargs) @@ -1128,7 +1209,9 @@ ) self.assertFalse(at_least_one_plt) - @unittest.skipIf(not _HAVE_SCIKIT_IMAGE, "No scikit-image found") + @unittest.skipIf( + not fixtures.HAVE_SCIKIT_IMAGE, fixtures.HAVE_SCIKIT_IMAGE_MSG + ) def test_psnr_non_zero_non_monotonically_decreasing(self): """ SCENARIO: The PSNR keyword argument is non-monotonically increasing @@ -1137,13 +1220,15 @@ EXPECTED RESULT: RuntimeError """ kwargs = { - 'data': skimage.data.camera(), + 'data': fixtures.skimage.data.camera(), 'psnr': [30, 35, 40, 30], } with self.assertRaises(RuntimeError): Jp2k(self.temp_jp2_filename, **kwargs) - @unittest.skipIf(not _HAVE_SCIKIT_IMAGE, "No scikit-image found") + @unittest.skipIf( + not fixtures.HAVE_SCIKIT_IMAGE, fixtures.HAVE_SCIKIT_IMAGE_MSG + ) def test_psnr(self): """ SCENARIO: Four peak signal-to-noise ratio values are supplied, the @@ -1152,7 +1237,7 @@ EXPECTED RESULT: Four quality layers, the first should be lossless. """ kwargs = { - 'data': skimage.data.camera(), + 'data': fixtures.skimage.data.camera(), 'psnr': [30, 35, 40, 0], } with open(self.temp_jp2_filename, mode='wb') as tfile: @@ -1168,8 +1253,8 @@ # warning warnings.simplefilter('ignore') psnr = [ - skimage.metrics.peak_signal_noise_ratio( - skimage.data.camera(), d[j] + fixtures.skimage.metrics.peak_signal_noise_ratio( + fixtures.skimage.data.camera(), d[j] ) for j in range(4) ] @@ -1252,8 +1337,12 @@ size are present. The precinct sizes validate. """ with open(self.temp_j2k_filename, mode='wb') as tfile: - j = Jp2k(tfile.name, data=self.jp2_data, psnr=[30, 35, 40], - cbsize=(16, 16), psizes=[(64, 64)]) + j = Jp2k( + tfile.name, + data=self.jp2_data, + psnr=[30, 35, 40], + cbsize=(16, 16), psizes=[(64, 64)] + ) codestream = j.get_codestream() @@ -1266,14 +1355,16 @@ self.assertEqual(codestream.segment[2].num_res, 5) # levels self.assertEqual(tuple(codestream.segment[2].code_block_size), (16, 16)) # cblksz - self.verify_codeblock_style(codestream.segment[2].cstyle, - [False, False, - False, False, False, False]) + self.verify_codeblock_style( + codestream.segment[2].cstyle, + [False, False, False, False, False, False] + ) self.assertEqual(codestream.segment[2].xform, glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) - self.assertEqual(codestream.segment[2].precinct_size, - ((2, 2), (4, 4), (8, 8), (16, 16), (32, 32), - (64, 64))) + self.assertEqual( + codestream.segment[2].precinct_size, + ((2, 2), (4, 4), (8, 8), (16, 16), (32, 32), (64, 64)) + ) def test_NR_ENC_Bretagne2_ppm_4_encode(self): """ @@ -1283,12 +1374,14 @@ """ with open(self.temp_j2k_filename, mode='wb') as tfile: - j = Jp2k(tfile.name, - data=self.jp2_data, - psizes=[(128, 128)] * 3, - cratios=[100, 20, 2], - tilesize=(480, 640), - cbsize=(32, 32)) + j = Jp2k( + tfile.name, + data=self.jp2_data, + psizes=[(128, 128)] * 3, + cratios=[100, 20, 2], + tilesize=(480, 640), + cbsize=(32, 32) + ) # Should be three layers. codestream = j.get_codestream() @@ -1305,16 +1398,25 @@ self.assertEqual(codestream.segment[2].layers, 3) # layers = 3 self.assertEqual(codestream.segment[2].mct, 1) # mct self.assertEqual(codestream.segment[2].num_res, 5) # levels - self.assertEqual(tuple(codestream.segment[2].code_block_size), - (32, 32)) # cblksz - self.verify_codeblock_style(codestream.segment[2].cstyle, - [False, False, - False, False, False, False]) - self.assertEqual(codestream.segment[2].xform, - glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) - self.assertEqual(codestream.segment[2].precinct_size, - ((16, 16), (32, 32), (64, 64), (128, 128), - (128, 128), (128, 128))) + self.assertEqual( + tuple(codestream.segment[2].code_block_size), + (32, 32) + ) # cblksz + self.verify_codeblock_style( + codestream.segment[2].cstyle, + [False, False, False, False, False, False] + ) + self.assertEqual( + codestream.segment[2].xform, + glymur.core.WAVELET_XFORM_5X3_REVERSIBLE + ) + self.assertEqual( + codestream.segment[2].precinct_size, + ( + (16, 16), (32, 32), (64, 64), (128, 128), (128, 128), + (128, 128) + ) + ) def test_NR_ENC_Bretagne2_ppm_5_encode(self): """ @@ -1343,9 +1445,10 @@ self.assertEqual(codestream.segment[2].num_res, 5) # levels self.assertEqual(tuple(codestream.segment[2].code_block_size), (64, 64)) # cblksz - self.verify_codeblock_style(codestream.segment[2].cstyle, - [False, False, - False, False, False, False]) + self.verify_codeblock_style( + codestream.segment[2].cstyle, + [False, False, False, False, False, False] + ) self.assertEqual(codestream.segment[2].xform, glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(codestream.segment[2].precinct_size, @@ -1565,10 +1668,16 @@ codestream = jp2.box[3].codestream - kwargs = {'rsiz': 0, 'xysiz': (2592, 1456), 'xyosiz': (0, 0), - 'xytsiz': (2592, 1456), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + kwargs = { + 'rsiz': 0, + 'xysiz': (2592, 1456), + 'xyosiz': (0, 0), + 'xytsiz': (2592, 1456), + 'xytosiz': (0, 0), + 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)] + } self.verifySizSegment(codestream.segment[1], glymur.codestream.SIZsegment(**kwargs)) @@ -1602,10 +1711,16 @@ codestream = j.get_codestream(header_only=False) - kwargs = {'rsiz': 0, 'xysiz': (1024, 1024), 'xyosiz': (0, 0), - 'xytsiz': (1024, 1024), 'xytosiz': (0, 0), - 'bitdepth': (16,), 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} + kwargs = { + 'rsiz': 0, + 'xysiz': (1024, 1024), + 'xyosiz': (0, 0), + 'xytsiz': (1024, 1024), + 'xytosiz': (0, 0), + 'bitdepth': (16,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)] + } self.verifySizSegment(codestream.segment[1], glymur.codestream.SIZsegment(**kwargs)) diff -Nru glymur-0.9.6/tests/test_libtiff.py glymur-0.9.7/tests/test_libtiff.py --- glymur-0.9.6/tests/test_libtiff.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/tests/test_libtiff.py 2021-12-27 23:53:21.000000000 +0000 @@ -3,13 +3,15 @@ # 3rd party library imports import numpy as np -import skimage.data # local imports from . import fixtures from glymur.lib import tiff as libtiff +@unittest.skipIf( + not fixtures.HAVE_SCIKIT_IMAGE, fixtures.HAVE_SCIKIT_IMAGE_MSG +) @unittest.skipIf(fixtures.TIFF_NOT_AVAILABLE, fixtures.TIFF_NOT_AVAILABLE_MSG) class TestSuite(fixtures.TestCommon): @@ -17,7 +19,7 @@ """ SCENARIO: create a simple monochromatic 2x2 tiled image """ - data = skimage.data.moon() + data = fixtures.skimage.data.moon() h, w = data.shape th, tw = h // 2, w // 2 diff -Nru glymur-0.9.6/tests/test_openjp2.py glymur-0.9.7/tests/test_openjp2.py --- glymur-0.9.6/tests/test_openjp2.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/tests/test_openjp2.py 2021-12-27 23:53:21.000000000 +0000 @@ -9,7 +9,6 @@ # Third party library imports ... import numpy as np -import skimage.data # Local imports ... import glymur @@ -184,11 +183,14 @@ xtx5_setup(filename, short_sig=True) self.assertTrue(True) + @unittest.skipIf( + not fixtures.HAVE_SCIKIT_IMAGE, fixtures.HAVE_SCIKIT_IMAGE_MSG + ) def test_tile_write_moon(self): """ Test writing tiles for a 2D image. """ - img = skimage.data.moon() + img = fixtures.skimage.data.moon() num_comps = 1 image_height, image_width = img.shape @@ -266,12 +268,15 @@ openjp2.end_compress(codec, strm) + @unittest.skipIf( + not fixtures.HAVE_SCIKIT_IMAGE, fixtures.HAVE_SCIKIT_IMAGE_MSG + ) def test_write_tiles_3D(self): """ Test writing tiles for an RGB image. """ - img = skimage.data.astronaut() + img = fixtures.skimage.data.astronaut() image_height, image_width, num_comps = img.shape diff -Nru glymur-0.9.6/tests/test_printing.py glymur-0.9.7/tests/test_printing.py --- glymur-0.9.6/tests/test_printing.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/tests/test_printing.py 2021-12-27 23:53:21.000000000 +0000 @@ -337,7 +337,7 @@ expected = ( "SIZ marker segment @ (2, 47)\n" - " Profile: Cinema 2K\n" + " Profile: 2K cinema\n" " Reference Grid Height, Width: (1080 x 1920)\n" " Vertical, Horizontal Reference Grid Offset: (0 x 0)\n" " Reference Tile Height, Width: (1080 x 1920)\n" diff -Nru glymur-0.9.6/tests/test_tiff2jp2.py glymur-0.9.7/tests/test_tiff2jp2.py --- glymur-0.9.6/tests/test_tiff2jp2.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/tests/test_tiff2jp2.py 2021-12-27 23:53:21.000000000 +0000 @@ -11,13 +11,6 @@ # 3rd party library imports import numpy as np -try: - import skimage.data - import skimage.io - import skimage.metrics - _HAVE_SCIKIT_IMAGE = True -except ModuleNotFoundError: - _HAVE_SCIKIT_IMAGE = False # Local imports import glymur @@ -27,46 +20,18 @@ from glymur.lib import tiff as libtiff +@unittest.skipIf( + not fixtures.HAVE_SCIKIT_IMAGE, fixtures.HAVE_SCIKIT_IMAGE_MSG +) @unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) class TestSuite(fixtures.TestCommon): @classmethod - def setup_rgb_evenly_stripped(cls, path): - """ - SCENARIO: create a simple RGB stripped image, stripsize of 32 - """ - j = Jp2k(glymur.data.goodstuff()) - data = j[:] - h, w, spp = data.shape - rps = 32 - - fp = libtiff.open(path, mode='w') - - libtiff.setField(fp, 'Photometric', libtiff.Photometric.RGB) - libtiff.setField(fp, 'Compression', libtiff.Compression.DEFLATE) - libtiff.setField(fp, 'ImageLength', data.shape[0]) - libtiff.setField(fp, 'ImageWidth', data.shape[1]) - libtiff.setField(fp, 'RowsPerStrip', rps) - libtiff.setField(fp, 'BitsPerSample', 8) - libtiff.setField(fp, 'SamplesPerPixel', spp) - libtiff.setField(fp, 'PlanarConfig', libtiff.PlanarConfig.CONTIG) - - for stripnum in range(25): - row = rps * stripnum - stripdata = data[row:row + rps, :, :].copy() - libtiff.writeEncodedStrip(fp, stripnum, stripdata) - - libtiff.close(fp) - - cls.goodstuff_data = data - cls.goodstuff_path = path - - @classmethod def setup_minisblack_spp1(cls, path): """ SCENARIO: create a simple monochromatic 2x2 tiled image """ - data = skimage.data.moon() + data = fixtures.skimage.data.moon() h, w = data.shape th, tw = h // 2, w // 2 @@ -117,7 +82,7 @@ SCENARIO: create a simple monochromatic 2x2 tiled image with partial tiles. """ - data = skimage.data.moon() + data = fixtures.skimage.data.moon() h, w = 480, 480 th, tw = 256, 256 @@ -147,7 +112,7 @@ """ SCENARIO: create a simple monochromatic 3x3 tiled image """ - data = skimage.data.moon() + data = fixtures.skimage.data.moon() data = data[:480, :480] h, w = data.shape @@ -185,7 +150,7 @@ SCENARIO: create a simple monochromatic 3-strip image. The strips evenly divide the image. """ - data = skimage.data.moon() + data = fixtures.skimage.data.moon() data = data[:480, :480] h, w = data.shape @@ -215,7 +180,7 @@ """ SCENARIO: create a simple monochromatic 3-strip image """ - data = skimage.data.moon() + data = fixtures.skimage.data.moon() data = data[:480, :480] h, w = data.shape @@ -251,7 +216,7 @@ """ SCENARIO: create a simple color 2x2 tiled 16bit image """ - data = skimage.data.astronaut().astype(np.uint16) + data = fixtures.skimage.data.astronaut().astype(np.uint16) h, w, z = data.shape th, tw = h // 2, w // 2 @@ -303,7 +268,7 @@ """ SCENARIO: create a simple color 2x2 tiled image """ - data = skimage.data.astronaut() + data = fixtures.skimage.data.astronaut() h, w, z = data.shape th, tw = h // 2, w // 2 @@ -356,7 +321,7 @@ """ SCENARIO: create a simple color 2x2 tiled image, bigtiff """ - data = skimage.data.astronaut() + data = fixtures.skimage.data.astronaut() h, w, z = data.shape th, tw = h // 2, w // 2 @@ -407,7 +372,7 @@ """ SCENARIO: create a simple color 2x2 tiled image """ - data = skimage.data.astronaut() + data = fixtures.skimage.data.astronaut() h, w, z = data.shape th, tw = h // 2, w // 2 @@ -472,7 +437,6 @@ cls.setup_rgb(cls.test_tiff_path / 'astronaut.tif') cls.setup_rgb_bigtiff(cls.test_tiff_path / 'rbg_bigtiff.tif') - cls.setup_rgb_evenly_stripped(cls.test_tiff_path / 'goodstuff.tif') cls.setup_ycbcr_jpeg( cls.test_tiff_path / 'astronaut_ycbcr_jpeg_tiled.tif' @@ -586,7 +550,6 @@ ) self.assertFalse(at_least_one_uuid) - @unittest.skipIf(not _HAVE_SCIKIT_IMAGE, "No scikit-image found") def test_psnr(self): """ SCENARIO: Convert TIFF file to JP2 with the irreversible transform. @@ -611,8 +574,8 @@ # warning warnings.simplefilter('ignore') psnr = [ - skimage.metrics.peak_signal_noise_ratio( - skimage.data.moon(), d[j] + fixtures.skimage.metrics.peak_signal_noise_ratio( + fixtures.skimage.data.moon(), d[j] ) for j in range(4) ] @@ -858,7 +821,7 @@ EXPECTED RESULT: RuntimeError """ - data = skimage.data.moon().astype(np.uint32) + data = fixtures.skimage.data.moon().astype(np.uint32) h, w = data.shape th, tw = h // 2, w // 2 @@ -892,7 +855,7 @@ EXPECTED RESULT: RuntimeError """ - data = skimage.data.moon().astype(np.float32) + data = fixtures.skimage.data.moon().astype(np.float32) h, w = data.shape th, tw = h // 2, w // 2 @@ -1252,49 +1215,13 @@ self.assertEqual(c.segment[1].xtsiz, 256) self.assertEqual(c.segment[1].ytsiz, 256) - def test_stripped_logging(self): - """ - Scenario: input TIFF is organized by strips and logging is turned on. - - Expected result: there are 104 log messages, one for each tile - """ - with Tiff2Jp2k( - self.goodstuff_path, self.temp_jp2_filename, tilesize=(64, 64), - verbosity=logging.INFO - ) as j: - with self.assertLogs(logger='tiff2jp2', level=logging.INFO) as cm: - j.run() - - self.assertEqual(len(cm.output), 104) - - def test_rgb_stripped(self): - """ - Scenario: input TIFF is evenly divided into strips, but the tile size - does not evenly divide either dimension. - """ - with Tiff2Jp2k( - self.goodstuff_path, self.temp_jp2_filename, tilesize=(64, 64) - ) as j: - j.run() - - jp2 = Jp2k(self.temp_jp2_filename) - actual = jp2[:] - - np.testing.assert_array_equal(actual, self.goodstuff_data) - - c = jp2.get_codestream() - self.assertEqual(c.segment[1].xsiz, 480) - self.assertEqual(c.segment[1].ysiz, 800) - self.assertEqual(c.segment[1].xtsiz, 64) - self.assertEqual(c.segment[1].ytsiz, 64) - def test_cmyk(self): """ Scenario: CMYK (or separated) is not a supported colorspace. Expected result: RuntimeError """ - data = skimage.data.moon() + data = fixtures.skimage.data.moon() data = np.dstack((data, data)) h, w, spp = data.shape @@ -1325,6 +1252,84 @@ with self.assertRaises(RuntimeError): j.run() + +class TestSuiteNoScikitImage(fixtures.TestCommon): + + @classmethod + def setUpClass(cls): + + cls.test_tiff_dir = tempfile.mkdtemp() + cls.test_tiff_path = pathlib.Path(cls.test_tiff_dir) + + cls.setup_rgb_evenly_stripped(cls.test_tiff_path / 'goodstuff.tif') + + @classmethod + def setup_rgb_evenly_stripped(cls, path): + """ + SCENARIO: create a simple RGB stripped image, stripsize of 32 + """ + j = Jp2k(glymur.data.goodstuff()) + data = j[:] + h, w, spp = data.shape + rps = 32 + + fp = libtiff.open(path, mode='w') + + libtiff.setField(fp, 'Photometric', libtiff.Photometric.RGB) + libtiff.setField(fp, 'Compression', libtiff.Compression.DEFLATE) + libtiff.setField(fp, 'ImageLength', data.shape[0]) + libtiff.setField(fp, 'ImageWidth', data.shape[1]) + libtiff.setField(fp, 'RowsPerStrip', rps) + libtiff.setField(fp, 'BitsPerSample', 8) + libtiff.setField(fp, 'SamplesPerPixel', spp) + libtiff.setField(fp, 'PlanarConfig', libtiff.PlanarConfig.CONTIG) + + for stripnum in range(25): + row = rps * stripnum + stripdata = data[row:row + rps, :, :].copy() + libtiff.writeEncodedStrip(fp, stripnum, stripdata) + + libtiff.close(fp) + + cls.goodstuff_data = data + cls.goodstuff_path = path + + def test_stripped_logging(self): + """ + Scenario: input TIFF is organized by strips and logging is turned on. + + Expected result: there are 104 log messages, one for each tile + """ + with Tiff2Jp2k( + self.goodstuff_path, self.temp_jp2_filename, tilesize=(64, 64), + verbosity=logging.INFO + ) as j: + with self.assertLogs(logger='tiff2jp2', level=logging.INFO) as cm: + j.run() + + self.assertEqual(len(cm.output), 104) + + def test_rgb_stripped(self): + """ + Scenario: input TIFF is evenly divided into strips, but the tile size + does not evenly divide either dimension. + """ + with Tiff2Jp2k( + self.goodstuff_path, self.temp_jp2_filename, tilesize=(64, 64) + ) as j: + j.run() + + jp2 = Jp2k(self.temp_jp2_filename) + actual = jp2[:] + + np.testing.assert_array_equal(actual, self.goodstuff_data) + + c = jp2.get_codestream() + self.assertEqual(c.segment[1].xsiz, 480) + self.assertEqual(c.segment[1].ysiz, 800) + self.assertEqual(c.segment[1].xtsiz, 64) + self.assertEqual(c.segment[1].ytsiz, 64) + def test_rgb_stripped_bottom_of_tile_coincides_with_bottom_of_strip(self): """ Scenario: input TIFF is evenly divided into strips, but the tile size diff -Nru glymur-0.9.6/tests/test_writing_tiles.py glymur-0.9.7/tests/test_writing_tiles.py --- glymur-0.9.6/tests/test_writing_tiles.py 2021-11-04 23:16:40.000000000 +0000 +++ glymur-0.9.7/tests/test_writing_tiles.py 2021-12-27 23:53:21.000000000 +0000 @@ -2,7 +2,6 @@ import unittest # 3rd party library imports -import skimage.io import numpy as np # local imports @@ -12,6 +11,9 @@ from .fixtures import OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG +@unittest.skipIf( + not fixtures.HAVE_SCIKIT_IMAGE, fixtures.HAVE_SCIKIT_IMAGE_MSG +) @unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) class TestSuite(fixtures.TestCommon): """ @@ -23,7 +25,7 @@ EXPECTED RESULT: the written image validates """ - j2k_data = skimage.data.astronaut() + j2k_data = fixtures.skimage.data.astronaut() data = [ j2k_data[:256, :256, :], j2k_data[:256, 256:512, :], @@ -49,7 +51,7 @@ EXPECTED RESULT: the written image matches the 2x2 grid """ - j2k_data = skimage.data.astronaut() + j2k_data = fixtures.skimage.data.astronaut() shape = ( j2k_data.shape[0] * 2, j2k_data.shape[1] * 2, j2k_data.shape[2] @@ -71,7 +73,7 @@ EXPECTED RESULT: the written image matches the 3x2 grid """ - jp2_data = skimage.data.moon() + jp2_data = fixtures.skimage.data.moon() shape = jp2_data.shape[0] * 3, jp2_data.shape[1] * 2 tilesize = (jp2_data.shape[0], jp2_data.shape[1]) @@ -92,7 +94,7 @@ EXPECTED RESULT: RuntimeError """ - jp2_data = skimage.data.moon() + jp2_data = fixtures.skimage.data.moon() shape = jp2_data.shape[0] * 2, jp2_data.shape[1] * 2 tilesize = (jp2_data.shape[0], jp2_data.shape[1]) @@ -109,7 +111,7 @@ EXPECTED RESULT: RuntimeError """ - jp2_data = skimage.data.moon() + jp2_data = fixtures.skimage.data.moon() shape = jp2_data.shape[0] * 2, jp2_data.shape[1] * 2 tilesize = (jp2_data.shape[0], jp2_data.shape[1]) @@ -126,7 +128,7 @@ EXPECTED RESULT: RuntimeError """ - jp2_data = skimage.data.moon() + jp2_data = fixtures.skimage.data.moon() shape = jp2_data.shape[0] * 2, jp2_data.shape[1] * 2 tilesize = (jp2_data.shape[0], jp2_data.shape[1]) @@ -142,7 +144,7 @@ EXPECTED RESULT: There are three layers. """ - jp2_data = skimage.data.moon() + jp2_data = fixtures.skimage.data.moon() shape = jp2_data.shape[0] * 2, jp2_data.shape[1] * 2 tilesize = (jp2_data.shape[0], jp2_data.shape[1]) @@ -164,7 +166,7 @@ EXPECTED RESULT: Plt segment is detected. """ - j2k_data = skimage.data.astronaut() + j2k_data = fixtures.skimage.data.astronaut() shape = ( j2k_data.shape[0] * 2, j2k_data.shape[1] * 2, j2k_data.shape[2]