diff --git a/.travis.yml b/.travis.yml index 406e470..822c717 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ before_install: - sudo apt-get install -qq python-numpy - wget http://openjpeg.googlecode.com/files/openjpeg-1.5.0-Linux-x86_64.tar.gz - sudo tar -xvf openjpeg-1.5.0-Linux-x86_64.tar.gz --strip-components=1 -C / + - pip install coveralls # command to install dependencies install: @@ -19,6 +20,11 @@ install: # command to run tests script: - python -m unittest discover +after_success: + - if [[ $ENV == pythone=3.4* ]]; then + coveralls; + fi + notifications: email: "john.g.evans.ne@gmail.com" diff --git a/CHANGES.txt b/CHANGES.txt index 042e351..758941b 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,8 +1,3 @@ -Jan 10, 2015 - v0.8.0 Reduced number of steps required for writing - images. Deprecated old read and write methods in favor of - array-style slicing. Added ignore_pclr_cmap_cdef, verbose, - shape, codestream, layer properties. - Oct 06, 2014 - v0.7.2 Added ellipsis support in array-style slicing. Oct 02, 2014 - v0.7.1 Fixed README to mention Python 3.4 diff --git a/docs/source/api.rst b/docs/source/api.rst new file mode 100644 index 0000000..7584718 --- /dev/null +++ b/docs/source/api.rst @@ -0,0 +1,116 @@ +--- +API +--- + +Jp2k +---- +.. autoclass:: glymur.Jp2k + :members: read, write, wrap, read_bands, get_codestream + +Individual Boxes +---------------- +Jp2kbox +''''''' +.. autoclass:: glymur.jp2box.Jp2kBox + :members: + +AssociationBox +'''''''''''''' +.. autoclass:: glymur.jp2box.AssociationBox + :members: + +ColourSpecificationBox +'''''''''''''''''''''' +.. autoclass:: glymur.jp2box.ColourSpecificationBox + :members: + +ChannelDefinitionBox +'''''''''''''''''''''' +.. autoclass:: glymur.jp2box.ChannelDefinitionBox + :members: + +ComponentMappingBox +''''''''''''''''''' +.. autoclass:: glymur.jp2box.ComponentMappingBox + :members: + +ContiguousCodestreamBox +''''''''''''''''''''''' +.. autoclass:: glymur.jp2box.ContiguousCodestreamBox + :members: + +DataEntryURLBox +''''''''''''''' +.. autoclass:: glymur.jp2box.DataEntryURLBox + :members: + +FileTypeBox +''''''''''' +.. autoclass:: glymur.jp2box.FileTypeBox + :members: + +ImageHeaderBox +'''''''''''''' +.. autoclass:: glymur.jp2box.ImageHeaderBox + :members: + +JP2HeaderBox +'''''''''''' +.. autoclass:: glymur.jp2box.JP2HeaderBox + :members: + +JPEG2000SignatureBox +'''''''''''''''''''' +.. autoclass:: glymur.jp2box.JPEG2000SignatureBox + :members: + +LabelBox +'''''''' +.. autoclass:: glymur.jp2box.LabelBox + :members: + +PaletteBox +'''''''''' +.. autoclass:: glymur.jp2box.PaletteBox + :members: + +ReaderRequirementsBox +''''''''''''''''''''' +.. autoclass:: glymur.jp2box.ReaderRequirementsBox + :members: + +ResolutionBox +''''''''''''' +.. autoclass:: glymur.jp2box.ResolutionBox + :members: + +CaptureResolutionBox +'''''''''''''''''''' +.. autoclass:: glymur.jp2box.CaptureResolutionBox + :members: + +DisplayResolutionBox +'''''''''''''''''''' +.. autoclass:: glymur.jp2box.DisplayResolutionBox + :members: + +UUIDBox +''''''' +.. autoclass:: glymur.jp2box.UUIDBox + :members: + +UUIDInfoBox +''''''''''' +.. autoclass:: glymur.jp2box.UUIDInfoBox + :members: + +UUIDListBox +''''''''''' +.. autoclass:: glymur.jp2box.UUIDListBox + :members: + +XMLBox +'''''' +.. autoclass:: glymur.jp2box.XMLBox + :members: + diff --git a/docs/source/conf.py b/docs/source/conf.py index 76f96f6..8a87a64 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -13,6 +13,7 @@ # serve to show the default. import sys +import os class Mock(object): @@ -41,12 +42,12 @@ for mod_name in MOCK_MODULES: # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) +#sys.path.insert(0, os.path.abspath('.')) # -- General configuration ---------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' +#needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. @@ -61,7 +62,7 @@ templates_path = ['_templates'] source_suffix = '.rst' # The encoding of source files. -# source_encoding = 'utf-8-sig' +#source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' @@ -75,19 +76,19 @@ copyright = u'2013, John Evans' # built documents. # # The short X.Y version. -version = '0.8' +version = '0.7' # The full version, including alpha/beta/rc tags. -release = '0.8.0' +release = '0.7.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -# language = None +#language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -# today = '' +#today = '' # Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' +#today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -95,24 +96,24 @@ exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all # documents. -# default_role = None +#default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True +#add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -# add_module_names = True +#add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -# show_authors = False +#show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] +#modindex_common_prefix = [] # -- Options for HTML output -------------------------------------------------- @@ -124,26 +125,26 @@ html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -# html_theme_options = {} +#html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] +#html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -# html_title = None +#html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None +#html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. -# html_logo = None +#html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -# html_favicon = None +#html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -152,44 +153,44 @@ html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' +#html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -# html_use_smartypants = True +#html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -# html_sidebars = {} +#html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -# html_additional_pages = {} +#html_additional_pages = {} # If false, no module index is generated. -# html_domain_indices = True +#html_domain_indices = True # If false, no index is generated. -# html_use_index = True +#html_use_index = True # If true, the index is split into individual pages for each letter. -# html_split_index = False +#html_split_index = False # If true, links to the reST sources are added to the pages. html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True +#html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True +#html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. -# html_use_opensearch = '' +#html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None +#html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'glymurdoc' @@ -198,13 +199,13 @@ htmlhelp_basename = 'glymurdoc' # -- Options for LaTeX output ------------------------------------------------- # The paper size ('letterpaper' or 'a4paper'). -# 'papersize': 'letterpaper', +#'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). -# 'pointsize': '10pt', +#'pointsize': '10pt', # Additional stuff for the LaTeX preamble. -# 'preamble': '', +#'preamble': '', latex_elements = {} # Grouping the document tree into LaTeX files. List of tuples @@ -215,23 +216,23 @@ latex_documents = [('index', 'glymur.tex', u'glymur Documentation', # The name of an image file (relative to this directory) to place at the top of # the title page. -# latex_logo = None +#latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -# latex_use_parts = False +#latex_use_parts = False # If true, show page references after internal links. -# latex_show_pagerefs = False +#latex_show_pagerefs = False # If true, show URL addresses after external links. -# latex_show_urls = False +#latex_show_urls = False # Documents to append as an appendix to all manuals. -# latex_appendices = [] +#latex_appendices = [] # If false, no module index is generated. -# latex_domain_indices = True +#latex_domain_indices = True # -- Options for manual page output ------------------------------------------- @@ -244,7 +245,7 @@ man_pages = [ ] # If true, show URL addresses after external links. -# man_show_urls = False +#man_show_urls = False # -- Options for Texinfo output ----------------------------------------------- @@ -257,13 +258,13 @@ texinfo_documents = [('index', 'glymur', u'glymur Documentation', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. -# texinfo_appendices = [] +#texinfo_appendices = [] # If false, no module index is generated. -# texinfo_domain_indices = True +#texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' +#texinfo_show_urls = 'footnote' # Example configuration for intersphinx: refer to the Python standard library. diff --git a/docs/source/detailed_installation.rst b/docs/source/detailed_installation.rst index 7068b56..1a9281c 100644 --- a/docs/source/detailed_installation.rst +++ b/docs/source/detailed_installation.rst @@ -15,7 +15,7 @@ or if you use windows, then read on. Glymur uses ctypes to access the openjp2/openjpeg libraries, and because ctypes accesses libraries in a platform-dependent manner, -it is recommended that **if** you compile and install OpenJPEG into a +it is recommended that if you compile and install OpenJPEG into a non-standard location, you should then create a configuration file to help Glymur properly find the openjpeg or openjp2 libraries (linux users or macports users don’t need to bother with this if @@ -50,9 +50,6 @@ installed in a non-standard place, i.e. :: [library] openjpeg: /somewhere/lib/libopenjpeg.so -Once again, you should not have to bother with a configuration file if you use -mac or linux and OpenJPEG is provided by your package manager. - ''''''' Testing ''''''' diff --git a/docs/source/how_do_i.rst b/docs/source/how_do_i.rst index 88d94fa..5c66a58 100644 --- a/docs/source/how_do_i.rst +++ b/docs/source/how_do_i.rst @@ -26,10 +26,10 @@ 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', data=np.zeros((640, 480), dtype=np.uint8) + >>> data = np.zeros((640, 480), dtype=np.uint8) + >>> jp2 = glymur.Jp2k('zeros.jp2', data=data) -You must have OpenJPEG version 1.5 or more recent in order to write JPEG 2000 -images with glymur. +You should have OpenJPEG version 1.5 or more recent before writing JPEG 2000 images. ... display metadata? ===================== @@ -214,9 +214,9 @@ making use of the :py:meth:`set_printoptions` function:: UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP) Contiguous Codestream Box (jp2c) @ (3223, 1132296) -It is possible to easily print the codestream header details as well, i.e. :: +It is possible to print all the gory codestream details as well, i.e. :: - >>> print(j.codestream) # details not show + >>> print(j.get_codestream()) # details not shown ... add XML metadata? ===================== @@ -249,8 +249,11 @@ The :py:meth:`append` method can add an XML box as shown below:: >>> jp2.append(xmlbox) >>> print(jp2) -... add metadata in a more general fashion? -=========================================== +... perform even more advanced maneuvers, like ...? +=================================================== + +... edit JP2 boxes? +------------------- An existing raw codestream (or JP2 file) can be wrapped (re-wrapped) in a user-defined set of JP2 boxes. To get just a minimal JP2 jacket on the codestream provided by `goodstuff.j2k` (a file consisting of a raw codestream), @@ -334,7 +337,7 @@ produces a new JP2 file, while :py:meth:`append` modifies an existing file and is currently limited to XML and UUID boxes. ... create an image with an alpha layer? -======================================== +---------------------------------------- OpenJPEG can create JP2 files with more than 3 components (use version 2.1.0+ for this), but by default, any extra components are not described @@ -395,7 +398,7 @@ Here's how the Preview application on the mac shows the RGBA image. ... work with XMP UUIDs? -======================== +------------------------ `Wikipedia `_ states that "The Extensible Metadata Platform (XMP) is an ISO standard, originally created by Adobe Systems Inc., for the creation, processing @@ -442,7 +445,7 @@ following 'Google' But that would be painful. A better solution is to install the Python XMP -Toolkit (make sure it is at least version 2.0):: +Toolkit (make sure it is version 2.0):: >>> from libxmp import XMPMeta >>> from libxmp.consts import XMP_NS_XMP as NS_XAP @@ -604,3 +607,20 @@ We can then append the XMP in a UUID box just as before:: +... turn on OpenJPEG callbacks? +------------------------------- +The OpenJPEG info callback handler mechanism can be controlled with a Jp2k +property :: + + >>> jp2file = glymur.data.nemo() + >>> jp2 = glymur.Jp2k(jp2file) + >>> jp2.verbose = True + >>> data = jp2[:] + [INFO] Start to read j2k main header (3231). + [INFO] Main header has been correctly decoded. + [INFO] No decoded area parameters, set the decoded area to the whole image + [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. + [INFO] Stream reached its end ! + diff --git a/docs/source/index.rst b/docs/source/index.rst index 62e118d..8c1fb03 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -17,6 +17,7 @@ Contents: how_do_i whatsnew/index roadmap + api ------------------ Indices and tables diff --git a/docs/source/whatsnew/0.8.rst b/docs/source/whatsnew/0.8.rst index e7215ad..f36b593 100644 --- a/docs/source/whatsnew/0.8.rst +++ b/docs/source/whatsnew/0.8.rst @@ -6,19 +6,5 @@ Changes in 0.8.0 ================= * Simplified writing images by moving data and options into the - constructor. + constructor. This is backwards-incompatible with 0.7.x. * Deprecated :py:meth:`read` method in favor of array-style slicing. - In order to retain certain functionality, the following parameters - to the :py:meth:`read` method have become top-level properties - - * verbose - * layer - * ignore_pclr_cmap_cdef - - * Two additional properties were introduced. - - * codestream - * shape - - - diff --git a/glymur/__init__.py b/glymur/__init__.py index d8971b2..9a4d8b1 100644 --- a/glymur/__init__.py +++ b/glymur/__init__.py @@ -1,25 +1,21 @@ """glymur - read, write, and interrogate JPEG 2000 files """ +import sys import unittest from glymur import version __version__ = version.version from .jp2k import Jp2k -from .jp2box import (get_printoptions, - set_printoptions, - get_parseoptions, - set_parseoptions) +from .jp2box import ( + get_printoptions, set_printoptions, + get_parseoptions, set_parseoptions +) from . import data - def runtests(): """Discover and run all tests for the glymur package. """ suite = unittest.defaultTestLoader.discover(__path__[0]) unittest.TextTestRunner(verbosity=2).run(suite) - - -__all__ = [__version__, Jp2k, get_printoptions, set_printoptions, - get_parseoptions, set_parseoptions, data, runtests] diff --git a/glymur/_uuid_io.py b/glymur/_uuid_io.py index 3c63b0a..bf9960a 100644 --- a/glymur/_uuid_io.py +++ b/glymur/_uuid_io.py @@ -3,13 +3,14 @@ Part of glymur. """ from collections import OrderedDict +import pprint +import re import struct import sys import warnings import lxml.etree as ET - def xml(raw_data): """ XMP data to be parsed as XML. @@ -22,7 +23,6 @@ def xml(raw_data): return ET.ElementTree(elt) - def tiff_header(read_buffer): """ Interpret the uuid raw data as a tiff header. @@ -37,8 +37,8 @@ def tiff_header(read_buffer): # big endian endian = '>' else: - msg = "The byte order indication in the TIFF header ({0}) is " - msg += "invalid. It should be either {1} or {2}." + msg = "The byte order indication in the TIFF header ({0}) is invalid. " + msg += "It should be either {1} or {2}." msg = msg.format(read_buffer[6:8], bytes([73, 73]), bytes([77, 77])) raise IOError(msg) @@ -503,3 +503,6 @@ class _ExifInteroperabilityIfd(_Ifd): def __init__(self, endian, read_buffer, offset): _Ifd.__init__(self, endian, read_buffer, offset) self.post_process(self.tagnum2name) + + + diff --git a/glymur/codestream.py b/glymur/codestream.py index ea94afd..c8ab00f 100644 --- a/glymur/codestream.py +++ b/glymur/codestream.py @@ -6,13 +6,16 @@ codestreams. # The number of lines in the module is long and that's ok. It would not help # matters to move anything out to another file. +# pylint: disable=C0302 # "Too many instance attributes", "Too many arguments" # Some segments just have a lot of information. # It doesn't make sense to subclass just for that. +# pylint: disable=R0902,R0913 # "Too few public methods" Some segments don't define any new methods from # the base Segment class. +# pylint: disable=R0903 import math import struct @@ -21,22 +24,24 @@ import warnings import numpy as np -from .core import (LRCP, RLCP, RPCL, PCRL, CPRL, - WAVELET_XFORM_9X7_IRREVERSIBLE, - WAVELET_XFORM_5X3_REVERSIBLE, - _Keydefaultdict) +from .core import ( + LRCP, RLCP, RPCL, PCRL, CPRL, + WAVELET_XFORM_9X7_IRREVERSIBLE, WAVELET_XFORM_5X3_REVERSIBLE, + _Keydefaultdict +) from .lib import openjp2 as opj2 _factory = lambda x: '{0} (invalid)'.format(x) -_PROGRESSION_ORDER_DISPLAY = _Keydefaultdict(_factory, {LRCP: 'LRCP', - RLCP: 'RLCP', - RPCL: 'RPCL', - PCRL: 'PCRL', - CPRL: 'CPRL'}) +_PROGRESSION_ORDER_DISPLAY = _Keydefaultdict(_factory, + { LRCP: 'LRCP', + RLCP: 'RLCP', + RPCL: 'RPCL', + PCRL: 'PCRL', + CPRL: 'CPRL'}) -_keysvalues = {WAVELET_XFORM_9X7_IRREVERSIBLE: '9-7 irreversible', - WAVELET_XFORM_5X3_REVERSIBLE: '5-3 reversible'} -_WAVELET_TRANSFORM_DISPLAY = _Keydefaultdict(_factory, _keysvalues) +_WAVELET_TRANSFORM_DISPLAY = _Keydefaultdict(_factory, + { WAVELET_XFORM_9X7_IRREVERSIBLE: '9-7 irreversible', + WAVELET_XFORM_5X3_REVERSIBLE: '5-3 reversible'}) _NO_PROFILE = 0 _PROFILE_0 = 1 @@ -47,11 +52,12 @@ _PROFILE_4 = 4 _KNOWN_PROFILES = [_NO_PROFILE, _PROFILE_0, _PROFILE_1, _PROFILE_3, _PROFILE_4] # How to display the codestream profile. -_CAPABILITIES_DISPLAY = _Keydefaultdict(_factory, {_NO_PROFILE: 'no profile', - _PROFILE_0: '0', - _PROFILE_1: '1', - _PROFILE_3: 'Cinema 2K', - _PROFILE_4: 'Cinema 4K'}) +_CAPABILITIES_DISPLAY = _Keydefaultdict(_factory, + { _NO_PROFILE: 'no profile', + _PROFILE_0: '0', + _PROFILE_1: '1', + _PROFILE_3: 'Cinema 2K', + _PROFILE_4: 'Cinema 4K'} ) # Need a catch-all list of valid markers. # See table A-1 in ISO/IEC FCD15444-1. @@ -293,6 +299,7 @@ class Codestream(object): msg += ''.join(strs) return msg + # pylint: disable=R0201 def _parse_cme_segment(self, fptr): """Parse the CME marker segment. @@ -688,7 +695,7 @@ class Codestream(object): try: num_tiles_x = (xysiz[0] - xyosiz[0]) / (xytsiz[0] - xytosiz[0]) num_tiles_y = (xysiz[1] - xyosiz[1]) / (xytsiz[1] - xytosiz[1]) - except ZeroDivisionError: + except ZeroDivisionError as err: warnings.warn("Invalid tile dimensions.") else: numtiles = math.ceil(num_tiles_x) * math.ceil(num_tiles_y) @@ -696,6 +703,7 @@ class Codestream(object): msg = "Invalid number of tiles ({0}).".format(numtiles) warnings.warn(msg) + kwargs = {'rsiz': rsiz, 'xysiz': xysiz, 'xyosiz': xyosiz, @@ -822,6 +830,7 @@ class Codestream(object): return TLMsegment(length, offset, ztlm, ttlm, ptlm) + # pylint: disable=W0613 def _parse_reserved_marker(self, fptr): """Marker range between 0xff30 and 0xff39. """ @@ -1605,7 +1614,6 @@ class SOCsegment(Segment): msg = "glymur.codestream.SOCsegment()" return msg - class SODsegment(Segment): """Container for Start of Data (SOD) segment information. diff --git a/glymur/command_line.py b/glymur/command_line.py index 3d1d57e..bf96293 100644 --- a/glymur/command_line.py +++ b/glymur/command_line.py @@ -3,35 +3,33 @@ Entry point for console script jp2dump. """ import argparse import os +import sys import warnings -from . import Jp2k, set_printoptions, set_parseoptions, lib - +from . import Jp2k, set_printoptions, lib def main(): """ Entry point for console script jp2dump. """ - kwargs = {'description': 'Print JPEG2000 metadata.', - 'formatter_class': argparse.ArgumentDefaultsHelpFormatter} - parser = argparse.ArgumentParser(**kwargs) + description='Print JPEG2000 metadata.' + parser = argparse.ArgumentParser(description=description) parser.add_argument('-x', '--noxml', - help='suppress XML', - action='store_true') + help='Suppress XML.', + action='store_true') parser.add_argument('-s', '--short', - help='only print box id, offset, and length', - action='store_true') + help='Only print box id, offset, and length.', + action='store_true') - chelp = 'Level of codestream information. 0 suppresses all details, ' - chelp += '1 prints the main header, 2 prints the full codestream.' + chelp = 'Level of codestream information. 0 suppressed all details, ' + chelp += '1 prints headers, 2 prints the full codestream' parser.add_argument('-c', '--codestream', - help=chelp, - metavar='LEVEL', - nargs=1, - type=int, - default=[1]) + help=chelp, + nargs=1, + type=int, + default=[0]) parser.add_argument('filename') @@ -40,31 +38,30 @@ def main(): set_printoptions(xml=False) if args.short: set_printoptions(short=True) - + codestream_level = args.codestream[0] if codestream_level not in [0, 1, 2]: raise ValueError("Invalid level of codestream information specified.") if codestream_level == 0: set_printoptions(codestream=False) - elif codestream_level == 2: - set_parseoptions(full_codestream=True) - + print_full_codestream = False + elif codestream_level == 1: + print_full_codestream = False + else: + print_full_codestream = True + filename = args.filename - + with warnings.catch_warnings(record=True) as wctx: # JP2 metadata can be extensive, so don't print any warnings until we # are done with the metadata. jp2 = Jp2k(filename) - if jp2._codec_format == lib.openjp2.CODEC_J2K: - if codestream_level == 0: - print('File: {0}'.format(os.path.basename(filename))) - elif codestream_level == 1: - print(jp2) - elif codestream_level == 2: - print('File: {0}'.format(os.path.basename(filename))) - print(jp2.get_codestream(header_only=False)) + if jp2._codec_format == lib.openjp2.CODEC_J2K and codestream_level == 0: + print('File: {0}'.format(os.path.basename(filename))) + elif print_full_codestream: + print(jp2.get_codestream(header_only=False)) else: print(jp2) diff --git a/glymur/core.py b/glymur/core.py index 644dcfd..4d9a3af 100644 --- a/glymur/core.py +++ b/glymur/core.py @@ -1,7 +1,8 @@ """Core definitions to be shared amongst the modules. """ import collections - +import copy +import lxml.etree as ET class _Keydefaultdict(collections.defaultdict): """Unlisted keys help form their own error message. @@ -120,12 +121,12 @@ ROMM_RGB = 21 _factory = lambda x: '{0} (unrecognized)'.format(x) _COLORSPACE_MAP_DISPLAY = _Keydefaultdict(_factory, - {CMYK: 'CMYK', - SRGB: 'sRGB', - GREYSCALE: 'greyscale', - YCC: 'YCC', - E_SRGB: 'e-sRGB', - ROMM_RGB: 'ROMM-RGB'}) + { CMYK: 'CMYK', + SRGB: 'sRGB', + GREYSCALE: 'greyscale', + YCC: 'YCC', + E_SRGB: 'e-sRGB', + ROMM_RGB: 'ROMM-RGB'} ) # enumerated color channel types COLOR = 0 @@ -133,11 +134,11 @@ OPACITY = 1 PRE_MULTIPLIED_OPACITY = 2 _UNSPECIFIED = 65535 _factory = lambda x: '{0} (invalid)'.format(x) -_dict = {COLOR: 'color', - OPACITY: 'opacity', - PRE_MULTIPLIED_OPACITY: 'pre-multiplied opacity', - _UNSPECIFIED: 'unspecified'} -_COLOR_TYPE_MAP_DISPLAY = _Keydefaultdict(_factory, _dict) +_COLOR_TYPE_MAP_DISPLAY = _Keydefaultdict(_factory, + { COLOR: 'color', + OPACITY: 'opacity', + PRE_MULTIPLIED_OPACITY: 'pre-multiplied opacity', + _UNSPECIFIED: 'unspecified'}) # color channel definitions. RED = 1 @@ -152,3 +153,4 @@ _COLORSPACE = {SRGB: {"R": 1, "G": 2, "B": 3}, YCC: {"Y": 1, "Cb": 2, "Cr": 3}, E_SRGB: {"R": 1, "G": 2, "B": 3}, ROMM_RGB: {"R": 1, "G": 2, "B": 3}} + diff --git a/glymur/data/__init__.py b/glymur/data/__init__.py index 066edd2..de1e62a 100644 --- a/glymur/data/__init__.py +++ b/glymur/data/__init__.py @@ -43,3 +43,4 @@ def jpxfile(): """ filename = pkg_resources.resource_filename(__name__, "heliov.jpx") return filename + diff --git a/glymur/jp2box.py b/glymur/jp2box.py index 98b0e6a..a2148ae 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -11,6 +11,8 @@ References Extensions """ +# pylint: disable=C0302,R0903,R0913,W0142 + from collections import OrderedDict import datetime import io @@ -20,37 +22,35 @@ import pprint import struct import sys import textwrap -from uuid import UUID +import uuid import warnings import lxml.etree as ET import numpy as np from .codestream import Codestream -from .core import (_COLORSPACE_MAP_DISPLAY, _COLOR_TYPE_MAP_DISPLAY, - SRGB, GREYSCALE, YCC, - ENUMERATED_COLORSPACE, RESTRICTED_ICC_PROFILE, - ANY_ICC_PROFILE, VENDOR_COLOR_METHOD, - _Keydefaultdict) +from .core import ( + _COLORSPACE_MAP_DISPLAY, _COLOR_TYPE_MAP_DISPLAY, + SRGB, GREYSCALE, YCC, + ENUMERATED_COLORSPACE, RESTRICTED_ICC_PROFILE, + ANY_ICC_PROFILE, VENDOR_COLOR_METHOD, + _Keydefaultdict +) from . import _uuid_io -_factory = lambda x: '{0} (invalid)'.format(x) -_keysvalues = {ENUMERATED_COLORSPACE: 'enumerated colorspace', - RESTRICTED_ICC_PROFILE: 'restricted ICC profile', - ANY_ICC_PROFILE: 'any ICC profile', - VENDOR_COLOR_METHOD: 'vendor color method'} -_METHOD_DISPLAY = _Keydefaultdict(_factory, _keysvalues) +_METHOD_DISPLAY = { + ENUMERATED_COLORSPACE: 'enumerated colorspace', + RESTRICTED_ICC_PROFILE: 'restricted ICC profile', + ANY_ICC_PROFILE: 'any ICC profile', + VENDOR_COLOR_METHOD: 'vendor color method'} _factory = lambda x: '{0} (invalid)'.format(x) -_keysvalues = {1: 'accurately represents correct colorspace definition', - 2: ('approximates correct colorspace definition, ' - 'exceptional quality'), - 3: ('approximates correct colorspace definition, ' - 'reasonable quality'), - 4: 'approximates correct colorspace definition, poor quality'} -_APPROX_DISPLAY = _Keydefaultdict(_factory, _keysvalues) - +_APPROX_DISPLAY = _Keydefaultdict(_factory, + {1: 'accurately represents correct colorspace definition', + 2: 'approximates correct colorspace definition, exceptional quality', + 3: 'approximates correct colorspace definition, reasonable quality', + 4: 'approximates correct colorspace definition, poor quality'}) class Jp2kBox(object): """Superclass for JPEG 2000 boxes. @@ -109,6 +109,7 @@ class Jp2kBox(object): msg += '\n' + self._indent(boxstr) return msg + def _indent(self, textstr, indent_level=4): """ Indent a string. @@ -134,6 +135,7 @@ class Jp2kBox(object): lst = [(' ' * indent_level + x) for x in textstr.split('\n')] return '\n'.join(lst) + def _write_superbox(self, fptr, box_id): """Write a superbox. @@ -189,14 +191,13 @@ class Jp2kBox(object): try: box = parser(fptr, start, num_bytes) except ValueError as err: - msg = "Encountered an unrecoverable ValueError while parsing a " - msg += "{0} box at byte offset {1}. The original error message " - msg += "was \"{2}\"" + msg = "Encountered an unrecoverable ValueError while parsing a {0} " + msg += "box at byte offset {1}. The original error message was " + msg += "\"{2}\"" msg = msg.format(_BOX_WITH_ID[box_id].longname, start, str(err)) warnings.warn(msg, UserWarning) box = UnknownBox(box_id.decode('utf-8'), - length=num_bytes, - offset=start, longname='Unknown') + length=num_bytes, offset=start, longname='Unknown') return box @@ -298,7 +299,6 @@ class ColourSpecificationBox(Jp2kBox): """ longname = 'Colour Specification' box_id = 'colr' - def __init__(self, method=ENUMERATED_COLORSPACE, precedence=0, approximation=0, colorspace=None, icc_profile=None, length=0, offset=-1): @@ -337,16 +337,16 @@ class ColourSpecificationBox(Jp2kBox): if self.icc_profile is None: if self.colorspace not in [SRGB, GREYSCALE, YCC]: - msg = "Colorspace should correspond to one of SRGB, " - msg += "GREYSCALE, or YCC." + msg = "Colorspace should correspond to one of SRGB, GREYSCALE, " + msg += "or YCC." self._dispatch_validation_error(msg, writing=True) self._validate(writing=True) + def __repr__(self): msg = "glymur.jp2box.ColourSpecificationBox(" - msg += "method={0}, precedence={1}, approximation={2}, " - msg += "colorspace={3}, " + msg += "method={0}, precedence={1}, approximation={2}, colorspace={3}, " msg += "icc_profile={4})" msg = msg.format(self.method, self.precedence, @@ -357,7 +357,7 @@ class ColourSpecificationBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg msg += '\n Method: {0}'.format(_METHOD_DISPLAY[self.method]) @@ -619,9 +619,10 @@ class ChannelDefinitionBox(Jp2kBox): msg += " 65535 - unspecified" self._dispatch_validation_error(msg, writing=writing) + def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg for j in range(len(self.association)): @@ -841,7 +842,7 @@ class CompositingLayerHeaderBox(Jp2kBox): List of boxes contained in this superbox. """ box_id = 'jplh' - longname = 'Compositing Layer Header' + longname='Compositing Layer Header' def __init__(self, box=None, length=0, offset=-1): Jp2kBox.__init__(self) @@ -930,7 +931,7 @@ class ComponentMappingBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg for k in range(len(self.component_index)): @@ -1001,19 +1002,18 @@ class ContiguousCodestreamBox(Jp2kBox): offset of the box from the start of the file. longname : str more verbose description of the box. - codestream : Codestream object - Contains list of codestream marker/segments. By default, only the main - header is retrieved. + main_header : Codestream object + contains list of main header marker/segments main_header_offset : int offset of main header from start of file """ box_id = 'jp2c' longname = 'Contiguous Codestream' - def __init__(self, codestream=None, main_header_offset=None, length=0, + def __init__(self, main_header=None, main_header_offset=None, length=0, offset=-1): Jp2kBox.__init__(self) - self._codestream = codestream + self._main_header = main_header self.length = length self.offset = offset self.main_header_offset = main_header_offset @@ -1022,33 +1022,29 @@ class ContiguousCodestreamBox(Jp2kBox): self._filename = None @property - def codestream(self): - if _parseoptions['full_codestream'] is True: - header_only = False - else: - header_only = True - if self._codestream is None: + def main_header(self): + if self._main_header is None: if self._filename is not None: with open(self._filename, 'rb') as fptr: fptr.seek(self.main_header_offset) - codestream = Codestream(fptr, self._length, - header_only=header_only) - self._codestream = codestream - return self._codestream + main_header = Codestream(fptr, self._length, header_only=True) + self._main_header = main_header + return self._main_header def __repr__(self): - msg = "glymur.jp2box.ContiguousCodeStreamBox(codestream={0})" - return msg.format(repr(self.codestream)) + msg = "glymur.jp2box.ContiguousCodeStreamBox(main_header={0})" + return msg.format(repr(self.main_header)) def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg - if _printoptions['codestream'] is False: + if _printoptions['codestream'] == False: return msg - for segment in self.codestream.segment: - msg += '\n' + self._indent(str(segment), indent_level=4) + msg += '\n Main header:' + for segment in self.main_header.segment: + msg += '\n' + self._indent(str(segment), indent_level=8) return msg @@ -1070,11 +1066,11 @@ class ContiguousCodestreamBox(Jp2kBox): ContiguousCodestreamBox instance """ main_header_offset = fptr.tell() - if _parseoptions['full_codestream'] is True: - codestream = Codestream(fptr, length, header_only=False) + if _parseoptions['codestream'] is True: + main_header = Codestream(fptr, length, header_only=True) else: - codestream = None - box = cls(codestream, main_header_offset=main_header_offset, + main_header = None + box = cls(main_header, main_header_offset=main_header_offset, length=length, offset=offset) box._filename = fptr.name box._length = length @@ -1122,8 +1118,7 @@ class DataReferenceBox(Jp2kBox): """Verify that the box obeys the specifications for writing. """ if len(self.DR) == 0: - msg = "A data reference box cannot be empty when written to a " - msg += "file." + msg = "A data reference box cannot be empty when written to a file." self._dispatch_validation_error(msg, writing=True) self._validate(writing=True) @@ -1150,7 +1145,7 @@ class DataReferenceBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg for box in self.DR: @@ -1253,7 +1248,7 @@ class FileTypeBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg lst = [msg, @@ -1316,18 +1311,12 @@ class FileTypeBox(Jp2kBox): brand = brand.decode('utf-8') # Extract the compatibility list. Each entry has 4 bytes. - num_entries = int((length - 16) / 4) + num_entries = int((length - 16)/ 4) compatibility_list = [] for j in range(int(num_entries)): entry, = struct.unpack_from('>4s', read_buffer, 8 + j * 4) if sys.hexversion >= 0x03000000: - try: - entry = entry.decode('utf-8') - except UnicodeDecodeError: - # The entry is invalid, but we've got code to catch this - # later on. - pass - + entry = entry.decode('utf-8') compatibility_list.append(entry) return cls(brand=brand, minor_version=minor_version, @@ -1385,7 +1374,7 @@ class FragmentListBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg for j in range(len(self.fragment_offset)): @@ -1469,10 +1458,7 @@ class FragmentTableBox(Jp2kBox): def __repr__(self): msg = "glymur.jp2box.FragmentTableBox(box={0})" - if len(self.box) == 0: - msg = msg.format(None) - else: - msg = msg.format(self.box) + msg = msg.format(None) if (len(self.box) == 0) else msg.format(self.box) return msg def __str__(self): @@ -1519,6 +1505,7 @@ class FragmentTableBox(Jp2kBox): self._write_superbox(fptr, b'ftbl') + class FreeBox(Jp2kBox): """Container for JPX free box information. @@ -1547,7 +1534,7 @@ class FreeBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg return msg @@ -1643,7 +1630,7 @@ class ImageHeaderBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg msg = "{0}" @@ -1874,7 +1861,7 @@ class JPEG2000SignatureBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg msg += '\n Signature: {0:02x}{1:02x}{2:02x}{3:02x}' @@ -1963,7 +1950,7 @@ class PaletteBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg msg += '\n Size: ({0} x {1})'.format(*self.palette.shape) @@ -1993,6 +1980,7 @@ class PaletteBox(Jp2kBox): *bps_signed) fptr.write(write_buffer) + bps = self.bits_per_component # All components are the same. Writing is straightforward. if self.bits_per_component[0] <= 8: write_buffer = memoryview(self.palette.astype(np.uint8)) @@ -2032,10 +2020,13 @@ class PaletteBox(Jp2kBox): # Ok the palette has the same datatype for all columns. We should # be able to efficiently read it. if bps[0] <= 8: + nbytes_per_row = ncols dtype = np.uint8 elif bps[0] <= 16: + nbytes_per_row = 2 * ncols dtype = np.uint16 elif bps[0] <= 32: + nbytes_per_row = 3 * ncols dtype = np.uint32 palette = np.frombuffer(read_buffer[3 + ncols:], dtype=dtype) @@ -2079,80 +2070,80 @@ _READER_REQUIREMENTS_DISPLAY = { 7: 'JPEG codestream as defined in ISO/IEC 10918-1', 8: 'Deprecated - does not contain opacity', 9: 'Non-premultiplied opacity channel', - 10: 'Premultiplied opacity channel', - 11: 'Chroma-key based opacity', - 12: 'Deprecated - codestream is contiguous', - 13: 'Fragmented codestream where all fragments are in file and in order', - 14: ('Fragmented codestream where all fragments are in file ' - 'but are out of order'), - 15: ('Fragmented codestream where not all fragments are within the file ' - 'but are all in locally accessible files'), - 16: ('Fragmented codestream where some fragments may be accessible ' - 'only through a URL specified network connection'), - 17: ('Compositing required to produce rendered result from multiple ' - 'compositing layers'), - 18: 'Deprecated - support for compositing is not required', - 19: ('Deprecated - contains multiple, discrete layers that should not ' - 'be combined through either animation or compositing'), - 20: ('Deprecated - compositing layers each contain only a single ' - 'codestream'), - 21: 'At least one compositing layer consists of multiple codestreams', - 22: 'Deprecated - all compositing layers are in the same colourspace', - 23: ('Colourspace transformations are required to combine compositing ' - 'layers; not all compositing layers are in the same colourspace'), - 24: 'Deprecated - rendered result created without using animation', - 25: ('Deprecated - animated, but first layer covers entire area and is ' - 'opaque'), - 26: 'First animation layer does not cover entire rendered result', - 27: 'Deprecated - animated, and no layer is reused', - 28: 'Reuse of animation layers', - 29: 'Deprecated - animated, but layers are reused', - 30: 'Some animated frames are non-persistent', - 31: 'Deprecated - rendered result created without using scaling', - 32: 'Rendered result involves scaling within a layer', - 33: 'Rendered result involves scaling between layers', - 34: 'ROI metadata', - 35: 'IPR metadata', - 36: 'Content metadata', - 37: 'History metadata', - 38: 'Creation metadata', - 39: 'JPX digital signatures', - 40: 'JPX checksums', - 41: 'Desires Graphics Arts Reproduction specified', - 42: 'Deprecated - compositing layer uses palettized colour', - 43: 'Deprecated - compositing layer uses restricted ICC profile', - 44: 'Compositing layer uses Any ICC profile', - 45: 'Deprecated - compositing layer uses sRGB enumerated colourspace', - 46: 'Deprecated - compositing layer uses sRGB-grey enumerated colourspace', - 47: 'BiLevel 1 enumerated colourspace', - 48: 'BiLevel 2 enumerated colourspace', - 49: 'YCbCr 1 enumerated colourspace', - 50: 'YCbCr 2 enumerated colourspace', - 51: 'YCbCr 3 enumerated colourspace', - 52: 'PhotoYCC enumerated colourspace', - 53: 'YCCK enumerated colourspace', - 54: 'CMY enumerated colourspace', - 55: 'CMYK enumerated colorspace', - 56: 'CIELab enumerated colourspace with default parameters', - 57: 'CIELab enumerated colourspace with non-default parameters', - 58: 'CIEJab enumerated colourspace with default parameters', - 59: 'CIEJab enumerated colourspace with non-default parameters', - 60: 'e-sRGB enumerated colorspace', - 61: 'ROMM_RGB enumerated colorspace', - 62: 'Non-square samples', - 63: 'Deprecated - compositing layers have labels', - 64: 'Deprecated - codestreams have labels', - 65: 'Deprecated - compositing layers have different colour spaces', - 66: 'Deprecated - compositing layers have different metadata', - 67: 'GIS metadata XML box', - 68: 'JPSEC extensions in codestream as specified by ISO/IEC 15444-8', - 69: 'JP3D extensions in codestream as specified by ISO/IEC 15444-10', - 70: 'Deprecated - compositing layer uses sYCC enumerated colour space', - 71: 'e-sYCC enumerated colourspace', - 72: ('JPEG 2000 Part 2 codestream as restricted by baseline conformance ' - 'requirements in M.9.2.3'), - 73: 'YPbPr(1125/60) enumerated colourspace', - 74: 'YPbPr(1250/50) enumerated colourspace'} + 10: 'Premultiplied opacity channel', + 11: 'Chroma-key based opacity', + 12: 'Deprecated - codestream is contiguous', + 13: 'Fragmented codestream where all fragments are in file and in order', + 14: 'Fragmented codestream where all fragments are in file ' + + 'but are out of order', + 15: 'Fragmented codestream where not all fragments are within the file ' + + 'but are all in locally accessible files', + 16: 'Fragmented codestream where some fragments may be accessible ' + + 'only through a URL specified network connection', + 17: 'Compositing required to produce rendered result from multiple ' + + 'compositing layers', + 18: 'Deprecated - support for compositing is not required', + 19: 'Deprecated - contains multiple, discrete layers that should not ' + + 'be combined through either animation or compositing', + 20: 'Deprecated - compositing layers each contain only a single ' + + 'codestream', + 21: 'At least one compositing layer consists of multiple codestreams', + 22: 'Deprecated - all compositing layers are in the same colourspace', + 23: 'Colourspace transformations are required to combine compositing ' + + 'layers; not all compositing layers are in the same colourspace', + 24: 'Deprecated - rendered result created without using animation', + 25: 'Deprecated - animated, but first layer covers entire area and is ' + + 'opaque', + 26: 'First animation layer does not cover entire rendered result', + 27: 'Deprecated - animated, and no layer is reused', + 28: 'Reuse of animation layers', + 29: 'Deprecated - animated, but layers are reused', + 30: 'Some animated frames are non-persistent', + 31: 'Deprecated - rendered result created without using scaling', + 32: 'Rendered result involves scaling within a layer', + 33: 'Rendered result involves scaling between layers', + 34: 'ROI metadata', + 35: 'IPR metadata', + 36: 'Content metadata', + 37: 'History metadata', + 38: 'Creation metadata', + 39: 'JPX digital signatures', + 40: 'JPX checksums', + 41: 'Desires Graphics Arts Reproduction specified', + 42: 'Deprecated - compositing layer uses palettized colour', + 43: 'Deprecated - compositing layer uses restricted ICC profile', + 44: 'Compositing layer uses Any ICC profile', + 45: 'Deprecated - compositing layer uses sRGB enumerated colourspace', + 46: 'Deprecated - compositing layer uses sRGB-grey enumerated colourspace', + 47: 'BiLevel 1 enumerated colourspace', + 48: 'BiLevel 2 enumerated colourspace', + 49: 'YCbCr 1 enumerated colourspace', + 50: 'YCbCr 2 enumerated colourspace', + 51: 'YCbCr 3 enumerated colourspace', + 52: 'PhotoYCC enumerated colourspace', + 53: 'YCCK enumerated colourspace', + 54: 'CMY enumerated colourspace', + 55: 'CMYK enumerated colorspace', + 56: 'CIELab enumerated colourspace with default parameters', + 57: 'CIELab enumerated colourspace with non-default parameters', + 58: 'CIEJab enumerated colourspace with default parameters', + 59: 'CIEJab enumerated colourspace with non-default parameters', + 60: 'e-sRGB enumerated colorspace', + 61: 'ROMM_RGB enumerated colorspace', + 62: 'Non-square samples', + 63: 'Deprecated - compositing layers have labels', + 64: 'Deprecated - codestreams have labels', + 65: 'Deprecated - compositing layers have different colour spaces', + 66: 'Deprecated - compositing layers have different metadata', + 67: 'GIS metadata XML box', + 68: 'JPSEC extensions in codestream as specified by ISO/IEC 15444-8', + 69: 'JP3D extensions in codestream as specified by ISO/IEC 15444-10', + 70: 'Deprecated - compositing layer uses sYCC enumerated colour space', + 71: 'e-sYCC enumerated colourspace', + 72: 'JPEG 2000 Part 2 codestream as restricted by baseline conformance ' + + 'requirements in M.9.2.3', + 73: 'YPbPr(1125/60) enumerated colourspace', + 74: 'YPbPr(1250/50) enumerated colourspace'} class ReaderRequirementsBox(Jp2kBox): @@ -2212,11 +2203,10 @@ class ReaderRequirementsBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg - msg += '\n Fully Understands Aspect Mask: 0x{0:x}' - msg = msg.format(self.fuam) + msg += '\n Fully Understands Aspect Mask: 0x{0:x}'.format(self.fuam) msg += '\n Display Completely Mask: 0x{0:x}'.format(self.dcm) msg += '\n Standard Features and Masks:' @@ -2272,8 +2262,7 @@ class ReaderRequirementsBox(Jp2kBox): standard_flag, standard_mask = data nflags = len(standard_flag) - vendor_offset = (1 + 2 * mask_length + 2 - + (2 + mask_length) * nflags) + vendor_offset = 1 + 2 * mask_length + 2 + (2 + mask_length) * nflags data = _parse_vendor_features(read_buffer[vendor_offset:], mask_length) vendor_feature, vendor_mask = data @@ -2330,8 +2319,8 @@ def _parse_rreq3(read_buffer, length, offset): read_buffer = read_buffer[9 + num_standard_features * 10:] for j in range(num_vendor_features): uslice = slice(j * entry_length, (j + 1) * entry_length) - ubuffer = read_buffer[uslice] - vendor_feature.append(UUID(bytes=ubuffer[0:16])) + ubuffer = read_buffer[slice] + vendor_feature.append(uuid.UUID(bytes=ubuffer[0:16])) lst = struct.unpack('>BBB', ubuffer[16:]) vmask = lst[0] << 16 | lst[1] << 8 | lst[2] @@ -2359,11 +2348,14 @@ def _parse_standard_flag(read_buffer, mask_length): # from the buffer read from file. mask_format = {1: 'B', 2: 'H', 4: 'I'}[mask_length] + #read_buffer = fptr.read(2) num_standard_flags, = struct.unpack_from('>H', read_buffer, offset=0) # Read in standard flags and standard masks. Each standard flag should # be two bytes, but the standard mask flag is as long as specified by # the mask length. + #read_buffer = fptr.read(num_standard_flags * (2 + mask_length)) + fmt = '>' + ('H' + mask_format) * num_standard_flags data = struct.unpack_from(fmt, read_buffer, offset=2) @@ -2394,12 +2386,13 @@ def _parse_vendor_features(read_buffer, mask_length): # Each vendor feature consists of a 16-byte UUID plus a mask whose # length is specified by, you guessed it, "mask_length". entry_length = 16 + mask_length + #read_buffer = fptr.read(num_vendor_features * entry_length) vendor_feature = [] vendor_mask = [] for j in range(num_vendor_features): uslice = slice(2 + j * entry_length, 2 + (j + 1) * entry_length) ubuffer = read_buffer[uslice] - vendor_feature.append(UUID(bytes=ubuffer[0:16])) + vendor_feature.append(uuid.UUID(bytes=ubuffer[0:16])) vmask = struct.unpack('>' + mask_format, ubuffer[16:]) vendor_mask.append(vmask) @@ -2501,7 +2494,7 @@ class CaptureResolutionBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg msg += '\n VCR: {0}'.format(self.vertical_resolution) @@ -2567,7 +2560,7 @@ class DisplayResolutionBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg msg += '\n VDR: {0}'.format(self.vertical_resolution) @@ -2627,7 +2620,7 @@ class LabelBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg msg += '\n Label: {0}'.format(self.label) @@ -2695,7 +2688,7 @@ class NumberListBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg for j, association in enumerate(self.associations): @@ -2745,8 +2738,7 @@ class NumberListBox(Jp2kBox): def write(self, fptr): """Write a NumberList box to file. """ - fptr.write(struct.pack('>I4s', - len(self.associations) * 4 + 8, b'nlst')) + fptr.write(struct.pack('>I4s', len(self.associations) * 4 + 8, b'nlst')) fmt = '>' + 'I' * len(self.associations) write_buffer = struct.pack(fmt, *self.associations) @@ -2798,9 +2790,9 @@ class XMLBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg - if _printoptions['xml'] is False: + if _printoptions['xml'] == False: return msg msg += '\n' @@ -2919,7 +2911,7 @@ class UUIDListBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg for j, uuid_item in enumerate(self.ulst): @@ -2950,8 +2942,8 @@ class UUIDListBox(Jp2kBox): ulst = [] for j in range(num_uuids): - uuid_buffer = read_buffer[2 + j * 16:2 + (j + 1) * 16] - ulst.append(UUID(bytes=uuid_buffer)) + uuid_buffer = read_buffer[2 + j * 16 : 2 + (j + 1) * 16] + ulst.append(uuid.UUID(bytes=uuid_buffer)) return cls(ulst, length=length, offset=offset) @@ -3064,6 +3056,7 @@ class DataEntryURLBox(Jp2kBox): fptr.write(write_buffer) fptr.write(url) + def __repr__(self): msg = "glymur.jp2box.DataEntryURLBox({0}, {1}, '{2}')" msg = msg.format(self.version, self.flag, self.url) @@ -3071,7 +3064,7 @@ class DataEntryURLBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg msg += '\n ' @@ -3209,7 +3202,7 @@ class UUIDBox(Jp2kBox): """ Private function for parsing UUID payloads if possible. """ - if self.uuid == UUID('be7acfcb-97a9-42e8-9c71-999491e3afac'): + if self.uuid == uuid.UUID('be7acfcb-97a9-42e8-9c71-999491e3afac'): self.data = _uuid_io.xml(self.raw_data) elif self.uuid.bytes == b'JpgTiffExif->JP2': self.data = _uuid_io.tiff_header(self.raw_data) @@ -3223,23 +3216,23 @@ class UUIDBox(Jp2kBox): def __str__(self): msg = Jp2kBox.__str__(self) - if _printoptions['short'] is True: + if _printoptions['short'] == True: return msg msg = '{0}\n UUID: {1}'.format(msg, self.uuid) - if self.uuid == UUID('be7acfcb-97a9-42e8-9c71-999491e3afac'): + if self.uuid == uuid.UUID('be7acfcb-97a9-42e8-9c71-999491e3afac'): msg += ' (XMP)' elif self.uuid.bytes == b'JpgTiffExif->JP2': msg += ' (EXIF)' else: msg += ' (unknown)' - if (((_printoptions['xml'] is False) and - (self.uuid == UUID('be7acfcb-97a9-42e8-9c71-999491e3afac')))): + if (((_printoptions['xml'] == False) and + (self.uuid == uuid.UUID('be7acfcb-97a9-42e8-9c71-999491e3afac')))): # If it's an XMP UUID, don't print the XML contents. return msg - if self.uuid == UUID('be7acfcb-97a9-42e8-9c71-999491e3afac'): + if self.uuid == uuid.UUID('be7acfcb-97a9-42e8-9c71-999491e3afac'): line = '\n UUID Data:\n{0}' xmlstring = ET.tostring(self.data, encoding='utf-8', @@ -3282,7 +3275,7 @@ class UUIDBox(Jp2kBox): """ num_bytes = offset + length - fptr.tell() read_buffer = fptr.read(num_bytes) - the_uuid = UUID(bytes=read_buffer[0:16]) + the_uuid = uuid.UUID(bytes=read_buffer[0:16]) return cls(the_uuid, read_buffer[16:], length=length, offset=offset) @@ -3317,20 +3310,18 @@ _BOX_WITH_ID = { b'uuid': UUIDBox, b'xml ': XMLBox} -_parseoptions = {'full_codestream': False} +_parseoptions = {'codestream': True} - -def set_parseoptions(full_codestream=True): +def set_parseoptions(codestream=True): """Set parsing options. These options determine the way JPEG 2000 boxes are parsed. Parameters ---------- - full_codestream : bool, defaults to True - When False, only the codestream header is parsed for metadata. This - can results in faster JP2/JPX parsing. When True, the entire - codestream is parsed for metadata. + codestream : bool, defaults to True + When False, the codestream header is only parsed when accessed. This + can results in faster JP2/JPX parsing. See also -------- @@ -3341,10 +3332,9 @@ def set_parseoptions(full_codestream=True): To put back the default options, you can use: >>> import glymur - >>> glymur.set_parseoptions(full_codestream=True) + >>> glymur.set_parseoptions(codestream=True) """ - _parseoptions['full_codestream'] = full_codestream - + _parseoptions['codestream'] = codestream def get_parseoptions(): """Return the current parsing options. @@ -3366,7 +3356,6 @@ def get_parseoptions(): _printoptions = {'short': False, 'xml': True, 'codestream': True} - def set_printoptions(**kwargs): """Set printing options. @@ -3376,15 +3365,12 @@ def set_printoptions(**kwargs): ---------- short : bool, optional When True, only the box ID, offset, and length are displayed. Useful - for displaying only the basic structure or skeleton of a JPEG 2000 - file. + for displaying only the basic structure or skeleton of a JPEG 2000 file. xml : bool, optional When False, printing of the XML contents of any XML boxes or UUID XMP boxes is suppressed. codestream : bool, optional - When False, only the codestream header is printed. When True, the - entire codestream is printed. This option has no effect when the - 'short' option is set to True. + When False, printing of the codestream contents is suppressed. See also -------- @@ -3402,7 +3388,6 @@ def set_printoptions(**kwargs): raise TypeError('"{0}" not a valid keyword parameter.'.format(key)) _printoptions[key] = value - def get_printoptions(): """Return the current print options. @@ -3422,3 +3407,5 @@ def get_printoptions(): set_printoptions """ return _printoptions + + diff --git a/glymur/jp2k.py b/glymur/jp2k.py index ee6eedc..74834a9 100644 --- a/glymur/jp2k.py +++ b/glymur/jp2k.py @@ -10,12 +10,13 @@ License: MIT import sys # Exitstack not found in contextlib in 2.7 +# pylint: disable=E0611 if sys.hexversion >= 0x03030000: from contextlib import ExitStack - from itertools import filterfalse + from itertools import compress, filterfalse else: from contextlib2 import ExitStack - from itertools import ifilterfalse as filterfalse + from itertools import compress, ifilterfalse as filterfalse from collections import Counter import ctypes @@ -30,12 +31,12 @@ import numpy as np from .codestream import Codestream from . import core, version -from .jp2box import (Jp2kBox, JPEG2000SignatureBox, FileTypeBox, - JP2HeaderBox, ColourSpecificationBox, - ContiguousCodestreamBox, ImageHeaderBox) +from .jp2box import ( + Jp2kBox, JPEG2000SignatureBox, FileTypeBox, JP2HeaderBox, + ColourSpecificationBox, ContiguousCodestreamBox, ImageHeaderBox +) from .lib import openjpeg as opj, openjp2 as opj2, c as libc - class Jp2k(Jp2kBox): """JPEG 2000 file. @@ -60,8 +61,6 @@ class Jp2k(Jp2kBox): verbose : bool whether or not to print informational messages produced by the OpenJPEG library, defaults to false - codestream : object - JP2 or J2K codestream object Examples -------- @@ -139,6 +138,7 @@ class Jp2k(Jp2kBox): not (X, Y) verbose : bool, optional print informational messages produced by the OpenJPEG library + """ Jp2kBox.__init__(self) self.filename = filename @@ -147,7 +147,6 @@ class Jp2k(Jp2kBox): self._codec_format = None self._colorspace = None self._layer = 0 - self._codestream = None if data is not None: self._shape = data.shape else: @@ -177,21 +176,11 @@ class Jp2k(Jp2kBox): @layer.setter def layer(self, layer): if version.openjpeg_version_tuple[0] < 2: - msg = "Layer property not supported unless the version of " - msg += "OpenJPEG is 2.0 or higher." + msg = "Layer property not supported unless the version of OpenJPEG " + msg += "is 2.0 or higher." raise RuntimeError(msg) self._layer = layer - @property - def codestream(self): - if self._codestream is None: - self._codestream = self.get_codestream(header_only=True) - return self._codestream - - @codestream.setter - def codestream(self, the_codestream): - self._codestream = the_codestream - @property def verbose(self): return self._verbose @@ -205,30 +194,28 @@ class Jp2k(Jp2kBox): if self._shape is not None: return self._shape - if self._codec_format == opj2.CODEC_J2K: - # get the image size from the codestream - cstr = self.codestream - height = cstr.segment[1].ysiz - width = cstr.segment[1].xsiz - num_components = len(cstr.segment[1].xrsiz) - else: - # try to get the image size from the IHDR box - jp2h = [box for box in self.box if box.box_id == 'jp2h'][0] - ihdr = [box for box in jp2h.box if box.box_id == 'ihdr'][0] - - height, width = ihdr.height, ihdr.width - num_components = ihdr.num_components - - if num_components == 1: - # but if there is a PCLR box, then we need to check that as - # well, as that turns a single-channel image into a - # multi-channel image - pclr = [box for box in jp2h.box if box.box_id == 'pclr'] - if len(pclr) > 0: - num_components = len(pclr[0].signed) + cstr = self.get_codestream(header_only=True) + height = cstr.segment[1].ysiz + width = cstr.segment[1].xsiz + num_components = len(cstr.segment[1].xrsiz) + # If JP2 and a palette box is present, then determine the shape from + # that. if num_components == 1: - self.shape = (height, width) + if self._codec_format == opj2.CODEC_J2K: + # There's no palette box or component mapping in a J2K file. + # The 3rd component in the shape would then be 1, but we'll + # ignore that. + self.shape = (height, width) + else: + jp2h = [box for box in self.box if box.box_id == 'jp2h'][0] + pclr = [box for box in jp2h.box if box.box_id == 'pclr'] + if len(pclr) == 0: + # No palette box, so just one component, which we will + # ignore. + self.shape = (height, width) + else: + self.shape = (height, width, len(pclr[0].signed)) else: self.shape = (height, width, num_components) @@ -248,7 +235,8 @@ class Jp2k(Jp2kBox): for box in self.box: metadata.append(str(box)) else: - metadata.append(str(self.codestream)) + codestream = self.get_codestream() + metadata.append(str(codestream)) return '\n'.join(metadata) def parse(self): @@ -373,8 +361,8 @@ class Jp2k(Jp2kBox): kwargs : dictionary non-image keyword inputs provided to write method """ - if ((('cinema2k' in kwargs or 'cinema4k' in kwargs) and - (len(set(kwargs)) > 1))): + if (('cinema2k' in kwargs or 'cinema4k' in kwargs) and + (len(set(kwargs)) > 1)): msg = "Cannot specify cinema2k/cinema4k along with other options." raise IOError(msg) @@ -496,10 +484,9 @@ class Jp2k(Jp2kBox): This method can only be used to create JPEG 2000 images that can fit in memory. """ - if re.match("0|1.[0-4]", version.openjpeg_version) is not None: - msg = "You must have at least version 1.5 of OpenJPEG " - msg += "in order to write images." - raise RuntimeError(msg) + 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._determine_colorspace(**kwargs) self._populate_cparams(img_array, **kwargs) @@ -530,12 +517,10 @@ class Jp2k(Jp2kBox): # set image offset and reference grid image.contents.x0 = self._cparams.image_offset_x0 image.contents.y0 = self._cparams.image_offset_y0 - image.contents.x1 = (image.contents.x0 - + (numcols - 1) * self._cparams.subsampling_dx - + 1) - image.contents.y1 = (image.contents.y0 - + (numrows - 1) * self._cparams.subsampling_dy - + 1) + image.contents.x1 = image.contents.x0 \ + + (numcols - 1) * self._cparams.subsampling_dx + 1 + image.contents.y1 = image.contents.y0 \ + + (numrows - 1) * self._cparams.subsampling_dy + 1 # Stage the image data to the openjpeg data structure. for k in range(0, numlayers): @@ -648,7 +633,7 @@ class Jp2k(Jp2kBox): def _determine_colorspace(self, colorspace=None, **kwargs): """Determine the colorspace from the supplied inputs. - + Parameters ---------- colorspace : str, optional @@ -673,7 +658,7 @@ class Jp2k(Jp2kBox): elif colorspace.lower() == 'rgb' and self.shape[2] < 3: msg = 'RGB colorspace requires at least 3 components.' raise IOError(msg) - + # Turn the colorspace from a string to the enumerated value that # the library expects. COLORSPACE_MAP = {'rgb': opj2.CLRSPC_SRGB, @@ -682,7 +667,8 @@ class Jp2k(Jp2kBox): 'ycc': opj2.CLRSPC_YCC} self._colorspace = COLORSPACE_MAP[colorspace.lower()] - + + def _write_openjp2(self, img_array, verbose=False): """ Write JPEG 2000 file using OpenJPEG 2.x interface. @@ -748,8 +734,7 @@ class Jp2k(Jp2kBox): if not ((box.box_id == 'xml ') or (box.box_id == 'uuid' and box.uuid == UUID('be7acfcb-97a9-42e8-9c71-999491e3afac'))): - msg = "Only XML boxes and XMP UUID boxes can currently be " - msg += "appended." + msg = "Only XML boxes and XMP UUID boxes can currently be appended." raise IOError(msg) # Check the last box. If the length field is zero, then rewrite @@ -845,7 +830,7 @@ class Jp2k(Jp2kBox): raise IOError(msg) # Find the first codestream in the file. - jp2c = [_box for _box in self.box if _box.box_id == 'jp2c'] + jp2c = [box for box in self.box if box.box_id == 'jp2c'] offset = jp2c[0].offset # Ready to write the codestream. @@ -879,9 +864,10 @@ class Jp2k(Jp2kBox): FileTypeBox(), JP2HeaderBox(), ContiguousCodestreamBox()] - height = self.codestream.segment[1].ysiz - width = self.codestream.segment[1].xsiz - num_components = len(self.codestream.segment[1].xrsiz) + codestream = self.get_codestream() + height = codestream.segment[1].ysiz + width = codestream.segment[1].xsiz + num_components = len(codestream.segment[1].xrsiz) if num_components < 3: colorspace = core.GREYSCALE else: @@ -905,9 +891,9 @@ class Jp2k(Jp2kBox): Slicing protocol. """ if ((isinstance(index, slice) and - (index.start is None and - index.stop is None and - index.step is None)) or (index is Ellipsis)): + (index.start == None and + index.stop == None and + index.step == None)) or (index is Ellipsis)): # Case of jp2[:] = data, i.e. write the entire image. # # Should have a slice object where start = stop = step = None @@ -920,11 +906,10 @@ class Jp2k(Jp2kBox): """ Slicing protocol. """ - if len(self.shape) == 2: - numrows, numcols = self.shape - numbands = 1 - else: - numrows, numcols, numbands = self.shape + codestream = self.get_codestream(header_only=True) + numrows = codestream.segment[1].ysiz + numcols = codestream.segment[1].xsiz + numbands = codestream.segment[1].Csiz if isinstance(pargs, int): # Not a very good use of this protocol, but technically legal. @@ -938,14 +923,12 @@ class Jp2k(Jp2kBox): return self._read() if isinstance(pargs, slice): - if (((pargs.start is None) and - (pargs.stop is None) and - (pargs.step is None))): + if pargs.start is None and pargs.stop is None and pargs.step is None: # Case of jp2[:] 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 + # members. Just augment it with an ellipsis and let the code # below handle it. pargs = (pargs, Ellipsis) @@ -988,7 +971,8 @@ class Jp2k(Jp2kBox): # Reduce dimensionality in the scalar dimension. return np.squeeze(data, axis=idx) - # Assuming pargs is a tuple of slices from now on. + + # Assuming pargs is a tuple of slices from now on. rows = pargs[0] cols = pargs[1] if len(pargs) == 2: @@ -1005,14 +989,15 @@ class Jp2k(Jp2kBox): # Ok, reduce layer step is the same in both xy directions, so just take # one of them. step = rows_step - + # Check if the step size is a power of 2. if np.abs(np.log2(step) - np.round(np.log2(step))) > 1e-6: msg = "Row and column strides must be powers of 2." raise IndexError(msg) rlevel = np.int(np.round(np.log2(step))) - area = (0 if rows.start is None else rows.start, + area = ( + 0 if rows.start is None else rows.start, 0 if cols.start is None else cols.start, numrows if rows.stop is None else rows.stop, numcols if cols.stop is None else cols.stop @@ -1024,6 +1009,7 @@ class Jp2k(Jp2kBox): # Ok, 3 arguments in pargs. return data[:, :, bands] + def _read(self, **kwargs): """Read a JPEG 2000 image. @@ -1046,34 +1032,34 @@ class Jp2k(Jp2kBox): def read(self, **kwargs): """ """ - # Read a JPEG 2000 image. + #Read a JPEG 2000 image. # - # Parameters - # ---------- - # rlevel : int, optional - # Factor by which to rlevel output resolution. Use -1 to get the - # lowest resolution thumbnail. This is the only keyword option - # available to use when the OpenJPEG version is 1.5 or earlier. - # layer : int, optional - # Number of quality layer to decode. - # area : tuple, optional - # Specifies decoding image area, - # (first_row, first_col, last_row, last_col) - # tile : int, optional - # Number of tile to decode. - # verbose : bool, optional - # Print informational messages produced by the OpenJPEG library. + #Parameters + #---------- + #rlevel : int, optional + # Factor by which to rlevel output resolution. Use -1 to get the + # lowest resolution thumbnail. This is the only keyword option + # available to use when the OpenJPEG version is 1.5 or earlier. + #layer : int, optional + # Number of quality layer to decode. + #area : tuple, optional + # Specifies decoding image area, + # (first_row, first_col, last_row, last_col) + #tile : int, optional + # Number of tile to decode. + #verbose : bool, optional + # Print informational messages produced by the OpenJPEG library. # - # Returns - # ------- - # img_array : ndarray - # The image data. + #Returns + #------- + #img_array : ndarray + # The image data. # - # Raises - # ------ - # IOError - # If the image has differing subsample factors. - + #Raises + #------ + #IOError + # If the image has differing subsample factors. + 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) @@ -1086,8 +1072,9 @@ class Jp2k(Jp2kBox): def _subsampling_sanity_check(self): """Check for differing subsample factors. """ - dxs = np.array(self.codestream.segment[1].xrsiz) - dys = np.array(self.codestream.segment[1].yrsiz) + codestream = self.get_codestream(header_only=True) + dxs = np.array(codestream.segment[1].xrsiz) + dys = np.array(codestream.segment[1].yrsiz) if np.any(dxs - dxs[0]) or np.any(dys - dys[0]): msg = "Components must all have the same subsampling factors " msg += "to use this method. Please consider using OPENJP2 and " @@ -1176,8 +1163,7 @@ class Jp2k(Jp2kBox): return data - def _read_openjp2(self, rlevel=0, layer=None, area=None, tile=None, - verbose=False): + def _read_openjp2(self, rlevel=0, layer=None, area=None, tile=None, verbose=False): """Read a JPEG 2000 image using libopenjp2. Parameters @@ -1290,7 +1276,8 @@ class Jp2k(Jp2kBox): # Must check the specified rlevel against the maximum. if rlevel != 0: # Must check the specified rlevel against the maximum. - max_rlevel = self.codestream.segment[2].spcod[4] + codestream = self.get_codestream() + max_rlevel = codestream.segment[2].spcod[4] if rlevel == -1: # -1 is shorthand for the largest rlevel rlevel = max_rlevel @@ -1446,6 +1433,7 @@ class Jp2k(Jp2kBox): codestream = Codestream(fptr, self.length, header_only=header_only) else: + ftyp = self.box[1] box = [x for x in self.box if x.box_id == 'jp2c'] fptr.seek(box[0].offset) read_buffer = fptr.read(8) @@ -1465,7 +1453,7 @@ class Jp2k(Jp2kBox): def _populate_image_struct(self, image, imgdata): """Populates image struct needed for compression. - + Parameters ---------- image : ImageType(ctypes.Structure) @@ -1473,9 +1461,9 @@ class Jp2k(Jp2kBox): img_array : ndarray Image data to be written to file. """ - + numrows, numcols, num_comps = imgdata.shape - + # set image offset and reference grid image.contents.x0 = self._cparams.image_offset_x0 image.contents.y0 = self._cparams.image_offset_y0 @@ -1483,7 +1471,7 @@ class Jp2k(Jp2kBox): (numcols - 1) * self._cparams.subsampling_dx + 1) image.contents.y1 = (image.contents.y0 + (numrows - 1) * self._cparams.subsampling_dy + 1) - + # Stage the image data to the openjpeg data structure. for k in range(0, num_comps): if re.match("2.0", version.openjpeg_version) is not None: @@ -1497,19 +1485,19 @@ class Jp2k(Jp2kBox): core.OPJ_PROFILE_CINEMA_4K): image.contents.comps[k].prec = 12 image.contents.comps[k].bpp = 12 - + layer = np.ascontiguousarray(imgdata[:, :, k], dtype=np.int32) dest = image.contents.comps[k].data src = layer.ctypes.data ctypes.memmove(dest, src, layer.nbytes) - + return image - + def _populate_comptparms(self, img_array): """Instantiate and populate comptparms structure. - + This structure defines the image components. - + Parameters ---------- img_array : ndarray @@ -1538,8 +1526,8 @@ class Jp2k(Jp2kBox): comptparms[j].sgnd = 0 self._comptparms = comptparms - - + + def _component2dtype(component): """Take an OpenJPEG component structure and determine the numpy datatype. @@ -1585,7 +1573,6 @@ JP2_IDS = ['colr', 'cdef', 'cmap', 'jp2c', 'ftyp', 'ihdr', 'jp2h', 'jP ', 'pclr', 'res ', 'resc', 'resd', 'xml ', 'ulst', 'uinf', 'url ', 'uuid'] - def _validate_jp2_box_sequence(boxes): """Run through series of tests for JP2 box legality. @@ -1601,13 +1588,12 @@ def _validate_jp2_box_sequence(boxes): count = _collect_box_count(boxes) for box_id in count.keys(): if box_id not in JP2_IDS: - msg = "The presence of a '{0}' box requires that the file " - msg += "type brand be set to 'jpx '." + msg = "The presence of a '{0}' box requires that the file type " + msg += "brand be set to 'jpx '." raise IOError(msg.format(box_id)) _validate_jp2_colr(boxes) - def _validate_jp2_colr(boxes): """ Validate JP2 requirements on colour specification boxes. @@ -1619,7 +1605,6 @@ def _validate_jp2_colr(boxes): msg = "A JP2 colr box cannot have a non-zero approximation field." raise IOError(msg) - def _validate_jpx_box_sequence(boxes): """Run through series of tests for JPX box legality.""" _validate_label(boxes) @@ -1628,7 +1613,6 @@ def _validate_jpx_box_sequence(boxes): _validate_singletons(boxes) _validate_top_level(boxes) - def _validate_signature_compatibility(boxes): """Validate the file signature and compatibility status.""" # Check for a bad sequence of boxes. @@ -1716,8 +1700,6 @@ def _validate_channel_definition(jp2h, colr): JP2H_CHILDREN = set(['bpcc', 'cdef', 'cmap', 'ihdr', 'pclr']) - - def _check_jp2h_child_boxes(boxes, parent_box_name): """Certain boxes can only reside in the JP2 header.""" box_ids = set([box.box_id for box in boxes]) @@ -1745,7 +1727,6 @@ def _collect_box_count(boxes): TOP_LEVEL_ONLY_BOXES = set(['dtbl']) - def _check_superbox_for_top_levels(boxes): """Several boxes can only occur at the top level.""" # We are only looking at the boxes contained in a superbox, so if any of @@ -1761,7 +1742,6 @@ def _check_superbox_for_top_levels(boxes): if hasattr(box, 'box'): _check_superbox_for_top_levels(box.box) - def _validate_top_level(boxes): """Several boxes can only occur at the top level.""" # Add the counts in the superboxes. @@ -1781,7 +1761,6 @@ def _validate_top_level(boxes): msg += 'a fragment table box as well.' raise IOError(msg) - def _validate_singletons(boxes): """Several boxes can only occur once.""" count = _collect_box_count(boxes) @@ -1792,7 +1771,6 @@ def _validate_singletons(boxes): JPX_IDS = ['asoc', 'nlst'] - def _validate_jpx_brand(boxes, brand): """ If there is a JPX box then the brand must be 'jpx '. @@ -1807,7 +1785,6 @@ def _validate_jpx_brand(boxes, brand): # Same set of checks on any child boxes. _validate_jpx_brand(box.box, brand) - def _validate_jpx_compatibility(boxes, compatibility_list): """ If there is a JPX box then the compatibility list must also contain 'jpx '. @@ -1823,7 +1800,6 @@ def _validate_jpx_compatibility(boxes, compatibility_list): # Same set of checks on any child boxes. _validate_jpx_compatibility(box.box, compatibility_list) - def _validate_label(boxes): """ Label boxes can only be inside association, codestream headers, or @@ -1840,7 +1816,6 @@ def _validate_label(boxes): # Same set of checks on any child boxes. _validate_label(box.box) - def extract_image_cube(image): """Extract 3D image from openjpeg data structure. """ @@ -1896,6 +1871,7 @@ def extract_image_bands(image): return data + # Setup the default callback handlers. See the callback functions subsection # in the ctypes section of the Python documentation for a solid explanation of # what's going on here. diff --git a/glymur/lib/__init__.py b/glymur/lib/__init__.py index ddce813..a283f7f 100644 --- a/glymur/lib/__init__.py +++ b/glymur/lib/__init__.py @@ -2,5 +2,3 @@ from . import openjp2 as openjp2 from . import openjpeg as openjpeg from . import c - -__all__ = [openjp2, openjpeg, c] diff --git a/glymur/lib/config.py b/glymur/lib/config.py index 8af038a..4b92b9d 100644 --- a/glymur/lib/config.py +++ b/glymur/lib/config.py @@ -1,6 +1,9 @@ """ Configure glymur to use installed libraries if possible. """ +# configparser is new in python3 (pylint/python-2.7) +# pylint: disable=F0401 + import ctypes from ctypes.util import find_library import os @@ -16,21 +19,18 @@ else: from configparser import NoOptionError # default library locations for MacPorts -_macports_default_location = {'openjp2': '/opt/local/lib/libopenjp2.dylib', - 'openjpeg': '/opt/local/lib/libopenjpeg.dylib'} +_macports_default_location = { + 'openjp2': '/opt/local/lib/libopenjp2.dylib', + 'openjpeg': '/opt/local/lib/libopenjpeg.dylib' +} # default library locations on Windows -_windows_default_location = {'openjp2': os.path.join('C:\\', - 'Program files', - 'OpenJPEG 2.0', - 'bin', - 'openjp2.dll'), - 'openjpeg': os.path.join('C:\\', - 'Program files', - 'OpenJPEG 1.5', - 'bin', - 'openjpeg.dll')} - +_windows_default_location = { + 'openjp2': os.path.join('C:\\', 'Program files', 'OpenJPEG 2.0', + 'bin', 'openjp2.dll'), + 'openjpeg': os.path.join('C:\\', 'Program files', 'OpenJPEG 1.5', + 'bin', 'openjpeg.dll') +} def glymurrc_fname(): """Return the path to the configuration file. @@ -55,9 +55,8 @@ def glymurrc_fname(): # didn't find a configuration file. return None - def load_openjpeg_library(libname): - + path = read_config_file(libname) if path is not None: return load_library_handle(path) @@ -80,15 +79,13 @@ def load_openjpeg_library(libname): return load_library_handle(path) - def load_library_handle(path): """Load the library, return the ctypes handle.""" if path is None or path in ['None', 'none']: - # Either could not find a library via ctypes or - # user-configuration-file, or we could not find it in any of the - # default locations, or possibly the user intentionally does not want - # one of the libraries to load. + # Either could not find a library via ctypes or user-configuration-file, + # or we could not find it in any of the default locations, or possibly + # the user intentionally does not want one of the libraries to load. return None try: @@ -97,10 +94,10 @@ def load_library_handle(path): else: opj_lib = ctypes.CDLL(path) except (TypeError, OSError): - msg = 'The library specified by configuration file at {0} could not ' - msg += 'be loaded.' - warnings.warn(msg.format(path), UserWarning) - opj_lib = None + msg = 'The library specified by configuration file at {0} could not be ' + msg += 'loaded.' + warnings.warn(msg.format(path), UserWarning) + opj_lib = None return opj_lib @@ -133,7 +130,6 @@ def read_config_file(libname): path = None return path - def glymur_config(): """ Try to ascertain locations of openjp2, openjpeg libraries. @@ -148,10 +144,9 @@ def glymur_config(): lst.append(load_openjpeg_library(libname)) if all(handle is None for handle in lst): msg = "Neither the openjp2 nor the openjpeg library could be loaded. " - warnings.warn(msg) + raise IOError(msg) return tuple(lst) - def get_configdir(): """Return string representing the configuration directory. diff --git a/glymur/lib/openjp2.py b/glymur/lib/openjp2.py index aed4db6..5e58cf4 100644 --- a/glymur/lib/openjp2.py +++ b/glymur/lib/openjp2.py @@ -2,6 +2,8 @@ Wraps individual functions in openjp2 library. """ +# pylint: disable=C0302,R0903,W0201 + import ctypes import re import sys @@ -11,7 +13,6 @@ from .config import glymur_config OPENJP2, OPENJPEG = glymur_config() - def version(): """Wrapper for opj_version library routine.""" try: @@ -49,6 +50,13 @@ JPWL_MAX_NO_TILESPECS = 16 TRUE = 1 FALSE = 0 +#PROFILE = {'none': 0, # No profile +# 0: 1, # Profile 0 +# 1: 2, # Profile 1 +# 'part2': 0x8000, # At least one extension +# 'Cinema2K': 0x0003, # 2K cinema profile +# 'Cinema4K': 0x0004, # 4K cinema profile + # supported color spaces CLRSPC_UNKNOWN = -1 CLRSPC_UNSPECIFIED = 0 @@ -408,6 +416,7 @@ class CompressionParametersType(ctypes.Structure): for j in range(self.numpocs): msg += " [#{0}]:".format(j) msg += " {0}".format(str(self.poc[j])) + msg += textwrap.indent(textstr, ' ' * 12) elif field_name in ['tcp_rates', 'tcp_distoratio']: lst = [] @@ -539,6 +548,7 @@ class ImageType(ctypes.Structure): return msg + class ImageComptParmType(ctypes.Structure): """Component parameters structure used by image_create function. @@ -737,6 +747,28 @@ def encode(codec, stream): OPENJP2.opj_encode(codec, stream) +def get_cstr_info(codec): + """get the codestream information from the codec + + Wraps the openjp2 library function opj_get_cstr_info. + + Parameters + ---------- + codec : CODEC_TYPE + The jpeg2000 codec. + + Returns + ------- + cstr_info_p : CodestreamInfoV2 + Reference to codestream information. + """ + OPENJP2.opj_get_cstr_info.argtypes = [CODEC_TYPE] + OPENJP2.opj_get_cstr_info.restype = ctypes.POINTER(CodestreamInfoV2) + + cstr_info_p = OPENJP2.opj_get_cstr_info(codec) + return cstr_info_p + + def get_decoded_tile(codec, stream, imagep, tile_index): """get the decoded tile from the codec @@ -767,6 +799,23 @@ def get_decoded_tile(codec, stream, imagep, tile_index): OPENJP2.opj_get_decoded_tile(codec, stream, imagep, tile_index) +def destroy_cstr_info(cstr_info_p): + """destroy codestream information after compression or decompression + + Wraps the openjp2 library function opj_destroy_cstr_info. + + Parameters + ---------- + cstr_info_p : CodestreamInfoV2 pointer + Pointer to codestream info structure. + """ + ARGTYPES = [ctypes.POINTER(ctypes.POINTER(CodestreamInfoV2))] + OPENJP2.opj_destroy_cstr_info.argtypes = ARGTYPES + OPENJP2.opj_destroy_cstr_info.restype = ctypes.c_void_p + + OPENJP2.opj_destroy_cstr_info(ctypes.byref(cstr_info_p)) + + def end_compress(codec, stream): """End of compressing the current image. @@ -909,7 +958,7 @@ def read_header(stream, codec): ARGTYPES = [STREAM_TYPE_P, CODEC_TYPE, ctypes.POINTER(ctypes.POINTER(ImageType))] OPENJP2.opj_read_header.argtypes = ARGTYPES - OPENJP2.opj_read_header.restype = check_error + OPENJP2.opj_read_header.restype = check_error imagep = ctypes.POINTER(ImageType)() OPENJP2.opj_read_header(stream, codec, ctypes.byref(imagep)) @@ -1268,7 +1317,6 @@ def _stream_create_default_file_stream_2p0(fptr, isa_read_stream): stream = OPENJP2.opj_stream_create_default_file_stream(fptr, read_stream) return stream - def _stream_create_default_file_stream_2p1(fname, isa_read_stream): """Wraps openjp2 library function opj_stream_create_default_vile_stream. @@ -1295,7 +1343,7 @@ def _stream_create_default_file_stream_2p1(fname, isa_read_stream): stream = OPENJP2.opj_stream_create_default_file_stream(file_argument, read_stream) return stream - + if re.match(r'''2.0''', version()): stream_create_default_file_stream = _stream_create_default_file_stream_2p0 else: diff --git a/glymur/lib/openjpeg.py b/glymur/lib/openjpeg.py index d2f156b..d1918ad 100644 --- a/glymur/lib/openjpeg.py +++ b/glymur/lib/openjpeg.py @@ -1,9 +1,13 @@ """Wraps library calls to openjpeg. """ +# pylint: disable=R0903 + import ctypes import sys +import numpy as np + from .config import glymur_config _, OPENJPEG = glymur_config() @@ -55,10 +59,8 @@ class CommonStructType(ctypes.Structure): ("mj2_handle", ctypes.c_void_p)] -STREAM_READ = 0x0001 # The stream was opened for reading. -STREAM_WRITE = 0x0002 # The stream was opened for writing. - - +STREAM_READ = 0x0001 # The stream was opened for reading. +STREAM_WRITE = 0x0002 # The stream was opened for writing. class CioType(ctypes.Structure): """Byte input-output stream (CIO) @@ -89,57 +91,70 @@ class CompressionInfoType(CommonStructType): class PocType(ctypes.Structure): """Progression order changes.""" _fields_ = [("resno", ctypes.c_int), - # Resolution num start, Component num start, given by POC - ("compno0", ctypes.c_int), + # Resolution num start, Component num start, given by POC + ("compno0", ctypes.c_int), - # Layer num end,Resolution num end, Component num end, given - # by POC - ("layno1", ctypes.c_int), - ("resno1", ctypes.c_int), - ("compno1", ctypes.c_int), + # Layer num end,Resolution num end, Component num end, given by POC + ("layno1", ctypes.c_int), + ("resno1", ctypes.c_int), + ("compno1", ctypes.c_int), - # Layer num start,Precinct num start, Precinct num end - ("layno0", ctypes.c_int), - ("precno0", ctypes.c_int), - ("precno1", ctypes.c_int), + # Layer num start,Precinct num start, Precinct num end + ("layno0", ctypes.c_int), + ("precno0", ctypes.c_int), + ("precno1", ctypes.c_int), - # Progression order enum - # OPJ_PROG_ORDER prg1,prg; - ("prg1", ctypes.c_int), - ("prg", ctypes.c_int), + # Progression order enum + # OPJ_PROG_ORDER prg1,prg; + ("prg1", ctypes.c_int), + ("prg", ctypes.c_int), - # Progression order string - # char progorder[5]; - ("progorder", ctypes.c_char * 5), + # Progression order string + # char progorder[5]; + ("progorder", ctypes.c_char * 5), - # Tile number - # int tile; - ("tile", ctypes.c_int), + # Tile number + # int tile; + ("tile", ctypes.c_int), - ("tx0", ctypes.c_int), - ("tx1", ctypes.c_int), - ("ty0", ctypes.c_int), - ("ty1", ctypes.c_int), - ("layS", ctypes.c_int), - ("resS", ctypes.c_int), - ("compS", ctypes.c_int), - ("prcS", ctypes.c_int), - ("layE", ctypes.c_int), - ("resE", ctypes.c_int), - ("compE", ctypes.c_int), - ("prcE", ctypes.c_int), - ("txS", ctypes.c_int), - ("txE", ctypes.c_int), - ("tyS", ctypes.c_int), - ("tyE", ctypes.c_int), - ("dx", ctypes.c_int), - ("dy", ctypes.c_int), - ("lay_t", ctypes.c_int), - ("res_t", ctypes.c_int), - ("comp_t", ctypes.c_int), - ("prc_t", ctypes.c_int), - ("tx0_t", ctypes.c_int), - ("ty0_t", ctypes.c_int)] + # /** Start and end values for Tile width and height*/ + # int tx0,tx1,ty0,ty1; + ("tx0", ctypes.c_int), + ("tx1", ctypes.c_int), + ("ty0", ctypes.c_int), + ("ty1", ctypes.c_int), + + # /** Start value, initialised in pi_initialise_encode*/ + # int layS, resS, compS, prcS; + ("layS", ctypes.c_int), + ("resS", ctypes.c_int), + ("compS", ctypes.c_int), + ("prcS", ctypes.c_int), + + # /** End value, initialised in pi_initialise_encode */ + # int layE, resE, compE, prcE; + ("layE", ctypes.c_int), + ("resE", ctypes.c_int), + ("compE", ctypes.c_int), + ("prcE", ctypes.c_int), + + # Start and end values of Tile width and height, initialised in + # pi_initialise_encode int txS,txE,tyS,tyE,dx,dy; + ("txS", ctypes.c_int), + ("txE", ctypes.c_int), + ("tyS", ctypes.c_int), + ("tyE", ctypes.c_int), + ("dx", ctypes.c_int), + ("dy", ctypes.c_int), + + # Temporary values for Tile parts, initialised in pi_create_encode + # int lay_t, res_t, comp_t, prc_t,tx0_t,ty0_t; + ("lay_t", ctypes.c_int), + ("res_t", ctypes.c_int), + ("comp_t", ctypes.c_int), + ("prc_t", ctypes.c_int), + ("tx0_t", ctypes.c_int), + ("ty0_t", ctypes.c_int)] class CompressionParametersType(ctypes.Structure): @@ -360,47 +375,48 @@ class DecompressionParametersType(ctypes.Structure): class ImageComptParmType(ctypes.Structure): """Component parameters structure used by the opj_image_create function. """ - _fields_ = [("dx", ctypes.c_int), - # XRsiz: horizontal separation of a sample of ith component - # with respect to the reference grid + _fields_ = [ + # XRsiz: horizontal separation of a sample of ith component with + # respect to the reference grid + ("dx", ctypes.c_int), - # YRsiz: vertical separation of a sample of ith component with - # respect to the reference grid */ - ("dy", ctypes.c_int), + # YRsiz: vertical separation of a sample of ith component with + # respect to the reference grid */ + ("dy", ctypes.c_int), - # data width, height - ("w", ctypes.c_int), - ("h", ctypes.c_int), + # data width, height + ("w", ctypes.c_int), + ("h", ctypes.c_int), - # x component offset compared to the whole image - # y component offset compared to the whole image - ("x0", ctypes.c_int), - ("y0", ctypes.c_int), + # x component offset compared to the whole image + # y component offset compared to the whole image + ("x0", ctypes.c_int), + ("y0", ctypes.c_int), - # precision - ('prec', ctypes.c_int), + # precision + ('prec', ctypes.c_int), - # image depth in bits - ('bpp', ctypes.c_int), + # image depth in bits + ('bpp', ctypes.c_int), - # signed (1) / unsigned (0) - ('sgnd', ctypes.c_int)] + # signed (1) / unsigned (0) + ('sgnd', ctypes.c_int)] class ImageCompType(ctypes.Structure): """Defines a single image component. """ _fields_ = [("dx", ctypes.c_int), - ("dy", ctypes.c_int), - ("w", ctypes.c_int), - ("h", ctypes.c_int), - ("x0", ctypes.c_int), - ("y0", ctypes.c_int), - ("prec", ctypes.c_int), - ("bpp", ctypes.c_int), - ("sgnd", ctypes.c_int), - ("resno_decoded", ctypes.c_int), - ("factor", ctypes.c_int), - ("data", ctypes.POINTER(ctypes.c_int))] + ("dy", ctypes.c_int), + ("w", ctypes.c_int), + ("h", ctypes.c_int), + ("x0", ctypes.c_int), + ("y0", ctypes.c_int), + ("prec", ctypes.c_int), + ("bpp", ctypes.c_int), + ("sgnd", ctypes.c_int), + ("resno_decoded", ctypes.c_int), + ("factor", ctypes.c_int), + ("data", ctypes.POINTER(ctypes.c_int))] class ImageType(ctypes.Structure): @@ -452,7 +468,6 @@ def cio_tell(cio): pos = OPENJPEG.cio_tell(cio) return pos - def create_compress(fmt): """Wrapper for openjpeg library function opj_create_compress. @@ -523,11 +538,56 @@ def destroy_decompress(dinfo): OPENJPEG.opj_destroy_decompress(dinfo) +def image_cmptparm_t_from_np(np_image): + """Return appropriate image_cmptparm_t based on given numpy array. + """ + try: + num_comps = np_image.shape[2] + except IndexError: + num_comps = 1 + + cmpt_parm_array_t = ImageCmptparmType * num_comps + tarr = cmpt_parm_array_t() + + if np_image.dtype == np.uint8: + prec = 8 + bpp = 8 + sgnd = 0 + elif np_image.dtype == np.int8: + prec = 8 + bpp = 8 + sgnd = 1 + elif np_image.dtype == np.uint16: + prec = 16 + bpp = 16 + sgnd = 0 + elif np_image.dtype == np.int16: + prec = 16 + bpp = 16 + sgnd = 1 + else: + raise(TypeError("unhandled")) + + for j in range(0, num_comps): + tarr[j].dx = 1 + tarr[j].dy = 1 + tarr[j].w = np_image.shape[1] + tarr[j].h = np_image.shape[0] + tarr[j].x0 = 0 + tarr[j].y0 = 0 + tarr[j].prec = prec + tarr[j].bpp = bpp + tarr[j].sgnd = sgnd + + return(tarr) + + def image_create(cmptparms, cspace): """Wrapper for openjpeg library function opj_image_create. """ - lst = [ctypes.c_int, ctypes.POINTER(ImageComptParmType), ctypes.c_int] - OPENJPEG.opj_image_create.argtypes = lst + OPENJPEG.opj_image_create.argtypes = [ctypes.c_int, + ctypes.POINTER(ImageComptParmType), + ctypes.c_int] OPENJPEG.opj_image_create.restype = ctypes.POINTER(ImageType) image = OPENJPEG.opj_image_create(len(cmptparms), cmptparms, cspace) diff --git a/glymur/lib/test/test_openjp2.py b/glymur/lib/test/test_openjp2.py index c32ee89..988ace1 100644 --- a/glymur/lib/test/test_openjp2.py +++ b/glymur/lib/test/test_openjp2.py @@ -1,8 +1,13 @@ """ Tests for libopenjp2 wrapping functions. """ +# R0904: Seems like pylint is fooled in this situation +# W0142: using kwargs is ok in this context +# pylint: disable=R0904,W0142 + import os import re +import sys import tempfile import unittest @@ -16,8 +21,8 @@ from glymur.lib import openjp2 @unittest.skipIf(openjp2.OPENJP2 is None, "Missing openjp2 library.") @unittest.skipIf(re.match(r'''(1|2.0)''', - glymur.version.openjpeg_version) is not None, - "Not to be run until 2.1.0") + glymur.version.openjpeg_version) is not None, + "Not to be run until 2.1.0") class TestOpenJP2(unittest.TestCase): """Test openjp2 library functionality. @@ -147,7 +152,6 @@ class TestOpenJP2(unittest.TestCase): xtx5_setup(tfile.name) self.assertTrue(True) - def tile_encoder(**kwargs): """Fixture used by many tests.""" num_tiles = ((kwargs['image_width'] / kwargs['tile_width']) * @@ -211,7 +215,7 @@ def tile_encoder(**kwargs): openjp2.setup_encoder(codec, l_param, l_image) stream = openjp2.stream_create_default_file_stream(kwargs['filename'], - False) + False) openjp2.start_compress(codec, l_image, stream) for j in np.arange(num_tiles): @@ -222,14 +226,13 @@ def tile_encoder(**kwargs): openjp2.destroy_codec(codec) openjp2.image_destroy(l_image) - def tile_decoder(**kwargs): """Fixture called with various configurations by many tests. Reads a tile. That's all it does. """ stream = openjp2.stream_create_default_file_stream(kwargs['filename'], - True) + True) dparam = openjp2.set_default_decoder_parameters() dparam.decod_format = kwargs['codec_format'] @@ -267,7 +270,6 @@ def tile_decoder(**kwargs): openjp2.stream_destroy(stream) openjp2.image_destroy(image) - def ttx0_setup(filename): """Runs tests tte0, tte0.""" kwargs = {'filename': filename, @@ -281,7 +283,6 @@ def ttx0_setup(filename): 'tile_width': 100} tile_encoder(**kwargs) - def xtx2_setup(filename): """Runs tests rta2, tte2, ttd2.""" kwargs = {'filename': filename, @@ -295,7 +296,6 @@ def xtx2_setup(filename): 'tile_width': 128} tile_encoder(**kwargs) - def xtx3_setup(filename): """Runs tests tte3, rta3.""" kwargs = {'filename': filename, @@ -309,7 +309,6 @@ def xtx3_setup(filename): 'tile_width': 128} tile_encoder(**kwargs) - def xtx4_setup(filename): """Runs tests rta4, tte4.""" kwargs = {'filename': filename, @@ -323,7 +322,6 @@ def xtx4_setup(filename): 'tile_width': 128} tile_encoder(**kwargs) - def xtx5_setup(filename): """Runs tests rta5, tte5.""" kwargs = {'filename': filename, @@ -336,3 +334,6 @@ def xtx5_setup(filename): 'tile_height': 256, 'tile_width': 256} tile_encoder(**kwargs) + +if __name__ == "__main__": + unittest.main() diff --git a/glymur/lib/test/test_openjpeg.py b/glymur/lib/test/test_openjpeg.py index 449083f..f28656c 100644 --- a/glymur/lib/test/test_openjpeg.py +++ b/glymur/lib/test/test_openjpeg.py @@ -1,6 +1,8 @@ """ Tests for OpenJPEG module. """ +# pylint: disable=E1101,R0904 + import ctypes import re import sys @@ -8,7 +10,6 @@ import unittest import glymur - @unittest.skipIf(glymur.lib.openjpeg.OPENJPEG is None, "Missing openjpeg library.") class TestOpenJPEG(unittest.TestCase): diff --git a/glymur/lib/test/test_printing.py b/glymur/lib/test/test_printing.py index c7be21c..3d0e2b6 100644 --- a/glymur/lib/test/test_printing.py +++ b/glymur/lib/test/test_printing.py @@ -16,9 +16,8 @@ else: import glymur from . import fixtures - @unittest.skipIf(sys.hexversion < 0x03000000, "do not care about 2.7 here") -@unittest.skipIf(re.match('0|1|2.0', glymur.version.openjpeg_version), +@unittest.skipIf(re.match('1|2.0', glymur.version.openjpeg_version), "Requires openjpeg 2.1.0 or higher") class TestPrintingOpenjp2(unittest.TestCase): """Tests for verifying how printing works on openjp2 library structures.""" @@ -73,3 +72,6 @@ class TestPrintingOpenjp2(unittest.TestCase): expected = fixtures.default_image_type self.assertRegex(actual, expected) + + + diff --git a/glymur/test/fixtures.py b/glymur/test/fixtures.py index 34327fc..481da2d 100644 --- a/glymur/test/fixtures.py +++ b/glymur/test/fixtures.py @@ -13,14 +13,6 @@ import six import glymur -# If openjpeg is not installed, many tests cannot be run. -if glymur.version.openjpeg_version == '0.0.0': - OPENJPEG_NOT_AVAILABLE = True - OPENJPEG_NOT_AVAILABLE_MSG = 'OpenJPEG library not installed' -else: - OPENJPEG_NOT_AVAILABLE = False - OPENJPEG_NOT_AVAILABLE_MSG = None - # Some versions of "six" on python3 cause problems when verifying warnings. # Only use when the version is 1.7 or higher. # And moreover, we only test using the 3.x infrastructure, never on 2.x. @@ -37,7 +29,6 @@ elif re.match('1.[0-6]', six.__version__) is not None: # Cannot reopen a named temporary file in windows. WINDOWS_TMP_FILE_MSG = "cannot use NamedTemporaryFile like this in windows" - class MetadataBase(unittest.TestCase): """ Base class for testing metadata. @@ -102,8 +93,8 @@ class MetadataBase(unittest.TestCase): """ verify the fields of a RGN segment """ - self.assertEqual(actual.crgn, expected.crgn) # 0 = component - self.assertEqual(actual.srgn, expected.srgn) # 0 = implicit + self.assertEqual(actual.crgn, expected.crgn) # 0 = component + self.assertEqual(actual.srgn, expected.srgn) # 0 = implicit self.assertEqual(actual.sprgn, expected.sprgn) def verifySOTsegment(self, actual, expected): @@ -126,9 +117,8 @@ class MetadataBase(unittest.TestCase): """ Verify the fields of the SIZ segment. """ - for field in ['rsiz', 'xsiz', 'ysiz', 'xosiz', 'yosiz', 'xtsiz', - 'ytsiz', 'xtosiz', 'ytosiz', 'bitdepth', - 'xrsiz', 'yrsiz']: + for field in ['rsiz', 'xsiz', 'ysiz', 'xosiz', 'yosiz', 'xtsiz', + 'ytsiz', 'xtosiz', 'ytosiz', 'bitdepth', 'xrsiz', 'yrsiz']: self.assertEqual(getattr(actual, field), getattr(expected, field)) def verifyImageHeaderBox(self, box1, box2): @@ -155,7 +145,7 @@ class MetadataBase(unittest.TestCase): else: self.assertEqual(actual.colorspace, expected.colorspace) self.assertIsNone(actual.icc_profile) - + # The Python XMP Toolkit may be used for XMP UUIDs, but only if available and # if the version is at least 2.0.0. @@ -185,7 +175,7 @@ except: # The Cinema2K/4K tests seem to need the freeimage backend to skimage.io # in order to work. Unfortunately, scikit-image/freeimage is about as wonky as # it gets. Anaconda can get totally weirded out on versions up through 3.6.4 -# on Python3 with scikit-image up through version 0.10.0. +# on Python3 with scikit-image up through version 0.10.0. NO_SKIMAGE_FREEIMAGE_SUPPORT = False try: import skimage @@ -213,7 +203,7 @@ def _indent(textstr): String to be indented. indent_level : str Number of spaces of indentation to add. - + Returns ------- indented_string : str @@ -236,6 +226,7 @@ try: # The whole point of trying to import PIL is to determine if it's there # or not. We won't use it directly. + # pylint: disable=F0401,W0611 import PIL NO_READ_BACKEND = False @@ -545,7 +536,7 @@ text_gbr_34 = """Colour Specification Box (colr) @ (179, 1339) dump = r'''JPEG 2000 Signature Box (jP ) @ (0, 12) Signature: 0d0a870a File Type Box (ftyp) @ (12, 20) - Brand: jp2 + Brand: jp2 Compatibility: ['jp2 '] JP2 Header Box (jp2h) @ (32, 45) Image Header Box (ihdr) @ (40, 22) @@ -601,6 +592,7 @@ Contiguous Codestream Box (jp2c) @ (3223, 1132296) "Created by OpenJPEG version 2.0.0"''' nemo_with_codestream_header = dump.format(_indent(nemo_xmp)) +#nemo_dump_full = dump.format(_indent(nemo_xmp)) nemo_dump_short = r"""JPEG 2000 Signature Box (jP ) @ (0, 12) File Type Box (ftyp) @ (12, 20) @@ -613,7 +605,7 @@ Contiguous Codestream Box (jp2c) @ (3223, 1132296)""" nemo_dump_no_xml = '''JPEG 2000 Signature Box (jP ) @ (0, 12) Signature: 0d0a870a File Type Box (ftyp) @ (12, 20) - Brand: jp2 + Brand: jp2 Compatibility: ['jp2 '] JP2 Header Box (jp2h) @ (32, 45) Image Header Box (ihdr) @ (40, 22) @@ -669,7 +661,7 @@ Contiguous Codestream Box (jp2c) @ (3223, 1132296) dump = r"""JPEG 2000 Signature Box (jP ) @ (0, 12) Signature: 0d0a870a File Type Box (ftyp) @ (12, 20) - Brand: jp2 + Brand: jp2 Compatibility: ['jp2 '] JP2 Header Box (jp2h) @ (32, 45) Image Header Box (ihdr) @ (40, 22) @@ -691,26 +683,6 @@ nemo_dump_no_codestream = dump.format(_indent(nemo_xmp)) nemo_dump_no_codestream_no_xml = r"""JPEG 2000 Signature Box (jP ) @ (0, 12) Signature: 0d0a870a -File Type Box (ftyp) @ (12, 20) - Brand: jp2 - Compatibility: ['jp2 '] -JP2 Header Box (jp2h) @ (32, 45) - Image Header Box (ihdr) @ (40, 22) - Size: [1456 2592 3] - Bitdepth: 8 - Signed: False - Compression: wavelet - Colorspace Unknown: False - Colour Specification Box (colr) @ (62, 15) - Method: enumerated colorspace - Precedence: 0 - Colorspace: sRGB -UUID Box (uuid) @ (77, 3146) - UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP) -Contiguous Codestream Box (jp2c) @ (3223, 1132296)""" - -nemo = """JPEG 2000 Signature Box (jP ) @ (0, 12) - Signature: 0d0a870a File Type Box (ftyp) @ (12, 20) Brand: jp2 Compatibility: ['jp2 '] @@ -727,171 +699,7 @@ JP2 Header Box (jp2h) @ (32, 45) Colorspace: sRGB UUID Box (uuid) @ (77, 3146) UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP) - UUID Data: - - - - - Google - 2013-02-09T14:47:53 - - - 1 - 72/1 - 72/1 - 2 - HTC - HTC Glacier - 2592 - 1456 - - - 8 - 8 - 8 - - - 2 - 3 - - - 1343036288/4294967295 - 1413044224/4294967295 - - - - - 2748779008/4294967295 - 1417339264/4294967295 - 1288490240/4294967295 - 2576980480/4294967295 - 644245120/4294967295 - 257698032/4294967295 - - - - - 1 - 2528 - 1424 - 353/100 - 0 - 0/1 - WGS-84 - 2013-02-09T14:47:53 - - - 76 - - - 0220 - 0100 - - - 1 - 2 - 3 - 0 - - - 42,20.56N - 71,5.29W - 2013-02-09T19:47:53Z - NETWORK - - - 2013-02-09T14:47:53 - - - - - Glymur - Python XMP Toolkit - - - - - - -Contiguous Codestream Box (jp2c) @ (3223, 1132296) - SOC marker segment @ (3231, 0) - SIZ marker segment @ (3233, 47) - Profile: no profile - Reference Grid Height, Width: (1456 x 2592) - Vertical, Horizontal Reference Grid Offset: (0 x 0) - Reference Tile Height, Width: (1456 x 2592) - Vertical, Horizontal Reference Tile Offset: (0 x 0) - Bitdepth: (8, 8, 8) - Signed: (False, False, False) - Vertical, Horizontal Subsampling: ((1, 1), (1, 1), (1, 1)) - COD marker segment @ (3282, 12) - Coding style: - Entropy coder, without partitions - SOP marker segments: False - EPH marker segments: False - Coding style parameters: - Progression order: LRCP - Number of layers: 2 - Multiple component transformation usage: reversible - Number of resolutions: 2 - Code block height, width: (64 x 64) - Wavelet transform: 5-3 reversible - Precinct size: default, 2^15 x 2^15 - Code block context: - Selective arithmetic coding bypass: False - Reset context probabilities on coding pass boundaries: False - Termination on each coding pass: False - Vertically stripe causal context: False - Predictable termination: False - Segmentation symbols: False - QCD marker segment @ (3296, 7) - Quantization style: no quantization, 2 guard bits - Step size: [(0, 8), (0, 9), (0, 9), (0, 10)] - CME marker segment @ (3305, 37) - "Created by OpenJPEG version 2.0.0" - SOT marker segment @ (3344, 10) - Tile part index: 0 - Tile part length: 1132173 - Tile part instance: 0 - Number of tile parts: 1 - COC marker segment @ (3356, 9) - Associated component: 1 - Coding style for this component: Entropy coder, PARTITION = 0 - Coding style parameters: - Number of resolutions: 2 - Code block height, width: (64 x 64) - Wavelet transform: 5-3 reversible - Code block context: - Selective arithmetic coding bypass: False - Reset context probabilities on coding pass boundaries: False - Termination on each coding pass: False - Vertically stripe causal context: False - Predictable termination: False - Segmentation symbols: False - QCC marker segment @ (3367, 8) - Associated Component: 1 - Quantization style: no quantization, 2 guard bits - Step size: [(0, 8), (0, 9), (0, 9), (0, 10)] - COC marker segment @ (3377, 9) - Associated component: 2 - Coding style for this component: Entropy coder, PARTITION = 0 - Coding style parameters: - Number of resolutions: 2 - Code block height, width: (64 x 64) - Wavelet transform: 5-3 reversible - Code block context: - Selective arithmetic coding bypass: False - Reset context probabilities on coding pass boundaries: False - Termination on each coding pass: False - Vertically stripe causal context: False - Predictable termination: False - Segmentation symbols: False - QCC marker segment @ (3388, 8) - Associated Component: 2 - Quantization style: no quantization, 2 guard bits - Step size: [(0, 8), (0, 9), (0, 9), (0, 10)] - SOD marker segment @ (3398, 0) - EOC marker segment @ (1135517, 0)""" +Contiguous Codestream Box (jp2c) @ (3223, 1132296)""" # Output of reader requirements printing for text_GBR.jp2 text_GBR_rreq = r"""Reader Requirements Box (rreq) @ (40, 109) @@ -927,7 +735,7 @@ issue_183_colr = """Colour Specification Box (colr) @ (62, 12) Method: restricted ICC profile Precedence: 0 ICC Profile: None""" - + # Progression order is invalid. issue_186_progression_order = """COD marker segment @ (174, 12) @@ -1092,3 +900,4 @@ goodstuff_with_full_header = r"""Codestream: Step size: [(0, 8), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10)] SOD marker segment @ (164, 0) EOC marker segment @ (115218, 0)""" + diff --git a/glymur/test/test_callbacks.py b/glymur/test/test_callbacks.py index cc30de8..c29f816 100644 --- a/glymur/test/test_callbacks.py +++ b/glymur/test/test_callbacks.py @@ -1,6 +1,12 @@ """ Test suite for openjpeg's callback functions. """ +# R0904: Seems like pylint is fooled in this situation +# pylint: disable=R0904 + +# 'mock' most certainly is in unittest (Python 3.3) +# pylint: disable=E0611,F0401 + import os import re import sys @@ -19,7 +25,6 @@ import glymur from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG - class TestCallbacks(unittest.TestCase): """Test suite for callbacks.""" @@ -41,7 +46,7 @@ class TestCallbacks(unittest.TestCase): tiledata = j.read(tile=0) with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: with patch('sys.stdout', new=StringIO()) as fake_out: - glymur.Jp2k(tfile.name, data=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) @@ -55,13 +60,11 @@ class TestCallbacks(unittest.TestCase): tiledata = j[:] with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: with patch('sys.stdout', new=StringIO()) as fake_out: - glymur.Jp2k(tfile.name, data=tiledata, verbose=True) + jp2 = 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] == '0', - "Missing openjpeg/openjp2 library.") def test_info_callbacks_on_read(self): """stdio output when info callback handler is enabled""" @@ -93,6 +96,8 @@ class TestCallbacks(unittest.TestCase): [0-9]+\.[0-9]+\ss""", re.VERBOSE) + # assertRegex in Python 3.3 (python2.7/pylint issue) + # pylint: disable=E1101 if sys.hexversion <= 0x03020000: self.assertRegexpMatches(actual, regex) else: diff --git a/glymur/test/test_config.py b/glymur/test/test_config.py index 59a8ef3..feb3235 100644 --- a/glymur/test/test_config.py +++ b/glymur/test/test_config.py @@ -1,7 +1,16 @@ """These tests are for edge cases where OPENJPEG does not exist, but OPENJP2 may be present in some form or other. """ -import contextlib +# unittest doesn't work well with R0904. +# pylint: disable=R0904 + +# tempfile.TemporaryDirectory, unittest.assertWarns introduced in 3.2 +# pylint: disable=E1101 + +# unittest.mock only in Python 3.3 (python2.7/pylint import issue) +# pylint: disable=E0611,F0401 + +import contextlib import ctypes import imp import os @@ -17,42 +26,41 @@ else: import glymur from glymur import Jp2k -from .fixtures import (WARNING_INFRASTRUCTURE_ISSUE, - WARNING_INFRASTRUCTURE_MSG, - WINDOWS_TMP_FILE_MSG) - +from .fixtures import ( + WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG, + WINDOWS_TMP_FILE_MSG +) def openjpeg_not_found_by_ctypes(): """ Need to know if openjpeg library can be picked right up by ctypes for one of the tests. """ - with patch.dict('os.environ', - {'DYLD_FALLBACK_LIBRARY_PATH': '/opt/local/lib'}): + with patch.dict('os.environ', {'DYLD_FALLBACK_LIBRARY_PATH': '/opt/local/lib'}): if ctypes.util.find_library('openjpeg') is None: return True else: return False -@contextlib.contextmanager -def chdir(dirname=None): +@contextlib.contextmanager +def chdir(dirname=None): """ This context manager restores the value of the current working directory (cwd) after the enclosed code block completes or raises an exception. If a directory name is supplied to the context manager then the cwd is changed - prior to running the code block. + prior to running the code block. Shamelessly lifted from http://www.astropython.org/snippet/2009/10/chdir-context-manager """ - curdir = os.getcwd() - try: - if dirname is not None: - os.chdir(dirname) - yield - finally: - os.chdir(curdir) + curdir = os.getcwd() + try: + if dirname is not None: + os.chdir(dirname) + yield + finally: + os.chdir(curdir) @unittest.skipIf(sys.hexversion < 0x03020000, @@ -89,6 +97,7 @@ class TestSuite(unittest.TestCase): # Need to reliably recover the location of the openjp2 library, # so using '_name' appears to be the only way to do it. + # pylint: disable=W0212 libloc = glymur.lib.openjp2.OPENJP2._name line = 'openjp2: {0}\n'.format(libloc) tfile.write(line) @@ -121,7 +130,7 @@ class TestSuite(unittest.TestCase): "Needs openjp2 and openjpeg before this test make sense.") @unittest.skipIf(os.name == "nt", WINDOWS_TMP_FILE_MSG) def test_library_specified_as_None(self): - """Verify that we can stop library from being loaded by using None.""" + """Verify that we can stop a library from being loaded by using None.""" with tempfile.TemporaryDirectory() as tdir: configdir = os.path.join(tdir, 'glymur') os.mkdir(configdir) @@ -131,9 +140,7 @@ class TestSuite(unittest.TestCase): # openjpeg instead. fptr.write('[library]\n') fptr.write('openjp2: None\n') - msg = 'openjpeg: {0}\n' - msg = msg.format(glymur.lib.openjp2.OPENJPEG._name) - fptr.write(msg) + fptr.write('openjpeg: {0}\n'.format(glymur.lib.openjp2.OPENJPEG._name)) fptr.flush() with patch.dict('os.environ', {'XDG_CONFIG_HOME': tdir}): imp.reload(glymur.lib.openjp2) @@ -142,17 +149,18 @@ class TestSuite(unittest.TestCase): @unittest.skipIf(glymur.lib.openjp2.OPENJPEG is None, "Needs openjpeg before this test make sense.") - @unittest.skipIf(openjpeg_not_found_by_ctypes(), - "OpenJPEG must be found before this test can work.") + @unittest.skipIf(openjpeg_not_found_by_ctypes(), + "OpenJPEG must be easily found before this test can work.") @unittest.skipIf(os.name == "nt", WINDOWS_TMP_FILE_MSG) def test_config_dir_but_no_config_file(self): with tempfile.TemporaryDirectory() as tdir: configdir = os.path.join(tdir, 'glymur') os.mkdir(configdir) + fname = os.path.join(configdir, 'glymurrc') with patch.dict('os.environ', {'XDG_CONFIG_HOME': tdir}): # Should still be able to load openjpeg, despite the - # configuration file not being there + # configuration file being empty. imp.reload(glymur.lib.openjpeg) self.assertIsNotNone(glymur.lib.openjp2.OPENJPEG) @@ -170,3 +178,4 @@ class TestSuite(unittest.TestCase): # Should be able to load openjp2 as before. imp.reload(glymur.lib.openjp2) self.assertEqual(glymur.lib.openjp2.OPENJP2._name, libloc) + diff --git a/glymur/test/test_glymur_warnings.py b/glymur/test/test_glymur_warnings.py index 8086004..b8e5c8b 100644 --- a/glymur/test/test_glymur_warnings.py +++ b/glymur/test/test_glymur_warnings.py @@ -1,32 +1,32 @@ """ Test suite for warnings issued by glymur. """ + +# unittest doesn't work well with R0904. +# pylint: disable=R0904 + +import platform import os import re import struct +import sys import tempfile import unittest +import six + from glymur import Jp2k import glymur from .fixtures import opj_data_file, OPJ_DATA_ROOT from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG - @unittest.skipIf(OPJ_DATA_ROOT is None, "OPJ_DATA_ROOT environment variable not set") @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) class TestWarnings(unittest.TestCase): """Test suite for warnings issued by glymur.""" - def test_invalid_compatibility_list_entry(self): - """should not error out with invalid compatibility list entry""" - filename = opj_data_file('input/nonregression/issue397.jp2') - with self.assertWarns(UserWarning): - Jp2k(filename) - self.assertTrue(True) - def test_exceeded_box_length(self): """ should warn if reading past end of a box @@ -53,11 +53,12 @@ class TestWarnings(unittest.TestCase): """ relpath = 'input/nonregression/issue188_beach_64bitsbox.jp2' jfile = opj_data_file(relpath) - pattern = r"""Unrecognized\sbox\s\(b'XML\s'\)\sencountered.""" - regex = re.compile(pattern, re.VERBOSE) + regex = re.compile(r"""Unrecognized\sbox\s\(b'XML\s'\)\sencountered.""", + re.VERBOSE) with self.assertWarnsRegex(UserWarning, regex): Jp2k(jfile) + def test_NR_gdal_fuzzer_unchecked_numresolutions_dump(self): """ Has an invalid number of resolutions. @@ -69,7 +70,7 @@ class TestWarnings(unittest.TestCase): \(\d+\)\.""", re.VERBOSE) with self.assertWarnsRegex(UserWarning, regex): - Jp2k(jfile).get_codestream() + Jp2k(jfile) @unittest.skipIf(re.match("1.5|2.0.0", glymur.version.openjpeg_version), "Test not passing on 1.5.x, not introduced until 2.x") @@ -84,7 +85,7 @@ class TestWarnings(unittest.TestCase): \(\d+\)\.""", re.VERBOSE) with self.assertWarnsRegex(UserWarning, regex): - Jp2k(jfile).get_codestream() + Jp2k(jfile) def test_NR_gdal_fuzzer_check_comp_dx_dy_jp2_dump(self): """ @@ -97,7 +98,7 @@ class TestWarnings(unittest.TestCase): dx=\d+,\s*dy=\d+""", re.VERBOSE) with self.assertWarnsRegex(UserWarning, regex): - Jp2k(jfile).get_codestream() + Jp2k(jfile) def test_NR_gdal_fuzzer_assert_in_opj_j2k_read_SQcd_SQcc_patch_jp2(self): lst = ['input', 'nonregression', @@ -107,32 +108,53 @@ class TestWarnings(unittest.TestCase): number\sof\scomponents\sis\sonly\s\d+""", re.VERBOSE) with self.assertWarnsRegex(UserWarning, regex): - Jp2k(jfile).get_codestream() + Jp2k(jfile) + + def test_NR_broken_jp2_dump(self): + """ + The colr box has a ridiculously incorrect box length. + """ + jfile = opj_data_file('input/nonregression/broken.jp2') + regex = re.compile(r'''b'colr'\sbox\shas\sincorrect\sbox\slength\s + \(\d+\)''', + re.VERBOSE) + with self.assertWarnsRegex(UserWarning, regex): + jp2 = Jp2k(jfile) + + def test_NR_broken2_jp2_dump(self): + """ + Invalid marker ID on codestream. + """ + jfile = opj_data_file('input/nonregression/broken2.jp2') + regex = re.compile(r'''Invalid\smarker\sid\sencountered\sat\sbyte\s + \d+\sin\scodestream:\s*"0x[a-fA-F0-9]{4}"''', + re.VERBOSE) + with self.assertWarnsRegex(UserWarning, regex): + Jp2k(jfile) def test_bad_rsiz(self): """Should warn if RSIZ is bad. Issue196""" filename = opj_data_file('input/nonregression/edf_c2_1002767.jp2') with self.assertWarnsRegex(UserWarning, 'Invalid profile'): - Jp2k(filename).get_codestream() + Jp2k(filename) def test_bad_wavelet_transform(self): """Should warn if wavelet transform is bad. Issue195""" filename = opj_data_file('input/nonregression/edf_c2_10025.jp2') with self.assertWarnsRegex(UserWarning, 'Invalid wavelet transform'): - Jp2k(filename).get_codestream() + Jp2k(filename) def test_invalid_progression_order(self): """Should still be able to parse even if prog order is invalid.""" jfile = opj_data_file('input/nonregression/2977.pdf.asan.67.2198.jp2') with self.assertWarnsRegex(UserWarning, 'Invalid progression order'): - Jp2k(jfile).get_codestream() + Jp2k(jfile) def test_tile_height_is_zero(self): """Zero tile height should not cause an exception.""" - filename = 'input/nonregression/2539.pdf.SIGFPE.706.1712.jp2' - filename = opj_data_file(filename) + filename = opj_data_file('input/nonregression/2539.pdf.SIGFPE.706.1712.jp2') with self.assertWarnsRegex(UserWarning, 'Invalid tile dimensions'): - Jp2k(filename).get_codestream() + Jp2k(filename) @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") def test_unknown_marker_segment(self): @@ -155,9 +177,9 @@ class TestWarnings(unittest.TestCase): read_buffer = ifile.read() tfile.write(read_buffer) tfile.flush() - + with self.assertWarnsRegex(UserWarning, 'Unrecognized marker'): - Jp2k(tfile.name).get_codestream() + codestream = Jp2k(tfile.name).get_codestream() if __name__ == "__main__": diff --git a/glymur/test/test_icc.py b/glymur/test/test_icc.py index e18775c..c6b63e8 100644 --- a/glymur/test/test_icc.py +++ b/glymur/test/test_icc.py @@ -1,7 +1,13 @@ """ ICC profile tests. """ + +# unittest doesn't work well with R0904. +# pylint: disable=R0904 + import datetime +import os +import sys import unittest import numpy as np @@ -60,6 +66,11 @@ class TestICC(unittest.TestCase): """invalid ICC header data should cause UserWarning""" jfile = opj_data_file('input/nonregression/orb-blue10-lin-jp2.jp2') + # assertWarns in Python 3.3 (python2.7/pylint issue) + # pylint: disable=E1101 regex = 'ICC profile header is corrupt' with self.assertWarnsRegex(UserWarning, regex): Jp2k(jfile) + +if __name__ == "__main__": + unittest.main() diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py index f9e7c5c..9d1f9cf 100644 --- a/glymur/test/test_jp2box.py +++ b/glymur/test/test_jp2box.py @@ -1,6 +1,18 @@ """ Test suite specifically targeting JP2 box layout. """ +# E1103: return value from read may be list or np array +# pylint: disable=E1103 + +# R0902: More than 7 instance attributes are just fine for testing. +# pylint: disable=R0902 + +# R0904: Seems like pylint is fooled in this situation +# pylint: disable=R0904 + +# W0613: load_tests doesn't need to use ignore or loader arguments. +# pylint: disable=W0613 + import doctest import os import re @@ -8,6 +20,7 @@ import shutil import struct import sys import tempfile +import uuid from uuid import UUID import unittest @@ -22,33 +35,26 @@ from glymur.jp2box import JPEG2000SignatureBox from glymur.core import COLOR, OPACITY from glymur.core import RED, GREEN, BLUE, GREY, WHOLE_IMAGE -from .fixtures import (WARNING_INFRASTRUCTURE_ISSUE, - WARNING_INFRASTRUCTURE_MSG, - WINDOWS_TMP_FILE_MSG, MetadataBase) - - -def docTearDown(doctest_obj): - glymur.set_parseoptions(full_codestream=False) - +from .fixtures import ( + WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG, + WINDOWS_TMP_FILE_MSG, MetadataBase +) def load_tests(loader, tests, ignore): """Run doc tests as well.""" if os.name == "nt": # Can't do it on windows, temporary file issue. return tests - tests.addTests(doctest.DocTestSuite('glymur.jp2box', - tearDown=docTearDown)) + tests.addTests(doctest.DocTestSuite('glymur.jp2box')) return tests - @unittest.skipIf(os.name == "nt", WINDOWS_TMP_FILE_MSG) class TestDataEntryURL(unittest.TestCase): """Test suite for DataEntryURL boxes.""" def setUp(self): self.jp2file = glymur.data.nemo() - @unittest.skipIf(re.match("1.5|2", - glymur.version.openjpeg_version) is None, + @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.""" @@ -64,7 +70,7 @@ class TestDataEntryURL(unittest.TestCase): with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile2: jp2 = j2k.wrap(tfile2.name) self.assertEqual(jp2.box[2].box[1].colorspace, - glymur.core.GREYSCALE) + glymur.core.GREYSCALE) def test_basic_url(self): """Just your most basic URL box.""" @@ -86,7 +92,7 @@ class TestDataEntryURL(unittest.TestCase): self.assertEqual(jp22.box[4].url, url) def test_null_termination(self): - """I.9.3.2 specifies that location field must be null terminated.""" + """I.9.3.2 specifies that the location field must be null terminated.""" jp2 = Jp2k(self.jp2file) url = 'http://glymur.readthedocs.org' @@ -97,21 +103,18 @@ class TestDataEntryURL(unittest.TestCase): jp22 = jp2.wrap(tfile.name, boxes=boxes) self.assertEqual(jp22.box[-1].length, 42) - - # Go to the last box. Seek past the L, T, version, - # and flag fields. + + # Go to the last box. Seek past the L, T, version, and flag fields. 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) -@unittest.skipIf(re.match(r'''0|1|2.0.0''', +@unittest.skipIf(re.match(r'''(1|2.0.0)''', glymur.version.openjpeg_version) is not None, "Not supported until 2.1") @unittest.skipIf(os.name == "nt", WINDOWS_TMP_FILE_MSG) @@ -125,18 +128,18 @@ class TestChannelDefinition(unittest.TestCase): data = j2k[:] # Write the first component back out to file. with tempfile.NamedTemporaryFile(suffix=".j2k", delete=False) as tfile: - Jp2k(tfile.name, data=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: - Jp2k(tfile.name, data=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: shape = (data.shape[0], data.shape[1], 1) alpha = np.zeros((shape), dtype=data.dtype) data4 = np.concatenate((data, alpha), axis=2) - Jp2k(tfile.name, data=data4) + rgba_jp2 = Jp2k(tfile.name, data=data4) cls.four_planes = tfile.name @classmethod @@ -389,7 +392,7 @@ class TestFileTypeBox(unittest.TestCase): ftyp = glymur.jp2box.FileTypeBox(brand='jp3') with self.assertRaises(IOError): with tempfile.TemporaryFile() as tfile: - ftyp.write(tfile) + ftyp.write(tfile) @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) def test_cl_entry_unknown(self): @@ -399,8 +402,7 @@ class TestFileTypeBox(unittest.TestCase): ftyp = glymur.jp2box.FileTypeBox(compatibility_list=['jp3']) with self.assertRaises(IOError): with tempfile.TemporaryFile() as tfile: - ftyp.write(tfile) - + ftyp.write(tfile) class TestColourSpecificationBox(unittest.TestCase): """Test suite for colr box instantiation.""" @@ -523,8 +525,8 @@ class TestPaletteBox(unittest.TestCase): bps = (8, 8, 8) signed = (False, False) with self.assertWarns(UserWarning): - glymur.jp2box.PaletteBox(palette, bits_per_component=bps, - signed=signed) + pclr = glymur.jp2box.PaletteBox(palette, bits_per_component=bps, + signed=signed) @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) def test_mismatched_signed_palette(self): @@ -533,8 +535,8 @@ class TestPaletteBox(unittest.TestCase): bps = (8, 8, 8, 8) signed = (False, False, False, False) with self.assertWarns(UserWarning): - glymur.jp2box.PaletteBox(palette, bits_per_component=bps, - signed=signed) + pclr = glymur.jp2box.PaletteBox(palette, bits_per_component=bps, + signed=signed) def test_writing_with_different_bitdepths(self): """Bitdepths must be the same when writing.""" @@ -634,7 +636,7 @@ class TestAppend(unittest.TestCase): jp2 = Jp2k(tfile.name) # Make a UUID box. Only XMP UUID boxes can currently be appended. - uuid_instance = UUID('00000000-0000-0000-0000-000000000000') + uuid_instance = uuid.UUID('00000000-0000-0000-0000-000000000000') data = b'0123456789' uuidbox = glymur.jp2box.UUIDBox(uuid_instance, data) with self.assertRaises(IOError): @@ -790,7 +792,7 @@ class TestWrap(unittest.TestCase): # list to trigger the error. boxes[2].box = [] with self.assertRaises(IOError): - jp2.wrap(tfile.name, boxes=boxes) + jp22 = jp2.wrap(tfile.name, boxes=boxes) def test_default_layout_with_boxes(self): """basic test for rewrapping a jp2 file, boxes specified""" @@ -855,8 +857,8 @@ class TestWrap(unittest.TestCase): """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) @@ -968,8 +970,7 @@ class TestWrap(unittest.TestCase): """Rewrap a jpx file.""" with tempfile.NamedTemporaryFile(suffix='.jp2') 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] @@ -1021,11 +1022,11 @@ class TestJp2Boxes(unittest.TestCase): """Raw instantiation should not produce a main_header.""" box = ContiguousCodestreamBox() self.assertEqual(box.box_id, 'jp2c') - self.assertIsNone(box.codestream) + self.assertIsNone(box.main_header) def test_codestream_main_header_offset(self): """main_header_offset is an attribute of the CCS box""" - j = Jp2k(self.jpxfile) + j = Jp2k(self.jpxfile); self.assertEqual(j.box[5].main_header_offset, j.box[5].offset + 8) @@ -1226,8 +1227,8 @@ class TestRepr(MetadataBase): def test_uuidlist_box(self): """Verify __repr__ method on ulst box.""" - uuid1 = UUID('00000000-0000-0000-0000-000000000001') - uuid2 = UUID('00000000-0000-0000-0000-000000000002') + uuid1 = uuid.UUID('00000000-0000-0000-0000-000000000001') + uuid2 = uuid.UUID('00000000-0000-0000-0000-000000000002') uuids = [uuid1, uuid2] ulst = glymur.jp2box.UUIDListBox(ulst=uuids) newbox = eval(repr(ulst)) @@ -1239,6 +1240,7 @@ class TestRepr(MetadataBase): """Verify Palette box repr.""" palette = np.array([[255, 0, 1000], [0, 255, 0]], dtype=np.int32) bps = (8, 8, 16) + signed = (True, False, True) box = glymur.jp2box.PaletteBox(palette=palette, bits_per_component=bps, signed=(True, False, True)) @@ -1281,15 +1283,14 @@ class TestRepr(MetadataBase): def test_uuid_box_generic(self): """Verify uuid repr method.""" - uuid_instance = UUID('00000000-0000-0000-0000-000000000000') + uuid_instance = uuid.UUID('00000000-0000-0000-0000-000000000000') data = b'0123456789' box = glymur.jp2box.UUIDBox(the_uuid=uuid_instance, raw_data=data) # 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()). regexp = r"""glymur.jp2box.UUIDBox\(""" - regexp += """the_uuid=""" - regexp += """UUID\('00000000-0000-0000-0000-000000000000'\),\s""" + regexp += """the_uuid=UUID\('00000000-0000-0000-0000-000000000000'\),\s""" regexp += """raw_data=\)""" if sys.hexversion < 0x03000000: @@ -1306,8 +1307,7 @@ class TestRepr(MetadataBase): # 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()). regexp = r"""glymur.jp2box.UUIDBox\(""" - regexp += """the_uuid=""" - regexp += """UUID\('be7acfcb-97a9-42e8-9c71-999491e3afac'\),\s""" + regexp += """the_uuid=UUID\('be7acfcb-97a9-42e8-9c71-999491e3afac'\),\s""" regexp += """raw_data=\)""" if sys.hexversion < 0x03000000: @@ -1323,7 +1323,7 @@ class TestRepr(MetadataBase): # Difficult to eval(repr()) this, so just match the general pattern. regexp = "glymur.jp2box.ContiguousCodeStreamBox" - regexp += "[(]codestream=> 16, - standard_masks[j] & 0x0000ffff >> 8, + standard_masks[j] & 0x0000ffff>> 8, standard_masks[j] & 0x000000ff) struct.pack_into('>HBBB', rreq_buffer, 17 + j * 5, standard_flags[j], *mask) @@ -599,6 +599,7 @@ class TestJPX(unittest.TestCase): self.assertEqual(jpx.box[2].standard_flag, (5, 42, 45, 2, 18, 19, 1, 8, 12, 31, 20)) + def test_nlst(self): """Verify that we can handle a number list box.""" j = Jp2k(self.jpxfile) diff --git a/glymur/test/test_jp2box_uuid.py b/glymur/test/test_jp2box_uuid.py index 6886c30..8ec35a2 100644 --- a/glymur/test/test_jp2box_uuid.py +++ b/glymur/test/test_jp2box_uuid.py @@ -1,7 +1,17 @@ # -*- coding: utf-8 -*- """Test suite for printing. """ +# C0302: don't care too much about having too many lines in a test module +# pylint: disable=C0302 + +# E061: unittest.mock introduced in 3.3 (python-2.7/pylint issue) +# pylint: disable=E0611,F0401 + +# R0904: Not too many methods in unittest. +# pylint: disable=R0904 + import os +import re import shutil import struct import sys @@ -13,18 +23,30 @@ if sys.hexversion < 0x02070000: else: import unittest +if sys.hexversion < 0x03000000: + from StringIO import StringIO +else: + from io import StringIO + +if sys.hexversion <= 0x03030000: + from mock import patch +else: + from unittest.mock import patch + import lxml.etree -from .fixtures import (WARNING_INFRASTRUCTURE_ISSUE, - WARNING_INFRASTRUCTURE_MSG, - WINDOWS_TMP_FILE_MSG) +from .fixtures import HAS_PYTHON_XMP_TOOLKIT, OPJ_DATA_ROOT +from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG + +if HAS_PYTHON_XMP_TOOLKIT: + from libxmp import XMPMeta import glymur from glymur import Jp2k -from .fixtures import SimpleRDF +from .fixtures import OPJ_DATA_ROOT, opj_data_file, SimpleRDF -@unittest.skipIf(os.name == "nt", WINDOWS_TMP_FILE_MSG) +@unittest.skipIf(os.name == "nt", "Unexplained failure on windows") class TestSuite(unittest.TestCase): """Tests for XMP, Exif UUIDs.""" @@ -79,9 +101,8 @@ class TestSuite(unittest.TestCase): jp2 = glymur.Jp2k(tfile.name) self.assertEqual(jp2.box[-1].data['Make'], "HTC") - @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) -@unittest.skipIf(os.name == "nt", WINDOWS_TMP_FILE_MSG) +@unittest.skipIf(os.name == "nt", "Unexplained failure on windows") class TestSuiteWarns(unittest.TestCase): """Tests for XMP, Exif UUIDs, issues warnings.""" @@ -90,7 +111,7 @@ class TestSuiteWarns(unittest.TestCase): def tearDown(self): pass - + def test_unrecognized_exif_tag(self): """Verify warning in case of unrecognized tag.""" with tempfile.NamedTemporaryFile(suffix='.jp2', mode='wb') as tfile: @@ -114,7 +135,7 @@ class TestSuiteWarns(unittest.TestCase): tfile.flush() with self.assertWarnsRegex(UserWarning, 'Unrecognized Exif tag'): - glymur.Jp2k(tfile.name) + j = glymur.Jp2k(tfile.name) def test_bad_tag_datatype(self): """Only certain datatypes are allowable""" @@ -170,3 +191,6 @@ class TestSuiteWarns(unittest.TestCase): jp2 = glymur.Jp2k(tfile.name) self.assertEqual(jp2.box[-1].box_id, 'uuid') + +if __name__ == "__main__": + unittest.main() diff --git a/glymur/test/test_jp2box_xml.py b/glymur/test/test_jp2box_xml.py index 87bdd38..45d02f1 100644 --- a/glymur/test/test_jp2box_xml.py +++ b/glymur/test/test_jp2box_xml.py @@ -2,12 +2,35 @@ """ Test suite specifically targeting JP2 box layout. """ +# E1103: return value from read may be list or np array +# pylint: disable=E1103 + +# R0902: More than 7 instance attributes are just fine for testing. +# pylint: disable=R0902 + +# R0904: Seems like pylint is fooled in this situation +# pylint: disable=R0904 + +# W0613: load_tests doesn't need to use ignore or loader arguments. +# pylint: disable=W0613 + import os import re import struct +import sys import tempfile import unittest +if sys.hexversion < 0x03000000: + from StringIO import StringIO +else: + from io import StringIO + +if sys.hexversion <= 0x03030000: + from mock import patch +else: + from unittest.mock import patch + import lxml.etree as ET import glymur @@ -20,7 +43,6 @@ from .fixtures import OPJ_DATA_ROOT, opj_data_file from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG from . import fixtures - @unittest.skipIf(os.name == "nt", fixtures.WINDOWS_TMP_FILE_MSG) class TestXML(unittest.TestCase): """Test suite for XML boxes.""" @@ -145,6 +167,7 @@ class TestXML(unittest.TestCase): u'Россия') + class TestJp2kBadXmlFile(unittest.TestCase): """Test suite for bad XML box situations""" @@ -270,19 +293,22 @@ class TestXML_OpjDataRoot(unittest.TestCase): 'nonregression', 'issue171.jp2')) msg = 'An illegal BOM \(byte order marker\) was detected and removed ' - msg += 'from the XML contents in the box starting at byte offset \d+' + msg += 'from the XML contents in the box starting at byte offset \d+' with self.assertWarnsRegex(UserWarning, re.compile(msg)): jp2 = Jp2k(filename) self.assertIsNotNone(jp2.box[3].xml) + def test_invalid_utf8(self): """Bad byte sequence that cannot be parsed.""" - relname = '26ccf3651020967f7778238ef5af08af.SIGFPE.d25.527.jp2' filename = opj_data_file(os.path.join('input', 'nonregression', - relname)) + '26ccf3651020967f7778238ef5af08af.SIGFPE.d25.527.jp2')) with self.assertWarns((UserWarning, UserWarning)): jp2 = Jp2k(filename) self.assertIsNone(jp2.box[3].box[1].box[1].xml) + + + diff --git a/glymur/test/test_jp2k.py b/glymur/test/test_jp2k.py index 52945f9..b903dda 100644 --- a/glymur/test/test_jp2k.py +++ b/glymur/test/test_jp2k.py @@ -1,9 +1,19 @@ """ Tests for general glymur functionality. """ +# E1101: assertWarns introduced in python 3.2 +# pylint: disable=E1101 + +# R0904: Not too many methods in unittest. +# pylint: disable=R0904 + +# E0611: unittest.mock is unknown to python2.7/pylint +# pylint: disable=E0611,F0401 + import doctest import os import re +import shutil import struct import sys import tempfile @@ -26,7 +36,6 @@ from glymur.version import openjpeg_version from .fixtures import HAS_PYTHON_XMP_TOOLKIT from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG -from .fixtures import OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG if HAS_PYTHON_XMP_TOOLKIT: import libxmp @@ -35,20 +44,18 @@ if HAS_PYTHON_XMP_TOOLKIT: from .fixtures import OPJ_DATA_ROOT, opj_data_file from . import fixtures - -def docTearDown(doctest_obj): - glymur.set_parseoptions(full_codestream=False) - - # Doc tests should be run as well. def load_tests(loader, tests, ignore): + # W0613: "loader" and "ignore" are necessary for the protocol + # They are unused here, however. + # pylint: disable=W0613 + """Should run doc tests as well""" if os.name == "nt": # 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')) return tests @@ -69,8 +76,6 @@ class SliceProtocolBase(unittest.TestCase): self.j2k_data_r1 = self.j2k[::2, ::2] self.j2k_data_r5 = self.j2k[::32, ::32] - -@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) @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) @@ -138,9 +143,13 @@ class TestSliceProtocolBaseWrite(SliceProtocolBase): j[:25, :45, :] = self.j2k_data[:25, :25, :] -@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) class TestSliceProtocolRead(SliceProtocolBase): + def test_resolution_strides_cannot_differ(self): + with self.assertRaises(IndexError): + # Strides in x/y directions cannot differ. + self.j2k[::2, ::3] + def test_resolution_strides_cannot_differ(self): with self.assertRaises(IndexError): # Strides in x/y directions cannot differ. @@ -157,8 +166,8 @@ class TestSliceProtocolRead(SliceProtocolBase): np.testing.assert_array_equal(self.j2k_data[:, :, j], band) def test_slice_in_third_dimension(self): - actual = self.j2k[:, :, 1:3] - expected = self.j2k_data[:, :, 1:3] + actual = self.j2k[:,:,1:3] + expected = self.j2k_data[:,:,1:3] np.testing.assert_array_equal(actual, expected) def test_reduce_resolution_and_slice_in_third_dimension(self): @@ -172,12 +181,12 @@ class TestSliceProtocolRead(SliceProtocolBase): np.testing.assert_array_equal(actual, expected) def test_retrieve_single_pixel(self): - actual = self.jp2[0, 0] + actual = self.jp2[0,0] expected = self.jp2_data[0, 0] np.testing.assert_array_equal(actual, expected) def test_retrieve_single_component(self): - actual = self.jp2[20, 20, 2] + actual = self.jp2[20,20,2] expected = self.jp2_data[20, 20, 2] np.testing.assert_array_equal(actual, expected) @@ -214,7 +223,7 @@ class TestSliceProtocolRead(SliceProtocolBase): def test_single_slice(self): rows = slice(3, 8) actual = self.j2k[rows] - expected = self.j2k_data[3:8, :, :] + expected = self.j2k_data[3:8, :,:] np.testing.assert_array_equal(actual, expected) @unittest.skipIf(re.match("0|1", glymur.version.openjpeg_version), @@ -223,7 +232,7 @@ class TestSliceProtocolRead(SliceProtocolBase): """ maximim rlevel - There seems to be a difference between version of openjpeg, as + 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). """ @@ -231,7 +240,6 @@ class TestSliceProtocolRead(SliceProtocolBase): expected = self.j2k_data_r5[1:17, 1:14] np.testing.assert_array_equal(actual, expected) - class TestJp2k(unittest.TestCase): """These tests should be run by just about all configuration.""" @@ -243,7 +251,6 @@ class TestJp2k(unittest.TestCase): def tearDown(self): pass - @unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) def test_warn_if_using_read_method(self): """Should warn if deprecated read method is called""" @@ -306,9 +313,8 @@ class TestJp2k(unittest.TestCase): actdata = j2[:] self.assertTrue(fixtures.mse(actdata[0], expdata[0]) < 0.38) - @unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) @unittest.skipIf(re.match('1.[0-4]', openjpeg_version) is not None, - "Not supported on OpenJPEG {0}".format(openjpeg_version)) + "Not supported with OpenJPEG {0}".format(openjpeg_version)) @unittest.skipIf(re.match('1.5.(1|2)', openjpeg_version) is not None, "Mysteriously fails in 1.5.1 and 1.5.2") def test_no_cxform_pclr_jpx(self): @@ -339,7 +345,6 @@ class TestJp2k(unittest.TestCase): self.assertEqual(newjp2.filename, self.j2kfile) self.assertEqual(len(newjp2.box), 0) - @unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) def test_rlevel_max_backwards_compatibility(self): """ @@ -362,7 +367,6 @@ class TestJp2k(unittest.TestCase): np.testing.assert_array_equal(thumbnail1, thumbnail2) self.assertEqual(thumbnail1.shape, (25, 15, 3)) - @unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) def test_rlevel_too_high(self): """Should error out appropriately if reduce level too high""" j = Jp2k(self.jp2file) @@ -514,14 +518,12 @@ class TestJp2k(unittest.TestCase): self.assertEqual(new_jp2.box[j].length, baseline_jp2.box[j].length) - @unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) def test_basic_jp2(self): """Just a very basic test that reading a JP2 file does not error out. """ j2k = Jp2k(self.jp2file) j2k[::2, ::2] - @unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) def test_basic_j2k(self): """This test is only useful when openjp2 is not available and OPJ_DATA_ROOT is not set. We need at least one @@ -627,7 +629,7 @@ class TestJp2k(unittest.TestCase): self.assertEqual(ET.tostring(jp2k.box[3].xml.getroot()), b'this is a test') - @unittest.skipIf(not HAS_PYTHON_XMP_TOOLKIT, + @unittest.skipIf(not HAS_PYTHON_XMP_TOOLKIT, "Requires Python XMP Toolkit >= 2.0") def test_xmp_attribute(self): """Verify the XMP packet in the shipping example file can be read.""" @@ -643,11 +645,9 @@ class TestJp2k(unittest.TestCase): xmp = XMPMeta() xmp.parse_from_str(j.box[3].raw_data.decode('utf-8'), xmpmeta_wrap=False) - creator_tool = xmp.get_property(libxmp.consts.XMP_NS_XMP, - 'CreatorTool') - self.assertEqual(creator_tool, 'Google') + creator_tool = xmp.get_property(libxmp.consts.XMP_NS_XMP, 'CreatorTool') + self.assertEqual(creator_tool, 'Google') - @unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) @unittest.skipIf(re.match(r'''(1|2.0.0)''', glymur.version.openjpeg_version) is not None, "Not supported until 2.0.1") @@ -664,8 +664,6 @@ class TestJp2k(unittest.TestCase): with self.assertRaises(RuntimeError): glymur.Jp2k(self.jp2file).read_bands() - -@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) @unittest.skipIf(re.match('1.[0-4]', openjpeg_version) is not None, "Not supported with OpenJPEG {0}".format(openjpeg_version)) @unittest.skipIf(os.name == "nt", fixtures.WINDOWS_TMP_FILE_MSG) @@ -684,30 +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): - Jp2k(tfile.name, data=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): - Jp2k(tfile.name, data=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): - Jp2k(tfile.name, data=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): - Jp2k(tfile.name, data=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""" @@ -717,7 +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): - Jp2k(tfile.name, data=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 @@ -736,31 +734,31 @@ class TestJp2k_write(unittest.TestCase): """OpenJP2 only allows 2D or 3D images.""" with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: with self.assertRaises(IOError): - Jp2k(tfile.name, - data=np.zeros((128, 128, 2, 2), dtype=np.uint8)) + 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: with self.assertRaises(IOError): - Jp2k(tfile.name, - data=np.zeros((128, 128, 2), dtype=np.uint8), - 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: with self.assertRaises(IOError): - Jp2k(tfile.name, - data=np.zeros((128, 128, 3), dtype=np.uint8), - 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, - data=np.zeros((128, 128, 3), dtype=np.uint8), - colorspace='rgb') + 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): @@ -795,7 +793,7 @@ class TestJp2k_write(unittest.TestCase): with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: with self.assertRaises(IOError): data = np.zeros((128, 128, 3), dtype=np.uint8) - Jp2k(tfile.name, data=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.""" @@ -824,7 +822,7 @@ class TestJp2k_write(unittest.TestCase): expdata = j2k[:] with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: with self.assertRaises(IOError): - Jp2k(tfile.name, data=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""" @@ -871,7 +869,6 @@ class TestJp2k_1_x(unittest.TestCase): @unittest.skipIf(os.name == "nt", fixtures.WINDOWS_TMP_FILE_MSG) -@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) class Test_2p0_official(unittest.TestCase): """Tests specific to v2.0.0""" @@ -915,7 +912,7 @@ class TestJp2k_2_0(unittest.TestCase): with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: data = np.zeros((128, 128, 3), dtype=np.uint8) with self.assertRaises(IOError): - Jp2k(tfile.name, data=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): @@ -924,7 +921,7 @@ class TestJp2k_2_0(unittest.TestCase): # OpenJPEG doesn't have such a file. data = Jp2k(self.jp2file)[::2, ::2] with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: - Jp2k(tfile.name, data=data) + j = Jp2k(tfile.name, data=data) with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile2: @@ -965,7 +962,6 @@ class TestJp2k_2_0(unittest.TestCase): self.assertEqual(jasoc.box[3].box[1].box_id, 'xml ') -@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) @unittest.skipIf(re.match(r'''(1|2.0.0)''', glymur.version.openjpeg_version) is not None, "Not to be run until unless 2.0.1 or higher is present") @@ -1032,15 +1028,12 @@ class TestJp2k_2_1(unittest.TestCase): Invalid\svalues\sfor\scomp\s=\s0\s+ :\sdx=1\sdy=0''', re.VERBOSE) if sys.hexversion < 0x03020000: - with self.assertRaisesRegexp((IOError, OSError), - regexp): + with self.assertRaisesRegexp((IOError, OSError), regexp): j[::2, ::2] else: - with self.assertRaisesRegex((IOError, OSError), - regexp): + with self.assertRaisesRegex((IOError, OSError), regexp): j[::2, ::2] - @unittest.skipIf(OPJ_DATA_ROOT is None, "OPJ_DATA_ROOT environment variable not set") class TestParsing(unittest.TestCase): @@ -1048,31 +1041,31 @@ class TestParsing(unittest.TestCase): def setUp(self): self.jp2file = glymur.data.nemo() # Reset parseoptions for every test. - glymur.set_parseoptions(full_codestream=False) + glymur.set_parseoptions(codestream=True) def tearDown(self): - glymur.set_parseoptions(full_codestream=False) + glymur.set_parseoptions(codestream=True) @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) def test_bad_rsiz(self): """Should not warn if RSIZ when parsing is turned off.""" filename = opj_data_file('input/nonregression/edf_c2_1002767.jp2') - glymur.set_parseoptions(full_codestream=False) - Jp2k(filename) + glymur.set_parseoptions(codestream=False) + j = Jp2k(filename) - glymur.set_parseoptions(full_codestream=True) + glymur.set_parseoptions(codestream=True) with self.assertWarnsRegex(UserWarning, 'Invalid profile'): - Jp2k(filename) + jp2 = Jp2k(filename) def test_main_header(self): - """verify that the main header isn't loaded during normal parsing""" + """Verify that the main header is not loaded when parsing turned off.""" # The hidden _main_header attribute should show up after accessing it. + glymur.set_parseoptions(codestream=False) jp2 = Jp2k(self.jp2file) jp2c = jp2.box[4] - self.assertIsNone(jp2c._codestream) - jp2c.codestream - self.assertIsNotNone(jp2c._codestream) - + self.assertIsNone(jp2c._main_header) + main_header = jp2c.main_header + self.assertIsNotNone(jp2c._main_header) @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) @unittest.skipIf(OPJ_DATA_ROOT is None, @@ -1095,13 +1088,13 @@ class TestJp2kOpjDataRootWarnings(unittest.TestCase): """Should warn in case of bad ftyp brand.""" filename = opj_data_file('input/nonregression/edf_c2_1000290.jp2') with self.assertWarns(UserWarning): - Jp2k(filename) + jp2 = Jp2k(filename) def test_invalid_approximation(self): """Should warn in case of invalid approximation.""" filename = opj_data_file('input/nonregression/edf_c2_1015644.jp2') with self.assertWarnsRegex(UserWarning, 'Invalid approximation'): - Jp2k(filename) + jp2 = Jp2k(filename) def test_invalid_colorspace(self): """ @@ -1111,19 +1104,19 @@ class TestJp2kOpjDataRootWarnings(unittest.TestCase): """ filename = opj_data_file('input/nonregression/edf_c2_1103421.jp2') with self.assertWarns(UserWarning): - Jp2k(filename) + jp2 = Jp2k(filename) def test_stupid_windows_eol_at_end(self): """Garbage characters at the end of the file.""" filename = opj_data_file('input/nonregression/issue211.jp2') with self.assertWarns(UserWarning): - Jp2k(filename) + jp2 = Jp2k(filename) @unittest.skipIf(OPJ_DATA_ROOT is None, "OPJ_DATA_ROOT environment variable not set") class TestJp2kOpjDataRoot(unittest.TestCase): - """These tests should be run by just about all configurations.""" + """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") @@ -1132,9 +1125,9 @@ class TestJp2kOpjDataRoot(unittest.TestCase): """Irreversible""" filename = opj_data_file('input/nonregression/issue141.rawl') expdata = np.fromfile(filename, dtype=np.uint16) - expdata.resize((32, 2048)) + expdata.resize((2816, 2048)) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - j = Jp2k(tfile.name, data=expdata, irreversible=True, numres=5) + j = Jp2k(tfile.name, data=expdata, irreversible=True) codestream = j.get_codestream() self.assertEqual(codestream.segment[2].spcod[8], @@ -1174,7 +1167,7 @@ class TestJp2kOpjDataRoot(unittest.TestCase): j = Jp2k(filename) with self.assertRaises(RuntimeError): j[:] - + @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) def test_no_cxform_cmap(self): """Bands as physically ordered, not as physically intended""" @@ -1190,11 +1183,31 @@ class TestJp2kOpjDataRoot(unittest.TestCase): expected = np.zeros(ycbcr.shape, ycbcr.dtype) for k in range(crcby.shape[2]): - expected[:, :, crcby.shape[2] - k - 1] = crcby[:, :, k] + expected[:,:,crcby.shape[2] - k - 1] = crcby[:,:,k] np.testing.assert_array_equal(ycbcr, expected) +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): @@ -1248,6 +1261,7 @@ class TestCodestreamOpjData(unittest.TestCase): # 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') @@ -1302,16 +1316,6 @@ class TestCodestreamRepr(unittest.TestCase): self.assertEqual(newseg.bitdepth, (8, 8, 8)) self.assertEqual(newseg.signed, (False, False, False)) - 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)) - class TestCodestream(unittest.TestCase): """Test suite for unusual codestream cases.""" @@ -1331,3 +1335,112 @@ class TestCodestream(unittest.TestCase): # 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 9e8a0eb..cf44eaa 100644 --- a/glymur/test/test_opj_suite.py +++ b/glymur/test/test_opj_suite.py @@ -2,6 +2,31 @@ 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 @@ -13,14 +38,13 @@ import glymur from glymur import Jp2k from glymur.jp2box import FileTypeBox, ImageHeaderBox, ColourSpecificationBox -from .fixtures import (OPJ_DATA_ROOT, MetadataBase, - WARNING_INFRASTRUCTURE_ISSUE, - WARNING_INFRASTRUCTURE_MSG, - mse, peak_tolerance, read_pgx, opj_data_file, - OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) +from .fixtures import ( + OPJ_DATA_ROOT, MetadataBase, + WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG, + mse, peak_tolerance, read_pgx, opj_data_file +) -@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG) @unittest.skipIf(OPJ_DATA_ROOT is None, "OPJ_DATA_ROOT environment variable not set") class TestSuite(unittest.TestCase): @@ -359,14 +383,11 @@ class TestSuiteWarns(MetadataBase): jpdata = jp2k[:] self.assertEqual(jpdata.shape, (512, 768, 3)) - def test_NR_broken1_jp2_dump(self): - jfile = opj_data_file('input/nonregression/broken1.jp2') + def test_NR_broken_jp2_dump(self): + jfile = opj_data_file('input/nonregression/broken.jp2') - # The colr box has a ridiculously incorrect box length. - regex = re.compile(r'''b'colr'\sbox\shas\sincorrect\sbox\slength\s - \(\d+\)''', - re.VERBOSE) - with self.assertWarnsRegex(UserWarning, regex): + with self.assertWarns(UserWarning): + # colr box has bad length. jp2 = Jp2k(jfile) ids = [box.box_id for box in jp2.box] @@ -385,24 +406,23 @@ class TestSuiteWarns(MetadataBase): expected = ColourSpecificationBox(colorspace=glymur.core.SRGB) self.verifyColourSpecificationBox(jp2.box[2].box[1], expected) - c = jp2.box[3].codestream + c = jp2.box[3].main_header ids = [x.marker_id for x in c.segment] expected = ['SOC', 'SIZ', 'CME', 'COD', 'QCD', 'QCC', 'QCC'] self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (203, 152), 'xyosiz': (0, 0), - 'xytsiz': (203, 152), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + 'xytsiz': (203, 152), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + glymur.codestream.SIZsegment(**kwargs)) pargs = (glymur.core.RCME_ISO_8859_1, - "Creator: JasPer Version 1.701.0".encode()) + "Creator: JasPer Version 1.701.0".encode()) self.verifyCMEsegment(c.segment[2], - glymur.codestream.CMEsegment(*pargs)) + glymur.codestream.CMEsegment(*pargs)) # COD: Coding style default self.assertFalse(c.segment[3].scod & 2) # no sop @@ -414,7 +434,7 @@ class TestSuiteWarns(MetadataBase): self.assertEqual(tuple(c.segment[3].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[3].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[3].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[3].spcod), 9) @@ -462,7 +482,7 @@ class TestSuiteWarns(MetadataBase): @unittest.skipIf(OPJ_DATA_ROOT is None, "OPJ_DATA_ROOT environment variable not set") -@unittest.skipIf(glymur.version.openjpeg_version_tuple[0] != 2, +@unittest.skipIf(glymur.version.openjpeg_version_tuple[0] == 1, "Feature not supported in glymur until openjpeg 2.0") class TestSuiteBands(unittest.TestCase): """ @@ -557,7 +577,7 @@ class TestSuiteBands(unittest.TestCase): @unittest.skipIf(OPJ_DATA_ROOT is None, "OPJ_DATA_ROOT environment variable not set") -@unittest.skipIf(glymur.version.openjpeg_version_tuple[0] < 2, +@unittest.skipIf(glymur.version.openjpeg_version_tuple[0] == 1, "Tests not passing until 2.0") class TestSuite2point0(unittest.TestCase): """Runs tests introduced in version 2.0 or that pass only in 2.0""" @@ -587,16 +607,13 @@ class TestSuite2point0(unittest.TestCase): @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) def test_NR_DEC_broken2_jp2_5_decode(self): - """ - Invalid marker ID on codestream, Null pointer access upon read. - """ + # Null pointer access jfile = opj_data_file('input/nonregression/broken2.jp2') - regex = re.compile(r'''Invalid\smarker\sid\sencountered\sat\sbyte\s - \d+\sin\scodestream:\s*"0x[a-fA-F0-9]{4}"''', - re.VERBOSE) with self.assertRaises(IOError): - with self.assertWarnsRegex(UserWarning, regex): + with self.assertWarns(UserWarning): + # Invalid marker ID. Jp2k(jfile)[:] + self.assertTrue(True) @unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG) def test_NR_DEC_broken4_jp2_7_decode(self): @@ -624,7 +641,7 @@ class TestSuite2point0(unittest.TestCase): @unittest.skipIf(OPJ_DATA_ROOT is None, "OPJ_DATA_ROOT environment variable not set") -@unittest.skipIf(re.match(r'''0|1|2.0.0''', +@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): @@ -707,7 +724,7 @@ class TestSuite2point1(unittest.TestCase): 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 + tdata = jp2k[896:1024, 896:1024] # last tile odata = jp2k[:] np.testing.assert_array_equal(tdata, odata[896:1024, 896:1024]) @@ -779,16 +796,15 @@ class TestSuite2point1(unittest.TestCase): with self.assertRaises(IOError): j[:] - @unittest.skipIf(OPJ_DATA_ROOT is None, "OPJ_DATA_ROOT environment variable not set") -@unittest.skipIf(re.match(r'''0|1|2.0.0''', +@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 diff --git a/glymur/test/test_opj_suite_dump.py b/glymur/test/test_opj_suite_dump.py index 7ac513f..ee1838b 100644 --- a/glymur/test/test_opj_suite_dump.py +++ b/glymur/test/test_opj_suite_dump.py @@ -2,26 +2,48 @@ 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 warnings import numpy as np import glymur from glymur import Jp2k from glymur.codestream import CMEsegment, SOTsegment, RGNsegment -from glymur.core import (RCME_ISO_8859_1, RCME_BINARY, SRGB, - GREYSCALE, RESTRICTED_ICC_PROFILE, - ENUMERATED_COLORSPACE) +from glymur.core import RCME_ISO_8859_1, RCME_BINARY from glymur.jp2box import FileTypeBox -from .fixtures import (MetadataBase, OPJ_DATA_ROOT, - WARNING_INFRASTRUCTURE_ISSUE, - WARNING_INFRASTRUCTURE_MSG, - opj_data_file) - -comment1 = "Creator: AV-J2K (c) 2000,2001 Algo Vision Technology" +from .fixtures import ( + MetadataBase, OPJ_DATA_ROOT, + WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG, + mse, peak_tolerance, read_pgx, opj_data_file +) @unittest.skipIf(OPJ_DATA_ROOT is None, @@ -53,19 +75,17 @@ class TestSuite(MetadataBase): colr = glymur.jp2box.ColourSpecificationBox(colorspace=glymur.core.YCC) self.verifyColourSpecificationBox(jp2.box[2].box[1], colr) - c = jp2.box[3].codestream + c = jp2.box[3].main_header ids = [x.marker_id for x in c.segment] expected = ['SOC', 'SIZ', 'COD', 'QCD'] self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (720, 243), 'xyosiz': (0, 0), - 'xytsiz': (720, 243), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': [(1, 2, 2), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (720, 243), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 2, 2), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -77,7 +97,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (32, 128)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -101,10 +121,9 @@ class TestSuite(MetadataBase): self.assertEqual(actual, expected) kwargs = {'rsiz': 1, 'xysiz': (128, 128), 'xyosiz': (0, 0), - 'xytsiz': (128, 128), 'xytosiz': (0, 0), 'bitdepth': (8,), - 'signed': (False,), 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (128, 128), 'xytosiz': (0, 0), 'bitdepth': (8,), + 'signed': (False,), 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # QCD: Quantization default self.assertEqual(c.segment[2].sqcd & 0x1f, 0) @@ -124,7 +143,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[3].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[3].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[3].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) @@ -135,10 +154,9 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 1, 'xysiz': (127, 126), 'xyosiz': (0, 0), - 'xytsiz': (127, 126), 'xytosiz': (0, 0), 'bitdepth': (8,), - 'signed': (False,), 'xyrsiz': [(2,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (127, 126), 'xytosiz': (0, 0), 'bitdepth': (8,), + 'signed': (False,), 'xyrsiz': [(2,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertTrue(c.segment[2].scod & 2) # sop @@ -150,7 +168,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, True, False, True, True]) + [False, False, True, False, True, True]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) @@ -160,7 +178,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[3].code_block_size), (32, 32)) # cblk self.verify_codeblock_style(c.segment[3].spcoc[3], - [False, False, True, False, True, True]) + [False, False, True, False, True, True]) self.assertEqual(c.segment[3].spcoc[4], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) @@ -173,8 +191,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[4].mantissa, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) - pargs = (RCME_ISO_8859_1, - "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) + pargs = RCME_ISO_8859_1, "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode() self.verifyCMEsegment(c.segment[5], CMEsegment(*pargs)) # One unknown marker @@ -200,10 +217,9 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 1, 'xysiz': (256, 256), 'xyosiz': (0, 0), - 'xytsiz': (128, 128), 'xytosiz': (0, 0), 'bitdepth': (4,), - 'signed': (True,), 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (128, 128), 'xytosiz': (0, 0), 'bitdepth': (4,), + 'signed': (True,), 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertTrue(c.segment[2].scod & 2) @@ -215,7 +231,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) @@ -247,11 +263,11 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[6].xcrg, (65424,)) self.assertEqual(c.segment[6].ycrg, (32558,)) - pargs = (RCME_ISO_8859_1, - "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) + pargs = RCME_ISO_8859_1, "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode() self.verifyCMEsegment(c.segment[7], CMEsegment(*pargs)) - pargs = (RCME_ISO_8859_1, comment1.encode()) + pargs = (RCME_ISO_8859_1, + "Creator: AV-J2K (c) 2000,2001 Algo Vision Technology".encode()) self.verifyCMEsegment(c.segment[8], CMEsegment(*pargs)) pargs = (RCME_BINARY, c.segment[9].ccme) @@ -274,12 +290,10 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 1, 'xysiz': (640, 480), 'xyosiz': (0, 0), - 'xytsiz': (640, 480), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (640, 480), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) @@ -291,7 +305,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, True, False, False, False]) + [False, False, True, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(c.segment[2].precinct_size, @@ -339,7 +353,7 @@ class TestSuite(MetadataBase): 2002, 1888]) pargs = (RCME_ISO_8859_1, - "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) + "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) self.verifyCMEsegment(c.segment[6], CMEsegment(*pargs)) self.verifySOTsegment(c.segment[7], SOTsegment(0, 264383, 0, 1)) @@ -353,12 +367,11 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 1, 'xysiz': (1024, 1024), 'xyosiz': (0, 0), - 'xytsiz': (1024, 1024), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8, 8), - 'signed': (False, False, False, False), - 'xyrsiz': [(1, 1, 2, 2), (1, 1, 2, 2)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (1024, 1024), 'xytosiz': (0, 0), + 'bitdepth': (8, 8, 8, 8), + 'signed': (False, False, False, False), + 'xyrsiz': [(1, 1, 2, 2), (1, 1, 2, 2)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) @@ -370,7 +383,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (32, 32)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -381,7 +394,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[3].code_block_size), (32, 32)) # cblk self.verify_codeblock_style(c.segment[3].spcoc[3], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[3].spcoc[4], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) @@ -391,7 +404,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[4].code_block_size), (32, 32)) # cblk self.verify_codeblock_style(c.segment[4].spcoc[3], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[4].spcoc[4], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) @@ -428,7 +441,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[7].mantissa, [0] * 19) pargs = (RCME_ISO_8859_1, - "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) + "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) self.verifyCMEsegment(c.segment[8], CMEsegment(*pargs)) # TLM (tile-part length) @@ -447,12 +460,11 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 2, 'xysiz': (513, 129), 'xyosiz': (0, 0), - 'xytsiz': (513, 129), 'xytosiz': (0, 0), - 'bitdepth': (12, 12, 12, 12), - 'signed': (False, False, False, False), - 'xyrsiz': [(1, 2, 1, 2), (1, 1, 2, 2)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (513, 129), 'xytosiz': (0, 0), + 'bitdepth': (12, 12, 12, 12), + 'signed': (False, False, False, False), + 'xyrsiz': [(1, 2, 1, 2), (1, 1, 2, 2)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) @@ -464,7 +476,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -523,7 +535,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[7].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[7].spcoc[3], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[7].spcoc[4], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) @@ -540,12 +552,10 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 1, 'xysiz': (2048, 2048), 'xyosiz': (0, 0), - 'xytsiz': (128, 128), 'xytosiz': (0, 0), - 'bitdepth': (12, 12, 12), - 'signed': (True, True, True), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (128, 128), 'xytosiz': (0, 0), 'bitdepth': (12, 12, 12), + 'signed': (True, True, True), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertTrue(c.segment[2].scod & 2) @@ -557,7 +567,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -585,6 +595,7 @@ class TestSuite(MetadataBase): # PLT: packet length, tile part self.assertEqual(c.segment[7].zplt, 0) + #self.assertEqual(c.segment[7].iplt), 99) # SOD: start of data self.assertEqual(c.segment[8].marker_id, 'SOD') @@ -594,12 +605,10 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 1, 'xysiz': (513, 3072), 'xyosiz': (0, 0), - 'xytsiz': (513, 3072), 'xytosiz': (0, 0), - 'bitdepth': (12, 12, 12), - 'signed': (True, True, True), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (513, 3072), 'xytosiz': (0, 0), 'bitdepth': (12, 12, 12), + 'signed': (True, True, True), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertTrue(c.segment[2].scod & 2) @@ -611,7 +620,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -622,7 +631,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[3].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[3].spcoc[3], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[3].spcoc[4], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) @@ -632,7 +641,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[4].code_block_size), (32, 32)) # cblk self.verify_codeblock_style(c.segment[4].spcoc[3], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[4].spcoc[4], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) @@ -642,7 +651,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[5].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[5].spcoc[3], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[5].spcoc[4], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) @@ -687,10 +696,9 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 0, 'xysiz': (17, 37), 'xyosiz': (0, 0), - 'xytsiz': (17, 37), 'xytosiz': (0, 0), 'bitdepth': (8,), - 'signed': (False,), 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (17, 37), 'xytosiz': (0, 0), 'bitdepth': (8,), + 'signed': (False,), 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) @@ -702,7 +710,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -735,12 +743,10 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 1, 'xysiz': (256, 256), 'xyosiz': (0, 0), - 'xytsiz': (128, 128), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': [(4, 4, 4), (4, 4, 4)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (128, 128), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(4, 4, 4), (4, 4, 4)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) @@ -752,7 +758,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -799,10 +805,9 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 1, 'xysiz': (128, 1), 'xyosiz': (0, 0), - 'xytsiz': (128, 128), 'xytosiz': (0, 0), 'bitdepth': (8,), - 'signed': (False,), 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (128, 128), 'xytosiz': (0, 0), 'bitdepth': (8,), + 'signed': (False,), 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) @@ -814,7 +819,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, True]) + [False, False, False, False, False, True]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(c.segment[2].precinct_size, [(128, 2)]) @@ -827,7 +832,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[3].exponent, [8]) pargs = (RCME_ISO_8859_1, - "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) + "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) self.verifyCMEsegment(c.segment[4], CMEsegment(*pargs)) self.verifySOTsegment(c.segment[5], SOTsegment(0, 118, 0, 1)) @@ -849,11 +854,10 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 1, 'xysiz': (3, 5), 'xyosiz': (0, 0), - 'xytsiz': (3, 5), 'xytosiz': (0, 0), 'bitdepth': (8,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (3, 5), 'xytosiz': (0, 0), 'bitdepth': (8,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertTrue(c.segment[2].scod & 2) @@ -865,7 +869,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (32, 32)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, True, False, False, False]) + [False, False, True, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -878,8 +882,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[3].exponent, [8, 9, 9, 10, 9, 9, 10, 9, 9, 10]) - pargs = (RCME_ISO_8859_1, - "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) + pargs = (RCME_ISO_8859_1, "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) self.verifyCMEsegment(c.segment[4], CMEsegment(*pargs)) self.verifySOTsegment(c.segment[5], SOTsegment(0, 162, 0, 1)) @@ -901,12 +904,10 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 1, 'xysiz': (1, 1), 'xyosiz': (0, 0), - 'xytsiz': (1, 1), 'xytosiz': (0, 0), - 'bitdepth': tuple([8] * 257), - 'signed': tuple([False] * 257), - 'xyrsiz': [tuple([1] * 257), tuple([1] * 257)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (1, 1), 'xytosiz': (0, 0), 'bitdepth': tuple([8] * 257), + 'signed': tuple([False] * 257), + 'xyrsiz': [tuple([1] * 257), tuple([1] * 257)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -917,7 +918,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 1) # levels self.assertEqual(tuple(c.segment[2].code_block_size), (32, 32)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, True, False]) + [False, False, False, False, True, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -927,7 +928,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[3].spcoc[0], 1) # levels self.assertEqual(tuple(c.segment[3].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[3].spcoc[3], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[3].spcoc[4], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) @@ -968,8 +969,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[8].ppod, (glymur.core.RLCP, glymur.core.CPRL)) - pargs = (RCME_ISO_8859_1, - "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) + pargs = (RCME_ISO_8859_1, "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) self.verifyCMEsegment(c.segment[9], CMEsegment(*pargs)) self.verifySOTsegment(c.segment[10], SOTsegment(0, 1537, 0, 1)) @@ -985,11 +985,10 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 0, 'xysiz': (49, 49), 'xyosiz': (0, 0), - 'xytsiz': (49, 49), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (49, 49), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) @@ -1000,7 +999,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 5) # levels self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -1026,11 +1025,10 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 1, 'xysiz': (256, 256), 'xyosiz': (0, 0), - 'xytsiz': (128, 128), 'xytosiz': (0, 0), 'bitdepth': (4,), - 'signed': (True,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (128, 128), 'xytosiz': (0, 0), 'bitdepth': (4,), + 'signed': (True,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertTrue(c.segment[2].scod & 2) @@ -1041,7 +1039,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 1) # levels self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -1074,11 +1072,11 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[6].xcrg, (65424,)) self.assertEqual(c.segment[6].ycrg, (32558,)) - pargs = (RCME_ISO_8859_1, - "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) + pargs = (RCME_ISO_8859_1, "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) self.verifyCMEsegment(c.segment[7], CMEsegment(*pargs)) - pargs = (RCME_ISO_8859_1, comment1.encode()) + pargs = (RCME_ISO_8859_1, + "Creator: AV-J2K (c) 2000,2001 Algo Vision Technology".encode()) self.verifyCMEsegment(c.segment[8], CMEsegment(*pargs)) pargs = (RCME_BINARY, c.segment[9].ccme) @@ -1127,11 +1125,10 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 0, 'xysiz': (128, 128), 'xyosiz': (0, 0), - 'xytsiz': (128, 128), 'xytosiz': (0, 0), 'bitdepth': (8,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (128, 128), 'xytosiz': (0, 0), 'bitdepth': (8,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) @@ -1142,7 +1139,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 3) # levels self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -1168,11 +1165,10 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 2, 'xysiz': (127, 227), 'xyosiz': (5, 128), - 'xytsiz': (127, 126), 'xytosiz': (1, 101), 'bitdepth': (8,), - 'signed': (False,), - 'xyrsiz': [(2,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (127, 126), 'xytosiz': (1, 101), 'bitdepth': (8,), + 'signed': (False,), + 'xyrsiz': [(2,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertTrue(c.segment[2].scod & 2) # SOP @@ -1183,7 +1179,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 3) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, True, False, True, True]) + [False, False, True, False, True, True]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -1193,7 +1189,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[3].spcoc[0], 3) # level self.assertEqual(tuple(c.segment[3].code_block_size), (32, 32)) self.verify_codeblock_style(c.segment[3].spcoc[3], - [False, False, True, False, True, True]) + [False, False, True, False, True, True]) self.assertEqual(c.segment[3].spcoc[4], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) @@ -1205,8 +1201,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[4].exponent, [8, 9, 9, 10, 9, 9, 10, 9, 9, 10]) - pargs = (RCME_ISO_8859_1, - "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) + pargs = (RCME_ISO_8859_1, "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) self.verifyCMEsegment(c.segment[5], CMEsegment(*pargs)) self.verifySOTsegment(c.segment[6], SOTsegment(0, 4627, 0, 1)) @@ -1228,12 +1223,10 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 2, 'xysiz': (640, 480), 'xyosiz': (0, 0), - 'xytsiz': (640, 480), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (640, 480), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -1245,7 +1238,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, True, False, True, False, False]) + [False, True, False, True, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(c.segment[2].precinct_size, @@ -1292,8 +1285,7 @@ class TestSuite(MetadataBase): [14, 14, 14, 14, 13, 13, 13, 12, 12, 12, 11, 11, 11, 9, 9, 9, 9, 9, 9]) - pargs = (RCME_ISO_8859_1, - "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) + pargs = (RCME_ISO_8859_1, "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) self.verifyCMEsegment(c.segment[6], CMEsegment(*pargs)) self.verifySOTsegment(c.segment[7], SOTsegment(0, 262838, 0, 1)) @@ -1313,12 +1305,11 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 2, 'xysiz': (1024, 1024), 'xyosiz': (0, 0), - 'xytsiz': (1024, 1024), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8, 8), - 'signed': (False, False, False, False), - 'xyrsiz': [(1, 1, 2, 2), (1, 1, 2, 2)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (1024, 1024), 'xytosiz': (0, 0), + 'bitdepth': (8, 8, 8, 8), + 'signed': (False, False, False, False), + 'xyrsiz': [(1, 1, 2, 2), (1, 1, 2, 2)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -1329,7 +1320,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 6) # level self.assertEqual(tuple(c.segment[2].code_block_size), (32, 32)) self.verify_codeblock_style(c.segment[2].spcod[7], - [True, False, True, False, False, False]) + [True, False, True, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -1339,7 +1330,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[3].spcoc[0], 3) # level self.assertEqual(tuple(c.segment[3].code_block_size), (32, 32)) self.verify_codeblock_style(c.segment[3].spcoc[3], - [True, False, True, False, False, False]) + [True, False, True, False, False, False]) self.assertEqual(c.segment[3].spcoc[4], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) @@ -1348,7 +1339,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[4].spcoc[0], 6) # level self.assertEqual(tuple(c.segment[4].code_block_size), (32, 32)) self.verify_codeblock_style(c.segment[4].spcoc[3], - [True, False, True, False, False, False]) + [True, False, True, False, False, False]) self.assertEqual(c.segment[4].spcoc[4], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) @@ -1384,8 +1375,7 @@ class TestSuite(MetadataBase): [8, 9, 9, 10, 9, 9, 10, 9, 9, 10, 9, 9, 10, 9, 9, 10, 9, 9, 10]) - pargs = (RCME_ISO_8859_1, - "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) + pargs = (RCME_ISO_8859_1, "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) self.verifyCMEsegment(c.segment[8], CMEsegment(*pargs)) # PPM: packed packet headers, main header @@ -1410,11 +1400,10 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 2, 'xysiz': (1024, 1024), 'xyosiz': (0, 0), - 'xytsiz': (128, 128), 'xytosiz': (0, 0), 'bitdepth': (12,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (128, 128), 'xytosiz': (0, 0), 'bitdepth': (12,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -1425,7 +1414,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 3) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -1498,12 +1487,10 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 2, 'xysiz': (529, 524), 'xyosiz': (17, 12), - 'xytsiz': (37, 37), 'xytosiz': (8, 2), - 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (37, 37), 'xytosiz': (8, 2), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertTrue(c.segment[2].scod & 2) # sop @@ -1514,7 +1501,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 7) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 8)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [True, False, False, True, True, False]) + [True, False, False, True, True, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(c.segment[2].precinct_size, [(16, 16)] * 8) @@ -1529,8 +1516,7 @@ class TestSuite(MetadataBase): [17, 17, 17, 17, 16, 16, 16, 15, 15, 15, 14, 14, 14, 13, 13, 13, 11, 11, 11, 11, 11, 11]) - pargs = (RCME_ISO_8859_1, - "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) + pargs = (RCME_ISO_8859_1, "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) self.verifyCMEsegment(c.segment[4], CMEsegment(*pargs)) # 225 consecutive PPM segments. @@ -1557,11 +1543,10 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 2, 'xysiz': (12, 12), 'xyosiz': (0, 0), - 'xytsiz': (3, 3), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (3, 3), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertTrue(c.segment[2].scod & 2) # sop @@ -1572,7 +1557,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 4) # level self.assertEqual(tuple(c.segment[2].code_block_size), (32, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, True, False, True]) + [False, False, False, True, False, True]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -1588,8 +1573,7 @@ class TestSuite(MetadataBase): [14, 14, 14, 14, 13, 13, 13, 11, 11, 11, 11, 11, 11]) - pargs = (RCME_ISO_8859_1, - "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) + pargs = (RCME_ISO_8859_1, "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) self.verifyCMEsegment(c.segment[4], CMEsegment(*pargs)) self.verifySOTsegment(c.segment[5], SOTsegment(0, 349, 0, 1)) @@ -1620,11 +1604,10 @@ class TestSuite(MetadataBase): c = Jp2k(jfile).get_codestream(header_only=False) kwargs = {'rsiz': 2, 'xysiz': (12, 12), 'xyosiz': (4, 0), - 'xytsiz': (12, 12), 'xytosiz': (4, 0), 'bitdepth': (8, 8), - 'signed': (False, False), - 'xyrsiz': [(4, 1), (1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (12, 12), 'xytosiz': (4, 0), 'bitdepth': (8, 8), + 'signed': (False, False), + 'xyrsiz': [(4, 1), (1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertTrue(c.segment[2].scod & 2) # sop @@ -1635,7 +1618,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 1) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(c.segment[2].precinct_size, [(1, 1), (2, 2)]) @@ -1645,7 +1628,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[3].spcoc[0], 1) # level self.assertEqual(tuple(c.segment[3].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[3].spcoc[3], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[3].spcoc[4], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(c.segment[3].precinct_size, [(2, 2), (4, 4)]) @@ -1657,8 +1640,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[4].mantissa, [0] * 4) self.assertEqual(c.segment[4].exponent, [8, 9, 9, 10]) - pargs = (RCME_ISO_8859_1, - "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) + pargs = (RCME_ISO_8859_1, "Creator: AV-J2K (c) 2000,2001 Algo Vision".encode()) self.verifyCMEsegment(c.segment[5], CMEsegment(*pargs)) self.verifySOTsegment(c.segment[6], SOTsegment(0, 434, 0, 1)) @@ -1675,12 +1657,11 @@ class TestSuite(MetadataBase): c = jp2k.get_codestream(header_only=False) kwargs = {'rsiz': 3, 'xysiz': (1920, 1080), 'xyosiz': (0, 0), - 'xytsiz': (1920, 1080), 'xytosiz': (0, 0), - 'bitdepth': (12, 12, 12), - 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (1920, 1080), 'xytosiz': (0, 0), + 'bitdepth': (12, 12, 12), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -1691,7 +1672,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 5) # level self.assertEqual(tuple(c.segment[2].code_block_size), (32, 32)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(c.segment[2].precinct_size[0], (128, 128)) @@ -1713,7 +1694,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[4].spcoc[0], 5) # level self.assertEqual(tuple(c.segment[4].code_block_size), (32, 32)) self.verify_codeblock_style(c.segment[4].spcoc[3], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[4].spcoc[4], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) @@ -1735,7 +1716,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[6].spcoc[0], 5) # level self.assertEqual(tuple(c.segment[6].code_block_size), (32, 32)) self.verify_codeblock_style(c.segment[6].spcoc[3], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[6].spcoc[4], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) @@ -1780,12 +1761,10 @@ class TestSuite(MetadataBase): c = jp2k.get_codestream(header_only=False) kwargs = {'rsiz': 0, 'xysiz': (2592, 1944), 'xyosiz': (0, 0), - 'xytsiz': (640, 480), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (640, 480), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -1796,7 +1775,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 5) # level self.assertEqual(tuple(c.segment[2].code_block_size), (32, 32)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(c.segment[2].precinct_size, @@ -1815,11 +1794,10 @@ class TestSuite(MetadataBase): c = jp2k.get_codestream(header_only=False) kwargs = {'rsiz': 0, 'xysiz': (512, 512), 'xyosiz': (0, 0), - 'xytsiz': (512, 512), 'xytosiz': (0, 0), 'bitdepth': (16,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (512, 512), 'xytosiz': (0, 0), 'bitdepth': (16,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -1830,7 +1808,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 5) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -1845,11 +1823,10 @@ class TestSuite(MetadataBase): c = jp2k.get_codestream(header_only=False) kwargs = {'rsiz': 0, 'xysiz': (512, 512), 'xyosiz': (0, 0), - 'xytsiz': (512, 512), 'xytosiz': (0, 0), 'bitdepth': (16,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (512, 512), 'xytosiz': (0, 0), 'bitdepth': (16,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -1860,7 +1837,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 5) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -1883,11 +1860,10 @@ class TestSuite(MetadataBase): self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (1420, 1416), 'xyosiz': (0, 0), - 'xytsiz': (1420, 1416), 'xytosiz': (0, 0), 'bitdepth': (16,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (1420, 1416), 'xytosiz': (0, 0), 'bitdepth': (16,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -1898,7 +1874,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 11) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -1921,11 +1897,10 @@ class TestSuite(MetadataBase): self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (512, 614), 'xyosiz': (0, 0), - 'xytsiz': (512, 614), 'xytosiz': (0, 0), 'bitdepth': (12,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (512, 614), 'xytosiz': (0, 0), 'bitdepth': (12,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -1936,7 +1911,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 5) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -1965,11 +1940,10 @@ class TestSuite(MetadataBase): self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (256, 256), 'xyosiz': (0, 0), - 'xytsiz': (256, 256), 'xytosiz': (0, 0), 'bitdepth': (8,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (256, 256), 'xytosiz': (0, 0), 'bitdepth': (8,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -1980,7 +1954,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 5) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2007,11 +1981,10 @@ class TestSuite(MetadataBase): self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (1420, 1416), 'xyosiz': (0, 0), - 'xytsiz': (1420, 1416), 'xytosiz': (0, 0), 'bitdepth': (16,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (1420, 1416), 'xytosiz': (0, 0), 'bitdepth': (16,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2022,7 +1995,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 11) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2044,12 +2017,10 @@ class TestSuite(MetadataBase): self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (256, 256), 'xyosiz': (0, 0), - 'xytsiz': (256, 256), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), - 'signed': (True, True, True), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (256, 256), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (True, True, True), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2060,7 +2031,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 5) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2083,11 +2054,10 @@ class TestSuite(MetadataBase): c = jp2k.get_codestream() kwargs = {'rsiz': 0, 'xysiz': (2048, 2500), 'xyosiz': (0, 0), - 'xytsiz': (2048, 2500), 'xytosiz': (0, 0), 'bitdepth': (16,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (2048, 2500), 'xytosiz': (0, 0), 'bitdepth': (16,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2098,7 +2068,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 8) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2131,17 +2101,17 @@ class TestSuite(MetadataBase): pargs = (RCME_ISO_8859_1, ccme.encode()) self.verifyCMEsegment(c.segment[5], CMEsegment(*pargs)) + def test_NR_MarkerIsNotCompliant_j2k_dump(self): jfile = opj_data_file('input/nonregression/MarkerIsNotCompliant.j2k') jp2k = Jp2k(jfile) c = jp2k.get_codestream() kwargs = {'rsiz': 0, 'xysiz': (1420, 1416), 'xyosiz': (0, 0), - 'xytsiz': (1420, 1416), 'xytosiz': (0, 0), 'bitdepth': (16,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (1420, 1416), 'xytosiz': (0, 0), 'bitdepth': (16,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2152,7 +2122,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 11) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2172,12 +2142,10 @@ class TestSuite(MetadataBase): c = jp2k.get_codestream() kwargs = {'rsiz': 0, 'xysiz': (1920, 1080), 'xyosiz': (0, 0), - 'xytsiz': (1920, 1080), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (1920, 1080), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2188,7 +2156,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 5) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2206,12 +2174,10 @@ class TestSuite(MetadataBase): c = jp2k.get_codestream() kwargs = {'rsiz': 0, 'xysiz': (1920, 1080), 'xyosiz': (0, 0), - 'xytsiz': (1920, 1080), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (1920, 1080), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2222,7 +2188,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 5) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2240,12 +2206,10 @@ class TestSuite(MetadataBase): c = jp2k.get_codestream() kwargs = {'rsiz': 0, 'xysiz': (1920, 1080), 'xyosiz': (0, 0), - 'xytsiz': (1920, 1080), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (1920, 1080), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2256,7 +2220,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 5) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2278,12 +2242,10 @@ class TestSuite(MetadataBase): self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (117, 117), 'xyosiz': (0, 0), - 'xytsiz': (117, 117), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8, 8), - 'signed': (False, False, False, False), - 'xyrsiz': [(1, 1, 1, 1), (1, 1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (117, 117), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8, 8), + 'signed': (False, False, False, False), + 'xyrsiz': [(1, 1, 1, 1), (1, 1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2294,7 +2256,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 5) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2316,12 +2278,10 @@ class TestSuite(MetadataBase): self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (117, 117), 'xyosiz': (0, 0), - 'xytsiz': (117, 117), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8, 8), - 'signed': (False, False, False, False), - 'xyrsiz': [(1, 1, 1, 1), (1, 1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (117, 117), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8, 8), + 'signed': (False, False, False, False), + 'xyrsiz': [(1, 1, 1, 1), (1, 1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2332,7 +2292,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 5) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2354,12 +2314,10 @@ class TestSuite(MetadataBase): self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (512, 512), 'xyosiz': (0, 0), - 'xytsiz': (512, 512), 'xytosiz': (0, 0), - 'bitdepth': (16,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (512, 512), 'xytosiz': (0, 0), 'bitdepth': (16,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2370,7 +2328,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 5) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2396,12 +2354,10 @@ class TestSuite(MetadataBase): self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (1024, 1024), 'xyosiz': (0, 0), - 'xytsiz': (1024, 1024), 'xytosiz': (0, 0), - 'bitdepth': (12,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (1024, 1024), 'xytosiz': (0, 0), 'bitdepth': (12,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2412,7 +2368,7 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].spcod[4], 5) # level self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2438,12 +2394,10 @@ class TestSuite(MetadataBase): self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (1800, 1800), 'xyosiz': (0, 0), - 'xytsiz': (1800, 1800), 'xytosiz': (0, 0), - 'bitdepth': (16,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (1800, 1800), 'xytosiz': (0, 0), 'bitdepth': (16,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2452,9 +2406,10 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].layers, 1) # layers = 1 self.assertEqual(c.segment[2].spcod[3], 1) # mct self.assertEqual(c.segment[2].spcod[4], 11) # level - self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) + self.assertEqual(tuple(c.segment[2].code_block_size), + (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2476,12 +2431,10 @@ class TestSuite(MetadataBase): self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (1800, 1800), 'xyosiz': (0, 0), - 'xytsiz': (1800, 1800), 'xytosiz': (0, 0), - 'bitdepth': (16,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (1800, 1800), 'xytosiz': (0, 0), 'bitdepth': (16,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2490,9 +2443,10 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].layers, 1) # layers = 1 self.assertEqual(c.segment[2].spcod[3], 1) # mct self.assertEqual(c.segment[2].spcod[4], 11) # level - self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) + self.assertEqual(tuple(c.segment[2].code_block_size), + (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2514,12 +2468,10 @@ class TestSuite(MetadataBase): self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (2048, 1556), 'xyosiz': (0, 0), - 'xytsiz': (2048, 1556), 'xytosiz': (0, 0), - 'bitdepth': (12, 12, 12), - 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (2048, 1556), 'xytosiz': (0, 0), 'bitdepth': (12, 12, 12), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2528,9 +2480,10 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].layers, 2) # layers = 2 self.assertEqual(c.segment[2].spcod[3], 1) # mct self.assertEqual(c.segment[2].spcod[4], 5) # level - self.assertEqual(tuple(c.segment[2].code_block_size), (32, 32)) + self.assertEqual(tuple(c.segment[2].code_block_size), + (32, 32)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(c.segment[2].precinct_size, @@ -2559,9 +2512,7 @@ class TestSuite(MetadataBase): self.verifySignatureBox(jp2.box[0]) self.verify_filetype_box(jp2.box[1], - FileTypeBox(compatibility_list=['jp2 ', - 'jpxb', - 'jpx '])) + FileTypeBox(compatibility_list=['jp2 ', 'jpxb', 'jpx '])) # Reader requirements talk. # unrestricted jpeg 2000 part 1 @@ -2570,9 +2521,9 @@ class TestSuite(MetadataBase): ihdr = glymur.jp2box.ImageHeaderBox(203, 479, colorspace_unknown=True) self.verifyImageHeaderBox(jp2.box[3].box[0], ihdr) - colr = glymur.jp2box.ColourSpecificationBox(colorspace=SRGB, - approximation=1, - precedence=2) + colr = glymur.jp2box.ColourSpecificationBox( + colorspace=glymur.core.SRGB, + approximation=1, precedence=2) self.verifyColourSpecificationBox(jp2.box[3].box[1], colr) # Jp2 Header @@ -2585,19 +2536,17 @@ class TestSuite(MetadataBase): self.assertEqual(jp2.box[3].box[3].mapping_type, (1, 1, 1)) self.assertEqual(jp2.box[3].box[3].palette_index, (0, 1, 2)) - c = jp2.box[4].codestream + c = jp2.box[4].main_header ids = [x.marker_id for x in c.segment] expected = ['SOC', 'SIZ', 'COD', 'QCD'] self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (479, 203), 'xyosiz': (0, 0), - 'xytsiz': (256, 203), 'xytosiz': (0, 0), - 'bitdepth': (8,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (256, 203), 'xytosiz': (0, 0), 'bitdepth': (8,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2606,9 +2555,10 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].layers, 1) # layers = 1 self.assertEqual(c.segment[2].spcod[3], 0) # mct self.assertEqual(c.segment[2].spcod[4], 5) # level - self.assertEqual(tuple(c.segment[2].code_block_size), (32, 32)) + self.assertEqual(tuple(c.segment[2].code_block_size), + (32, 32)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2631,37 +2581,32 @@ class TestSuite(MetadataBase): self.verifySignatureBox(jp2.box[0]) self.verify_filetype_box(jp2.box[1], - FileTypeBox(compatibility_list=['jp2 ', - 'jpxb', - 'jpx '])) + FileTypeBox(compatibility_list=['jp2 ', 'jpxb', 'jpx '])) # Reader requirements talk. # unrestricted jpeg 2000 part 1 self.assertTrue(5 in jp2.box[2].standard_flag) ihdr = glymur.jp2box.ImageHeaderBox(326, 431, - num_components=3, - colorspace_unknown=True) + num_components=3, colorspace_unknown=True) self.verifyImageHeaderBox(jp2.box[3].box[0], ihdr) - colr = glymur.jp2box.ColourSpecificationBox(colorspace=SRGB, - approximation=1, - precedence=2) + colr = glymur.jp2box.ColourSpecificationBox( + colorspace=glymur.core.SRGB, + approximation=1, precedence=2) self.verifyColourSpecificationBox(jp2.box[3].box[1], colr) - c = jp2.box[4].codestream + c = jp2.box[4].main_header ids = [x.marker_id for x in c.segment] expected = ['SOC', 'SIZ', 'COD', 'QCD'] self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (431, 326), 'xyosiz': (0, 0), - 'xytsiz': (256, 256), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (256, 256), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2670,9 +2615,10 @@ class TestSuite(MetadataBase): self.assertEqual(c.segment[2].layers, 1) # layers = 1 self.assertEqual(c.segment[2].spcod[3], 1) # mct self.assertEqual(c.segment[2].spcod[4], 5) # level - self.assertEqual(tuple(c.segment[2].code_block_size), (32, 32)) + self.assertEqual(tuple(c.segment[2].code_block_size), + (32, 32)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2700,10 +2646,11 @@ class TestSuite(MetadataBase): self.verify_filetype_box(jp2.box[1], FileTypeBox()) ihdr = glymur.jp2box.ImageHeaderBox(135, 135, num_components=2, - colorspace_unknown=True) + colorspace_unknown=True) self.verifyImageHeaderBox(jp2.box[2].box[0], ihdr) - colr = glymur.jp2box.ColourSpecificationBox(colorspace=GREYSCALE) + colr = glymur.jp2box.ColourSpecificationBox( + colorspace=glymur.core.GREYSCALE) self.verifyColourSpecificationBox(jp2.box[2].box[1], colr) # Jp2 Header @@ -2712,19 +2659,17 @@ class TestSuite(MetadataBase): self.assertEqual(jp2.box[2].box[2].channel_type, (0, 1)) # opacity self.assertEqual(jp2.box[2].box[2].association, (0, 0)) # both main - c = jp2.box[3].codestream + c = jp2.box[3].main_header ids = [x.marker_id for x in c.segment] expected = ['SOC', 'SIZ', 'COD', 'QCD', 'CME'] self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (135, 135), 'xyosiz': (0, 0), - 'xytsiz': (135, 135), 'xytosiz': (0, 0), - 'bitdepth': (8, 8), - 'signed': (False, False), - 'xyrsiz': [(1, 1), (1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (135, 135), 'xytosiz': (0, 0), 'bitdepth': (8, 8), + 'signed': (False, False), + 'xyrsiz': [(1, 1), (1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2736,7 +2681,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2765,23 +2710,20 @@ class TestSuite(MetadataBase): self.verifySignatureBox(jp2.box[0]) self.verify_filetype_box(jp2.box[1], - FileTypeBox(compatibility_list=['jp2 ', - 'jpxb', - 'jpx '])) + FileTypeBox(compatibility_list=['jp2 ', 'jpxb', 'jpx '])) # Reader requirements talk. # unrestricted jpeg 2000 part 1 self.assertTrue(5 in jp2.box[2].standard_flag) ihdr = glymur.jp2box.ImageHeaderBox(46, 124, bits_per_component=4, - colorspace_unknown=True) + colorspace_unknown=True) self.verifyImageHeaderBox(jp2.box[3].box[0], ihdr) - method = ENUMERATED_COLORSPACE - colr = glymur.jp2box.ColourSpecificationBox(colorspace=SRGB, - method=method, - approximation=1, - precedence=2) + colr = glymur.jp2box.ColourSpecificationBox( + colorspace=glymur.core.SRGB, + method=glymur.core.ENUMERATED_COLORSPACE, + approximation=1, precedence=2) self.verifyColourSpecificationBox(jp2.box[3].box[1], colr) # Jp2 Header @@ -2795,19 +2737,17 @@ class TestSuite(MetadataBase): self.assertEqual(jp2.box[3].box[3].mapping_type, (1, 1, 1)) self.assertEqual(jp2.box[3].box[3].palette_index, (0, 1, 2)) - c = jp2.box[4].codestream + c = jp2.box[4].main_header ids = [x.marker_id for x in c.segment] expected = ['SOC', 'SIZ', 'COD', 'QCD'] self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (124, 46), 'xyosiz': (0, 0), - 'xytsiz': (124, 46), 'xytosiz': (0, 0), - 'bitdepth': (4,), - 'signed': (False,), - 'xyrsiz': [(1,), (1,)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (124, 46), 'xytosiz': (0, 0), 'bitdepth': (4,), + 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2819,7 +2759,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (32, 32)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2849,19 +2789,17 @@ class TestSuite(MetadataBase): colr = glymur.jp2box.ColourSpecificationBox(colorspace=glymur.core.YCC) self.verifyColourSpecificationBox(jp2.box[2].box[1], colr) - c = jp2.box[3].codestream + c = jp2.box[3].main_header ids = [x.marker_id for x in c.segment] expected = ['SOC', 'SIZ', 'COD', 'QCD', 'POD'] self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (766, 576), 'xyosiz': (0, 0), - 'xytsiz': (766, 576), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': [(1, 2, 2), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (766, 576), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 2, 2), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -2873,7 +2811,7 @@ class TestSuite(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (32, 128)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -2909,34 +2847,111 @@ class TestSuiteWarns(MetadataBase): relpath = 'input/nonregression/issue188_beach_64bitsbox.jp2' jfile = opj_data_file(relpath) with self.assertWarns(UserWarning): - Jp2k(jfile)[:] + d = Jp2k(jfile)[:] self.assertTrue(True) def test_NR_broken4_jp2_dump(self): jfile = opj_data_file('input/nonregression/broken4.jp2') - with warnings.catch_warnings(): - # Suppress a warning, all we really care is parsing the entire - # file. - warnings.simplefilter("ignore") - with self.assertWarns(UserWarning): - jp2 = Jp2k(jfile) - self.assertEqual(jp2.box[-1].codestream.segment[-1].marker_id, - 'QCC') + with self.assertWarns(UserWarning): + jp2 = Jp2k(jfile) + + self.assertEqual(jp2.box[-1].main_header.segment[-1].marker_id, 'QCC') + + @unittest.skipIf(sys.maxsize < 2**32, 'Do not run on 32-bit platforms') + def test_NR_broken3_jp2_dump(self): + """ + NR_broken3_jp2_dump + + The file in question here has a colr box with an erroneous box + length of over 1GB. Don't run it on 32-bit platforms. + """ + jfile = opj_data_file('input/nonregression/broken3.jp2') + with self.assertWarns(UserWarning): + # Bad box length. + jp2 = Jp2k(jfile) + + ids = [box.box_id for box in jp2.box] + self.assertEqual(ids, ['jP ', 'ftyp', 'jp2h', 'jp2c']) + + ids = [box.box_id for box in jp2.box[2].box] + self.assertEqual(ids, ['ihdr', 'colr']) + + self.verifySignatureBox(jp2.box[0]) + self.verify_filetype_box(jp2.box[1], FileTypeBox()) + + ihdr = glymur.jp2box.ImageHeaderBox(152, 203, num_components=3) + self.verifyImageHeaderBox(jp2.box[2].box[0], ihdr) + + colr = glymur.jp2box.ColourSpecificationBox(colorspace=glymur.core.SRGB) + self.verifyColourSpecificationBox(jp2.box[2].box[1], colr) + + c = jp2.box[3].main_header + + ids = [x.marker_id for x in c.segment] + expected = ['SOC', 'SIZ', 'CME', 'COD', 'QCD', 'QCC', 'QCC'] + self.assertEqual(ids, expected) + + kwargs = {'rsiz': 0, 'xysiz': (203, 152), 'xyosiz': (0, 0), + 'xytsiz': (203, 152), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) + + pargs = RCME_ISO_8859_1, "Creator: JasPer Vers)on 1.701.0".encode() + self.verifyCMEsegment(c.segment[2], CMEsegment(*pargs)) + + # COD: Coding style default + self.assertFalse(c.segment[3].scod & 2) # no sop + self.assertFalse(c.segment[3].scod & 4) # no eph + self.assertEqual(c.segment[3].spcod[0], glymur.core.LRCP) + self.assertEqual(c.segment[3].layers, 1) # layers = 1 + self.assertEqual(c.segment[3].spcod[3], 1) # mct + self.assertEqual(c.segment[3].spcod[4], 5) # level + self.assertEqual(tuple(c.segment[3].code_block_size), + (64, 64)) # cblk + self.verify_codeblock_style(c.segment[3].spcod[7], + [False, False, False, False, False, False]) + self.assertEqual(c.segment[3].spcod[8], + glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) + self.assertEqual(len(c.segment[3].spcod), 9) + + # QCD: Quantization default + self.assertEqual(c.segment[4].sqcd & 0x1f, 0) + self.assertEqual(c.segment[4].guard_bits, 2) + self.assertEqual(c.segment[4].mantissa, [0] * 16) + self.assertEqual(c.segment[4].exponent, + [8] + [9, 9, 10] * 5) + + # QCC: Quantization component + # associated component + self.assertEqual(c.segment[5].cqcc, 1) + self.assertEqual(c.segment[5].guard_bits, 2) + # quantization type + self.assertEqual(c.segment[5].sqcc & 0x1f, 0) # none + self.assertEqual(c.segment[5].mantissa, [0] * 16) + self.assertEqual(c.segment[5].exponent, + [8] + [9, 9, 10] * 5) + + # QCC: Quantization component + # associated component + self.assertEqual(c.segment[6].cqcc, 2) + self.assertEqual(c.segment[6].guard_bits, 2) + # quantization type + self.assertEqual(c.segment[6].sqcc & 0x1f, 0) # none + self.assertEqual(c.segment[6].mantissa, [0] * 16) + self.assertEqual(c.segment[6].exponent, + [8] + [9, 9, 10] * 5) def test_NR_broken2_jp2_dump(self): """ Invalid marker ID in the codestream. """ jfile = opj_data_file('input/nonregression/broken2.jp2') - with warnings.catch_warnings(): - # Suppress a warning, all we really care is parsing the entire - # file. - warnings.simplefilter("ignore") - with self.assertWarns(UserWarning): - # Invalid marker ID on codestream. - jp2 = Jp2k(jfile) - self.assertEqual(jp2.box[-1].codestream.segment[-1].marker_id, - 'QCC') + with self.assertWarns(UserWarning): + # Invalid marker ID on codestream. + jp2 = Jp2k(jfile) + + self.assertEqual(jp2.box[-1].main_header.segment[-1].marker_id, 'QCC') def test_NR_file1_dump(self): jfile = opj_data_file('input/conformance/file1.jp2') @@ -2963,8 +2978,8 @@ class TestSuiteWarns(MetadataBase): ihdr = glymur.jp2box.ImageHeaderBox(512, 768, num_components=3) self.verifyImageHeaderBox(jp2.box[3].box[0], ihdr) - colr = glymur.jp2box.ColourSpecificationBox(colorspace=SRGB, - approximation=1) + colr = glymur.jp2box.ColourSpecificationBox(colorspace=glymur.core.SRGB, + approximation=1) self.verifyColourSpecificationBox(jp2.box[3].box[1], colr) # XML box @@ -2991,7 +3006,7 @@ class TestSuiteWarns(MetadataBase): self.verifyImageHeaderBox(jp2.box[2].box[0], ihdr) colr = glymur.jp2box.ColourSpecificationBox(colorspace=glymur.core.YCC, - approximation=1) + approximation=1) self.verifyColourSpecificationBox(jp2.box[2].box[1], colr) # Jp2 Header @@ -3021,8 +3036,9 @@ class TestSuiteWarns(MetadataBase): ihdr = glymur.jp2box.ImageHeaderBox(640, 480, num_components=3) self.verifyImageHeaderBox(jp2.box[2].box[0], ihdr) - colr = glymur.jp2box.ColourSpecificationBox(colorspace=glymur.core.YCC, - approximation=1) + colr = glymur.jp2box.ColourSpecificationBox( + colorspace=glymur.core.YCC, + approximation=1) self.verifyColourSpecificationBox(jp2.box[2].box[1], colr) # sub-sampling @@ -3052,8 +3068,8 @@ class TestSuiteWarns(MetadataBase): ihdr = glymur.jp2box.ImageHeaderBox(512, 768) self.verifyImageHeaderBox(jp2.box[2].box[0], ihdr) - colr = glymur.jp2box.ColourSpecificationBox(colorspace=GREYSCALE, - approximation=1) + colr = glymur.jp2box.ColourSpecificationBox( + colorspace=glymur.core.GREYSCALE, approximation=1) self.verifyColourSpecificationBox(jp2.box[2].box[1], colr) def test_NR_file5_dump(self): @@ -3075,18 +3091,16 @@ class TestSuiteWarns(MetadataBase): self.assertEqual(ids, ['ihdr', 'colr', 'colr']) self.verifySignatureBox(jp2.box[0]) - expected = FileTypeBox(brand='jpx ', - compatibility_list=['jp2 ', 'jpx ', 'jpxb']) + expected = FileTypeBox( + brand='jpx ', compatibility_list=['jp2 ', 'jpx ', 'jpxb']) self.verify_filetype_box(jp2.box[1], expected) ihdr = glymur.jp2box.ImageHeaderBox(512, 768, num_components=3) self.verifyImageHeaderBox(jp2.box[3].box[0], ihdr) - method = RESTRICTED_ICC_PROFILE - icc_profile = bytes([0] * 546) - colr = glymur.jp2box.ColourSpecificationBox(method=method, - approximation=1, - icc_profile=icc_profile) + colr = glymur.jp2box.ColourSpecificationBox( + method=glymur.core.RESTRICTED_ICC_PROFILE, + approximation=1, icc_profile=bytes([0] * 546)) self.verifyColourSpecificationBox(jp2.box[3].box[1], colr) self.assertEqual(jp2.box[3].box[1].icc_profile['Size'], 546) @@ -3107,10 +3121,10 @@ class TestSuiteWarns(MetadataBase): ihdr = glymur.jp2box.ImageHeaderBox(512, 768, bits_per_component=12) self.verifyImageHeaderBox(jp2.box[2].box[0], ihdr) - method = ENUMERATED_COLORSPACE - colr = glymur.jp2box.ColourSpecificationBox(colorspace=GREYSCALE, - method=method, - approximation=1) + colr = glymur.jp2box.ColourSpecificationBox( + colorspace=glymur.core.GREYSCALE, + method=glymur.core.ENUMERATED_COLORSPACE, + approximation=1) self.verifyColourSpecificationBox(jp2.box[2].box[1], colr) def test_NR_file7_dump(self): @@ -3136,13 +3150,12 @@ class TestSuiteWarns(MetadataBase): self.assertEqual(jp2.box[1].compatibility_list[1], 'jp2 ') ihdr = glymur.jp2box.ImageHeaderBox(640, 480, - num_components=3, - bits_per_component=16) + num_components=3, bits_per_component=16) self.verifyImageHeaderBox(jp2.box[3].box[0], ihdr) - method = RESTRICTED_ICC_PROFILE - colr = glymur.jp2box.ColourSpecificationBox(method=method, - approximation=1) + colr = glymur.jp2box.ColourSpecificationBox( + method=glymur.core.RESTRICTED_ICC_PROFILE, + approximation=1) self.verifyColourSpecificationBox(jp2.box[3].box[1], colr) self.assertEqual(jp2.box[3].box[1].icc_profile['Size'], 13332) @@ -3166,9 +3179,9 @@ class TestSuiteWarns(MetadataBase): ihdr = glymur.jp2box.ImageHeaderBox(400, 700) self.verifyImageHeaderBox(jp2.box[2].box[0], ihdr) - method = RESTRICTED_ICC_PROFILE - colr = glymur.jp2box.ColourSpecificationBox(method=method, - approximation=1) + colr = glymur.jp2box.ColourSpecificationBox( + method=glymur.core.RESTRICTED_ICC_PROFILE, + approximation=1) self.verifyColourSpecificationBox(jp2.box[2].box[1], colr) self.assertEqual(jp2.box[2].box[1].icc_profile['Size'], 414) @@ -3221,15 +3234,16 @@ class TestSuiteWarns(MetadataBase): self.assertEqual(jp2.box[2].box[2].mapping_type, (1, 1, 1)) self.assertEqual(jp2.box[2].box[2].palette_index, (0, 1, 2)) - colr = glymur.jp2box.ColourSpecificationBox(colorspace=SRGB, - approximation=1) + colr = glymur.jp2box.ColourSpecificationBox( + colorspace=glymur.core.SRGB, + approximation=1) self.verifyColourSpecificationBox(jp2.box[2].box[3], colr) def test_NR_issue188_beach_64bitsbox(self): lst = ['input', 'nonregression', 'issue188_beach_64bitsbox.jp2'] jfile = opj_data_file('/'.join(lst)) with self.assertWarns(UserWarning): - # There's a warning for an unknown box. + # There's a warning for an unknown box. jp2 = Jp2k(jfile) ids = [box.box_id for box in jp2.box] @@ -3242,29 +3256,25 @@ class TestSuiteWarns(MetadataBase): self.verify_filetype_box(jp2.box[1], FileTypeBox()) ihdr = glymur.jp2box.ImageHeaderBox(200, 200, - num_components=3, - colorspace_unknown=True) + num_components=3, colorspace_unknown=True) self.verifyImageHeaderBox(jp2.box[2].box[0], ihdr) - cspace = glymur.core.SRGB - colr = glymur.jp2box.ColourSpecificationBox(colorspace=cspace) + colr = glymur.jp2box.ColourSpecificationBox(colorspace=glymur.core.SRGB) self.verifyColourSpecificationBox(jp2.box[2].box[1], colr) # Skip the 4th box, it is uknown. - c = jp2.box[4].codestream + c = jp2.box[4].main_header ids = [x.marker_id for x in c.segment] expected = ['SOC', 'SIZ', 'COD', 'QCD', 'CME', 'CME'] self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (200, 200), 'xyosiz': (0, 0), - 'xytsiz': (200, 200), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), - 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (200, 200), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -3276,7 +3286,7 @@ class TestSuiteWarns(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -3312,19 +3322,17 @@ class TestSuiteWarns(MetadataBase): self.assertIsNone(jp2.box[2].box[1].icc_profile) self.assertIsNone(jp2.box[2].box[1].colorspace) - c = jp2.box[3].codestream + c = jp2.box[3].main_header ids = [x.marker_id for x in c.segment] expected = ['SOC', 'SIZ', 'COD', 'QCD'] self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (117, 117), 'xyosiz': (0, 0), - 'xytsiz': (117, 117), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8, 8), - 'signed': (False, False, False, False), - 'xyrsiz': [(1, 1, 1, 1), (1, 1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (117, 117), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8, 8), + 'signed': (False, False, False, False), + 'xyrsiz': [(1, 1, 1, 1), (1, 1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -3336,7 +3344,7 @@ class TestSuiteWarns(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -3375,19 +3383,17 @@ class TestSuiteWarns(MetadataBase): self.assertIsNone(jp2.box[2].box[1].icc_profile) self.assertIsNone(jp2.box[2].box[1].colorspace) - c = jp2.box[3].codestream + c = jp2.box[3].main_header ids = [x.marker_id for x in c.segment] expected = ['SOC', 'SIZ', 'COD', 'QCD'] self.assertEqual(ids, expected) kwargs = {'rsiz': 0, 'xysiz': (117, 117), 'xyosiz': (0, 0), - 'xytsiz': (117, 117), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8, 8), - 'signed': (False, False, False, False), - 'xyrsiz': [(1, 1, 1, 1), (1, 1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (117, 117), 'xytosiz': (0, 0), 'bitdepth': (8, 8, 8, 8), + 'signed': (False, False, False, False), + 'xyrsiz': [(1, 1, 1, 1), (1, 1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -3399,7 +3405,7 @@ class TestSuiteWarns(MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) # cblk self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) diff --git a/glymur/test/test_opj_suite_neg.py b/glymur/test/test_opj_suite_neg.py index d2351a4..c7e31e5 100644 --- a/glymur/test/test_opj_suite_neg.py +++ b/glymur/test/test_opj_suite_neg.py @@ -2,8 +2,15 @@ The tests here do not correspond directly to the OpenJPEG test suite, but seem like logical negative tests to add. """ +# E1101: assertWarns introduced in python 3.2 +# pylint: disable=E1101 + +# R0904: Not too many methods in unittest. +# pylint: disable=R0904 + import os import re +import sys import tempfile import unittest @@ -81,6 +88,7 @@ class TestSuiteNegativeWrite(unittest.TestCase): 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): @@ -90,7 +98,8 @@ class TestSuiteNegativeWrite(unittest.TestCase): data = skimage.io.imread(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: with self.assertRaises(IOError): - Jp2k(tfile.name, data=data, cinema2k=36) + j = Jp2k(tfile.name, data=data, cinema2k=36) + @unittest.skipIf(NO_READ_BACKEND, NO_READ_BACKEND_MSG) def test_psnr_with_cratios(self): @@ -100,8 +109,8 @@ class TestSuiteNegativeWrite(unittest.TestCase): data = read_image(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: with self.assertRaises(IOError): - Jp2k(tfile.name, - data=data, psnr=[30, 35, 40], cratios=[2, 3, 4]) + 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""" @@ -111,13 +120,13 @@ class TestSuiteNegativeWrite(unittest.TestCase): with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: # opj_compress doesn't allow code block area to exceed 4096. with self.assertRaises(IOError): - Jp2k(tfile.name, data=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): - Jp2k(tfile.name, data=data, cbsize=(2048, 2)) + j = Jp2k(tfile.name, data=data, cbsize=(2048, 2)) with self.assertRaises(IOError): - Jp2k(tfile.name, data=data, cbsize=(2, 2048)) + j = Jp2k(tfile.name, data=data, cbsize=(2, 2048)) def test_precinct_size_not_p2(self): """precinct sizes should be powers of two.""" @@ -125,7 +134,7 @@ class TestSuiteNegativeWrite(unittest.TestCase): data = ifile[::4, ::4] with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: with self.assertRaises(IOError): - Jp2k(tfile.name, data=data, psizes=[(13, 13)]) + ofile = Jp2k(tfile.name, data=data, psizes=[(13, 13)]) def test_cblk_size_not_power_of_two(self): """code block sizes should be powers of two.""" @@ -133,7 +142,7 @@ class TestSuiteNegativeWrite(unittest.TestCase): data = ifile[::4, ::4] with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: with self.assertRaises(IOError): - Jp2k(tfile.name, data=data, cbsize=(13, 12)) + ofile = Jp2k(tfile.name, data=data, cbsize=(13, 12)) def test_cblk_size_precinct_size(self): """code block sizes should never exceed half that of precinct size.""" @@ -141,4 +150,6 @@ class TestSuiteNegativeWrite(unittest.TestCase): data = ifile[::4, ::4] with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: with self.assertRaises(IOError): - Jp2k(tfile.name, data=data, cbsize=(64, 64), psizes=[(64, 64)]) + ofile = Jp2k(tfile.name, + data=data, cbsize=(64, 64), psizes=[(64, 64)]) + diff --git a/glymur/test/test_opj_suite_write.py b/glymur/test/test_opj_suite_write.py index f44c7b4..ecb7a7d 100644 --- a/glymur/test/test_opj_suite_write.py +++ b/glymur/test/test_opj_suite_write.py @@ -2,6 +2,10 @@ The tests defined here roughly correspond to what is in the OpenJPEG test suite. """ +# C0103: method names longer that 30 chars are ok in tests, IMHO +# R0904: Seems like pylint is fooled in this situation +# pylint: disable=R0904,C0103 + import os import re import sys @@ -30,7 +34,6 @@ from glymur import Jp2k from glymur.codestream import SIZsegment from glymur.version import openjpeg_version - class CinemaBase(fixtures.MetadataBase): def verify_cinema_cod(self, cod_segment): @@ -41,14 +44,14 @@ class CinemaBase(fixtures.MetadataBase): self.assertEqual(cod_segment.layers, 1) self.assertEqual(cod_segment.spcod[3], 1) # mct self.assertEqual(cod_segment.spcod[4], 5) # levels - self.assertEqual(tuple(cod_segment.code_block_size), (32, 32)) + self.assertEqual(tuple(cod_segment.code_block_size), (32, 32)) # cblksz 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)]} + '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]) @@ -56,9 +59,9 @@ class CinemaBase(fixtures.MetadataBase): 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)]} + '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]) @@ -85,8 +88,8 @@ class WriteCinema(CinemaBase): data = skimage.io.imread(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: with self.assertRaises(IOError): - Jp2k(tfile.name, data=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.""" @@ -95,8 +98,8 @@ class WriteCinema(CinemaBase): data = skimage.io.imread(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: with self.assertRaises(IOError): - Jp2k(tfile.name, data=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) @@ -132,8 +135,7 @@ class WriteCinemaWarns(CinemaBase): infile = opj_data_file(relfile) data = skimage.io.imread(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - with self.assertWarnsRegex(UserWarning, - 'OpenJPEG library warning'): + with self.assertWarnsRegex(UserWarning, 'OpenJPEG library warning'): j = Jp2k(tfile.name, data=data, cinema2k=48) codestream = j.get_codestream() @@ -144,8 +146,7 @@ class WriteCinemaWarns(CinemaBase): infile = opj_data_file(relfile) data = skimage.io.imread(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - with self.assertWarnsRegex(UserWarning, - 'OpenJPEG library warning'): + with self.assertWarnsRegex(UserWarning, 'OpenJPEG library warning'): j = Jp2k(tfile.name, data=data, cinema2k=48) codestream = j.get_codestream() @@ -156,8 +157,7 @@ class WriteCinemaWarns(CinemaBase): infile = opj_data_file(relfile) data = skimage.io.imread(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - with self.assertWarnsRegex(UserWarning, - 'OpenJPEG library warning'): + with self.assertWarnsRegex(UserWarning, 'OpenJPEG library warning'): j = Jp2k(tfile.name, data=data, cinema2k=24) codestream = j.get_codestream() @@ -168,8 +168,7 @@ class WriteCinemaWarns(CinemaBase): infile = opj_data_file(relfile) data = skimage.io.imread(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: - with self.assertWarnsRegex(UserWarning, - 'OpenJPEG library warning'): + 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 = Jp2k(tfile.name, data=data, cinema2k=24) @@ -217,7 +216,7 @@ class TestNegative2pointzero(unittest.TestCase): with patch('glymur.version.openjpeg_version', new=version): with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: with self.assertRaises(IOError): - Jp2k(tfile.name, data=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,6 +248,7 @@ class TestSuiteWrite(fixtures.MetadataBase): self.assertEqual(codestream.segment[2].spcod[8], glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE) + def test_NR_ENC_Bretagne1_ppm_1_encode(self): """NR-ENC-Bretagne1.ppm-1-encode""" infile = opj_data_file('input/nonregression/Bretagne1.ppm') @@ -260,11 +260,10 @@ class TestSuiteWrite(fixtures.MetadataBase): c = j.get_codestream() kwargs = {'rsiz': 0, 'xysiz': (640, 480), 'xyosiz': (0, 0), - 'xytsiz': (640, 480), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), 'signed': (False, False, False), - 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} - self.verifySizSegment(c.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (640, 480), 'xytosiz': (0, 0), + 'bitdepth': (8, 8, 8), 'signed': (False, False, False), + 'xyrsiz': [(1, 1, 1), (1, 1, 1)]} + self.verifySizSegment(c.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(c.segment[2].scod & 2) # no sop @@ -276,7 +275,7 @@ class TestSuiteWrite(fixtures.MetadataBase): self.assertEqual(tuple(c.segment[2].code_block_size), (64, 64)) # cblksz self.verify_codeblock_style(c.segment[2].spcod[7], - [False, False, False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(c.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(c.segment[2].spcod), 9) @@ -292,11 +291,10 @@ class TestSuiteWrite(fixtures.MetadataBase): codestream = j.get_codestream() kwargs = {'rsiz': 0, 'xysiz': (640, 480), 'xyosiz': (0, 0), - 'xytsiz': (640, 480), '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)) + 'xytsiz': (640, 480), '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)) # COD: Coding style default self.assertFalse(codestream.segment[2].scod & 2) # no sop @@ -308,8 +306,7 @@ class TestSuiteWrite(fixtures.MetadataBase): self.assertEqual(tuple(codestream.segment[2].code_block_size), (64, 64)) # cblksz self.verify_codeblock_style(codestream.segment[2].spcod[7], - [False, False, - False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(codestream.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(codestream.segment[2].spcod), 9) @@ -319,19 +316,18 @@ 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, - data=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() kwargs = {'rsiz': 0, 'xysiz': (640, 480), 'xyosiz': (0, 0), - 'xytsiz': (640, 480), '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)) + 'xytsiz': (640, 480), '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)) # COD: Coding style default self.assertFalse(codestream.segment[2].scod & 2) # no sop @@ -343,8 +339,7 @@ class TestSuiteWrite(fixtures.MetadataBase): self.assertEqual(tuple(codestream.segment[2].code_block_size), (16, 16)) # cblksz self.verify_codeblock_style(codestream.segment[2].spcod[7], - [False, False, - False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(codestream.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(codestream.segment[2].precinct_size, @@ -357,21 +352,20 @@ class TestSuiteWrite(fixtures.MetadataBase): data = read_image(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: j = Jp2k(tfile.name, - data=data, - psizes=[(128, 128)] * 3, - cratios=[100, 20, 2], - tilesize=(480, 640), - cbsize=(32, 32)) + data=data, + psizes=[(128, 128)] * 3, + cratios=[100, 20, 2], + tilesize=(480, 640), + cbsize=(32, 32)) # Should be three layers. codestream = j.get_codestream() kwargs = {'rsiz': 0, 'xysiz': (2592, 1944), 'xyosiz': (0, 0), - 'xytsiz': (640, 480), '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)) + 'xytsiz': (640, 480), '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)) # COD: Coding style default self.assertFalse(codestream.segment[2].scod & 2) # no sop @@ -383,8 +377,7 @@ class TestSuiteWrite(fixtures.MetadataBase): self.assertEqual(tuple(codestream.segment[2].code_block_size), (32, 32)) # cblksz self.verify_codeblock_style(codestream.segment[2].spcod[7], - [False, False, - False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(codestream.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(codestream.segment[2].precinct_size, @@ -400,11 +393,10 @@ class TestSuiteWrite(fixtures.MetadataBase): codestream = j.get_codestream() kwargs = {'rsiz': 0, 'xysiz': (2592, 1944), 'xyosiz': (0, 0), - 'xytsiz': (127, 127), '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)) + 'xytsiz': (127, 127), '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)) # COD: Coding style default self.assertFalse(codestream.segment[2].scod & 2) # no sop @@ -416,8 +408,7 @@ class TestSuiteWrite(fixtures.MetadataBase): self.assertEqual(tuple(codestream.segment[2].code_block_size), (64, 64)) # cblksz self.verify_codeblock_style(codestream.segment[2].spcod[7], - [False, False, - False, False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(codestream.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(codestream.segment[2].spcod), 9) @@ -432,11 +423,10 @@ class TestSuiteWrite(fixtures.MetadataBase): codestream = j.get_codestream(header_only=False) kwargs = {'rsiz': 0, 'xysiz': (5183, 3887), 'xyosiz': (0, 0), - 'xytsiz': (5183, 3887), 'xytosiz': (0, 0), - 'bitdepth': (8, 8, 8), 'signed': (False, False, False), - 'xyrsiz': [(2, 2, 2), (2, 2, 2)]} - self.verifySizSegment(codestream.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (5183, 3887), 'xytosiz': (0, 0), + 'bitdepth': (8, 8, 8), 'signed': (False, False, False), + 'xyrsiz': [(2, 2, 2), (2, 2, 2)]} + self.verifySizSegment(codestream.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertTrue(codestream.segment[2].scod & 2) # sop @@ -448,8 +438,7 @@ class TestSuiteWrite(fixtures.MetadataBase): self.assertEqual(tuple(codestream.segment[2].code_block_size), (64, 64)) # cblksz self.verify_codeblock_style(codestream.segment[2].spcod[7], - [False, False, False, - False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(codestream.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(codestream.segment[2].spcod), 9) @@ -469,11 +458,10 @@ class TestSuiteWrite(fixtures.MetadataBase): codestream = j.get_codestream(header_only=False) kwargs = {'rsiz': 0, 'xysiz': (2592, 1944), 'xyosiz': (0, 0), - 'xytsiz': (2592, 1944), '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)) + 'xytsiz': (2592, 1944), '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)) # COD: Coding style default self.assertFalse(codestream.segment[2].scod & 2) # no sop @@ -483,10 +471,9 @@ class TestSuiteWrite(fixtures.MetadataBase): self.assertEqual(codestream.segment[2].spcod[3], 1) # mct self.assertEqual(codestream.segment[2].spcod[4], 5) # levels self.assertEqual(tuple(codestream.segment[2].code_block_size), - (64, 64)) # cblksz + (64, 64)) # cblksz self.verify_codeblock_style(codestream.segment[2].spcod[7], - [False, True, True, - False, False, True]) + [False, True, True, False, False, True]) self.assertEqual(codestream.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(codestream.segment[2].spcod), 9) @@ -501,16 +488,15 @@ class TestSuiteWrite(fixtures.MetadataBase): data = read_image(infile) with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile: j = Jp2k(tfile.name, - data=data, grid_offset=[300, 150], cratios=[800]) + data=data, grid_offset=[300, 150], cratios=[800]) codestream = j.get_codestream(header_only=False) kwargs = {'rsiz': 0, 'xysiz': (2742, 2244), 'xyosiz': (150, 300), - 'xytsiz': (2742, 2244), '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)) + 'xytsiz': (2742, 2244), '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)) # COD: Coding style default self.assertFalse(codestream.segment[2].scod & 2) # no sop @@ -522,8 +508,7 @@ class TestSuiteWrite(fixtures.MetadataBase): self.assertEqual(tuple(codestream.segment[2].code_block_size), (64, 64)) # cblksz self.verify_codeblock_style(codestream.segment[2].spcod[7], - [False, False, False, - False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(codestream.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(codestream.segment[2].spcod), 9) @@ -538,11 +523,10 @@ class TestSuiteWrite(fixtures.MetadataBase): codestream = j.get_codestream(header_only=False) kwargs = {'rsiz': 0, 'xysiz': (2592, 1944), 'xyosiz': (0, 0), - 'xytsiz': (2592, 1944), '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)) + 'xytsiz': (2592, 1944), '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)) # COD: Coding style default self.assertFalse(codestream.segment[2].scod & 2) # no sop @@ -554,8 +538,7 @@ class TestSuiteWrite(fixtures.MetadataBase): self.assertEqual(tuple(codestream.segment[2].code_block_size), (64, 64)) # cblksz self.verify_codeblock_style(codestream.segment[2].spcod[7], - [False, False, False, - False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(codestream.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(codestream.segment[2].spcod), 9) @@ -570,11 +553,10 @@ class TestSuiteWrite(fixtures.MetadataBase): codestream = j.get_codestream(header_only=False) kwargs = {'rsiz': 0, 'xysiz': (640, 480), 'xyosiz': (0, 0), - 'xytsiz': (640, 480), '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)) + 'xytsiz': (640, 480), '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)) # COD: Coding style default self.assertFalse(codestream.segment[2].scod & 2) # no sop @@ -586,8 +568,7 @@ class TestSuiteWrite(fixtures.MetadataBase): self.assertEqual(tuple(codestream.segment[2].code_block_size), (64, 64)) # cblksz self.verify_codeblock_style(codestream.segment[2].spcod[7], - [False, False, False, - False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(codestream.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(codestream.segment[2].spcod), 9) @@ -597,7 +578,7 @@ class TestSuiteWrite(fixtures.MetadataBase): data = read_image(opj_data_file('input/nonregression/Rome.bmp')) with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: jp2 = Jp2k(tfile.name, - data=data, psnr=[30, 35, 50], prog='LRCP', numres=3) + 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']) @@ -632,14 +613,13 @@ class TestSuiteWrite(fixtures.MetadataBase): self.assertIsNone(jp2.box[2].box[1].icc_profile) self.assertEqual(jp2.box[2].box[1].colorspace, glymur.core.SRGB) - codestream = jp2.box[3].codestream + codestream = jp2.box[3].main_header kwargs = {'rsiz': 0, 'xysiz': (640, 480), 'xyosiz': (0, 0), - 'xytsiz': (640, 480), '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)) + 'xytsiz': (640, 480), '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)) # COD: Coding style default self.assertFalse(codestream.segment[2].scod & 2) # no sop @@ -651,8 +631,7 @@ class TestSuiteWrite(fixtures.MetadataBase): self.assertEqual(tuple(codestream.segment[2].code_block_size), (64, 64)) # cblksz self.verify_codeblock_style(codestream.segment[2].spcod[7], - [False, False, False, - False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(codestream.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(codestream.segment[2].spcod), 9) @@ -669,11 +648,10 @@ class TestSuiteWrite(fixtures.MetadataBase): 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,)]} - self.verifySizSegment(codestream.segment[1], - glymur.codestream.SIZsegment(**kwargs)) + 'xytsiz': (1024, 1024), 'xytosiz': (0, 0), + 'bitdepth': (16,), 'signed': (False,), + 'xyrsiz': [(1,), (1,)]} + self.verifySizSegment(codestream.segment[1], glymur.codestream.SIZsegment(**kwargs)) # COD: Coding style default self.assertFalse(codestream.segment[2].scod & 2) # no sop @@ -685,8 +663,7 @@ class TestSuiteWrite(fixtures.MetadataBase): self.assertEqual(tuple(codestream.segment[2].code_block_size), (64, 64)) # cblksz self.verify_codeblock_style(codestream.segment[2].spcod[7], - [False, False, False, - False, False, False]) + [False, False, False, False, False, False]) self.assertEqual(codestream.segment[2].spcod[8], glymur.core.WAVELET_XFORM_5X3_REVERSIBLE) self.assertEqual(len(codestream.segment[2].spcod), 9) diff --git a/glymur/test/test_printing.py b/glymur/test/test_printing.py index bccaa00..5eedfe5 100644 --- a/glymur/test/test_printing.py +++ b/glymur/test/test_printing.py @@ -1,6 +1,15 @@ # -*- coding: utf-8 -*- """Test suite for printing. """ +# C0302: don't care too much about having too many lines in a test module +# pylint: disable=C0302 + +# E061: unittest.mock introduced in 3.3 (python-2.7/pylint issue) +# pylint: disable=E0611,F0401 + +# R0904: Not too many methods in unittest. +# pylint: disable=R0904 + import os import re import struct @@ -23,12 +32,11 @@ import lxml.etree as ET import glymur from glymur import Jp2k, command_line from . import fixtures -from .fixtures import (OPJ_DATA_ROOT, opj_data_file, - WARNING_INFRASTRUCTURE_ISSUE, - WARNING_INFRASTRUCTURE_MSG, - WINDOWS_TMP_FILE_MSG, - text_gbr_27, text_gbr_33, text_gbr_34) - +from .fixtures import ( + OPJ_DATA_ROOT, opj_data_file, + WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG, + WINDOWS_TMP_FILE_MSG, text_gbr_27, text_gbr_33, text_gbr_34 +) @unittest.skipIf(os.name == "nt", WINDOWS_TMP_FILE_MSG) class TestPrinting(unittest.TestCase): @@ -42,13 +50,25 @@ class TestPrinting(unittest.TestCase): glymur.set_printoptions(short=False, xml=True, codestream=True) def tearDown(self): - glymur.set_parseoptions(full_codestream=False) + pass + + def test_codestream(self): + """Should be able to print a raw codestream.""" + j = glymur.Jp2k(self.j2kfile) + with patch('sys.stdout', new=StringIO()) as fake_out: + print(j) + actual = fake_out.getvalue().strip() + # Remove the file line, as that is filesystem-dependent. + lines = actual.split('\n') + actual = '\n'.join(lines[1:]) + + self.assertEqual(actual, fixtures.codestream) def test_version_info(self): """Should be able to print(glymur.version.info)""" with patch('sys.stdout', new=StringIO()) as fake_out: print(glymur.version.info) - fake_out.getvalue().strip() + actual = fake_out.getvalue().strip() self.assertTrue(True) @@ -58,7 +78,7 @@ class TestPrinting(unittest.TestCase): with tempfile.NamedTemporaryFile(suffix='.jpx') as tfile: with open(self.jpxfile, 'rb') as ifile: tfile.write(ifile.read()) - + # Add the header for an unknown superbox. write_buffer = struct.pack('>I4s', 20, 'grp '.encode()) tfile.write(write_buffer) @@ -87,8 +107,7 @@ 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, + @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""" @@ -96,8 +115,9 @@ class TestPrinting(unittest.TestCase): # OpenJPEG doesn't have such a file. data = glymur.Jp2k(self.jp2file)[::2, ::2] with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: + j = glymur.Jp2k(tfile.name, data=data) + with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile2: - glymur.Jp2k(tfile.name, data=data) # Offset of the codestream is where we start. wbuffer = tfile.read(77) @@ -399,7 +419,7 @@ class TestPrinting(unittest.TestCase): @unittest.skipIf(sys.hexversion < 0x03000000, "Only trusting python3 for printing non-ascii chars") def test_xml_cyrrilic(self): - """Should be able to print XMLBox with utf-8 encoding (cyrrillic).""" + """Should be able to print an XMLBox with utf-8 encoding (cyrrillic).""" # Seems to be inconsistencies between different versions of python2.x # as to what gets printed. # @@ -417,8 +437,7 @@ class TestPrinting(unittest.TestCase): actual = fake_out.getvalue().strip() if sys.hexversion < 0x03000000: lines = ["XML Box (xml ) @ (-1, 0)", - (" Росс", - "ия")] + " Россия"] else: lines = ["XML Box (xml ) @ (-1, 0)", " Россия"] @@ -594,14 +613,12 @@ class TestPrinting(unittest.TestCase): lines = ["UUID Box (uuid) @ (1135519, 76)", " UUID: 4a706754-6966-6645-7869-662d3e4a5032 (EXIF)", - (" UUID Data: OrderedDict([('ImageWidth', 256)," - " ('ImageLength', 512), ('Make', 'HTC')])")] + " UUID Data: OrderedDict([('ImageWidth', 256), ('ImageLength', 512), ('Make', 'HTC')])"] expected = '\n'.join(lines) self.assertEqual(actual, expected) - @unittest.skipIf(OPJ_DATA_ROOT is None, "OPJ_DATA_ROOT environment variable not set") @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") @@ -809,7 +826,6 @@ class TestPrintingOpjDataRoot(unittest.TestCase): expected = '\n'.join(lines) self.assertEqual(actual, expected) - @unittest.skipIf(OPJ_DATA_ROOT is None, "OPJ_DATA_ROOT environment variable not set") @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") @@ -831,31 +847,20 @@ class TestPrintingOpjDataRootWarns(unittest.TestCase): def tearDown(self): pass - def test_invalid_colour_specification_method(self): - """should not error out with invalid colour specification method""" - # Don't care so much about what the output looks like, just that we - # do not error out. - filename = opj_data_file('input/nonregression/issue397.jp2') - with self.assertWarns(UserWarning): - jp2 = Jp2k(filename) - with patch('sys.stdout', new=StringIO()): - print(jp2) - self.assertTrue(True) - def test_invalid_colorspace(self): """An invalid colorspace shouldn't cause an error.""" filename = opj_data_file('input/nonregression/edf_c2_1103421.jp2') with self.assertWarns(UserWarning): jp2 = Jp2k(filename) - with patch('sys.stdout', new=StringIO()): + with patch('sys.stdout', new=StringIO()) as fake_out: print(jp2) def test_bad_rsiz(self): """Should still be able to print if rsiz is bad, issue196""" filename = opj_data_file('input/nonregression/edf_c2_1002767.jp2') with self.assertWarns(UserWarning): - j = Jp2k(filename).get_codestream() - with patch('sys.stdout', new=StringIO()): + j = Jp2k(filename) + with patch('sys.stdout', new=StringIO()) as fake_out: print(j) def test_bad_wavelet_transform(self): @@ -863,7 +868,7 @@ class TestPrintingOpjDataRootWarns(unittest.TestCase): filename = opj_data_file('input/nonregression/edf_c2_10025.jp2') with self.assertWarns(UserWarning): jp2 = Jp2k(filename) - with patch('sys.stdout', new=StringIO()): + with patch('sys.stdout', new=StringIO()) as fake_out: print(jp2) def test_invalid_progression_order(self): @@ -1024,7 +1029,7 @@ class TestPrintingOpjDataRootWarns(unittest.TestCase): 'issue171.jp2')) with self.assertWarns(UserWarning): jp2 = Jp2k(filename) - with patch('sys.stdout', new=StringIO()): + with patch('sys.stdout', new=StringIO()) as fake_out: # No need to verify, it's enough that we don't error out. print(jp2) @@ -1040,10 +1045,9 @@ class TestJp2dump(unittest.TestCase): # Reset printoptions for every test. glymur.set_printoptions(short=False, xml=True, codestream=True) - glymur.set_parseoptions(full_codestream=False) def tearDown(self): - glymur.set_parseoptions(full_codestream=False) + pass def run_jp2dump(self, args): sys.argv = args @@ -1056,53 +1060,24 @@ class TestJp2dump(unittest.TestCase): return actual def test_default_nemo(self): - """by default one should get the main header""" + """Should be able to dump a JP2 file's metadata with no codestream.""" actual = self.run_jp2dump(['', self.jp2file]) - # shave off the non-main-header segments - lines = fixtures.nemo.split('\n') - expected = lines[0:140] - expected = '\n'.join(expected) - self.assertEqual(actual, expected) + self.assertEqual(actual, fixtures.nemo_dump_no_codestream) - def test_jp2_codestream_0(self): + def test_codestream_0(self): """Verify dumping with -c 0, supressing all codestream details.""" actual = self.run_jp2dump(['', '-c', '0', self.jp2file]) - # shave off the codestream details - lines = fixtures.nemo.split('\n') - expected = lines[0:105] - expected = '\n'.join(expected) - self.assertEqual(actual, expected) + self.assertEqual(actual, fixtures.nemo_dump_no_codestream) - def test_jp2_codestream_1(self): + def test_codestream_1(self): """Verify dumping with -c 1, print just the header.""" actual = self.run_jp2dump(['', '-c', '1', self.jp2file]) - # shave off the non-main-header segments - lines = fixtures.nemo.split('\n') - expected = lines[0:140] - expected = '\n'.join(expected) - self.assertEqual(actual, expected) + self.assertEqual(actual, fixtures.nemo_with_codestream_header) - def test_jp2_codestream_2(self): - """Verify dumping with -c 2, print entire jp2 jacket, codestream.""" - actual = self.run_jp2dump(['', '-c', '2', self.jp2file]) - - # shave off the non-main-header segments - expected = fixtures.nemo - self.assertEqual(actual, expected) - - @unittest.skipIf(sys.hexversion < 0x03000000, "assertRegex not in 2.7") - def test_j2k_codestream_0(self): - """-c 0 should print just a single line when used on a codestream.""" - sys.argv = ['', '-c', '0', self.j2kfile] - with patch('sys.stdout', new=StringIO()) as fake_out: - command_line.main() - actual = fake_out.getvalue().strip() - self.assertRegex(actual, "File: .*") - - def test_j2k_codestream_2(self): + def test_codestream_2(self): """Verify dumping with -c 2, full details.""" with patch('sys.stdout', new=StringIO()) as fake_out: sys.argv = ['', '-c', '2', self.j2kfile] @@ -1127,9 +1102,14 @@ class TestJp2dump(unittest.TestCase): """Verify dumping with -x, suppress XML.""" actual = self.run_jp2dump(['', '-x', self.jp2file]) - # shave off the XML and non-main-header segments - lines = fixtures.nemo.split('\n') - expected = lines[0:18] - expected.extend(lines[104:140]) - expected = '\n'.join(expected) - self.assertEqual(actual, expected) + self.assertEqual(actual, fixtures.nemo_dump_no_codestream_no_xml) + + @unittest.skipIf(sys.hexversion < 0x03000000, "assertRegex not in 2.7") + def test_codestream_0_with_j2k_file(self): + """-c 0 should print just a single line when used on a codestream.""" + sys.argv = ['', '-c', '0', self.j2kfile] + with patch('sys.stdout', new=StringIO()) as fake_out: + command_line.main() + actual = fake_out.getvalue().strip() + self.assertRegex(actual, "File: .*") + diff --git a/glymur/version.py b/glymur/version.py index 4096ee5..55e4b88 100644 --- a/glymur/version.py +++ b/glymur/version.py @@ -18,7 +18,7 @@ from .lib import openjpeg as opj, openjp2 as opj2 # Do not change the format of this next line! Doing so risks breaking # setup.py -version = "0.8.0" +version = "0.7.2" _sv = LooseVersion(version) version_tuple = _sv.version diff --git a/setup.py b/setup.py index b49ed69..1a61dc3 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -from setuptools import setup +from setuptools import setup, find_packages import os import re import sys @@ -11,20 +11,18 @@ kwargs = {'name': 'Glymur', 'url': 'https://github.com/quintusdias/glymur', 'packages': ['glymur', 'glymur.data', 'glymur.test', 'glymur.lib', 'glymur.lib.test'], - 'package_data': {'glymur': ['data/*.jp2', - 'data/*.j2k', - 'data/*.jpx']}, + 'package_data': {'glymur': ['data/*.jp2', 'data/*.j2k', 'data/*.jpx']}, 'entry_points': { 'console_scripts': ['jp2dump=glymur.command_line:main'], }, 'license': 'MIT', 'test_suite': 'glymur.test'} -install_requires = ['numpy>=1.7.0', 'lxml>=3.0.0'] +instllrqrs = ['numpy>=1.4.1', 'lxml>=2.3.2'] if sys.hexversion < 0x03030000: - install_requires.append('contextlib2>=0.4') - install_requires.append('mock>=1.0.1') -kwargs['install_requires'] = install_requires + instllrqrs.append('contextlib2>=0.4') + instllrqrs.append('mock>=1.0.1') +kwargs['install_requires'] = instllrqrs clssfrs = ["Programming Language :: Python", "Programming Language :: Python :: 2.7",