Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1631408b50 |
38 changed files with 1612 additions and 1416 deletions
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
116
docs/source/api.rst
Normal file
116
docs/source/api.rst
Normal file
|
|
@ -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:
|
||||
|
||||
|
|
@ -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
|
||||
# "<project> v<release> 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 <link> 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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
'''''''
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
=====================
|
||||
|
|
@ -442,7 +442,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
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ Contents:
|
|||
how_do_i
|
||||
whatsnew/index
|
||||
roadmap
|
||||
api
|
||||
|
||||
------------------
|
||||
Indices and tables
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,20 +6,17 @@ 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
|
||||
|
||||
__all__ = [Jp2k, get_printoptions, set_printoptions, get_parseoptions,
|
||||
set_parseoptions, 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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -28,15 +31,12 @@ from .core import (LRCP, RLCP, RPCL, PCRL, CPRL,
|
|||
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'})
|
||||
_x = {LRCP: 'LRCP', RLCP: 'RLCP', RPCL: 'RPCL', PCRL: 'PCRL', CPRL: 'CPRL'}
|
||||
_PROGRESSION_ORDER_DISPLAY = _Keydefaultdict(_factory, _x)
|
||||
|
||||
_keysvalues = {WAVELET_XFORM_9X7_IRREVERSIBLE: '9-7 irreversible',
|
||||
WAVELET_XFORM_5X3_REVERSIBLE: '5-3 reversible'}
|
||||
_WAVELET_TRANSFORM_DISPLAY = _Keydefaultdict(_factory, _keysvalues)
|
||||
_x = {WAVELET_XFORM_9X7_IRREVERSIBLE: '9-7 irreversible',
|
||||
WAVELET_XFORM_5X3_REVERSIBLE: '5-3 reversible'}
|
||||
_WAVELET_TRANSFORM_DISPLAY = _Keydefaultdict(_factory, _x)
|
||||
|
||||
_NO_PROFILE = 0
|
||||
_PROFILE_0 = 1
|
||||
|
|
@ -47,11 +47,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'})
|
||||
_x = {_NO_PROFILE: 'no profile',
|
||||
_PROFILE_0: '0',
|
||||
_PROFILE_1: '1',
|
||||
_PROFILE_3: 'Cinema 2K',
|
||||
_PROFILE_4: 'Cinema 4K'}
|
||||
_CAPABILITIES_DISPLAY = _Keydefaultdict(_factory, _x)
|
||||
|
||||
# Need a catch-all list of valid markers.
|
||||
# See table A-1 in ISO/IEC FCD15444-1.
|
||||
|
|
@ -293,6 +294,7 @@ class Codestream(object):
|
|||
msg += ''.join(strs)
|
||||
return msg
|
||||
|
||||
# pylint: disable=R0201
|
||||
def _parse_cme_segment(self, fptr):
|
||||
"""Parse the CME marker segment.
|
||||
|
||||
|
|
@ -822,6 +824,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.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import argparse
|
|||
import os
|
||||
import warnings
|
||||
|
||||
from . import Jp2k, set_printoptions, set_parseoptions, lib
|
||||
from . import Jp2k, set_printoptions, lib
|
||||
|
||||
|
||||
def main():
|
||||
|
|
@ -13,25 +13,23 @@ 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',
|
||||
help='Suppress XML.',
|
||||
action='store_true')
|
||||
parser.add_argument('-s', '--short',
|
||||
help='only print box id, offset, and length',
|
||||
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])
|
||||
default=[0])
|
||||
|
||||
parser.add_argument('filename')
|
||||
|
||||
|
|
@ -47,8 +45,11 @@ def main():
|
|||
|
||||
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
|
||||
|
||||
|
|
@ -57,14 +58,11 @@ def main():
|
|||
# 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)
|
||||
|
||||
|
|
|
|||
|
|
@ -43,3 +43,4 @@ def jpxfile():
|
|||
"""
|
||||
filename = pkg_resources.resource_filename(__name__, "heliov.jpx")
|
||||
return filename
|
||||
|
||||
|
|
|
|||
177
glymur/jp2box.py
177
glymur/jp2box.py
|
|
@ -11,6 +11,8 @@ References
|
|||
Extensions
|
||||
"""
|
||||
|
||||
# pylint: disable=C0302,R0903,R0913,W0142
|
||||
|
||||
from collections import OrderedDict
|
||||
import datetime
|
||||
import io
|
||||
|
|
@ -20,7 +22,7 @@ import pprint
|
|||
import struct
|
||||
import sys
|
||||
import textwrap
|
||||
from uuid import UUID
|
||||
import uuid
|
||||
import warnings
|
||||
|
||||
import lxml.etree as ET
|
||||
|
|
@ -35,21 +37,18 @@ from .core import (_COLORSPACE_MAP_DISPLAY, _COLOR_TYPE_MAP_DISPLAY,
|
|||
|
||||
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)
|
||||
_x = {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, _x)
|
||||
|
||||
|
||||
class Jp2kBox(object):
|
||||
|
|
@ -1001,19 +1000,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,23 +1020,20 @@ 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)
|
||||
|
|
@ -1047,8 +1042,9 @@ class ContiguousCodestreamBox(Jp2kBox):
|
|||
if _printoptions['codestream'] is 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
|
||||
|
|
@ -1321,13 +1317,7 @@ class FileTypeBox(Jp2kBox):
|
|||
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,
|
||||
|
|
@ -2066,43 +2056,43 @@ class PaletteBox(Jp2kBox):
|
|||
|
||||
# Map rreq codes to display text.
|
||||
_READER_REQUIREMENTS_DISPLAY = {
|
||||
0: 'File not completely understood',
|
||||
1: 'Deprecated - contains no extensions',
|
||||
2: 'Contains multiple composition layers',
|
||||
3: 'Deprecated - codestream is compressed using JPEG 2000 and requires '
|
||||
+ 'at least a Profile 0 decoder as defind in ITU-T Rec. T.800 '
|
||||
+ '| ISO/IEC 15444-1, A.10 Table A.45',
|
||||
4: 'JPEG 2000 Part 1 Profile 1 codestream',
|
||||
5: 'Unrestricted JPEG 2000 Part 1 codestream, ITU-T Rec. T.800 '
|
||||
+ '| ISO/IEC 15444-1',
|
||||
6: 'Unrestricted JPEG 2000 Part 2 codestream',
|
||||
7: 'JPEG codestream as defined in ISO/IEC 10918-1',
|
||||
8: 'Deprecated - does not contain opacity',
|
||||
9: 'Non-premultiplied opacity channel',
|
||||
0: 'File not completely understood',
|
||||
1: 'Deprecated - contains no extensions',
|
||||
2: 'Contains multiple composition layers',
|
||||
3: 'Deprecated - codestream is compressed using JPEG 2000 and requires '
|
||||
+ 'at least a Profile 0 decoder as defind in ITU-T Rec. T.800 '
|
||||
+ '| ISO/IEC 15444-1, A.10 Table A.45',
|
||||
4: 'JPEG 2000 Part 1 Profile 1 codestream',
|
||||
5: 'Unrestricted JPEG 2000 Part 1 codestream, ITU-T Rec. T.800 '
|
||||
+ '| ISO/IEC 15444-1',
|
||||
6: 'Unrestricted JPEG 2000 Part 2 codestream',
|
||||
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'),
|
||||
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'),
|
||||
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'),
|
||||
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'),
|
||||
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',
|
||||
|
|
@ -2149,8 +2139,8 @@ _READER_REQUIREMENTS_DISPLAY = {
|
|||
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'),
|
||||
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'}
|
||||
|
||||
|
|
@ -2331,7 +2321,7 @@ def _parse_rreq3(read_buffer, length, offset):
|
|||
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]))
|
||||
vendor_feature.append(uuid.UUID(bytes=ubuffer[0:16]))
|
||||
|
||||
lst = struct.unpack('>BBB', ubuffer[16:])
|
||||
vmask = lst[0] << 16 | lst[1] << 8 | lst[2]
|
||||
|
|
@ -2399,7 +2389,7 @@ def _parse_vendor_features(read_buffer, mask_length):
|
|||
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)
|
||||
|
|
@ -2951,7 +2941,7 @@ 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))
|
||||
ulst.append(uuid.UUID(bytes=uuid_buffer))
|
||||
|
||||
return cls(ulst, length=length, offset=offset)
|
||||
|
||||
|
|
@ -3175,6 +3165,7 @@ class UUIDBox(Jp2kBox):
|
|||
"""
|
||||
box_id = 'uuid'
|
||||
longname = 'UUID'
|
||||
_xmp_uuid = uuid.UUID('be7acfcb-97a9-42e8-9c71-999491e3afac')
|
||||
|
||||
def __init__(self, the_uuid, raw_data, length=0, offset=-1):
|
||||
"""
|
||||
|
|
@ -3209,7 +3200,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)
|
||||
|
|
@ -3227,19 +3218,18 @@ class UUIDBox(Jp2kBox):
|
|||
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'] is False) and (self.uuid == self._xmp_uuid)):
|
||||
# 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 +3272,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 +3307,19 @@ _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,9 +3330,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():
|
||||
|
|
@ -3382,9 +3371,7 @@ def set_printoptions(**kwargs):
|
|||
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
|
||||
--------
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ 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
|
||||
|
|
@ -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
|
||||
--------
|
||||
|
|
@ -147,7 +146,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:
|
||||
|
|
@ -182,16 +180,6 @@ class Jp2k(Jp2kBox):
|
|||
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 +193,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 +234,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):
|
||||
|
|
@ -879,9 +866,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:
|
||||
|
|
@ -920,11 +908,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.
|
||||
|
|
@ -1086,8 +1073,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 "
|
||||
|
|
@ -1290,7 +1278,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
|
||||
|
|
|
|||
|
|
@ -2,5 +2,3 @@
|
|||
from . import openjp2 as openjp2
|
||||
from . import openjpeg as openjpeg
|
||||
from . import c
|
||||
|
||||
__all__ = [openjp2, openjpeg, c]
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -151,7 +147,6 @@ def glymur_config():
|
|||
warnings.warn(msg)
|
||||
return tuple(lst)
|
||||
|
||||
|
||||
def get_configdir():
|
||||
"""Return string representing the configuration directory.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
Wraps individual functions in openjp2 library.
|
||||
"""
|
||||
|
||||
# pylint: disable=C0302,R0903,W0201
|
||||
|
||||
import ctypes
|
||||
import re
|
||||
import sys
|
||||
|
|
@ -408,6 +410,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 = []
|
||||
|
|
@ -737,6 +740,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 +792,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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -360,9 +364,9 @@ 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
|
||||
_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 */
|
||||
|
|
@ -523,6 +527,50 @@ 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.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ 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),
|
||||
"Requires openjpeg 2.1.0 or higher")
|
||||
|
|
@ -73,3 +72,6 @@ class TestPrintingOpenjp2(unittest.TestCase):
|
|||
|
||||
expected = fixtures.default_image_type
|
||||
self.assertRegex(actual, expected)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,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 +101,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 +125,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 +153,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 +183,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 +211,7 @@ def _indent(textstr):
|
|||
String to be indented.
|
||||
indent_level : str
|
||||
Number of spaces of indentation to add.
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
indented_string : str
|
||||
|
|
@ -236,6 +234,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 +544,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 +600,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 +613,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 +669,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 +691,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 +707,7 @@ JP2 Header Box (jp2h) @ (32, 45)
|
|||
Colorspace: sRGB
|
||||
UUID Box (uuid) @ (77, 3146)
|
||||
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
|
||||
UUID Data:
|
||||
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
||||
<ns0:xmpmeta xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:ns0="adobe:ns:meta/" xmlns:ns2="http://ns.adobe.com/xap/1.0/" xmlns:ns3="http://ns.adobe.com/tiff/1.0/" xmlns:ns4="http://ns.adobe.com/exif/1.0/" xmlns:ns5="http://ns.adobe.com/photoshop/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ns0:xmptk="Exempi + XMP Core 5.1.2">
|
||||
<rdf:RDF>
|
||||
<rdf:Description rdf:about="">
|
||||
<ns2:CreatorTool>Google</ns2:CreatorTool>
|
||||
<ns2:CreateDate>2013-02-09T14:47:53</ns2:CreateDate>
|
||||
</rdf:Description>
|
||||
<rdf:Description rdf:about="">
|
||||
<ns3:YCbCrPositioning>1</ns3:YCbCrPositioning>
|
||||
<ns3:XResolution>72/1</ns3:XResolution>
|
||||
<ns3:YResolution>72/1</ns3:YResolution>
|
||||
<ns3:ResolutionUnit>2</ns3:ResolutionUnit>
|
||||
<ns3:Make>HTC</ns3:Make>
|
||||
<ns3:Model>HTC Glacier</ns3:Model>
|
||||
<ns3:ImageWidth>2592</ns3:ImageWidth>
|
||||
<ns3:ImageLength>1456</ns3:ImageLength>
|
||||
<ns3:BitsPerSample>
|
||||
<rdf:Seq>
|
||||
<rdf:li>8</rdf:li>
|
||||
<rdf:li>8</rdf:li>
|
||||
<rdf:li>8</rdf:li>
|
||||
</rdf:Seq>
|
||||
</ns3:BitsPerSample>
|
||||
<ns3:PhotometricInterpretation>2</ns3:PhotometricInterpretation>
|
||||
<ns3:SamplesPerPixel>3</ns3:SamplesPerPixel>
|
||||
<ns3:WhitePoint>
|
||||
<rdf:Seq>
|
||||
<rdf:li>1343036288/4294967295</rdf:li>
|
||||
<rdf:li>1413044224/4294967295</rdf:li>
|
||||
</rdf:Seq>
|
||||
</ns3:WhitePoint>
|
||||
<ns3:PrimaryChromaticities>
|
||||
<rdf:Seq>
|
||||
<rdf:li>2748779008/4294967295</rdf:li>
|
||||
<rdf:li>1417339264/4294967295</rdf:li>
|
||||
<rdf:li>1288490240/4294967295</rdf:li>
|
||||
<rdf:li>2576980480/4294967295</rdf:li>
|
||||
<rdf:li>644245120/4294967295</rdf:li>
|
||||
<rdf:li>257698032/4294967295</rdf:li>
|
||||
</rdf:Seq>
|
||||
</ns3:PrimaryChromaticities>
|
||||
</rdf:Description>
|
||||
<rdf:Description rdf:about="">
|
||||
<ns4:ColorSpace>1</ns4:ColorSpace>
|
||||
<ns4:PixelXDimension>2528</ns4:PixelXDimension>
|
||||
<ns4:PixelYDimension>1424</ns4:PixelYDimension>
|
||||
<ns4:FocalLength>353/100</ns4:FocalLength>
|
||||
<ns4:GPSAltitudeRef>0</ns4:GPSAltitudeRef>
|
||||
<ns4:GPSAltitude>0/1</ns4:GPSAltitude>
|
||||
<ns4:GPSMapDatum>WGS-84</ns4:GPSMapDatum>
|
||||
<ns4:DateTimeOriginal>2013-02-09T14:47:53</ns4:DateTimeOriginal>
|
||||
<ns4:ISOSpeedRatings>
|
||||
<rdf:Seq>
|
||||
<rdf:li>76</rdf:li>
|
||||
</rdf:Seq>
|
||||
</ns4:ISOSpeedRatings>
|
||||
<ns4:ExifVersion>0220</ns4:ExifVersion>
|
||||
<ns4:FlashpixVersion>0100</ns4:FlashpixVersion>
|
||||
<ns4:ComponentsConfiguration>
|
||||
<rdf:Seq>
|
||||
<rdf:li>1</rdf:li>
|
||||
<rdf:li>2</rdf:li>
|
||||
<rdf:li>3</rdf:li>
|
||||
<rdf:li>0</rdf:li>
|
||||
</rdf:Seq>
|
||||
</ns4:ComponentsConfiguration>
|
||||
<ns4:GPSLatitude>42,20.56N</ns4:GPSLatitude>
|
||||
<ns4:GPSLongitude>71,5.29W</ns4:GPSLongitude>
|
||||
<ns4:GPSTimeStamp>2013-02-09T19:47:53Z</ns4:GPSTimeStamp>
|
||||
<ns4:GPSProcessingMethod>NETWORK</ns4:GPSProcessingMethod>
|
||||
</rdf:Description>
|
||||
<rdf:Description rdf:about="">
|
||||
<ns5:DateCreated>2013-02-09T14:47:53</ns5:DateCreated>
|
||||
</rdf:Description>
|
||||
<rdf:Description rdf:about="">
|
||||
<dc:Creator>
|
||||
<rdf:Seq>
|
||||
<rdf:li>Glymur</rdf:li>
|
||||
<rdf:li>Python XMP Toolkit</rdf:li>
|
||||
</rdf:Seq>
|
||||
</dc:Creator>
|
||||
</rdf:Description>
|
||||
</rdf:RDF>
|
||||
</ns0:xmpmeta>
|
||||
<?xpacket end="w"?>
|
||||
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 +743,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 +908,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)"""
|
||||
|
||||
|
|
|
|||
|
|
@ -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,7 +60,7 @@ 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)
|
||||
|
|
@ -93,6 +98,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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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__":
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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,15 +103,12 @@ 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)
|
||||
|
|
@ -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=<byte\sarray\s10\selements>\)"""
|
||||
|
||||
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=<byte\sarray\s3122\selements>\)"""
|
||||
|
||||
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=<glymur.codestream.Codestream\sobject\s"
|
||||
regexp += "[(]main_header=<glymur.codestream.Codestream\sobject\s"
|
||||
regexp += "at\s0x([a-fA-F0-9]*)>[)]"
|
||||
|
||||
if sys.hexversion < 0x03000000:
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ Test suite specifically targeting JPX box layout.
|
|||
import ctypes
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
|
|
@ -19,7 +20,6 @@ from glymur.jp2box import ColourSpecificationBox
|
|||
|
||||
from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG
|
||||
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
class TestJPXWrap(unittest.TestCase):
|
||||
"""Test suite for wrapping JPX files."""
|
||||
|
|
@ -184,7 +184,7 @@ class TestJPXWrap(unittest.TestCase):
|
|||
|
||||
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
|
||||
with self.assertRaises(IOError):
|
||||
jp2.wrap(tfile.name, boxes=boxes)
|
||||
jpx = jp2.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
def test_cgrp_neg(self):
|
||||
"""Can't write a cgrp with anything but colr sub boxes"""
|
||||
|
|
@ -204,7 +204,7 @@ class TestJPXWrap(unittest.TestCase):
|
|||
|
||||
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
|
||||
with self.assertRaises(IOError):
|
||||
jp2.wrap(tfile.name, boxes=boxes)
|
||||
jpx = jp2.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
def test_ftbl(self):
|
||||
"""Write a fragment table box."""
|
||||
|
|
@ -484,7 +484,7 @@ class TestJPX(unittest.TestCase):
|
|||
ftbl.write(tfile)
|
||||
|
||||
def test_data_reference_requires_dtbl(self):
|
||||
"""The existance of data reference box requires a ftbl box as well."""
|
||||
"""The existance of a data reference box requires a ftbl box as well."""
|
||||
flag = 0
|
||||
version = (0, 0, 0)
|
||||
url1 = 'file:////usr/local/bin'
|
||||
|
|
@ -574,7 +574,7 @@ class TestJPX(unittest.TestCase):
|
|||
131072, 65536, 32768, 16384, 8192]
|
||||
for j in range(len(standard_flags)):
|
||||
mask = (standard_masks[j] >> 16,
|
||||
standard_masks[j] & 0x0000ffff >> 8,
|
||||
standard_masks[j] & 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)
|
||||
|
|
|
|||
|
|
@ -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,15 +23,29 @@ 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,
|
||||
from .fixtures import (HAS_PYTHON_XMP_TOOLKIT, OPJ_DATA_ROOT,
|
||||
WARNING_INFRASTRUCTURE_ISSUE,
|
||||
WARNING_INFRASTRUCTURE_MSG,
|
||||
WINDOWS_TMP_FILE_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)
|
||||
|
|
@ -79,7 +103,6 @@ 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)
|
||||
class TestSuiteWarns(unittest.TestCase):
|
||||
|
|
@ -90,7 +113,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 +137,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"""
|
||||
|
|
|
|||
|
|
@ -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'<country>Россия</country>')
|
||||
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -35,20 +45,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,7 +77,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")
|
||||
|
|
@ -141,6 +148,11 @@ class TestSliceProtocolBaseWrite(SliceProtocolBase):
|
|||
@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 +169,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 +184,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 +226,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 +235,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 +243,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."""
|
||||
|
||||
|
|
@ -308,7 +319,7 @@ class TestJp2k(unittest.TestCase):
|
|||
|
||||
@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):
|
||||
|
|
@ -627,7 +638,7 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(ET.tostring(jp2k.box[3].xml.getroot()),
|
||||
b'<test>this is a test</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,9 +654,8 @@ 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)''',
|
||||
|
|
@ -664,7 +674,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))
|
||||
|
|
@ -684,30 +693,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 +726,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 +745,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 +804,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 +833,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"""
|
||||
|
|
@ -915,7 +924,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 +933,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:
|
||||
|
||||
|
|
@ -1032,15 +1041,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 +1054,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 +1101,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 +1117,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 +1138,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],
|
||||
|
|
@ -1142,7 +1148,7 @@ class TestJp2kOpjDataRoot(unittest.TestCase):
|
|||
|
||||
actdata = j[:]
|
||||
self.assertTrue(fixtures.mse(actdata, expdata) < 250)
|
||||
|
||||
|
||||
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
|
||||
def test_no_cxform_pclr_jp2(self):
|
||||
"""Indices for pclr jpxfile if no color transform"""
|
||||
|
|
@ -1174,7 +1180,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 +1196,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 +1274,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 +1329,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 +1348,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))
|
||||
|
|
|
|||
|
|
@ -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,11 +38,12 @@ 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,
|
||||
OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG
|
||||
)
|
||||
|
||||
|
||||
@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG)
|
||||
|
|
@ -359,14 +385,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 +408,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 +436,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)
|
||||
|
|
@ -587,16 +609,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):
|
||||
|
|
@ -707,7 +726,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,7 +798,6 @@ 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''',
|
||||
|
|
@ -788,7 +806,7 @@ class TestSuite2point1(unittest.TestCase):
|
|||
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
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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)])
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)",
|
||||
(" <country>Росс",
|
||||
"ия</country>")]
|
||||
" <country>Россия</country>"]
|
||||
else:
|
||||
lines = ["XML Box (xml ) @ (-1, 0)",
|
||||
" <country>Россия</country>"]
|
||||
|
|
@ -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: .*")
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
14
setup.py
14
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",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue