Merge branch 'release-0.2.0'
This commit is contained in:
commit
fc07117faa
32 changed files with 6351 additions and 4883 deletions
|
|
@ -1,3 +1,5 @@
|
|||
Jul 11, 2013 - v0.2.0 Support for Python 2.7 on windows, OpenJPEG 1.5.1.
|
||||
|
||||
Jun 27, 2013 - v0.1.10 Can wrap codestreams in custom JP2 jackets. Exposing
|
||||
parameter to specify multi component transform. Added a raw codestream
|
||||
file.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
include *.txt *.md
|
||||
prune build
|
||||
exclude readthedocs-pip-requirements.txt
|
||||
exclude release.txt
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ copyright = u'2013, John Evans'
|
|||
# The short X.Y version.
|
||||
version = '0.1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.1.10'
|
||||
release = '0.2.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
|
|
|||
|
|
@ -1,16 +1,57 @@
|
|||
-----------------------------------------------------
|
||||
Detailed Instructions for Package Management, Testing
|
||||
-----------------------------------------------------
|
||||
----------------------------------
|
||||
Detailed Installation Instructions
|
||||
----------------------------------
|
||||
|
||||
You only need to read this page if you want detailed
|
||||
''''''''''''''''''''''
|
||||
Glymur Configuration
|
||||
''''''''''''''''''''''
|
||||
|
||||
The default glymur installation process relies upon OpenJPEG version
|
||||
1.5.1 being properly installed on your system. This will, however, only
|
||||
give you you basic read capabilities, so if you wish to take advantage
|
||||
of more of glymur's features, you should compile OpenJPEG as a shared
|
||||
library (named *openjp2* instead of *openjpeg*) from the developmental
|
||||
source that you can retrieve via subversion. As of this time of writing,
|
||||
svn revision 2345 works. You should also download the test data for
|
||||
the purpose of configuring and running OpenJPEG's test suite, check
|
||||
their instructions for all this. You should set the **OPJ_DATA_ROOT**
|
||||
environment variable for the purpose of running Glymur's test suite. ::
|
||||
|
||||
$ svn co http://openjpeg.googlecode.com/svn/data
|
||||
$ export OPJ_DATA_ROOT=`pwd`/data
|
||||
|
||||
Glymur uses ctypes (for the moment) to access the openjp2 library, and
|
||||
because ctypes access libraries in a platform-dependent manner, it is
|
||||
recommended that you create a configuration file to help Glymur properly find
|
||||
the openjp2 library. You may create the configuration file as follows::
|
||||
|
||||
$ mkdir -p ~/.config/glymur
|
||||
$ cd ~/.config/glymur
|
||||
$ cat > glymurrc << EOF
|
||||
> [library]
|
||||
> openjp2: /opt/openjp2-svn/lib/libopenjp2.so
|
||||
> EOF
|
||||
|
||||
This assumes, of course, that you've installed OpenJPEG into
|
||||
/opt/openjp2-svn on a linux system. You may also substitute
|
||||
**$XDG_CONFIG_HOME** for **$HOME/.config**.
|
||||
|
||||
You may also include a line for the version 1.5.1 library if you have it installed
|
||||
in a non-standard place, i.e. ::
|
||||
|
||||
[library]
|
||||
openjp2: /opt/openjp2-svn/lib/libopenjp2.so
|
||||
openjpeg: /not/the/usual/location/lib/libopenjpeg.so
|
||||
|
||||
'''''''''''''''''''''''''''''''''''''''''''
|
||||
Package Management Suggestions for Testing
|
||||
'''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
You only need to read this section if you want detailed
|
||||
platform-specific instructions on running as many tests as possible or wish to
|
||||
use your system's package manager to install as many required
|
||||
packages/RPMs/ports/whatever without going through pip. Otherwise go on to
|
||||
the next page.
|
||||
packages/RPMs/ports/whatever without going through pip.
|
||||
|
||||
''''''''
|
||||
Platform
|
||||
''''''''
|
||||
|
||||
Mac OS X
|
||||
--------
|
||||
|
|
@ -27,13 +68,29 @@ additionally be installed:
|
|||
* py33-scikit-image and either py33-Pillow or freeimage
|
||||
* py33-matplotlib and py33-Pillow
|
||||
|
||||
MacPorts supplies both OpenJPEG 1.5.0 and OpenJPEG 2.0.0. As previously
|
||||
mentioned, the 2.0.0 official release is not supported (although the 2.0+
|
||||
development version via SVN *is* supported).
|
||||
|
||||
Linux
|
||||
-----
|
||||
|
||||
Fedora 19
|
||||
'''''''''
|
||||
Fedora 18 ships with Python 3.3 and all the necessary RPMs are available to
|
||||
run the maximum number of tests.
|
||||
|
||||
* python3
|
||||
* python3-numpy
|
||||
* python3-setuptools
|
||||
* python3-matplotlib (for running tests)
|
||||
* python3-matplotlib-tk (or whichever matplotlib backend you prefer)
|
||||
* python3-pillow (for running tests)
|
||||
|
||||
Fedora 18
|
||||
'''''''''
|
||||
Fedora 18 ships with Python 3.3, so all the necessary RPMs are available to
|
||||
meet the minimal set of requirements.
|
||||
Fedora 18 ships with Python 3.3 and the following RPMs are available to
|
||||
meet the minimal set of requirements for running glymur.
|
||||
|
||||
* python3
|
||||
* python3-numpy
|
||||
|
|
@ -56,31 +113,10 @@ repositories::
|
|||
$ pip-python3 install Pillow --user
|
||||
$ export PYTHONPATH=$HOME/.local/lib/python3.3/site-packages:$PYTHONPATH
|
||||
|
||||
Raspbian
|
||||
''''''''
|
||||
Yeah, this was the first thing I tried after getting my new Raspberry Pi hooked
|
||||
up (couldn't help myself :-) Raspbian ships with Python 3.2 and 2.7, so these steps detail working with 2.7.
|
||||
|
||||
Additional required OS packages include::
|
||||
|
||||
* python-pip
|
||||
* python-pkg-resources
|
||||
* python-mock
|
||||
|
||||
You must install contextlib2 via pip, and then you can run at least
|
||||
a minimal number of tests. To attempt to run more of the tests,
|
||||
install the following debs::
|
||||
|
||||
* python-dev
|
||||
* python-matplotlib
|
||||
|
||||
and then install Pillow via pip. The tests take about 30 minutes to run, with
|
||||
one unexpected failure as of the time of writing.
|
||||
|
||||
Fedora 17
|
||||
'''''''''
|
||||
Fedora 17 ships with Python 3.2 and 2.7, so these steps detail working with
|
||||
2.7.
|
||||
Fedora 17 ships with Python 3.2 and 2.7, but OpenJPEG is only at version 1.4,
|
||||
so these steps detail working with Python 2.7 and the svn version of OpenJPEG.
|
||||
|
||||
Required RPMs include::
|
||||
|
||||
|
|
@ -111,19 +147,23 @@ it was installable via pip::
|
|||
|
||||
Windows
|
||||
-------
|
||||
Not currently supported.
|
||||
The only configuration I've tested is Python(xy), which uses Python 2.7.
|
||||
Python(xy) already comes with numpy, but you will have to install pip and then
|
||||
contextlib2 and mock as well. Both 1.5.1 and the svn development versions of
|
||||
openjpeg work.
|
||||
|
||||
|
||||
'''''''
|
||||
Testing
|
||||
'''''''
|
||||
|
||||
If you wish to run the tests (strongly suggested :-), you can either run them
|
||||
If you wish to run the tests (strongly recommended :-), you can either run them
|
||||
from within python as follows ... ::
|
||||
|
||||
>>> import glymur
|
||||
>>> glymur.runtests()
|
||||
|
||||
or from the unix command line. ::
|
||||
or from the command line. ::
|
||||
|
||||
$ cd /to/where/you/unpacked/glymur
|
||||
$ python -m unittest discover
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@ How do I...?
|
|||
Read the lowest resolution thumbnail?
|
||||
=====================================
|
||||
Printing the Jp2k object should reveal the number of resolutions (look in the
|
||||
COD segment section), but you can take a shortcut by supplying -1 as the reduce
|
||||
level. ::
|
||||
COD segment section), but you can take a shortcut by supplying -1 as the
|
||||
resolution level. ::
|
||||
|
||||
>>> import glymur
|
||||
>>> file = glymur.data.nemo()
|
||||
>>> j = glymur.Jp2k(file)
|
||||
>>> thumbnail = j.read(reduce=-1)
|
||||
>>> thumbnail = j.read(rlevel=-1)
|
||||
|
||||
Display metadata?
|
||||
=================
|
||||
|
|
|
|||
|
|
@ -2,14 +2,9 @@
|
|||
Glymur: a Python interface for JPEG 2000
|
||||
----------------------------------------
|
||||
|
||||
**Glymur** contains a Python interface to the OpenJPEG library
|
||||
which allows linux and mac users to read and write JPEG 2000 files. For more
|
||||
information about OpenJPEG, please consult http://www.openjpeg.org. Glymur
|
||||
currently relies upon a development version of the OpenJPEG library, and so,
|
||||
while useable, it is totally at the mercy of any upstream changes
|
||||
made to the development version of OpenJPEG.
|
||||
|
||||
Glymur supports both reading and writing of JPEG 2000 images (part 1). Writing
|
||||
**Glymur** is an interface to the OpenJPEG library
|
||||
which allows one to read and write JPEG 2000 files from within Python.
|
||||
Glymur supports both reading and writing of JPEG 2000 images. Writing
|
||||
JPEG 2000 images is currently limited to images that can fit in memory,
|
||||
however.
|
||||
|
||||
|
|
@ -23,34 +18,18 @@ Glymur works on Python 2.7 and 3.3. Python 3.3 is strongly recommended.
|
|||
|
||||
OpenJPEG Installation
|
||||
=====================
|
||||
OpenJPEG must be built as a shared library. In addition, you
|
||||
currently must compile OpenJPEG from the developmental source that
|
||||
you can retrieve via subversion. As of this time of writing, svn
|
||||
revision 2345 works. You should download the test data for the purpose
|
||||
of configuring and running OpenJPEG's test suite, check their instructions for
|
||||
all this. You should set the **OPJ_DATA_ROOT** environment variable for the
|
||||
purpose of running Glymur's test suite. ::
|
||||
The OpenJPEG library version must be either 1.5.1 or the trunk/development
|
||||
version of OpenJPEG. Version 2.0.0 or versions earlier than 1.5.0
|
||||
are not supported. Furthermore, the 1.5.x version of OpenJPEG is
|
||||
currently only utilized for read-only purposes. For more information
|
||||
about OpenJPEG, please consult http://www.openjpeg.org.
|
||||
|
||||
$ svn co http://openjpeg.googlecode.com/svn/data
|
||||
$ export OPJ_DATA_ROOT=`pwd`/data
|
||||
|
||||
Earlier versions of OpenJPEG through the 2.0 official release will **NOT**
|
||||
work and are not supported.
|
||||
|
||||
Glymur uses ctypes (for the moment) to access the openjp2 library, and
|
||||
because ctypes access libraries in a platform-dependent manner, it is
|
||||
recommended that you create a configuration file to help Glymur properly find
|
||||
the openjp2 library. You may create the configuration file as follows::
|
||||
|
||||
$ mkdir -p ~/.config/glymur
|
||||
$ cd ~/.config/glymur
|
||||
$ cat > glymurrc << EOF
|
||||
> [library]
|
||||
> openjp2: /opt/openjp2-svn/lib/libopenjp2.so
|
||||
> EOF
|
||||
|
||||
That assumes, of course, that you've installed OpenJPEG into /opt/openjp2-svn.
|
||||
You may also substitute **$XDG_CONFIG_HOME** for **$HOME/.config**.
|
||||
If you use MacPorts on the mac or if you have a sufficiently recent version of
|
||||
Linux, your package manager should already provide you with at least version
|
||||
1.5.1 of OpenJPEG, which means that glymur can be installed ready to read JPEG
|
||||
2000 images. If you use windows, I suggest using the 1.5.1 windows installer
|
||||
provided to you by the OpenJPEG folks at
|
||||
https://code.google.com/p/openjpeg/downloads/list .
|
||||
|
||||
Glymur Installation
|
||||
===================
|
||||
|
|
@ -76,5 +55,6 @@ You can run the tests from within python as follows::
|
|||
>>> import glymur
|
||||
>>> glymur.runtests()
|
||||
|
||||
Many tests are currently skipped; the important thing is whether or not any
|
||||
tests fail.
|
||||
Many tests are currently skipped; in fact most of them are skipped if you
|
||||
are relying on OpenJPEG 1.5.1. But the important thing, though, is whether or
|
||||
not any tests fail.
|
||||
|
|
|
|||
1847
glymur/codestream.py
1847
glymur/codestream.py
File diff suppressed because it is too large
Load diff
|
|
@ -1,3 +1,5 @@
|
|||
"""Core definitions to be shared amongst the modules.
|
||||
"""
|
||||
# Progression order
|
||||
LRCP = 0
|
||||
RLCP = 1
|
||||
|
|
@ -5,44 +7,21 @@ RPCL = 2
|
|||
PCRL = 3
|
||||
CPRL = 4
|
||||
|
||||
_progression_order_display = {
|
||||
LRCP: 'LRCP',
|
||||
RLCP: 'RLCP',
|
||||
RPCL: 'RPCL',
|
||||
PCRL: 'PCRL',
|
||||
CPRL: 'CPRL'}
|
||||
|
||||
progression_order = {
|
||||
PROGRESSION_ORDER = {
|
||||
'LRCP': LRCP,
|
||||
'RLCP': RLCP,
|
||||
'RPCL': RPCL,
|
||||
'PCRL': PCRL,
|
||||
'CPRL': CPRL}
|
||||
|
||||
WAVELET_TRANSFORM_9x7_IRREVERSIBLE = 0
|
||||
WAVELET_TRANSFORM_5x3_REVERSIBLE = 1
|
||||
|
||||
_wavelet_transform_display = {
|
||||
WAVELET_TRANSFORM_9x7_IRREVERSIBLE: '9-7 irreversible',
|
||||
WAVELET_TRANSFORM_5x3_REVERSIBLE: '5-3 reversible'}
|
||||
WAVELET_XFORM_9X7_IRREVERSIBLE = 0
|
||||
WAVELET_XFORM_5X3_REVERSIBLE = 1
|
||||
|
||||
ENUMERATED_COLORSPACE = 1
|
||||
RESTRICTED_ICC_PROFILE = 2
|
||||
ANY_ICC_PROFILE = 3
|
||||
VENDOR_COLOR_METHOD = 4
|
||||
|
||||
_method_display = {
|
||||
ENUMERATED_COLORSPACE: 'enumerated colorspace',
|
||||
RESTRICTED_ICC_PROFILE: 'restricted ICC profile',
|
||||
ANY_ICC_PROFILE: 'any ICC profile',
|
||||
VENDOR_COLOR_METHOD: 'vendor color method'}
|
||||
|
||||
_ = {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'}
|
||||
_approximation_display = _
|
||||
|
||||
# Registration values for comment markers.
|
||||
RCME_BINARY = 0 # binary value comments
|
||||
RCME_ISO_8859_1 = 1 # comments in latin-1 codec
|
||||
|
|
@ -55,7 +34,7 @@ YCC = 18
|
|||
E_SRGB = 20
|
||||
ROMM_RGB = 21
|
||||
|
||||
_colorspace_map_display = {
|
||||
_COLORSPACE_MAP_DISPLAY = {
|
||||
CMYK: 'CMYK',
|
||||
SRGB: 'sRGB',
|
||||
GREYSCALE: 'greyscale',
|
||||
|
|
@ -68,7 +47,7 @@ _COLOR = 0
|
|||
_OPACITY = 1
|
||||
_PRE_MULTIPLIED_OPACITY = 2
|
||||
_UNSPECIFIED = 65535
|
||||
_color_type_map_display = {
|
||||
_COLOR_TYPE_MAP_DISPLAY = {
|
||||
_COLOR: 'color',
|
||||
_OPACITY: 'opacity',
|
||||
_PRE_MULTIPLIED_OPACITY: 'pre-multiplied opacity',
|
||||
|
|
@ -81,49 +60,15 @@ BLUE = 3
|
|||
GREY = 1
|
||||
|
||||
# enumerated color channel associations
|
||||
_rgb_colorspace = {"R": 1, "G": 2, "B": 3}
|
||||
_greyscale_colorspace = {"Y": 1}
|
||||
_ycbcr_colorspace = {"Y": 1, "Cb": 2, "Cr": 3}
|
||||
_colorspace = {SRGB: _rgb_colorspace,
|
||||
GREYSCALE: _greyscale_colorspace,
|
||||
YCC: _ycbcr_colorspace,
|
||||
E_SRGB: _rgb_colorspace,
|
||||
ROMM_RGB: _rgb_colorspace}
|
||||
_COLORSPACE = {SRGB: {"R": 1, "G": 2, "B": 3},
|
||||
GREYSCALE: {"Y": 1},
|
||||
YCC: {"Y": 1, "Cb": 2, "Cr": 3},
|
||||
E_SRGB: {"R": 1, "G": 2, "B": 3},
|
||||
ROMM_RGB: {"R": 1, "G": 2, "B": 3}}
|
||||
|
||||
# How to display the codestream profile.
|
||||
_capabilities_display = {
|
||||
_CAPABILITIES_DISPLAY = {
|
||||
0: '2',
|
||||
1: '0',
|
||||
2: '1',
|
||||
3: '3'}
|
||||
|
||||
# Reader requirements
|
||||
RREQ_UNRESTRICTED_JPEG2000_PART_1 = 5
|
||||
RREQ_UNRESTRICTED_JPEG2000_PART_2 = 6
|
||||
RREQ_CMYK_ENUMERATED_COLORSPACE = 55
|
||||
RREQ_CMYK_ENUMERATED_COLORSPACE = 55
|
||||
RREQ_E_SRGB_ENUMERATED_COLORSPACE = 60
|
||||
RREQ_ROMM_RGB_ENUMERATED_COLORSPACE = 61
|
||||
_reader_requirements_display = {
|
||||
0: 'File not completely understood',
|
||||
1: 'Deprecated',
|
||||
2: 'Contains multiple composition layers',
|
||||
3: 'Deprecated',
|
||||
4: 'JPEG 2000 Part 1 Profile 1 codestream',
|
||||
RREQ_UNRESTRICTED_JPEG2000_PART_1:
|
||||
'Unrestricted JPEG 2000 Part 1 codestream, ITU-T Rec. T.800 '
|
||||
+ '| ISO/IEC 15444-1',
|
||||
RREQ_UNRESTRICTED_JPEG2000_PART_2:
|
||||
'Unrestricted JPEG 2000 Part 2 codestream',
|
||||
7: 'JPEG codestream as defined in ISO/IEC 10918-1',
|
||||
8: 'Deprecated',
|
||||
9: 'Non-premultiplied opacity channel',
|
||||
10: 'Premultiplied opacity channel',
|
||||
12: 'Deprecated',
|
||||
18: 'Deprecated',
|
||||
43: '(Deprecated) compositing layer uses restricted ICC profile',
|
||||
44: 'Compositing layer uses Any ICC profile',
|
||||
45: 'Deprecated',
|
||||
RREQ_CMYK_ENUMERATED_COLORSPACE: 'CMYK enumerated colorspace',
|
||||
RREQ_E_SRGB_ENUMERATED_COLORSPACE: 'e-sRGB enumerated colorspace',
|
||||
RREQ_ROMM_RGB_ENUMERATED_COLORSPACE: 'ROMM_RGB enumerated colorspace'}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ def nemo():
|
|||
file : str
|
||||
Platform-independent path to nemo.jp2.
|
||||
"""
|
||||
file = pkg_resources.resource_filename(__name__, "nemo.jp2")
|
||||
return file
|
||||
filename = pkg_resources.resource_filename(__name__, "nemo.jp2")
|
||||
return filename
|
||||
|
||||
|
||||
def goodstuff():
|
||||
|
|
@ -29,5 +29,5 @@ def goodstuff():
|
|||
file : str
|
||||
Platform-independent path to goodstuff.j2k.
|
||||
"""
|
||||
file = pkg_resources.resource_filename(__name__, "goodstuff.j2k")
|
||||
return file
|
||||
filename = pkg_resources.resource_filename(__name__, "goodstuff.j2k")
|
||||
return filename
|
||||
|
|
|
|||
Binary file not shown.
1318
glymur/jp2box.py
1318
glymur/jp2box.py
File diff suppressed because it is too large
Load diff
470
glymur/jp2k.py
470
glymur/jp2k.py
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
License: MIT
|
||||
"""
|
||||
|
||||
# pylint: disable=C0302
|
||||
|
||||
import sys
|
||||
if sys.hexversion >= 0x03030000:
|
||||
from contextlib import ExitStack
|
||||
|
|
@ -16,14 +19,23 @@ import warnings
|
|||
import numpy as np
|
||||
|
||||
from .codestream import Codestream
|
||||
from .core import *
|
||||
from .jp2box import *
|
||||
from .lib import openjp2 as opj2
|
||||
from .core import SRGB
|
||||
from .core import GREYSCALE
|
||||
from .core import PROGRESSION_ORDER
|
||||
from .jp2box import Jp2kBox
|
||||
from .jp2box import JPEG2000SignatureBox
|
||||
from .jp2box import FileTypeBox
|
||||
from .jp2box import JP2HeaderBox
|
||||
from .jp2box import ContiguousCodestreamBox
|
||||
from .jp2box import ImageHeaderBox
|
||||
from .jp2box import ColourSpecificationBox
|
||||
from .lib import _openjpeg as _opj
|
||||
from .lib import _openjp2 as _opj2
|
||||
|
||||
_cspace_map = {'rgb': opj2._CLRSPC_SRGB,
|
||||
'gray': opj2._CLRSPC_GRAY,
|
||||
'grey': opj2._CLRSPC_GRAY,
|
||||
'ycc': opj2._CLRSPC_YCC}
|
||||
_COLORSPACE_MAP = {'rgb': _opj2.CLRSPC_SRGB,
|
||||
'gray': _opj2.CLRSPC_GRAY,
|
||||
'grey': _opj2.CLRSPC_GRAY,
|
||||
'ycc': _opj2.CLRSPC_YCC}
|
||||
|
||||
# Setup the default callback handlers. See the callback functions subsection
|
||||
# in the ctypes section of the Python documentation for a solid explanation of
|
||||
|
|
@ -31,23 +43,26 @@ _cspace_map = {'rgb': opj2._CLRSPC_SRGB,
|
|||
_CMPFUNC = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p)
|
||||
|
||||
|
||||
def _default_error_handler(msg, client_data):
|
||||
def _default_error_handler(msg, _):
|
||||
"""Default error handler callback for openjpeg library."""
|
||||
msg = "OpenJPEG library error: {0}".format(msg.decode('utf-8').rstrip())
|
||||
opj2._set_error_message(msg)
|
||||
_opj2.set_error_message(msg)
|
||||
|
||||
|
||||
def _default_info_handler(msg, client_data):
|
||||
def _default_info_handler(msg, _):
|
||||
"""Default info handler callback for openjpeg library."""
|
||||
print("[INFO] {0}".format(msg.decode('utf-8').rstrip()))
|
||||
|
||||
|
||||
def _default_warning_handler(library_msg, client_data):
|
||||
def _default_warning_handler(library_msg, _):
|
||||
"""Default warning handler callback for openjpeg library."""
|
||||
library_msg = library_msg.decode('utf-8').rstrip()
|
||||
msg = "OpenJPEG library warning: {0}".format(library_msg)
|
||||
warnings.warn(msg)
|
||||
|
||||
_error_callback = _CMPFUNC(_default_error_handler)
|
||||
_info_callback = _CMPFUNC(_default_info_handler)
|
||||
_warning_callback = _CMPFUNC(_default_warning_handler)
|
||||
_ERROR_CALLBACK = _CMPFUNC(_default_error_handler)
|
||||
_INFO_CALLBACK = _CMPFUNC(_default_info_handler)
|
||||
_WARNING_CALLBACK = _CMPFUNC(_default_warning_handler)
|
||||
|
||||
|
||||
class Jp2k(Jp2kBox):
|
||||
|
|
@ -74,14 +89,16 @@ class Jp2k(Jp2kBox):
|
|||
mode : str, optional
|
||||
The mode used to open the file.
|
||||
"""
|
||||
Jp2kBox.__init__(self)
|
||||
self.filename = filename
|
||||
self.mode = mode
|
||||
self.box = []
|
||||
self.offset = 0
|
||||
self._codec_format = None
|
||||
self._file_size = 0
|
||||
|
||||
# Parse the file for JP2/JPX contents only if we are reading it.
|
||||
if mode == 'rb':
|
||||
self._parse()
|
||||
self.parse()
|
||||
|
||||
def __str__(self):
|
||||
metadata = ['File: ' + os.path.basename(self.filename)]
|
||||
|
|
@ -89,11 +106,11 @@ class Jp2k(Jp2kBox):
|
|||
for box in self.box:
|
||||
metadata.append(str(box))
|
||||
else:
|
||||
c = self.get_codestream()
|
||||
metadata.append(str(c))
|
||||
codestream = self.get_codestream()
|
||||
metadata.append(str(codestream))
|
||||
return '\n'.join(metadata)
|
||||
|
||||
def _parse(self):
|
||||
def parse(self):
|
||||
"""Parses the JPEG 2000 file.
|
||||
|
||||
Raises
|
||||
|
|
@ -105,39 +122,41 @@ class Jp2k(Jp2kBox):
|
|||
self.length = stat.st_size
|
||||
self._file_size = stat.st_size
|
||||
|
||||
with open(self.filename, 'rb') as f:
|
||||
with open(self.filename, 'rb') as fptr:
|
||||
|
||||
# Make sure we have a JPEG2000 file. It could be either JP2 or
|
||||
# J2C. Check for J2C first, single box in that case.
|
||||
buffer = f.read(2)
|
||||
signature, = struct.unpack('>H', buffer)
|
||||
read_buffer = fptr.read(2)
|
||||
signature, = struct.unpack('>H', read_buffer)
|
||||
if signature == 0xff4f:
|
||||
self._codec_format = opj2._CODEC_J2K
|
||||
self._codec_format = _opj2.CODEC_J2K
|
||||
# That's it, we're done. The codestream object is only
|
||||
# produced upon explicit request.
|
||||
return
|
||||
|
||||
self._codec_format = opj2._CODEC_JP2
|
||||
self._codec_format = _opj2.CODEC_JP2
|
||||
|
||||
# Should be JP2.
|
||||
# First 4 bytes should be 12, the length of the 'jP ' box.
|
||||
# 2nd 4 bytes should be the box ID ('jP ').
|
||||
# 3rd 4 bytes should be the box signature (13, 10, 135, 10).
|
||||
f.seek(0)
|
||||
buffer = f.read(12)
|
||||
values = struct.unpack('>I4s4B', buffer)
|
||||
L = values[0]
|
||||
T = values[1]
|
||||
fptr.seek(0)
|
||||
read_buffer = fptr.read(12)
|
||||
values = struct.unpack('>I4s4B', read_buffer)
|
||||
box_length = values[0]
|
||||
box_id = values[1]
|
||||
signature = values[2:]
|
||||
if L != 12 or T != b'jP ' or signature != (13, 10, 135, 10):
|
||||
if (((box_length != 12) or (box_id != b'jP ') or
|
||||
(signature != (13, 10, 135, 10)))):
|
||||
msg = '{0} is not a JPEG 2000 file.'.format(self.filename)
|
||||
raise IOError(msg)
|
||||
|
||||
# Back up and start again, we know we have a superbox (box of
|
||||
# boxes) here.
|
||||
f.seek(0)
|
||||
self.box = self._parse_superbox(f)
|
||||
fptr.seek(0)
|
||||
self.box = self.parse_superbox(fptr)
|
||||
|
||||
# pylint: disable-msg=W0221
|
||||
def write(self, img_array, cratios=None, eph=False, psnr=None, numres=None,
|
||||
cbsize=None, psizes=None, grid_offset=None, sop=False,
|
||||
subsam=None, tilesize=None, prog=None, modesw=None,
|
||||
|
|
@ -202,24 +221,24 @@ class Jp2k(Jp2kBox):
|
|||
>>> import glymur
|
||||
>>> jfile = glymur.data.nemo()
|
||||
>>> jp2 = glymur.Jp2k(jfile)
|
||||
>>> data = jp2.read(reduce=3)
|
||||
>>> data = jp2.read(rlevel=1)
|
||||
>>> from tempfile import NamedTemporaryFile
|
||||
>>> tfile = NamedTemporaryFile(suffix='.jp2', delete=False)
|
||||
>>> j = Jp2k(tfile.name, mode='wb')
|
||||
>>> j.write(data.astype(np.uint8))
|
||||
"""
|
||||
|
||||
cparams = opj2._set_default_encoder_parameters()
|
||||
cparams = _opj2.set_default_encoder_parameters()
|
||||
|
||||
outfile = self.filename.encode()
|
||||
n = opj2._PATH_LEN - len(outfile)
|
||||
outfile += b'0' * n
|
||||
num_pad_bytes = _opj2.PATH_LEN - len(outfile)
|
||||
outfile += b'0' * num_pad_bytes
|
||||
cparams.outfile = outfile
|
||||
|
||||
if self.filename[-4:].lower() == '.jp2':
|
||||
codec_fmt = opj2._CODEC_JP2
|
||||
codec_fmt = _opj2.CODEC_JP2
|
||||
else:
|
||||
codec_fmt = opj2._CODEC_J2K
|
||||
codec_fmt = _opj2.CODEC_J2K
|
||||
|
||||
cparams.cod_format = codec_fmt
|
||||
|
||||
|
|
@ -229,19 +248,19 @@ class Jp2k(Jp2kBox):
|
|||
cparams.cp_disto_alloc = 1
|
||||
|
||||
if cbsize is not None:
|
||||
w = cbsize[1]
|
||||
h = cbsize[0]
|
||||
if h * w > 4096 or h < 4 or w < 4:
|
||||
width = cbsize[1]
|
||||
height = cbsize[0]
|
||||
if height * width > 4096 or height < 4 or width < 4:
|
||||
msg = "Code block area cannot exceed 4096. "
|
||||
msg += "Code block height and width must be larger than 4."
|
||||
raise RuntimeError(msg)
|
||||
if ((math.log(h, 2) != math.floor(math.log(h, 2)) or
|
||||
math.log(w, 2) != math.floor(math.log(w, 2)))):
|
||||
if ((math.log(height, 2) != math.floor(math.log(height, 2)) or
|
||||
math.log(width, 2) != math.floor(math.log(width, 2)))):
|
||||
msg = "Bad code block size ({0}, {1}), "
|
||||
msg += "must be powers of 2."
|
||||
raise IOError(msg.format(h, w))
|
||||
cparams.cblockw_init = w
|
||||
cparams.cblockh_init = h
|
||||
raise IOError(msg.format(height, width))
|
||||
cparams.cblockw_init = width
|
||||
cparams.cblockh_init = height
|
||||
|
||||
if cratios is not None:
|
||||
cparams.tcp_numlayers = len(cratios)
|
||||
|
|
@ -257,16 +276,17 @@ class Jp2k(Jp2kBox):
|
|||
cparams.image_offset_y0 = grid_offset[0]
|
||||
|
||||
if modesw is not None:
|
||||
for x in range(6):
|
||||
if modesw & (1 << x):
|
||||
cparams.mode |= (1 << x)
|
||||
for shift in range(6):
|
||||
power_of_two = 1 << shift
|
||||
if modesw & power_of_two:
|
||||
cparams.mode |= power_of_two
|
||||
|
||||
if numres is not None:
|
||||
cparams.numresolution = numres
|
||||
|
||||
if prog is not None:
|
||||
prog = prog.upper()
|
||||
cparams.prog_order = progression_order[prog]
|
||||
cparams.prog_order = PROGRESSION_ORDER[prog]
|
||||
|
||||
if psnr is not None:
|
||||
cparams.tcp_numlayers = len(psnr)
|
||||
|
|
@ -303,7 +323,7 @@ class Jp2k(Jp2kBox):
|
|||
if tilesize is not None:
|
||||
cparams.cp_tdx = tilesize[1]
|
||||
cparams.cp_tdy = tilesize[0]
|
||||
cparams.tile_size_on = opj2._TRUE
|
||||
cparams.tile_size_on = _opj2.TRUE
|
||||
|
||||
if cratios is not None and psnr is not None:
|
||||
msg = "Cannot specify cratios and psnr together."
|
||||
|
|
@ -322,12 +342,12 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
if colorspace is None:
|
||||
if img_array.shape[2] == 1 or img_array.shape[2] == 2:
|
||||
colorspace = opj2._CLRSPC_GRAY
|
||||
colorspace = _opj2.CLRSPC_GRAY
|
||||
else:
|
||||
# No YCC unless specifically told to do so.
|
||||
colorspace = opj2._CLRSPC_SRGB
|
||||
colorspace = _opj2.CLRSPC_SRGB
|
||||
else:
|
||||
if codec_fmt == opj2._CODEC_J2K:
|
||||
if codec_fmt == _opj2.CODEC_J2K:
|
||||
raise IOError('Do not specify a colorspace with J2K.')
|
||||
colorspace = colorspace.lower()
|
||||
if colorspace not in ('rgb', 'grey', 'gray'):
|
||||
|
|
@ -337,15 +357,15 @@ class Jp2k(Jp2kBox):
|
|||
msg = 'RGB colorspace requires at least 3 components.'
|
||||
raise IOError(msg)
|
||||
else:
|
||||
colorspace = _cspace_map[colorspace]
|
||||
colorspace = _COLORSPACE_MAP[colorspace]
|
||||
|
||||
if mct is None:
|
||||
if colorspace == opj2._CLRSPC_SRGB:
|
||||
if colorspace == _opj2.CLRSPC_SRGB:
|
||||
cparams.tcp_mct = 1
|
||||
else:
|
||||
cparams.tcp_mct = 0
|
||||
else:
|
||||
if mct and colorspace == opj2._CLRSPC_GRAY:
|
||||
if mct and colorspace == _opj2.CLRSPC_GRAY:
|
||||
msg = "Cannot specify usage of the multi component transform "
|
||||
msg += "if the colorspace is gray."
|
||||
raise IOError(msg)
|
||||
|
|
@ -358,7 +378,7 @@ class Jp2k(Jp2kBox):
|
|||
else:
|
||||
raise RuntimeError("unhandled datatype")
|
||||
|
||||
comptparms = (opj2._image_comptparm_t * num_comps)()
|
||||
comptparms = (_opj2.ImageComptParmType * num_comps)()
|
||||
for j in range(num_comps):
|
||||
comptparms[j].dx = cparams.subsampling_dx
|
||||
comptparms[j].dy = cparams.subsampling_dy
|
||||
|
|
@ -370,7 +390,7 @@ class Jp2k(Jp2kBox):
|
|||
comptparms[j].bpp = comp_prec
|
||||
comptparms[j].sgnd = 0
|
||||
|
||||
image = opj2._image_create(comptparms, colorspace)
|
||||
image = _opj2.image_create(comptparms, colorspace)
|
||||
|
||||
# set image offset and reference grid
|
||||
image.contents.x0 = cparams.image_offset_x0
|
||||
|
|
@ -387,25 +407,25 @@ class Jp2k(Jp2kBox):
|
|||
src = layer.ctypes.data
|
||||
ctypes.memmove(dest, src, layer.nbytes)
|
||||
|
||||
codec = opj2._create_compress(codec_fmt)
|
||||
codec = _opj2.create_compress(codec_fmt)
|
||||
|
||||
if verbose:
|
||||
opj2._set_info_handler(codec, _info_callback)
|
||||
_opj2.set_info_handler(codec, _INFO_CALLBACK)
|
||||
else:
|
||||
opj2._set_info_handler(codec, None)
|
||||
_opj2.set_info_handler(codec, None)
|
||||
|
||||
opj2._set_warning_handler(codec, _warning_callback)
|
||||
opj2._set_error_handler(codec, _error_callback)
|
||||
opj2._setup_encoder(codec, cparams, image)
|
||||
strm = opj2._stream_create_default_file_stream_v3(self.filename, False)
|
||||
opj2._start_compress(codec, image, strm)
|
||||
opj2._encode(codec, strm)
|
||||
opj2._end_compress(codec, strm)
|
||||
opj2._stream_destroy_v3(strm)
|
||||
opj2._destroy_codec(codec)
|
||||
opj2._image_destroy(image)
|
||||
_opj2.set_warning_handler(codec, _WARNING_CALLBACK)
|
||||
_opj2.set_error_handler(codec, _ERROR_CALLBACK)
|
||||
_opj2.setup_encoder(codec, cparams, image)
|
||||
strm = _opj2.stream_create_default_file_stream_v3(self.filename, False)
|
||||
_opj2.start_compress(codec, image, strm)
|
||||
_opj2.encode(codec, strm)
|
||||
_opj2.end_compress(codec, strm)
|
||||
_opj2.stream_destroy_v3(strm)
|
||||
_opj2.destroy_codec(codec)
|
||||
_opj2.image_destroy(image)
|
||||
|
||||
self._parse()
|
||||
self.parse()
|
||||
|
||||
def wrap(self, filename, boxes=None):
|
||||
"""Write the codestream back out to file, wrapped in new JP2 jacket.
|
||||
|
|
@ -438,10 +458,10 @@ class Jp2k(Jp2kBox):
|
|||
FileTypeBox(),
|
||||
JP2HeaderBox(),
|
||||
ContiguousCodestreamBox()]
|
||||
c = self.get_codestream()
|
||||
height = c.segment[1].Ysiz
|
||||
width = c.segment[1].Xsiz
|
||||
num_components = len(c.segment[1].XRsiz)
|
||||
codestream = self.get_codestream()
|
||||
height = codestream.segment[1].ysiz
|
||||
width = codestream.segment[1].xsiz
|
||||
num_components = len(codestream.segment[1].xrsiz)
|
||||
boxes[2].box = [ImageHeaderBox(height=height,
|
||||
width=width,
|
||||
num_components=num_components),
|
||||
|
|
@ -449,15 +469,17 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
# Check for a bad sequence of boxes.
|
||||
# 1st two boxes must be 'jP ' and 'ftyp'
|
||||
if boxes[0].id != 'jP ' or boxes[1].id != 'ftyp':
|
||||
if boxes[0].box_id != 'jP ' or boxes[1].box_id != 'ftyp':
|
||||
msg = "The first box must be the signature box and the second "
|
||||
msg += "must be the file type box."
|
||||
raise IOError(msg)
|
||||
|
||||
# jp2c must be preceeded by jp2h
|
||||
jp2h_lst = [idx for (idx, box) in enumerate(boxes) if box.id == 'jp2h']
|
||||
jp2h_lst = [idx for (idx, box) in enumerate(boxes)
|
||||
if box.box_id == 'jp2h']
|
||||
jp2h_idx = jp2h_lst[0]
|
||||
jp2c_lst = [idx for (idx, box) in enumerate(boxes) if box.id == 'jp2c']
|
||||
jp2c_lst = [idx for (idx, box) in enumerate(boxes)
|
||||
if box.box_id == 'jp2c']
|
||||
if len(jp2c_lst) == 0:
|
||||
msg = "A codestream box must be defined in the outermost "
|
||||
msg += "list of boxes."
|
||||
|
|
@ -470,27 +492,28 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
# 1st jp2 header box must be ihdr
|
||||
jp2h = boxes[jp2h_idx]
|
||||
if jp2h.box[0].id != 'ihdr':
|
||||
if jp2h.box[0].box_id != 'ihdr':
|
||||
msg = "The first box in the jp2 header box must be the image "
|
||||
msg += "header box."
|
||||
raise IOError(msg)
|
||||
|
||||
# colr must be present in jp2 header box.
|
||||
jp2hb = jp2h.box
|
||||
colr_lst = [j for (j, box) in enumerate(jp2h.box) if box.id == 'colr']
|
||||
colr_lst = [j for (j, box) in enumerate(jp2h.box)
|
||||
if box.box_id == 'colr']
|
||||
if len(colr_lst) == 0:
|
||||
msg = "The jp2 header box must contain a color definition box."
|
||||
raise IOError(msg)
|
||||
colr = jp2h.box[colr_lst[0]]
|
||||
|
||||
# Any cdef box must be in the jp2 header following the image header.
|
||||
cdef_lst = [j for (j, box) in enumerate(boxes) if box.id == 'cdef']
|
||||
cdef_lst = [j for (j, box) in enumerate(boxes) if box.box_id == 'cdef']
|
||||
if len(cdef_lst) != 0:
|
||||
msg = "Any channel defintion box must be in the JP2 header "
|
||||
msg += "following the image header."
|
||||
raise IOError(msg)
|
||||
|
||||
cdef_lst = [j for (j, box) in enumerate(jp2h.box) if box.id == 'cdef']
|
||||
cdef_lst = [j for (j, box) in enumerate(jp2h.box)
|
||||
if box.box_id == 'cdef']
|
||||
if len(cdef_lst) > 1:
|
||||
msg = "Only one channel definition box is allowed in the "
|
||||
msg += "JP2 header."
|
||||
|
|
@ -499,7 +522,6 @@ class Jp2k(Jp2kBox):
|
|||
cdef = jp2h.box[cdef_lst[0]]
|
||||
assn = cdef.association
|
||||
typ = cdef.channel_type
|
||||
index = cdef.index
|
||||
if colr.colorspace == SRGB:
|
||||
if any([chan + 1 not in assn or typ[chan] != 0
|
||||
for chan in [0, 1, 2]]):
|
||||
|
|
@ -514,8 +536,8 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
with open(filename, 'wb') as ofile:
|
||||
for box in boxes:
|
||||
if box.id != 'jp2c':
|
||||
box._write(ofile)
|
||||
if box.box_id != 'jp2c':
|
||||
box.write(ofile)
|
||||
else:
|
||||
# The codestream gets written last.
|
||||
if len(self.box) == 0:
|
||||
|
|
@ -529,7 +551,8 @@ class Jp2k(Jp2kBox):
|
|||
else:
|
||||
# OK, I'm a jp2 file. Need to find out where the
|
||||
# raw codestream actually starts.
|
||||
jp2c = [box for box in self.box if box.id == 'jp2c']
|
||||
jp2c = [box for box in self.box
|
||||
if box.box_id == 'jp2c']
|
||||
jp2c = jp2c[0]
|
||||
ofile.write(struct.pack('>I', jp2c.length + 8))
|
||||
ofile.write('jp2c'.encode())
|
||||
|
|
@ -544,16 +567,17 @@ class Jp2k(Jp2kBox):
|
|||
jp2 = Jp2k(filename)
|
||||
return jp2
|
||||
|
||||
def read(self, reduce=0, layer=0, area=None, tile=None, verbose=False):
|
||||
def read(self, **kwargs):
|
||||
"""Read a JPEG 2000 image.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rlevel : int, optional
|
||||
Factor by which to rlevel output resolution. Use -1 to get the
|
||||
lowest resolution thumbnail. This is the only keyword option
|
||||
available to use when only OpenJPEG version 1.5.1 is present.
|
||||
layer : int, optional
|
||||
Number of quality layer to decode.
|
||||
reduce : int, optional
|
||||
Factor by which to reduce output resolution. Use -1 to get the
|
||||
lowest resolution thumbnail.
|
||||
area : tuple, optional
|
||||
Specifies decoding image area,
|
||||
(first_row, first_col, last_row, last_col)
|
||||
|
|
@ -583,19 +607,169 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
Read the lowest resolution thumbnail.
|
||||
|
||||
>>> thumbnail = jp.read(reduce=-1)
|
||||
>>> thumbnail = jp.read(rlevel=-1)
|
||||
>>> thumbnail.shape
|
||||
(46, 81, 3)
|
||||
(728, 1296, 3)
|
||||
"""
|
||||
if _opj2.OPENJP2 is not None:
|
||||
img = self._read_openjp2(**kwargs)
|
||||
else:
|
||||
img = self._read_openjpeg(**kwargs)
|
||||
return img
|
||||
|
||||
def _read_openjpeg(self, rlevel=0, verbose=False):
|
||||
"""Read a JPEG 2000 image using libopenjpeg.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rlevel : int, optional
|
||||
Factor by which to rlevel output resolution. Use -1 to get the
|
||||
lowest resolution thumbnail.
|
||||
verbose : bool, optional
|
||||
Print informational messages produced by the OpenJPEG library.
|
||||
|
||||
Returns
|
||||
-------
|
||||
img_array : ndarray
|
||||
The image data.
|
||||
|
||||
Raises
|
||||
------
|
||||
RuntimeError
|
||||
If the image has differing subsample factors.
|
||||
"""
|
||||
# Check for differing subsample factors.
|
||||
codestream = self.get_codestream(header_only=True)
|
||||
dxs = np.array(codestream.segment[1].XRsiz)
|
||||
dys = np.array(codestream.segment[1].YRsiz)
|
||||
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 with OpenJPEG 1.5.1. Please consider "
|
||||
msg += "using OPENJP2 instead."
|
||||
raise RuntimeError(msg)
|
||||
|
||||
with ExitStack() as stack:
|
||||
# Set decoding parameters.
|
||||
dparameters = _opj.DecompressionParametersType()
|
||||
_opj.set_default_decoder_parameters(ctypes.byref(dparameters))
|
||||
dparameters.cp_reduce = rlevel
|
||||
dparameters.decod_format = self._codec_format
|
||||
|
||||
infile = self.filename.encode()
|
||||
nelts = _opj.PATH_LEN - len(infile)
|
||||
infile += b'0' * nelts
|
||||
dparameters.infile = infile
|
||||
|
||||
dinfo = _opj.create_decompress(dparameters.decod_format)
|
||||
|
||||
event_mgr = _opj.EventMgrType()
|
||||
info_handler = ctypes.cast(_INFO_CALLBACK, ctypes.c_void_p)
|
||||
event_mgr.info_handler = info_handler if verbose else None
|
||||
event_mgr.warning_handler = ctypes.cast(_WARNING_CALLBACK,
|
||||
ctypes.c_void_p)
|
||||
event_mgr.error_handler = ctypes.cast(_ERROR_CALLBACK,
|
||||
ctypes.c_void_p)
|
||||
_opj.set_event_mgr(dinfo, ctypes.byref(event_mgr))
|
||||
|
||||
_opj.setup_decoder(dinfo, dparameters)
|
||||
|
||||
with open(self.filename, 'rb') as fptr:
|
||||
src = fptr.read()
|
||||
cio = _opj.cio_open(dinfo, src)
|
||||
|
||||
image = _opj.decode(dinfo, cio)
|
||||
|
||||
stack.callback(_opj.image_destroy, image)
|
||||
stack.callback(_opj.destroy_decompress, dinfo)
|
||||
stack.callback(_opj.cio_close, cio)
|
||||
|
||||
ncomps = image.contents.numcomps
|
||||
component = image.contents.comps[0]
|
||||
if component.sgnd:
|
||||
if component.prec <= 8:
|
||||
dtype = np.int8
|
||||
elif component.prec <= 16:
|
||||
dtype = np.int16
|
||||
else:
|
||||
raise RuntimeError("Unhandled precision, datatype")
|
||||
else:
|
||||
if component.prec <= 8:
|
||||
dtype = np.uint8
|
||||
elif component.prec <= 16:
|
||||
dtype = np.uint16
|
||||
else:
|
||||
raise RuntimeError("Unhandled precision, datatype")
|
||||
|
||||
nrows = image.contents.comps[0].h
|
||||
ncols = image.contents.comps[0].w
|
||||
ncomps = image.contents.numcomps
|
||||
data = np.zeros((nrows, ncols, ncomps), dtype)
|
||||
|
||||
for k in range(image.contents.numcomps):
|
||||
component = image.contents.comps[k]
|
||||
nrows = component.h
|
||||
ncols = component.w
|
||||
|
||||
if nrows == 0 or ncols == 0:
|
||||
# Letting this situation continue would segfault
|
||||
# Python.
|
||||
msg = "Component {0} has dimensions {1} x {2}"
|
||||
msg = msg.format(k, nrows, ncols)
|
||||
raise IOError(msg)
|
||||
|
||||
addr = ctypes.addressof(component.data.contents)
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
nelts = nrows * ncols
|
||||
band = np.ctypeslib.as_array(
|
||||
(ctypes.c_int32 * nelts).from_address(addr))
|
||||
data[:, :, k] = np.reshape(band.astype(dtype),
|
||||
(nrows, ncols))
|
||||
|
||||
if data.shape[2] == 1:
|
||||
data = data.view()
|
||||
data.shape = data.shape[0:2]
|
||||
|
||||
return data
|
||||
|
||||
def _read_openjp2(self, rlevel=0, layer=0, area=None, tile=None,
|
||||
verbose=False):
|
||||
"""Read a JPEG 2000 image using libopenjp2.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
layer : int, optional
|
||||
Number of quality layer to decode.
|
||||
rlevel : int, optional
|
||||
Factor by which to rlevel output resolution. Use -1 to get the
|
||||
lowest resolution thumbnail.
|
||||
area : tuple, optional
|
||||
Specifies decoding image area,
|
||||
(first_row, first_col, last_row, last_col)
|
||||
tile : int, optional
|
||||
Number of tile to decode.
|
||||
verbose : bool, optional
|
||||
Print informational messages produced by the OpenJPEG library.
|
||||
|
||||
Returns
|
||||
-------
|
||||
img_array : ndarray
|
||||
The image data.
|
||||
|
||||
Raises
|
||||
------
|
||||
RuntimeError
|
||||
If the image has differing subsample factors.
|
||||
"""
|
||||
# Check for differing subsample factors.
|
||||
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."
|
||||
raise IOError(msg)
|
||||
raise RuntimeError(msg)
|
||||
|
||||
img_array = self._read_common(reduce=reduce,
|
||||
img_array = self._read_common(rlevel=rlevel,
|
||||
layer=layer,
|
||||
area=area,
|
||||
tile=tile,
|
||||
|
|
@ -608,7 +782,7 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
return img_array
|
||||
|
||||
def _read_common(self, reduce=0, layer=0, area=None, tile=None,
|
||||
def _read_common(self, rlevel=0, layer=0, area=None, tile=None,
|
||||
verbose=False, as_bands=False):
|
||||
"""Read a JPEG 2000 image.
|
||||
|
||||
|
|
@ -616,8 +790,8 @@ class Jp2k(Jp2kBox):
|
|||
----------
|
||||
layer : int, optional
|
||||
Number of quality layer to decode.
|
||||
reduce : int, optional
|
||||
Factor by which to reduce output resolution.
|
||||
rlevel : int, optional
|
||||
Factor by which to rlevel output resolution.
|
||||
area : tuple, optional
|
||||
Specifies decoding image area,
|
||||
(first_row, first_col, last_row, last_col)
|
||||
|
|
@ -633,10 +807,10 @@ class Jp2k(Jp2kBox):
|
|||
img_array : ndarray
|
||||
The individual image components or a single array.
|
||||
"""
|
||||
dparam = opj2._set_default_decoder_parameters()
|
||||
dparam = _opj2.set_default_decoder_parameters()
|
||||
|
||||
infile = self.filename.encode()
|
||||
nelts = opj2._PATH_LEN - len(infile)
|
||||
nelts = _opj2.PATH_LEN - len(infile)
|
||||
infile += b'0' * nelts
|
||||
dparam.infile = infile
|
||||
|
||||
|
|
@ -644,12 +818,12 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
dparam.cp_layer = layer
|
||||
|
||||
if reduce == -1:
|
||||
if rlevel == -1:
|
||||
# Get the lowest resolution thumbnail.
|
||||
codestream = self.get_codestream()
|
||||
reduce = codestream.segment[2].SPcod[4]
|
||||
rlevel = codestream.segment[2].spcod[4]
|
||||
|
||||
dparam.cp_reduce = reduce
|
||||
dparam.cp_reduce = rlevel
|
||||
if area is not None:
|
||||
if area[0] < 0 or area[1] < 0:
|
||||
msg = "Upper left corner coordinates must be nonnegative: {0}"
|
||||
|
|
@ -669,31 +843,31 @@ class Jp2k(Jp2kBox):
|
|||
dparam.nb_tile_to_decode = 1
|
||||
|
||||
with ExitStack() as stack:
|
||||
stream = opj2._stream_create_default_file_stream_v3(self.filename,
|
||||
stream = _opj2.stream_create_default_file_stream_v3(self.filename,
|
||||
True)
|
||||
stack.callback(opj2._stream_destroy_v3, stream)
|
||||
codec = opj2._create_decompress(self._codec_format)
|
||||
stack.callback(opj2._destroy_codec, codec)
|
||||
stack.callback(_opj2.stream_destroy_v3, stream)
|
||||
codec = _opj2.create_decompress(self._codec_format)
|
||||
stack.callback(_opj2.destroy_codec, codec)
|
||||
|
||||
opj2._set_error_handler(codec, _error_callback)
|
||||
opj2._set_warning_handler(codec, _warning_callback)
|
||||
_opj2.set_error_handler(codec, _ERROR_CALLBACK)
|
||||
_opj2.set_warning_handler(codec, _WARNING_CALLBACK)
|
||||
if verbose:
|
||||
opj2._set_info_handler(codec, _info_callback)
|
||||
_opj2.set_info_handler(codec, _INFO_CALLBACK)
|
||||
else:
|
||||
opj2._set_info_handler(codec, None)
|
||||
_opj2.set_info_handler(codec, None)
|
||||
|
||||
opj2._setup_decoder(codec, dparam)
|
||||
image = opj2._read_header(stream, codec)
|
||||
stack.callback(opj2._image_destroy, image)
|
||||
_opj2.setup_decoder(codec, dparam)
|
||||
image = _opj2.read_header(stream, codec)
|
||||
stack.callback(_opj2.image_destroy, image)
|
||||
|
||||
if dparam.nb_tile_to_decode:
|
||||
opj2._get_decoded_tile(codec, stream, image, dparam.tile_index)
|
||||
_opj2.get_decoded_tile(codec, stream, image, dparam.tile_index)
|
||||
else:
|
||||
opj2._set_decode_area(codec, image,
|
||||
_opj2.set_decode_area(codec, image,
|
||||
dparam.DA_x0, dparam.DA_y0,
|
||||
dparam.DA_x1, dparam.DA_y1)
|
||||
opj2._decode(codec, stream, image)
|
||||
opj2._end_decompress(codec, stream)
|
||||
_opj2.decode(codec, stream, image)
|
||||
_opj2.end_decompress(codec, stream)
|
||||
|
||||
component = image.contents.comps[0]
|
||||
if component.sgnd:
|
||||
|
|
@ -734,16 +908,17 @@ class Jp2k(Jp2kBox):
|
|||
addr = ctypes.addressof(component.data.contents)
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
x = np.ctypeslib.as_array(
|
||||
band = np.ctypeslib.as_array(
|
||||
(ctypes.c_int32 * nrows * ncols).from_address(addr))
|
||||
if as_bands:
|
||||
data.append(np.reshape(x.astype(dtype), (nrows, ncols)))
|
||||
data.append(np.reshape(band.astype(dtype), (nrows, ncols)))
|
||||
else:
|
||||
data[:, :, k] = np.reshape(x.astype(dtype), (nrows, ncols))
|
||||
data[:, :, k] = np.reshape(band.astype(dtype),
|
||||
(nrows, ncols))
|
||||
|
||||
return data
|
||||
|
||||
def read_bands(self, reduce=0, layer=0, area=None, tile=None,
|
||||
def read_bands(self, rlevel=0, layer=0, area=None, tile=None,
|
||||
verbose=False):
|
||||
"""Read a JPEG 2000 image.
|
||||
|
||||
|
|
@ -755,8 +930,8 @@ class Jp2k(Jp2kBox):
|
|||
----------
|
||||
layer : int, optional
|
||||
Number of quality layer to decode.
|
||||
reduce : int, optional
|
||||
Factor by which to reduce output resolution.
|
||||
rlevel : int, optional
|
||||
Factor by which to rlevel output resolution.
|
||||
area : tuple, optional
|
||||
Specifies decoding image area,
|
||||
(first_row, first_col, last_row, last_col)
|
||||
|
|
@ -779,9 +954,18 @@ class Jp2k(Jp2kBox):
|
|||
>>> import glymur
|
||||
>>> jfile = glymur.data.nemo()
|
||||
>>> jp = glymur.Jp2k(jfile)
|
||||
>>> components_lst = jp.read_bands(reduce=1)
|
||||
>>> components_lst = jp.read_bands(rlevel=1)
|
||||
|
||||
Raises
|
||||
------
|
||||
NotImplementedError
|
||||
If the openjp2 library is not available.
|
||||
"""
|
||||
lst = self._read_common(reduce=reduce,
|
||||
if _opj2.OPENJP2 is None:
|
||||
msg = "Requires openjp2 library."
|
||||
raise NotImplementedError(msg)
|
||||
|
||||
lst = self._read_common(rlevel=rlevel,
|
||||
layer=layer,
|
||||
area=area,
|
||||
tile=tile,
|
||||
|
|
@ -807,14 +991,14 @@ class Jp2k(Jp2kBox):
|
|||
--------
|
||||
>>> import glymur
|
||||
>>> jfile = glymur.data.nemo()
|
||||
>>> jp = glymur.Jp2k(jfile)
|
||||
>>> codestream = jp.get_codestream()
|
||||
>>> jp2 = glymur.Jp2k(jfile)
|
||||
>>> codestream = jp2.get_codestream()
|
||||
>>> print(codestream.segment[1])
|
||||
SIZ marker segment @ (3137, 47)
|
||||
Profile: 2
|
||||
Reference Grid Height, Width: (1456 x 2592)
|
||||
Vertical, Horizontal Reference Grid Offset: (0 x 0)
|
||||
Reference Tile Height, Width: (512 x 512)
|
||||
Reference Tile Height, Width: (1456 x 2592)
|
||||
Vertical, Horizontal Reference Tile Offset: (0 x 0)
|
||||
Bitdepth: (8, 8, 8)
|
||||
Signed: (False, False, False)
|
||||
|
|
@ -825,20 +1009,20 @@ class Jp2k(Jp2kBox):
|
|||
IOError
|
||||
If the file is JPX with more than one codestream.
|
||||
"""
|
||||
with open(self.filename, 'rb') as fp:
|
||||
if self._codec_format == opj2._CODEC_J2K:
|
||||
codestream = Codestream(fp, header_only=header_only)
|
||||
with open(self.filename, 'rb') as fptr:
|
||||
if self._codec_format == _opj2.CODEC_J2K:
|
||||
codestream = Codestream(fptr, header_only=header_only)
|
||||
else:
|
||||
box = [x for x in self.box if x.id == 'jp2c']
|
||||
box = [x for x in self.box if x.box_id == 'jp2c']
|
||||
if len(box) != 1:
|
||||
msg = "JP2 files must have a single codestream."
|
||||
raise RuntimeError(msg)
|
||||
fp.seek(box[0].offset)
|
||||
buffer = fp.read(8)
|
||||
(L, T) = struct.unpack('>I4s', buffer)
|
||||
if L == 1:
|
||||
fptr.seek(box[0].offset)
|
||||
read_buffer = fptr.read(8)
|
||||
(box_length, _) = struct.unpack('>I4s', read_buffer)
|
||||
if box_length == 1:
|
||||
# Seek past the XL field.
|
||||
buffer = fp.read(8)
|
||||
codestream = Codestream(fp, header_only=header_only)
|
||||
read_buffer = fptr.read(8)
|
||||
codestream = Codestream(fptr, header_only=header_only)
|
||||
|
||||
return codestream
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
"""This package organizes individual libraries employed by glymur."""
|
||||
from . import openjp2
|
||||
from . import test
|
||||
from . import openjp2 as _openjp2
|
||||
from . import openjpeg as _openjpeg
|
||||
#from . import test
|
||||
|
|
|
|||
153
glymur/lib/config.py
Normal file
153
glymur/lib/config.py
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
"""
|
||||
Configure glymur to use installed libraries if possible.
|
||||
"""
|
||||
import ctypes
|
||||
from ctypes.util import find_library
|
||||
import os
|
||||
import platform
|
||||
import warnings
|
||||
|
||||
import sys
|
||||
if sys.hexversion <= 0x03000000:
|
||||
from ConfigParser import SafeConfigParser as ConfigParser
|
||||
from ConfigParser import NoOptionError
|
||||
else:
|
||||
from configparser import ConfigParser
|
||||
from configparser import NoOptionError
|
||||
|
||||
|
||||
def glymurrc_fname():
|
||||
"""Return the path to the configuration file.
|
||||
|
||||
Search order:
|
||||
1) current working directory
|
||||
2) environ var XDG_CONFIG_HOME
|
||||
3) $HOME/.config/glymur/glymurrc
|
||||
"""
|
||||
|
||||
# Current directory.
|
||||
fname = os.path.join(os.getcwd(), 'glymurrc')
|
||||
if os.path.exists(fname):
|
||||
return fname
|
||||
|
||||
confdir = get_configdir()
|
||||
if confdir is not None:
|
||||
fname = os.path.join(confdir, 'glymurrc')
|
||||
if os.path.exists(fname):
|
||||
return fname
|
||||
|
||||
# didn't find a configuration file.
|
||||
return None
|
||||
|
||||
|
||||
def load_openjpeg(libopenjpeg_path):
|
||||
"""Load the openjpeg library, falling back on defaults if necessary.
|
||||
"""
|
||||
if libopenjpeg_path is None:
|
||||
# Let ctypes try to find it.
|
||||
libopenjpeg_path = find_library('openjpeg')
|
||||
|
||||
# If we could not find it, then look in some likely locations.
|
||||
if libopenjpeg_path is None:
|
||||
if platform.system() == 'Darwin':
|
||||
path = '/opt/local/lib/libopenjpeg.dylib'
|
||||
if os.path.exists(path):
|
||||
libopenjpeg_path = path
|
||||
elif os.name == 'nt':
|
||||
path = os.path.join('C:\\', 'Program files', 'OpenJPEG 1.5',
|
||||
'bin', 'openjpeg.dll')
|
||||
if os.path.exists(path):
|
||||
libopenjpeg_path = path
|
||||
|
||||
try:
|
||||
if os.name == "nt":
|
||||
openjpeg_lib = ctypes.windll.LoadLibrary(libopenjpeg_path)
|
||||
else:
|
||||
openjpeg_lib = ctypes.CDLL(libopenjpeg_path)
|
||||
except OSError:
|
||||
openjpeg_lib = None
|
||||
|
||||
if openjpeg_lib is not None:
|
||||
# Must be at least 1.5.0
|
||||
openjpeg_lib.opj_version.restype = ctypes.c_char_p
|
||||
version = openjpeg_lib.opj_version().decode('utf-8')
|
||||
_, minor, _ = version.split('.')
|
||||
if minor != '5':
|
||||
openjpeg_lib = None
|
||||
return openjpeg_lib
|
||||
|
||||
|
||||
def read_config_file():
|
||||
"""
|
||||
We expect to not find openjp2 on the system path since the only version
|
||||
that we currently care about is still in the svn trunk at openjpeg.org.
|
||||
We must use a configuration file that the user must write.
|
||||
"""
|
||||
lib = {'openjp2': None, 'openjpeg': None}
|
||||
filename = glymurrc_fname()
|
||||
if filename is not None:
|
||||
# Read the configuration file for the library location.
|
||||
parser = ConfigParser()
|
||||
parser.read(filename)
|
||||
try:
|
||||
lib['openjp2'] = parser.get('library', 'openjp2')
|
||||
except NoOptionError:
|
||||
pass
|
||||
try:
|
||||
lib['openjpeg'] = parser.get('library', 'openjpeg')
|
||||
except NoOptionError:
|
||||
pass
|
||||
|
||||
return lib
|
||||
|
||||
|
||||
def load_openjp2(libopenjp2_path):
|
||||
"""Load the openjp2 library, falling back on defaults if necessary.
|
||||
"""
|
||||
if libopenjp2_path is None:
|
||||
# No help from the config file, try to find it ourselves.
|
||||
libopenjp2_path = find_library('openjp2')
|
||||
|
||||
if libopenjp2_path is None:
|
||||
return None
|
||||
|
||||
try:
|
||||
if os.name == "nt":
|
||||
openjp2_lib = ctypes.windll.LoadLibrary(libopenjp2_path)
|
||||
else:
|
||||
openjp2_lib = ctypes.CDLL(libopenjp2_path)
|
||||
except (TypeError, OSError):
|
||||
msg = '"Library {0}" could not be loaded. Operating in degraded mode.'
|
||||
msg = msg.format(libopenjp2_path)
|
||||
warnings.warn(msg, UserWarning)
|
||||
openjp2_lib = None
|
||||
|
||||
return openjp2_lib
|
||||
|
||||
|
||||
def glymur_config():
|
||||
"""Try to ascertain locations of openjp2, openjpeg libraries.
|
||||
"""
|
||||
libs = read_config_file()
|
||||
libopenjp2_handle = load_openjp2(libs['openjp2'])
|
||||
libopenjpeg_handle = load_openjpeg(libs['openjpeg'])
|
||||
return libopenjp2_handle, libopenjpeg_handle
|
||||
|
||||
|
||||
def get_configdir():
|
||||
"""Return string representing the configuration directory.
|
||||
|
||||
Default is $HOME/.config/glymur. You can override this with the
|
||||
XDG_CONFIG_HOME environment variable.
|
||||
"""
|
||||
|
||||
if 'XDG_CONFIG_HOME' in os.environ:
|
||||
return os.path.join(os.environ['XDG_CONFIG_HOME'], 'glymur')
|
||||
|
||||
if 'HOME' in os.environ:
|
||||
return os.path.join(os.environ['HOME'], '.config', 'glymur')
|
||||
|
||||
if 'USERPROFILE' in os.environ:
|
||||
# Windows?
|
||||
return os.path.join(os.environ['USERPROFILE'], 'Application Data',
|
||||
'glymur')
|
||||
File diff suppressed because it is too large
Load diff
213
glymur/lib/openjpeg.py
Normal file
213
glymur/lib/openjpeg.py
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
"""Wraps library calls to openjpeg.
|
||||
"""
|
||||
|
||||
# pylint: disable=R0903
|
||||
|
||||
import ctypes
|
||||
|
||||
from .config import glymur_config
|
||||
_, OPENJPEG = glymur_config()
|
||||
|
||||
PATH_LEN = 4096 # maximum allowed size for filenames
|
||||
|
||||
|
||||
class EventMgrType(ctypes.Structure):
|
||||
"""Message handler object.
|
||||
|
||||
Corresponds to event_mgr_t type in openjpeg headers.
|
||||
"""
|
||||
_fields_ = [("error_handler", ctypes.c_void_p),
|
||||
("warning_handler", ctypes.c_void_p),
|
||||
("info_handler", ctypes.c_void_p)]
|
||||
|
||||
|
||||
class CommonStructType(ctypes.Structure):
|
||||
"""Common fields between JPEG 2000 compression and decompression contextx.
|
||||
"""
|
||||
_fields_ = [("event_mgr", ctypes.POINTER(EventMgrType)),
|
||||
("client_data", ctypes.c_void_p),
|
||||
("is_decompressor", ctypes.c_bool),
|
||||
("codec_format", ctypes.c_int),
|
||||
("j2k_handle", ctypes.c_void_p),
|
||||
("jp2_handle", ctypes.c_void_p),
|
||||
("mj2_handle", ctypes.c_void_p)]
|
||||
|
||||
|
||||
class DecompressionInfoType(ctypes.Structure):
|
||||
"""This is for decompression contexts.
|
||||
|
||||
Corresponds to dinfo_t type in openjpeg headers.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class CioType(ctypes.Structure):
|
||||
"""Byte input-output stream (CIO)
|
||||
|
||||
Corresponds to cio_t in openjpeg headers.
|
||||
"""
|
||||
_fields_ = [("cinfo", ctypes.POINTER(CommonStructType)), # codec context
|
||||
# STREAM_READ or STREAM_WRITE
|
||||
("openmode", ctypes.c_int),
|
||||
# pointer to start of buffer
|
||||
("buffer", ctypes.POINTER(ctypes.c_char)),
|
||||
# buffer size in bytes
|
||||
("length", ctypes.c_int),
|
||||
# pointer to start of stream
|
||||
("start", ctypes.c_char_p),
|
||||
# pointer to end of stream
|
||||
("end", ctypes.c_char_p),
|
||||
# pointer to current position
|
||||
("bp", ctypes.c_char_p)]
|
||||
|
||||
|
||||
class DecompressionParametersType(ctypes.Structure):
|
||||
"""Decompression parameters.
|
||||
|
||||
Corresponds to dparameters_t type in openjpeg headers.
|
||||
"""
|
||||
# cp_reduce: the number of highest resolution levels to be discarded
|
||||
_fields_ = [("cp_reduce", ctypes.c_int),
|
||||
# cp_layer: the maximum number of quality layers to decode
|
||||
("cp_layer", ctypes.c_int),
|
||||
# infile: input file name
|
||||
("infile", ctypes.c_char * PATH_LEN),
|
||||
# outfile: output file name
|
||||
("outfile", ctypes.c_char * PATH_LEN),
|
||||
# decod_format: input file format 0: J2K, 1: JP2, 2: JPT
|
||||
("decod_format", ctypes.c_int),
|
||||
# cod_format: output file format 0: PGX, 1: PxM, 2: BMP
|
||||
("cod_format", ctypes.c_int),
|
||||
# jpwl_correct: activates the JPWL correction capabilities
|
||||
("jpwl_correct", ctypes.c_bool),
|
||||
# jpwl_exp_comps: expected number of components
|
||||
("jpwl_exp_comps", ctypes.c_int),
|
||||
# jpwl_max_tiles: maximum number of tiles
|
||||
("jpwl_max_tiles", ctypes.c_int),
|
||||
# cp_limit_decoding: whether decoding should be done on the
|
||||
# entire codestream or be limited to the main header
|
||||
("cp_limit_decoding", ctypes.c_int),
|
||||
("flags", ctypes.c_uint)]
|
||||
|
||||
|
||||
class ImageCompType(ctypes.Structure):
|
||||
"""Defines a single image component.
|
||||
|
||||
Corresponds to image_comp_t type in openjpeg.
|
||||
"""
|
||||
_fields_ = [("dx", ctypes.c_int),
|
||||
("dy", ctypes.c_int),
|
||||
("w", ctypes.c_int),
|
||||
("h", ctypes.c_int),
|
||||
("x0", ctypes.c_int),
|
||||
("y0", ctypes.c_int),
|
||||
("prec", ctypes.c_int),
|
||||
("bpp", ctypes.c_int),
|
||||
("sgnd", ctypes.c_int),
|
||||
("resno_decoded", ctypes.c_int),
|
||||
("factor", ctypes.c_int),
|
||||
("data", ctypes.POINTER(ctypes.c_int))]
|
||||
|
||||
|
||||
class ImageType(ctypes.Structure):
|
||||
"""Defines image data and characteristics.
|
||||
|
||||
Corresponds to image_t type in openjpeg headers.
|
||||
"""
|
||||
_fields_ = [("x0", ctypes.c_int),
|
||||
("y0", ctypes.c_int),
|
||||
("x1", ctypes.c_int),
|
||||
("y1", ctypes.c_int),
|
||||
("numcomps", ctypes.c_int),
|
||||
("color_space", ctypes.c_int),
|
||||
("comps", ctypes.POINTER(ImageCompType)),
|
||||
("icc_profile_buf", ctypes.c_char_p),
|
||||
("icc_profile_len", ctypes.c_int)]
|
||||
|
||||
|
||||
def cio_open(cinfo, src):
|
||||
"""Wrapper for openjpeg library function opj_cio_open."""
|
||||
argtypes = [ctypes.POINTER(CommonStructType), ctypes.c_char_p,
|
||||
ctypes.c_int]
|
||||
OPENJPEG.opj_cio_open.argtypes = argtypes
|
||||
OPENJPEG.opj_cio_open.restype = ctypes.POINTER(CioType)
|
||||
|
||||
cio = OPENJPEG.opj_cio_open(ctypes.cast(cinfo,
|
||||
ctypes.POINTER(CommonStructType)),
|
||||
src, len(src))
|
||||
return cio
|
||||
|
||||
|
||||
def cio_close(cio):
|
||||
"""Wraps openjpeg library function cio_close.
|
||||
"""
|
||||
OPENJPEG.opj_cio_close.argtypes = [ctypes.POINTER(CioType)]
|
||||
OPENJPEG.opj_cio_close(cio)
|
||||
|
||||
|
||||
def create_decompress(fmt):
|
||||
"""Wraps openjpeg library function opj_create_decompress.
|
||||
"""
|
||||
OPENJPEG.opj_create_decompress.argtypes = [ctypes.c_int]
|
||||
restype = ctypes.POINTER(DecompressionInfoType)
|
||||
OPENJPEG.opj_create_decompress.restype = restype
|
||||
dinfo = OPENJPEG.opj_create_decompress(fmt)
|
||||
return dinfo
|
||||
|
||||
|
||||
def decode(dinfo, cio):
|
||||
"""Wrapper for opj_decode.
|
||||
"""
|
||||
argtypes = [ctypes.POINTER(DecompressionInfoType), ctypes.POINTER(CioType)]
|
||||
OPENJPEG.opj_decode.argtypes = argtypes
|
||||
OPENJPEG.opj_decode.restype = ctypes.POINTER(ImageType)
|
||||
image = OPENJPEG.opj_decode(dinfo, cio)
|
||||
return image
|
||||
|
||||
|
||||
def destroy_decompress(dinfo):
|
||||
"""Wraps openjpeg library function opj_destroy_decompress."""
|
||||
argtypes = [ctypes.POINTER(DecompressionInfoType)]
|
||||
OPENJPEG.opj_destroy_decompress.argtypes = argtypes
|
||||
OPENJPEG.opj_destroy_decompress(dinfo)
|
||||
|
||||
|
||||
def image_destroy(image):
|
||||
"""Wraps openjpeg library function opj_image_destroy."""
|
||||
OPENJPEG.opj_image_destroy.argtypes = [ctypes.POINTER(ImageType)]
|
||||
OPENJPEG.opj_image_destroy(image)
|
||||
|
||||
|
||||
def set_default_decoder_parameters(dparams_p):
|
||||
"""Wrapper for opj_set_default_decoder_parameters.
|
||||
"""
|
||||
argtypes = [ctypes.POINTER(DecompressionParametersType)]
|
||||
OPENJPEG.opj_set_default_decoder_parameters.argtypes = argtypes
|
||||
OPENJPEG.opj_set_default_decoder_parameters(dparams_p)
|
||||
|
||||
|
||||
def set_event_mgr(dinfo, event_mgr, context=None):
|
||||
"""Wrapper for openjpeg library function opj_set_event_mgr.
|
||||
"""
|
||||
argtypes = [ctypes.POINTER(CommonStructType),
|
||||
ctypes.POINTER(EventMgrType),
|
||||
ctypes.c_void_p]
|
||||
OPENJPEG.opj_set_event_mgr.argtypes = argtypes
|
||||
OPENJPEG.opj_set_event_mgr(ctypes.cast(dinfo,
|
||||
ctypes.POINTER(CommonStructType)),
|
||||
event_mgr, context)
|
||||
|
||||
|
||||
def setup_decoder(dinfo, dparams):
|
||||
"""Wrapper for openjpeg library function opj_setup_decoder."""
|
||||
argtypes = [ctypes.POINTER(DecompressionInfoType),
|
||||
ctypes.POINTER(DecompressionParametersType)]
|
||||
OPENJPEG.opj_setup_decoder.argtypes = argtypes
|
||||
OPENJPEG.opj_setup_decoder(dinfo, dparams)
|
||||
|
||||
|
||||
def version():
|
||||
"""Wrapper for opj_version library routine."""
|
||||
OPENJPEG.opj_version.restype = ctypes.c_char_p
|
||||
library_version = OPENJPEG.opj_version()
|
||||
return library_version.decode('utf-8')
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
#pylint: disable-all
|
||||
import doctest
|
||||
import os
|
||||
import pkg_resources
|
||||
|
|
@ -12,13 +13,8 @@ import numpy as np
|
|||
import glymur
|
||||
|
||||
|
||||
def load_tests(loader, tests, ignore):
|
||||
if glymur.lib.openjp2._OPENJP2 is not None:
|
||||
tests.addTests(doctest.DocTestSuite('glymur.lib.openjp2'))
|
||||
return tests
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjp2._OPENJP2 is None,
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
@unittest.skipIf(glymur.lib._openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestOpenJP2(unittest.TestCase):
|
||||
|
||||
|
|
@ -29,7 +25,7 @@ class TestOpenJP2(unittest.TestCase):
|
|||
pass
|
||||
|
||||
def test_set_default_encoder_parameters(self):
|
||||
cparams = glymur.lib.openjp2._set_default_encoder_parameters()
|
||||
cparams = glymur.lib._openjp2.set_default_encoder_parameters()
|
||||
|
||||
self.assertEqual(cparams.res_spec, 0)
|
||||
self.assertEqual(cparams.cblockw_init, 64)
|
||||
|
|
@ -38,7 +34,7 @@ class TestOpenJP2(unittest.TestCase):
|
|||
self.assertEqual(cparams.subsampling_dx, 1)
|
||||
self.assertEqual(cparams.subsampling_dy, 1)
|
||||
self.assertEqual(cparams.mode, 0)
|
||||
self.assertEqual(cparams.prog_order, glymur.lib.openjp2.LRCP)
|
||||
self.assertEqual(cparams.prog_order, glymur.core.LRCP)
|
||||
self.assertEqual(cparams.roi_shift, 0)
|
||||
self.assertEqual(cparams.cp_tx0, 0)
|
||||
self.assertEqual(cparams.cp_ty0, 0)
|
||||
|
|
@ -46,7 +42,7 @@ class TestOpenJP2(unittest.TestCase):
|
|||
self.assertEqual(cparams.irreversible, 0)
|
||||
|
||||
def test_set_default_decoder_parameters(self):
|
||||
dparams = glymur.lib.openjp2._set_default_decoder_parameters()
|
||||
dparams = glymur.lib._openjp2.set_default_decoder_parameters()
|
||||
|
||||
self.assertEqual(dparams.DA_x0, 0)
|
||||
self.assertEqual(dparams.DA_y0, 0)
|
||||
|
|
@ -55,34 +51,34 @@ class TestOpenJP2(unittest.TestCase):
|
|||
|
||||
def tile_macro(self, codec, stream, imagep, tidx):
|
||||
# called only by j2k_random_tile_access
|
||||
glymur.lib.openjp2._get_decoded_tile(codec, stream, imagep, tidx)
|
||||
glymur.lib._openjp2.get_decoded_tile(codec, stream, imagep, tidx)
|
||||
for j in range(imagep.contents.numcomps):
|
||||
self.assertIsNotNone(imagep.contents.comps[j].data)
|
||||
|
||||
def j2k_random_tile_access(self, filename, codec_format=None):
|
||||
# called by the test_rtaX methods
|
||||
dparam = glymur.lib.openjp2._set_default_decoder_parameters()
|
||||
dparam = glymur.lib._openjp2.set_default_decoder_parameters()
|
||||
|
||||
infile = filename.encode()
|
||||
nelts = glymur.lib.openjp2._PATH_LEN - len(infile)
|
||||
nelts = glymur.lib._openjp2.PATH_LEN - len(infile)
|
||||
infile += b'0' * nelts
|
||||
dparam.infile = infile
|
||||
|
||||
dparam.decod_format = codec_format
|
||||
|
||||
codec = glymur.lib.openjp2._create_decompress(codec_format)
|
||||
codec = glymur.lib._openjp2.create_decompress(codec_format)
|
||||
|
||||
glymur.lib.openjp2._set_info_handler(codec, None)
|
||||
glymur.lib.openjp2._set_warning_handler(codec, None)
|
||||
glymur.lib.openjp2._set_error_handler(codec, None)
|
||||
glymur.lib._openjp2.set_info_handler(codec, None)
|
||||
glymur.lib._openjp2.set_warning_handler(codec, None)
|
||||
glymur.lib._openjp2.set_error_handler(codec, None)
|
||||
|
||||
x = (filename, True)
|
||||
stream = glymur.lib.openjp2._stream_create_default_file_stream_v3(*x)
|
||||
stream = glymur.lib._openjp2.stream_create_default_file_stream_v3(*x)
|
||||
|
||||
glymur.lib.openjp2._setup_decoder(codec, dparam)
|
||||
image = glymur.lib.openjp2._read_header(stream, codec)
|
||||
glymur.lib._openjp2.setup_decoder(codec, dparam)
|
||||
image = glymur.lib._openjp2.read_header(stream, codec)
|
||||
|
||||
cstr_info = glymur.lib.openjp2._get_cstr_info(codec)
|
||||
cstr_info = glymur.lib._openjp2.get_cstr_info(codec)
|
||||
|
||||
tile_ul = 0
|
||||
tile_ur = cstr_info.contents.tw - 1
|
||||
|
|
@ -94,18 +90,18 @@ class TestOpenJP2(unittest.TestCase):
|
|||
self.tile_macro(codec, stream, image, tile_lr)
|
||||
self.tile_macro(codec, stream, image, tile_ll)
|
||||
|
||||
glymur.lib.openjp2._destroy_cstr_info(cstr_info)
|
||||
glymur.lib._openjp2.destroy_cstr_info(cstr_info)
|
||||
|
||||
glymur.lib.openjp2._end_decompress(codec, stream)
|
||||
glymur.lib.openjp2._destroy_codec(codec)
|
||||
glymur.lib.openjp2._stream_destroy_v3(stream)
|
||||
glymur.lib.openjp2._image_destroy(image)
|
||||
glymur.lib._openjp2.end_decompress(codec, stream)
|
||||
glymur.lib._openjp2.destroy_codec(codec)
|
||||
glymur.lib._openjp2.stream_destroy_v3(stream)
|
||||
glymur.lib._openjp2.image_destroy(image)
|
||||
|
||||
def tile_decoder(self, x0=None, y0=None, x1=None, y1=None, filename=None,
|
||||
codec_format=None):
|
||||
x = (filename, True)
|
||||
stream = glymur.lib.openjp2._stream_create_default_file_stream_v3(*x)
|
||||
dparam = glymur.lib.openjp2._set_default_decoder_parameters()
|
||||
stream = glymur.lib._openjp2.stream_create_default_file_stream_v3(*x)
|
||||
dparam = glymur.lib._openjp2.set_default_decoder_parameters()
|
||||
|
||||
dparam.decod_format = codec_format
|
||||
|
||||
|
|
@ -115,30 +111,30 @@ class TestOpenJP2(unittest.TestCase):
|
|||
# do not use resolution reductions.
|
||||
dparam.cp_reduce = 0
|
||||
|
||||
codec = glymur.lib.openjp2._create_decompress(codec_format)
|
||||
codec = glymur.lib._openjp2.create_decompress(codec_format)
|
||||
|
||||
glymur.lib.openjp2._set_info_handler(codec, None)
|
||||
glymur.lib.openjp2._set_warning_handler(codec, None)
|
||||
glymur.lib.openjp2._set_error_handler(codec, None)
|
||||
glymur.lib._openjp2.set_info_handler(codec, None)
|
||||
glymur.lib._openjp2.set_warning_handler(codec, None)
|
||||
glymur.lib._openjp2.set_error_handler(codec, None)
|
||||
|
||||
glymur.lib.openjp2._setup_decoder(codec, dparam)
|
||||
image = glymur.lib.openjp2._read_header(stream, codec)
|
||||
glymur.lib.openjp2._set_decode_area(codec, image, x0, y0, x1, y1)
|
||||
glymur.lib._openjp2.setup_decoder(codec, dparam)
|
||||
image = glymur.lib._openjp2.read_header(stream, codec)
|
||||
glymur.lib._openjp2.set_decode_area(codec, image, x0, y0, x1, y1)
|
||||
|
||||
data = np.zeros((1150, 2048, 3), dtype=np.uint8)
|
||||
while True:
|
||||
rargs = glymur.lib.openjp2._read_tile_header(codec, stream)
|
||||
rargs = glymur.lib._openjp2.read_tile_header(codec, stream)
|
||||
tidx = rargs[0]
|
||||
sz = rargs[1]
|
||||
go_on = rargs[-1]
|
||||
if not go_on:
|
||||
break
|
||||
glymur.lib.openjp2._decode_tile_data(codec, tidx, data, sz, stream)
|
||||
glymur.lib._openjp2.decode_tile_data(codec, tidx, data, sz, stream)
|
||||
|
||||
glymur.lib.openjp2._end_decompress(codec, stream)
|
||||
glymur.lib.openjp2._destroy_codec(codec)
|
||||
glymur.lib.openjp2._stream_destroy_v3(stream)
|
||||
glymur.lib.openjp2._image_destroy(image)
|
||||
glymur.lib._openjp2.end_decompress(codec, stream)
|
||||
glymur.lib._openjp2.destroy_codec(codec)
|
||||
glymur.lib._openjp2.stream_destroy_v3(stream)
|
||||
glymur.lib._openjp2.image_destroy(image)
|
||||
|
||||
def tile_encoder(self, num_comps=None, tile_width=None, tile_height=None,
|
||||
filename=None, codec=None, comp_prec=None,
|
||||
|
|
@ -150,7 +146,7 @@ class TestOpenJP2(unittest.TestCase):
|
|||
data = np.random.random((tile_height, tile_width, num_comps))
|
||||
data = (data * 255).astype(np.uint8)
|
||||
|
||||
l_param = glymur.lib.openjp2._set_default_encoder_parameters()
|
||||
l_param = glymur.lib._openjp2.set_default_encoder_parameters()
|
||||
|
||||
l_param.tcp_numlayers = 1
|
||||
l_param.cp_fixed_quality = 1
|
||||
|
|
@ -170,9 +166,9 @@ class TestOpenJP2(unittest.TestCase):
|
|||
|
||||
l_param.numresolution = 6
|
||||
|
||||
l_param.prog_order = glymur.lib.openjp2.LRCP
|
||||
l_param.prog_order = glymur.core.LRCP
|
||||
|
||||
l_params = (glymur.lib.openjp2._image_comptparm_t * num_comps)()
|
||||
l_params = (glymur.lib._openjp2.ImageComptParmType * num_comps)()
|
||||
for j in range(num_comps):
|
||||
l_params[j].dx = 1
|
||||
l_params[j].dy = 1
|
||||
|
|
@ -183,38 +179,38 @@ class TestOpenJP2(unittest.TestCase):
|
|||
l_params[j].x0 = 0
|
||||
l_params[j].y0 = 0
|
||||
|
||||
codec = glymur.lib.openjp2._create_compress(codec)
|
||||
codec = glymur.lib._openjp2.create_compress(codec)
|
||||
|
||||
glymur.lib.openjp2._set_info_handler(codec, None)
|
||||
glymur.lib.openjp2._set_warning_handler(codec, None)
|
||||
glymur.lib.openjp2._set_error_handler(codec, None)
|
||||
glymur.lib._openjp2.set_info_handler(codec, None)
|
||||
glymur.lib._openjp2.set_warning_handler(codec, None)
|
||||
glymur.lib._openjp2.set_error_handler(codec, None)
|
||||
|
||||
cspace = glymur.lib.openjp2._CLRSPC_SRGB
|
||||
l_image = glymur.lib.openjp2._image_tile_create(l_params, cspace)
|
||||
cspace = glymur.lib._openjp2.CLRSPC_SRGB
|
||||
l_image = glymur.lib._openjp2.image_tile_create(l_params, cspace)
|
||||
|
||||
l_image.contents.x0 = 0
|
||||
l_image.contents.y0 = 0
|
||||
l_image.contents.x1 = image_width
|
||||
l_image.contents.y1 = image_height
|
||||
l_image.contents.color_space = glymur.lib.openjp2._CLRSPC_SRGB
|
||||
l_image.contents.color_space = glymur.lib._openjp2.CLRSPC_SRGB
|
||||
|
||||
glymur.lib.openjp2._setup_encoder(codec, l_param, l_image)
|
||||
glymur.lib._openjp2.setup_encoder(codec, l_param, l_image)
|
||||
|
||||
x = (filename, False)
|
||||
stream = glymur.lib.openjp2._stream_create_default_file_stream_v3(*x)
|
||||
glymur.lib.openjp2._start_compress(codec, l_image, stream)
|
||||
stream = glymur.lib._openjp2.stream_create_default_file_stream_v3(*x)
|
||||
glymur.lib._openjp2.start_compress(codec, l_image, stream)
|
||||
|
||||
for j in np.arange(num_tiles):
|
||||
glymur.lib.openjp2._write_tile(codec, j, data, tile_size, stream)
|
||||
glymur.lib._openjp2.write_tile(codec, j, data, tile_size, stream)
|
||||
|
||||
glymur.lib.openjp2._end_compress(codec, stream)
|
||||
glymur.lib.openjp2._stream_destroy_v3(stream)
|
||||
glymur.lib.openjp2._destroy_codec(codec)
|
||||
glymur.lib.openjp2._image_destroy(l_image)
|
||||
glymur.lib._openjp2.end_compress(codec, stream)
|
||||
glymur.lib._openjp2.stream_destroy_v3(stream)
|
||||
glymur.lib._openjp2.destroy_codec(codec)
|
||||
glymur.lib._openjp2.image_destroy(l_image)
|
||||
|
||||
def tte0_setup(self, filename):
|
||||
kwargs = {'filename': filename,
|
||||
'codec': glymur.lib.openjp2._CODEC_J2K,
|
||||
'codec': glymur.lib._openjp2.CODEC_J2K,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 1,
|
||||
'num_comps': 3,
|
||||
|
|
@ -241,12 +237,12 @@ class TestOpenJP2(unittest.TestCase):
|
|||
'x1': 1000,
|
||||
'y1': 1000,
|
||||
'filename': tfile.name,
|
||||
'codec_format': glymur.lib.openjp2._CODEC_J2K}
|
||||
'codec_format': glymur.lib._openjp2.CODEC_J2K}
|
||||
self.tile_decoder(**kwargs)
|
||||
|
||||
def tte1_setup(self, filename):
|
||||
kwargs = {'filename': filename,
|
||||
'codec': glymur.lib.openjp2._CODEC_J2K,
|
||||
'codec': glymur.lib._openjp2.CODEC_J2K,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 1,
|
||||
'num_comps': 3,
|
||||
|
|
@ -273,7 +269,7 @@ class TestOpenJP2(unittest.TestCase):
|
|||
'x1': 128,
|
||||
'y1': 128,
|
||||
'filename': tfile.name,
|
||||
'codec_format': glymur.lib.openjp2._CODEC_J2K}
|
||||
'codec_format': glymur.lib._openjp2.CODEC_J2K}
|
||||
self.tile_decoder(**kwargs)
|
||||
|
||||
def test_rta1(self):
|
||||
|
|
@ -281,12 +277,12 @@ class TestOpenJP2(unittest.TestCase):
|
|||
# Runs test designated rta1 in OpenJPEG test suite.
|
||||
self.tte1_setup(tfile.name)
|
||||
|
||||
kwargs = {'codec_format': glymur.lib.openjp2._CODEC_J2K}
|
||||
kwargs = {'codec_format': glymur.lib._openjp2.CODEC_J2K}
|
||||
self.j2k_random_tile_access(tfile.name, **kwargs)
|
||||
|
||||
def tte2_setup(self, filename):
|
||||
kwargs = {'filename': filename,
|
||||
'codec': glymur.lib.openjp2._CODEC_JP2,
|
||||
'codec': glymur.lib._openjp2.CODEC_JP2,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 1,
|
||||
'num_comps': 3,
|
||||
|
|
@ -312,7 +308,7 @@ class TestOpenJP2(unittest.TestCase):
|
|||
'x1': 128,
|
||||
'y1': 128,
|
||||
'filename': tfile.name,
|
||||
'codec_format': glymur.lib.openjp2._CODEC_JP2}
|
||||
'codec_format': glymur.lib._openjp2.CODEC_JP2}
|
||||
self.tile_decoder(**kwargs)
|
||||
|
||||
def test_rta2(self):
|
||||
|
|
@ -320,12 +316,12 @@ class TestOpenJP2(unittest.TestCase):
|
|||
# Runs test designated rta2 in OpenJPEG test suite.
|
||||
self.tte2_setup(tfile.name)
|
||||
|
||||
kwargs = {'codec_format': glymur.lib.openjp2._CODEC_JP2}
|
||||
kwargs = {'codec_format': glymur.lib._openjp2.CODEC_JP2}
|
||||
self.j2k_random_tile_access(tfile.name, **kwargs)
|
||||
|
||||
def tte3_setup(self, filename):
|
||||
kwargs = {'filename': filename,
|
||||
'codec': glymur.lib.openjp2._CODEC_J2K,
|
||||
'codec': glymur.lib._openjp2.CODEC_J2K,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 1,
|
||||
'num_comps': 1,
|
||||
|
|
@ -345,12 +341,12 @@ class TestOpenJP2(unittest.TestCase):
|
|||
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
|
||||
self.tte3_setup(tfile.name)
|
||||
|
||||
kwargs = {'codec_format': glymur.lib.openjp2._CODEC_J2K}
|
||||
kwargs = {'codec_format': glymur.lib._openjp2.CODEC_J2K}
|
||||
self.j2k_random_tile_access(tfile.name, **kwargs)
|
||||
|
||||
def tte4_setup(self, filename):
|
||||
kwargs = {'filename': filename,
|
||||
'codec': glymur.lib.openjp2._CODEC_J2K,
|
||||
'codec': glymur.lib._openjp2.CODEC_J2K,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 0,
|
||||
'num_comps': 1,
|
||||
|
|
@ -370,12 +366,12 @@ class TestOpenJP2(unittest.TestCase):
|
|||
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
|
||||
self.tte4_setup(tfile.name)
|
||||
|
||||
kwargs = {'codec_format': glymur.lib.openjp2._CODEC_J2K}
|
||||
kwargs = {'codec_format': glymur.lib._openjp2.CODEC_J2K}
|
||||
self.j2k_random_tile_access(tfile.name, **kwargs)
|
||||
|
||||
def tte5_setup(self, filename):
|
||||
kwargs = {'filename': filename,
|
||||
'codec': glymur.lib.openjp2._CODEC_J2K,
|
||||
'codec': glymur.lib._openjp2.CODEC_J2K,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 0,
|
||||
'num_comps': 1,
|
||||
|
|
@ -395,7 +391,7 @@ class TestOpenJP2(unittest.TestCase):
|
|||
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
|
||||
self.tte5_setup(tfile.name)
|
||||
|
||||
kwargs = {'codec_format': glymur.lib.openjp2._CODEC_J2K}
|
||||
kwargs = {'codec_format': glymur.lib._openjp2.CODEC_J2K}
|
||||
self.j2k_random_tile_access(tfile.name, **kwargs)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
39
glymur/lib/test/test_openjpeg.py
Normal file
39
glymur/lib/test/test_openjpeg.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#pylint: disable-all
|
||||
import ctypes
|
||||
import unittest
|
||||
|
||||
import glymur
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib._openjpeg.OPENJPEG is None,
|
||||
"Missing openjpeg library.")
|
||||
class TestOpenJPEG(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_version(self):
|
||||
v = glymur.lib._openjpeg.version()
|
||||
parts = v.split('.')
|
||||
self.assertEqual(parts[0], '1')
|
||||
self.assertEqual(parts[1], '5')
|
||||
|
||||
def test_set_default_decoder_parameters(self):
|
||||
# Verify that we properly set the default decode parameters.
|
||||
dp = glymur.lib._openjpeg.DecompressionParametersType()
|
||||
glymur.lib._openjpeg.set_default_decoder_parameters(ctypes.byref(dp))
|
||||
|
||||
self.assertEqual(dp.cp_reduce, 0)
|
||||
self.assertEqual(dp.cp_layer, 0)
|
||||
self.assertEqual(dp.infile, b'')
|
||||
self.assertEqual(dp.outfile, b'')
|
||||
self.assertEqual(dp.decod_format, -1)
|
||||
self.assertEqual(dp.cod_format, -1)
|
||||
self.assertEqual(dp.jpwl_correct, 0)
|
||||
self.assertEqual(dp.jpwl_exp_comps, 0)
|
||||
self.assertEqual(dp.jpwl_max_tiles, 0)
|
||||
self.assertEqual(dp.cp_limit_decoding, 0)
|
||||
self.assertEqual(dp.flags, 0)
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
from .test_callbacks import TestCallbacks as callbacks
|
||||
from .test_codestream import TestCodestream as codestream
|
||||
from .test_config import TestSuite as config
|
||||
from .test_jp2k import TestJp2k as jp2k
|
||||
from .test_icc import TestICC as icc
|
||||
from .test_printing import TestPrinting as printing
|
||||
from .test_opj_suite import TestSuite as suite
|
||||
from .test_opj_suite import TestSuiteDump as suitedump
|
||||
from .test_opj_suite_write import TestSuiteWrite as suitew
|
||||
from .test_opj_suite_neg import TestSuiteNegative as suiteneg
|
||||
from .test_jp2box import TestJp2Boxes as box
|
||||
|
|
|
|||
91
glymur/test/fixtures.py
Normal file
91
glymur/test/fixtures.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
import re
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def mse(amat, bmat):
|
||||
"""Mean Square Error"""
|
||||
diff = amat.astype(np.double) - bmat.astype(np.double)
|
||||
err = np.mean(diff**2)
|
||||
return err
|
||||
|
||||
|
||||
def peak_tolerance(amat, bmat):
|
||||
"""Peak Tolerance"""
|
||||
diff = np.abs(amat.astype(np.double) - bmat.astype(np.double))
|
||||
ptol = diff.max()
|
||||
return ptol
|
||||
|
||||
|
||||
def read_pgx(pgx_file):
|
||||
"""Helper function for reading the PGX comparison files.
|
||||
|
||||
Open the file in ascii mode and read the header line.
|
||||
Will look something like
|
||||
|
||||
PG ML + 8 128 128
|
||||
PG%[ \t]%c%c%[ \t+-]%d%[ \t]%d%[ \t]%d"
|
||||
"""
|
||||
header = ''
|
||||
with open(pgx_file, 'rb') as fptr:
|
||||
while True:
|
||||
char = fptr.read(1)
|
||||
if char[0] == 10 or char == '\n':
|
||||
pos = fptr.tell()
|
||||
break
|
||||
else:
|
||||
if sys.hexversion < 0x03000000:
|
||||
header += char
|
||||
else:
|
||||
header += chr(char[0])
|
||||
|
||||
header = header.rstrip()
|
||||
tokens = re.split('\s', header)
|
||||
|
||||
if (tokens[1][0] == 'M') and (sys.byteorder == 'little'):
|
||||
swapbytes = True
|
||||
elif (tokens[1][0] == 'L') and (sys.byteorder == 'big'):
|
||||
swapbytes = True
|
||||
else:
|
||||
swapbytes = False
|
||||
|
||||
if (len(tokens) == 6):
|
||||
bitdepth = int(tokens[3])
|
||||
signed = bitdepth < 0
|
||||
if signed:
|
||||
bitdepth = -1 * bitdepth
|
||||
nrows = int(tokens[5])
|
||||
ncols = int(tokens[4])
|
||||
else:
|
||||
bitdepth = int(tokens[2])
|
||||
signed = bitdepth < 0
|
||||
if signed:
|
||||
bitdepth = -1 * bitdepth
|
||||
nrows = int(tokens[4])
|
||||
ncols = int(tokens[3])
|
||||
|
||||
if signed:
|
||||
if bitdepth <= 8:
|
||||
dtype = np.int8
|
||||
elif bitdepth <= 16:
|
||||
dtype = np.int16
|
||||
else:
|
||||
raise RuntimeError("unhandled bitdepth")
|
||||
else:
|
||||
if bitdepth <= 8:
|
||||
dtype = np.uint8
|
||||
elif bitdepth <= 16:
|
||||
dtype = np.uint16
|
||||
else:
|
||||
raise RuntimeError("unhandled bitdepth")
|
||||
|
||||
shape = [nrows, ncols]
|
||||
|
||||
# Reopen the file in binary mode and seek to the start of the binary
|
||||
# data
|
||||
with open(pgx_file, 'rb') as fptr:
|
||||
fptr.seek(pos)
|
||||
data = np.fromfile(file=fptr, dtype=dtype).reshape(shape)
|
||||
|
||||
return(data.byteswap(swapbytes))
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
#pylint: disable-all
|
||||
import os
|
||||
import pkg_resources
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
|
@ -13,7 +15,7 @@ else:
|
|||
import glymur
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjp2._OPENJP2 is None,
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestCallbacks(unittest.TestCase):
|
||||
|
||||
|
|
@ -21,13 +23,14 @@ class TestCallbacks(unittest.TestCase):
|
|||
# Save sys.stdout.
|
||||
self.stdout = sys.stdout
|
||||
sys.stdout = StringIO()
|
||||
self.jp2file = pkg_resources.resource_filename(glymur.__name__,
|
||||
"data/nemo.jp2")
|
||||
self.jp2file = glymur.data.nemo()
|
||||
self.j2kfile = glymur.data.goodstuff()
|
||||
|
||||
def tearDown(self):
|
||||
# Restore stdout.
|
||||
sys.stdout = self.stdout
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_info_callback_on_write(self):
|
||||
# Verify the messages printed when writing an image in verbose mode.
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
|
|
@ -44,24 +47,69 @@ class TestCallbacks(unittest.TestCase):
|
|||
def test_info_warning_callbacks_on_read(self):
|
||||
# Verify that we get the expected stdio output when our internal info
|
||||
# callback handler is enabled.
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
d = j.read(reduce=3, verbose=True, area=(0, 0, 512, 1024))
|
||||
j = glymur.Jp2k(self.j2kfile)
|
||||
d = j.read(rlevel=1, verbose=True, area=(0, 0, 200, 150))
|
||||
actual = sys.stdout.getvalue().strip()
|
||||
|
||||
lines = ['[INFO] Start to read j2k main header (3135).',
|
||||
lines = ['[INFO] Start to read j2k main header (0).',
|
||||
'[INFO] Main header has been correctly decoded.',
|
||||
'[INFO] Setting decoding area to 0,0,1024,512',
|
||||
'[INFO] Header of tile 0 / 17 has been read.',
|
||||
'[INFO] Tile 1/18 has been decoded.',
|
||||
'[INFO] Image data has been updated with tile 1.',
|
||||
'[INFO] Header of tile 1 / 17 has been read.',
|
||||
'[INFO] Tile 2/18 has been decoded.',
|
||||
'[INFO] Image data has been updated with tile 2.',
|
||||
'[INFO] Stream reached its end !']
|
||||
'[INFO] Setting decoding area to 0,0,150,200',
|
||||
'[INFO] Header of tile 0 / 0 has been read.',
|
||||
'[INFO] Tile 1/1 has been decoded.',
|
||||
'[INFO] Image data has been updated with tile 1.']
|
||||
|
||||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJPEG is None,
|
||||
"Missing openjpeg library.")
|
||||
class TestCallbacks15(unittest.TestCase):
|
||||
"""This test suite is for OpenJPEG 1.5.1 properties.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# Monkey patch the package so as to use OPENJPEG instead of OPENJP2
|
||||
cls.openjp2 = glymur.lib.openjp2.OPENJP2
|
||||
glymur.lib.openjp2.OPENJP2 = None
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# Restore OPENJP2
|
||||
glymur.lib.openjp2.OPENJP2 = cls.openjp2
|
||||
|
||||
def setUp(self):
|
||||
# Save sys.stdout.
|
||||
self.stdout = sys.stdout
|
||||
sys.stdout = StringIO()
|
||||
self.jp2file = glymur.data.nemo()
|
||||
self.j2kfile = glymur.data.goodstuff()
|
||||
|
||||
def tearDown(self):
|
||||
# Restore stdout.
|
||||
sys.stdout = self.stdout
|
||||
|
||||
def test_info_callbacks_on_read(self):
|
||||
# Verify that we get the expected stdio output when our internal info
|
||||
# callback handler is enabled.
|
||||
j = glymur.Jp2k(self.j2kfile)
|
||||
d = j.read(rlevel=1, verbose=True)
|
||||
actual = sys.stdout.getvalue().strip()
|
||||
|
||||
regex = re.compile(r"""\[INFO\]\stile\s1\sof\s1\s+
|
||||
\[INFO\]\s-\stiers-1\stook\s
|
||||
[0-9]+\.[0-9]+\ss\s+
|
||||
\[INFO\]\s-\sdwt\stook\s
|
||||
(-){0,1}[0-9]+\.[0-9]+\ss\s+
|
||||
\[INFO\]\s-\stile\sdecoded\sin\s
|
||||
[0-9]+\.[0-9]+\ss""",
|
||||
re.VERBOSE)
|
||||
if sys.hexversion <= 0x03020000:
|
||||
self.assertRegexpMatches(actual, regex)
|
||||
else:
|
||||
self.assertRegex(actual, regex)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pylint: disable-all
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
|
|
@ -29,6 +30,7 @@ class TestCodestream(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
pass
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_reserved_marker_segment(self):
|
||||
# Some marker segments were reserved in FCD15444-1. Since that
|
||||
# standard is old, some of them may have come into use.
|
||||
|
|
@ -54,10 +56,11 @@ class TestCodestream(unittest.TestCase):
|
|||
j = Jp2k(tfile.name)
|
||||
c = j.get_codestream()
|
||||
|
||||
self.assertEqual(c.segment[2].id, '0xff6f')
|
||||
self.assertEqual(c.segment[2].marker_id, '0xff6f')
|
||||
self.assertEqual(c.segment[2].length, 3)
|
||||
self.assertEqual(c.segment[2].data, b'\x00')
|
||||
self.assertEqual(c.segment[2]._data, b'\x00')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
def test_unknown_marker_segment(self):
|
||||
|
|
@ -84,9 +87,9 @@ class TestCodestream(unittest.TestCase):
|
|||
j = Jp2k(tfile.name)
|
||||
c = j.get_codestream()
|
||||
|
||||
self.assertEqual(c.segment[2].id, '0xff79')
|
||||
self.assertEqual(c.segment[2].marker_id, '0xff79')
|
||||
self.assertEqual(c.segment[2].length, 3)
|
||||
self.assertEqual(c.segment[2].data, b'\x00')
|
||||
self.assertEqual(c.segment[2]._data, b'\x00')
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
"""These tests are for edge cases where OPENJPEG does not exist, but
|
||||
OPENJP2 may be present in some form or other.
|
||||
"""
|
||||
#pylint: disable-all
|
||||
|
||||
import imp
|
||||
import os
|
||||
import sys
|
||||
|
|
@ -16,14 +21,28 @@ from glymur import Jp2k
|
|||
from glymur.lib import openjp2 as opj2
|
||||
|
||||
|
||||
@unittest.skip("Cannot work when both OPENJPEG and OPENJP2 are both present.")
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Needs openjp2 library first before these tests make sense.")
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
class TestJp2k(unittest.TestCase):
|
||||
class TestSuite(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# Monkey patch the package so as to ignore OPENJPEG if it exists.
|
||||
cls.openjpeg = glymur.lib.openjpeg._OPENJPEG
|
||||
glymur.lib.openjp2._OPENJPEG = None
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# Restore OPENJPEG
|
||||
glymur.lib.openjpeg._OPENJPEG = cls.openjpeg
|
||||
|
||||
def setUp(self):
|
||||
self.jp2file = pkg_resources.resource_filename(glymur.__name__,
|
||||
"data/nemo.jp2")
|
||||
imp.reload(glymur)
|
||||
imp.reload(glymur.lib.openjp2)
|
||||
self.jp2file = glymur.data.nemo()
|
||||
|
||||
def tearDown(self):
|
||||
imp.reload(glymur)
|
||||
|
|
@ -37,7 +56,7 @@ class TestJp2k(unittest.TestCase):
|
|||
filename = os.path.join(configdir, 'glymurrc')
|
||||
with open(filename, 'wb') as tfile:
|
||||
tfile.write('[library]\n'.encode())
|
||||
libloc = glymur.lib.openjp2._OPENJP2._name
|
||||
libloc = glymur.lib.openjp2.OPENJP2._name
|
||||
line = 'openjp2: {0}\n'.format(libloc)
|
||||
tfile.write(line.encode())
|
||||
tfile.flush()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pylint: disable-all
|
||||
import datetime
|
||||
import os
|
||||
import struct
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
#pylint: disable-all
|
||||
import doctest
|
||||
import os
|
||||
import tempfile
|
||||
import xml.etree.cElementTree as ET
|
||||
import unittest
|
||||
|
|
@ -13,10 +15,16 @@ from glymur.jp2box import *
|
|||
|
||||
# Doc tests should be run as well.
|
||||
def load_tests(loader, tests, ignore):
|
||||
if os.name == "nt":
|
||||
# Can't do it on windows, temporary file issue.
|
||||
return tests
|
||||
tests.addTests(doctest.DocTestSuite('glymur.jp2box'))
|
||||
return tests
|
||||
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestChannelDefinition(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
|
|
@ -55,9 +63,9 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].Ysiz
|
||||
width = c.segment[1].Xsiz
|
||||
num_components = len(c.segment[1].XRsiz)
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
|
||||
self.jP = JPEG2000SignatureBox()
|
||||
self.ftyp = FileTypeBox()
|
||||
|
|
@ -85,7 +93,7 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
|
||||
jp2 = Jp2k(tfile.name)
|
||||
jp2h = jp2.box[2]
|
||||
boxes = [box.id for box in jp2h.box]
|
||||
boxes = [box.box_id for box in jp2h.box]
|
||||
self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
|
||||
self.assertEqual(jp2h.box[2].index, (0, 1, 2))
|
||||
self.assertEqual(jp2h.box[2].channel_type, (0, 0, 0))
|
||||
|
|
@ -105,7 +113,7 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
|
||||
jp2 = Jp2k(tfile.name)
|
||||
jp2h = jp2.box[2]
|
||||
boxes = [box.id for box in jp2h.box]
|
||||
boxes = [box.box_id for box in jp2h.box]
|
||||
self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
|
||||
self.assertEqual(jp2h.box[2].index, (0, 1, 2, 3))
|
||||
self.assertEqual(jp2h.box[2].channel_type, (0, 0, 0, 1))
|
||||
|
|
@ -138,7 +146,7 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
|
||||
jp2 = Jp2k(tfile.name)
|
||||
jp2h = jp2.box[2]
|
||||
boxes = [box.id for box in jp2h.box]
|
||||
boxes = [box.box_id for box in jp2h.box]
|
||||
self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
|
||||
self.assertEqual(jp2h.box[2].index, (0,))
|
||||
self.assertEqual(jp2h.box[2].channel_type, (0,))
|
||||
|
|
@ -158,7 +166,7 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
|
||||
jp2 = Jp2k(tfile.name)
|
||||
jp2h = jp2.box[2]
|
||||
boxes = [box.id for box in jp2h.box]
|
||||
boxes = [box.box_id for box in jp2h.box]
|
||||
self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
|
||||
self.assertEqual(jp2h.box[2].index, (0, 1))
|
||||
self.assertEqual(jp2h.box[2].channel_type, (0, 1))
|
||||
|
|
@ -229,6 +237,7 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
association=[1, 2, 3])
|
||||
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
class TestXML(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
|
@ -265,9 +274,9 @@ class TestXML(unittest.TestCase):
|
|||
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].Ysiz
|
||||
width = c.segment[1].Xsiz
|
||||
num_components = len(c.segment[1].XRsiz)
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
|
||||
self.jP = JPEG2000SignatureBox()
|
||||
self.ftyp = FileTypeBox()
|
||||
|
|
@ -288,6 +297,8 @@ class TestXML(unittest.TestCase):
|
|||
with self.assertRaises((IOError, OSError)) as ce:
|
||||
xmlb = glymur.jp2box.XMLBox(filename=self.xmlfile, xml=xml_object)
|
||||
|
||||
@unittest.skipIf(os.name == "nt",
|
||||
"Problems using NamedTemporaryFile on windows.")
|
||||
def test_basic_xml(self):
|
||||
# Should be able to write an XMLBox.
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
|
|
@ -304,10 +315,12 @@ class TestXML(unittest.TestCase):
|
|||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
jp2 = Jp2k(tfile.name)
|
||||
self.assertEqual(jp2.box[3].id, 'xml ')
|
||||
self.assertEqual(jp2.box[3].box_id, 'xml ')
|
||||
self.assertEqual(ET.tostring(jp2.box[3].xml),
|
||||
b'<data>0</data>')
|
||||
|
||||
@unittest.skipIf(os.name == "nt",
|
||||
"Problems using NamedTemporaryFile on windows.")
|
||||
def test_xml_from_file(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
|
||||
|
|
@ -319,7 +332,7 @@ class TestXML(unittest.TestCase):
|
|||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
jp2 = Jp2k(tfile.name)
|
||||
|
||||
output_boxes = [box.id for box in jp2.box]
|
||||
output_boxes = [box.box_id for box in jp2.box]
|
||||
self.assertEqual(output_boxes, ['jP ', 'ftyp', 'jp2h', 'xml ',
|
||||
'jp2c'])
|
||||
|
||||
|
|
@ -338,9 +351,9 @@ class TestColourSpecificationBox(unittest.TestCase):
|
|||
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].Ysiz
|
||||
width = c.segment[1].Xsiz
|
||||
num_components = len(c.segment[1].XRsiz)
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
|
||||
self.jP = JPEG2000SignatureBox()
|
||||
self.ftyp = FileTypeBox()
|
||||
|
|
@ -352,6 +365,8 @@ class TestColourSpecificationBox(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
pass
|
||||
|
||||
@unittest.skipIf(os.name == "nt",
|
||||
"Problems using NamedTemporaryFile on windows.")
|
||||
def test_color_specification_box_with_out_enumerated_colorspace(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
|
||||
|
|
@ -361,6 +376,7 @@ class TestColourSpecificationBox(unittest.TestCase):
|
|||
with self.assertRaises(NotImplementedError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_missing_colr_box(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
|
||||
|
|
@ -400,7 +416,7 @@ class TestColourSpecificationBox(unittest.TestCase):
|
|||
approximation=approx)
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjp2._OPENJP2 is None,
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestJp2Boxes(unittest.TestCase):
|
||||
|
||||
|
|
@ -440,37 +456,37 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
|
||||
def test_default_ContiguousCodestreamBox(self):
|
||||
b = ContiguousCodestreamBox()
|
||||
self.assertEqual(b.id, 'jp2c')
|
||||
self.assertEqual(b.main_header, [])
|
||||
self.assertEqual(b.box_id, 'jp2c')
|
||||
self.assertIsNone(b.main_header)
|
||||
|
||||
def verify_wrapped_raw(self, jp2file):
|
||||
# Shared method by at least two tests.
|
||||
jp2 = Jp2k(jp2file)
|
||||
self.assertEqual(len(jp2.box), 4)
|
||||
|
||||
self.assertEqual(jp2.box[0].id, 'jP ')
|
||||
self.assertEqual(jp2.box[0].box_id, 'jP ')
|
||||
self.assertEqual(jp2.box[0].offset, 0)
|
||||
self.assertEqual(jp2.box[0].length, 12)
|
||||
self.assertEqual(jp2.box[0].longname, 'JPEG 2000 Signature')
|
||||
|
||||
self.assertEqual(jp2.box[1].id, 'ftyp')
|
||||
self.assertEqual(jp2.box[1].box_id, 'ftyp')
|
||||
self.assertEqual(jp2.box[1].offset, 12)
|
||||
self.assertEqual(jp2.box[1].length, 20)
|
||||
self.assertEqual(jp2.box[1].longname, 'File Type')
|
||||
|
||||
self.assertEqual(jp2.box[2].id, 'jp2h')
|
||||
self.assertEqual(jp2.box[2].box_id, 'jp2h')
|
||||
self.assertEqual(jp2.box[2].offset, 32)
|
||||
self.assertEqual(jp2.box[2].length, 45)
|
||||
self.assertEqual(jp2.box[2].longname, 'JP2 Header')
|
||||
|
||||
self.assertEqual(jp2.box[3].id, 'jp2c')
|
||||
self.assertEqual(jp2.box[3].box_id, 'jp2c')
|
||||
self.assertEqual(jp2.box[3].offset, 77)
|
||||
self.assertEqual(jp2.box[3].length, 115228)
|
||||
|
||||
# jp2h super box
|
||||
self.assertEqual(len(jp2.box[2].box), 2)
|
||||
|
||||
self.assertEqual(jp2.box[2].box[0].id, 'ihdr')
|
||||
self.assertEqual(jp2.box[2].box[0].box_id, 'ihdr')
|
||||
self.assertEqual(jp2.box[2].box[0].offset, 40)
|
||||
self.assertEqual(jp2.box[2].box[0].length, 22)
|
||||
self.assertEqual(jp2.box[2].box[0].longname, 'Image Header')
|
||||
|
|
@ -483,7 +499,7 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
self.assertEqual(jp2.box[2].box[0].colorspace_unknown, False)
|
||||
self.assertEqual(jp2.box[2].box[0].ip_provided, False)
|
||||
|
||||
self.assertEqual(jp2.box[2].box[1].id, 'colr')
|
||||
self.assertEqual(jp2.box[2].box[1].box_id, 'colr')
|
||||
self.assertEqual(jp2.box[2].box[1].offset, 62)
|
||||
self.assertEqual(jp2.box[2].box[1].length, 15)
|
||||
self.assertEqual(jp2.box[2].box[1].longname, 'Colour Specification')
|
||||
|
|
@ -492,19 +508,22 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
self.assertEqual(jp2.box[2].box[1].colorspace, glymur.core.SRGB)
|
||||
self.assertIsNone(jp2.box[2].box[1].icc_profile)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_wrap(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
j2k.wrap(tfile.name)
|
||||
self.verify_wrapped_raw(tfile.name)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_wrap_jp2(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
jp2 = j2k.wrap(tfile.name)
|
||||
boxes = [box.id for box in jp2.box]
|
||||
boxes = [box.box_id for box in jp2.box]
|
||||
self.assertEqual(boxes, ['jP ', 'ftyp', 'jp2h', 'jp2c'])
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_default_layout_but_with_specified_boxes(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
boxes = [JPEG2000SignatureBox(),
|
||||
|
|
@ -512,9 +531,9 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
JP2HeaderBox(),
|
||||
ContiguousCodestreamBox()]
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].Ysiz
|
||||
width = c.segment[1].Xsiz
|
||||
num_components = len(c.segment[1].XRsiz)
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
boxes[2].box = [ImageHeaderBox(height=height,
|
||||
width=width,
|
||||
num_components=num_components),
|
||||
|
|
@ -523,6 +542,7 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
self.verify_wrapped_raw(tfile.name)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_image_header_box_not_first_in_jp2_header(self):
|
||||
# The specification says that ihdr must be the first box in jp2h.
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
|
|
@ -531,9 +551,9 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
JP2HeaderBox(),
|
||||
ContiguousCodestreamBox()]
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].Ysiz
|
||||
width = c.segment[1].Xsiz
|
||||
num_components = len(c.segment[1].XRsiz)
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
boxes[2].box = [ColourSpecificationBox(colorspace=glymur.core.SRGB),
|
||||
ImageHeaderBox(height=height,
|
||||
width=width,
|
||||
|
|
@ -542,12 +562,13 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
with self.assertRaises(IOError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_first_2_boxes_not_jP_and_ftyp(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].Ysiz
|
||||
width = c.segment[1].Xsiz
|
||||
num_components = len(c.segment[1].XRsiz)
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
|
||||
jP = JPEG2000SignatureBox()
|
||||
ftyp = FileTypeBox()
|
||||
|
|
@ -562,12 +583,13 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
with self.assertRaises(IOError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_jp2h_not_preceeding_jp2c(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].Ysiz
|
||||
width = c.segment[1].Xsiz
|
||||
num_components = len(c.segment[1].XRsiz)
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
|
||||
jP = JPEG2000SignatureBox()
|
||||
ftyp = FileTypeBox()
|
||||
|
|
@ -582,12 +604,13 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
with self.assertRaises(IOError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_missing_codestream(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].Ysiz
|
||||
width = c.segment[1].Xsiz
|
||||
num_components = len(c.segment[1].XRsiz)
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
|
||||
jP = JPEG2000SignatureBox()
|
||||
ftyp = FileTypeBox()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import contextlib
|
||||
import ctypes
|
||||
# pylint: disable-all
|
||||
import doctest
|
||||
import imp
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
|
|
@ -33,14 +31,18 @@ except:
|
|||
|
||||
# Doc tests should be run as well.
|
||||
def load_tests(loader, tests, ignore):
|
||||
if glymur.lib.openjp2._OPENJP2 is not None:
|
||||
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'))
|
||||
return tests
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjp2._OPENJP2 is None,
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestJp2k(unittest.TestCase):
|
||||
class TestJp2kBadXmlFile(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
|
@ -74,10 +76,8 @@ class TestJp2k(unittest.TestCase):
|
|||
os.unlink(cls._bad_xml_file)
|
||||
|
||||
def setUp(self):
|
||||
self.jp2file = pkg_resources.resource_filename(glymur.__name__,
|
||||
"data/nemo.jp2")
|
||||
self.j2kfile = pkg_resources.resource_filename(glymur.__name__,
|
||||
"data/goodstuff.j2k")
|
||||
self.jp2file = glymur.data.nemo()
|
||||
self.j2kfile = glymur.data.goodstuff()
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
|
@ -90,25 +90,37 @@ class TestJp2k(unittest.TestCase):
|
|||
with self.assertWarns(UserWarning) as cw:
|
||||
jp2k = Jp2k(self._bad_xml_file)
|
||||
|
||||
def test_reduce_max(self):
|
||||
# Verify that reduce=-1 gets us the lowest resolution image
|
||||
j = Jp2k(self.jp2file)
|
||||
thumbnail1 = j.read(reduce=-1)
|
||||
thumbnail2 = j.read(reduce=5)
|
||||
np.testing.assert_array_equal(thumbnail1, thumbnail2)
|
||||
self.assertEqual(thumbnail1.shape, (46, 81, 3))
|
||||
|
||||
def test_invalid_xml_box(self):
|
||||
# Should be able to recover from xml box with bad xml.
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
jp2k = Jp2k(self._bad_xml_file)
|
||||
|
||||
self.assertEqual(jp2k.box[3].id, 'xml ')
|
||||
self.assertEqual(jp2k.box[3].box_id, 'xml ')
|
||||
self.assertEqual(jp2k.box[3].offset, 77)
|
||||
self.assertEqual(jp2k.box[3].length, 28)
|
||||
self.assertIsNone(jp2k.box[3].xml)
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestJp2k(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.jp2file = glymur.data.nemo()
|
||||
self.j2kfile = glymur.data.goodstuff()
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_rlevel_max(self):
|
||||
# Verify that rlevel=-1 gets us the lowest resolution image
|
||||
j = Jp2k(self.j2kfile)
|
||||
thumbnail1 = j.read(rlevel=-1)
|
||||
thumbnail2 = j.read(rlevel=5)
|
||||
np.testing.assert_array_equal(thumbnail1, thumbnail2)
|
||||
self.assertEqual(thumbnail1.shape, (25, 15, 3))
|
||||
|
||||
def test_bad_area_parameter(self):
|
||||
# Verify that we error out appropriately if given a bad area parameter.
|
||||
j = Jp2k(self.jp2file)
|
||||
|
|
@ -122,11 +134,11 @@ class TestJp2k(unittest.TestCase):
|
|||
# End corner must be >= start corner
|
||||
d = j.read(area=(10, 10, 8, 8))
|
||||
|
||||
def test_reduce_too_high(self):
|
||||
def test_rlevel_too_high(self):
|
||||
# Verify that we error out appropriately if not given a JPEG 2000 file.
|
||||
j = Jp2k(self.jp2file)
|
||||
with self.assertRaises(IOError):
|
||||
d = j.read(reduce=6)
|
||||
d = j.read(rlevel=6)
|
||||
|
||||
def test_not_JPEG2000(self):
|
||||
# Verify that we error out appropriately if not given a JPEG 2000 file.
|
||||
|
|
@ -145,15 +157,7 @@ class TestJp2k(unittest.TestCase):
|
|||
filename = 'this file does not actually exist on the file system.'
|
||||
jp2k = Jp2k(filename)
|
||||
|
||||
def test_nemo_tile(self):
|
||||
# Issue 134, trouble reading first nemo tile.
|
||||
j = Jp2k(self.jp2file)
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
tiledata = j.read(tile=0)
|
||||
subsetdata = j.read(area=(0, 0, 512, 512))
|
||||
np.testing.assert_array_equal(tiledata, subsetdata)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_write_srgb_without_mct(self):
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
expdata = j2k.read()
|
||||
|
|
@ -164,8 +168,9 @@ class TestJp2k(unittest.TestCase):
|
|||
np.testing.assert_array_equal(actdata, expdata)
|
||||
|
||||
c = ofile.get_codestream()
|
||||
self.assertEqual(c.segment[2].SPcod[3], 0) # no mct
|
||||
self.assertEqual(c.segment[2].spcod[3], 0) # no mct
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_write_grayscale_with_mct(self):
|
||||
# MCT usage makes no sense for grayscale images.
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
|
|
@ -175,10 +180,11 @@ class TestJp2k(unittest.TestCase):
|
|||
with self.assertRaises(IOError):
|
||||
ofile.write(expdata[:, :, 0], mct=True)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_write_cprl(self):
|
||||
# Issue 17
|
||||
j = Jp2k(self.jp2file)
|
||||
expdata = j.read(reduce=2)
|
||||
expdata = j.read(rlevel=1)
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
ofile = Jp2k(tfile.name, 'wb')
|
||||
ofile.write(expdata, prog='CPRL')
|
||||
|
|
@ -186,7 +192,7 @@ class TestJp2k(unittest.TestCase):
|
|||
np.testing.assert_array_equal(actdata, expdata)
|
||||
|
||||
c = ofile.get_codestream()
|
||||
self.assertEqual(c.segment[2].SPcod[0], glymur.core.CPRL)
|
||||
self.assertEqual(c.segment[2].spcod[0], glymur.core.CPRL)
|
||||
|
||||
def test_jp2_boxes(self):
|
||||
# Verify the boxes of a JP2 file.
|
||||
|
|
@ -195,37 +201,37 @@ class TestJp2k(unittest.TestCase):
|
|||
# top-level boxes
|
||||
self.assertEqual(len(jp2k.box), 6)
|
||||
|
||||
self.assertEqual(jp2k.box[0].id, 'jP ')
|
||||
self.assertEqual(jp2k.box[0].box_id, 'jP ')
|
||||
self.assertEqual(jp2k.box[0].offset, 0)
|
||||
self.assertEqual(jp2k.box[0].length, 12)
|
||||
self.assertEqual(jp2k.box[0].longname, 'JPEG 2000 Signature')
|
||||
|
||||
self.assertEqual(jp2k.box[1].id, 'ftyp')
|
||||
self.assertEqual(jp2k.box[1].box_id, 'ftyp')
|
||||
self.assertEqual(jp2k.box[1].offset, 12)
|
||||
self.assertEqual(jp2k.box[1].length, 20)
|
||||
self.assertEqual(jp2k.box[1].longname, 'File Type')
|
||||
|
||||
self.assertEqual(jp2k.box[2].id, 'jp2h')
|
||||
self.assertEqual(jp2k.box[2].box_id, 'jp2h')
|
||||
self.assertEqual(jp2k.box[2].offset, 32)
|
||||
self.assertEqual(jp2k.box[2].length, 45)
|
||||
self.assertEqual(jp2k.box[2].longname, 'JP2 Header')
|
||||
|
||||
self.assertEqual(jp2k.box[3].id, 'uuid')
|
||||
self.assertEqual(jp2k.box[3].box_id, 'uuid')
|
||||
self.assertEqual(jp2k.box[3].offset, 77)
|
||||
self.assertEqual(jp2k.box[3].length, 638)
|
||||
|
||||
self.assertEqual(jp2k.box[4].id, 'uuid')
|
||||
self.assertEqual(jp2k.box[4].box_id, 'uuid')
|
||||
self.assertEqual(jp2k.box[4].offset, 715)
|
||||
self.assertEqual(jp2k.box[4].length, 2412)
|
||||
|
||||
self.assertEqual(jp2k.box[5].id, 'jp2c')
|
||||
self.assertEqual(jp2k.box[5].box_id, 'jp2c')
|
||||
self.assertEqual(jp2k.box[5].offset, 3127)
|
||||
self.assertEqual(jp2k.box[5].length, 1133427)
|
||||
self.assertEqual(jp2k.box[5].length, 1132296)
|
||||
|
||||
# jp2h super box
|
||||
self.assertEqual(len(jp2k.box[2].box), 2)
|
||||
|
||||
self.assertEqual(jp2k.box[2].box[0].id, 'ihdr')
|
||||
self.assertEqual(jp2k.box[2].box[0].box_id, 'ihdr')
|
||||
self.assertEqual(jp2k.box[2].box[0].offset, 40)
|
||||
self.assertEqual(jp2k.box[2].box[0].length, 22)
|
||||
self.assertEqual(jp2k.box[2].box[0].longname, 'Image Header')
|
||||
|
|
@ -238,7 +244,7 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(jp2k.box[2].box[0].colorspace_unknown, False)
|
||||
self.assertEqual(jp2k.box[2].box[0].ip_provided, False)
|
||||
|
||||
self.assertEqual(jp2k.box[2].box[1].id, 'colr')
|
||||
self.assertEqual(jp2k.box[2].box[1].box_id, 'colr')
|
||||
self.assertEqual(jp2k.box[2].box[1].offset, 62)
|
||||
self.assertEqual(jp2k.box[2].box[1].length, 15)
|
||||
self.assertEqual(jp2k.box[2].box[1].longname, 'Colour Specification')
|
||||
|
|
@ -255,6 +261,7 @@ class TestJp2k(unittest.TestCase):
|
|||
jp2k = Jp2k(filename)
|
||||
self.assertEqual(len(jp2k.box), 0)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_64bit_XL_field(self):
|
||||
# Verify that boxes with the XL field are properly read.
|
||||
# Don't have such a file on hand, so we create one. Copy our example
|
||||
|
|
@ -283,10 +290,11 @@ class TestJp2k(unittest.TestCase):
|
|||
|
||||
jp2k = Jp2k(tfile.name)
|
||||
|
||||
self.assertEqual(jp2k.box[5].id, 'jp2c')
|
||||
self.assertEqual(jp2k.box[5].box_id, 'jp2c')
|
||||
self.assertEqual(jp2k.box[5].offset, 3127)
|
||||
self.assertEqual(jp2k.box[5].length, 1133427 + 8)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_L_is_zero(self):
|
||||
# Verify that boxes with the L field as zero are correctly read.
|
||||
# This should only happen in the last box of a JPEG 2000 file.
|
||||
|
|
@ -314,8 +322,8 @@ class TestJp2k(unittest.TestCase):
|
|||
|
||||
# The top level boxes in each file should match.
|
||||
for j in range(len(baseline_jp2.box)):
|
||||
self.assertEqual(new_jp2.box[j].id,
|
||||
baseline_jp2.box[j].id)
|
||||
self.assertEqual(new_jp2.box[j].box_id,
|
||||
baseline_jp2.box[j].box_id)
|
||||
self.assertEqual(new_jp2.box[j].offset,
|
||||
baseline_jp2.box[j].offset)
|
||||
self.assertEqual(new_jp2.box[j].length,
|
||||
|
|
@ -330,7 +338,7 @@ class TestJp2k(unittest.TestCase):
|
|||
# Issue 86.
|
||||
filename = os.path.join(data_root, 'input/conformance/p0_05.j2k')
|
||||
j = Jp2k(filename)
|
||||
with self.assertRaises(IOError):
|
||||
with self.assertRaises(RuntimeError):
|
||||
j.read()
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
|
|
@ -342,6 +350,7 @@ class TestJp2k(unittest.TestCase):
|
|||
j = Jp2k(filename)
|
||||
self.assertEqual(j.box, [])
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_code_block_height_different_than_width(self):
|
||||
# Verify that we can set a code block size where height does not equal
|
||||
# width.
|
||||
|
|
@ -355,8 +364,9 @@ class TestJp2k(unittest.TestCase):
|
|||
c = j.get_codestream()
|
||||
|
||||
# Code block size is reported as XY in the codestream.
|
||||
self.assertEqual(tuple(c.segment[2].SPcod[5:7]), (3, 2))
|
||||
self.assertEqual(tuple(c.segment[2].spcod[5:7]), (3, 2))
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_negative_too_many_dimensions(self):
|
||||
# OpenJP2 only allows 2D or 3D images.
|
||||
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
|
||||
|
|
@ -365,6 +375,7 @@ class TestJp2k(unittest.TestCase):
|
|||
data = np.zeros((128, 128, 2, 2), dtype=np.uint8)
|
||||
j.write(data)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_unrecognized_jp2_colorspace(self):
|
||||
# We only allow RGB and GRAYSCALE.
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
|
|
@ -373,6 +384,7 @@ class TestJp2k(unittest.TestCase):
|
|||
data = np.zeros((128, 128, 3), dtype=np.uint8)
|
||||
j.write(data, colorspace='cmyk')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_2D_rgb(self):
|
||||
# RGB must have at least 3 components.
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
|
|
@ -381,6 +393,7 @@ class TestJp2k(unittest.TestCase):
|
|||
data = np.zeros((128, 128, 2), dtype=np.uint8)
|
||||
j.write(data, colorspace='rgb')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_colorspace_with_j2k(self):
|
||||
# Specifying a colorspace with J2K does not make sense.
|
||||
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
|
||||
|
|
@ -389,6 +402,7 @@ class TestJp2k(unittest.TestCase):
|
|||
data = np.zeros((128, 128, 3), dtype=np.uint8)
|
||||
j.write(data, colorspace='rgb')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_specify_rgb(self):
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
|
|
@ -396,6 +410,7 @@ class TestJp2k(unittest.TestCase):
|
|||
j.write(data, colorspace='rgb')
|
||||
self.assertEqual(j.box[2].box[1].colorspace, glymur.core.SRGB)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_specify_gray(self):
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
|
|
@ -404,6 +419,7 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(j.box[2].box[1].colorspace,
|
||||
glymur.core.GREYSCALE)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_specify_grey(self):
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
|
|
@ -412,6 +428,7 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(j.box[2].box[1].colorspace,
|
||||
glymur.core.GREYSCALE)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_grey_with_extra_component(self):
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
|
|
@ -423,6 +440,7 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(j.box[2].box[1].colorspace,
|
||||
glymur.core.GREYSCALE)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_grey_with_two_extra_components(self):
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
|
|
@ -434,6 +452,7 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(j.box[2].box[1].colorspace,
|
||||
glymur.core.GREYSCALE)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_rgb_with_extra_component(self):
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
|
|
@ -452,6 +471,7 @@ class TestJp2k(unittest.TestCase):
|
|||
data = np.zeros((128, 128, 3), dtype=np.uint8)
|
||||
j.write(data, colorspace='ycc')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_uinf_ulst_url_boxes(self):
|
||||
# Verify that we can read UINF, ULST, and URL boxes. I don't have
|
||||
# easy access to such a file, and there's no such file in the
|
||||
|
|
@ -490,24 +510,25 @@ class TestJp2k(unittest.TestCase):
|
|||
|
||||
jp2k = Jp2k(tfile.name)
|
||||
|
||||
self.assertEqual(jp2k.box[3].id, 'uinf')
|
||||
self.assertEqual(jp2k.box[3].box_id, 'uinf')
|
||||
self.assertEqual(jp2k.box[3].offset, 77)
|
||||
self.assertEqual(jp2k.box[3].length, 50)
|
||||
|
||||
self.assertEqual(jp2k.box[3].box[0].id, 'ulst')
|
||||
self.assertEqual(jp2k.box[3].box[0].box_id, 'ulst')
|
||||
self.assertEqual(jp2k.box[3].box[0].offset, 85)
|
||||
self.assertEqual(jp2k.box[3].box[0].length, 26)
|
||||
ulst = []
|
||||
ulst.append(uuid.UUID('00000000-0000-0000-0000-000000000000'))
|
||||
self.assertEqual(jp2k.box[3].box[0].ulst, ulst)
|
||||
|
||||
self.assertEqual(jp2k.box[3].box[1].id, 'url ')
|
||||
self.assertEqual(jp2k.box[3].box[1].box_id, 'url ')
|
||||
self.assertEqual(jp2k.box[3].box[1].offset, 111)
|
||||
self.assertEqual(jp2k.box[3].box[1].length, 16)
|
||||
self.assertEqual(jp2k.box[3].box[1].version, 0)
|
||||
self.assertEqual(jp2k.box[3].box[1].flag, (0, 0, 0))
|
||||
self.assertEqual(jp2k.box[3].box[1].URL, 'abcd')
|
||||
self.assertEqual(jp2k.box[3].box[1].url, 'abcd')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_xml_box_with_trailing_nulls(self):
|
||||
# ElementTree does not like trailing null chars after valid XML
|
||||
# text.
|
||||
|
|
@ -533,14 +554,15 @@ class TestJp2k(unittest.TestCase):
|
|||
|
||||
jp2k = Jp2k(tfile.name)
|
||||
|
||||
self.assertEqual(jp2k.box[3].id, 'xml ')
|
||||
self.assertEqual(jp2k.box[3].box_id, 'xml ')
|
||||
self.assertEqual(jp2k.box[3].offset, 77)
|
||||
self.assertEqual(jp2k.box[3].length, 36)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_asoc_label_box(self):
|
||||
# Construct a fake file with an asoc and a label box, as
|
||||
# OpenJPEG doesn't have such a file.
|
||||
data = Jp2k(self.jp2file).read(reduce=3)
|
||||
data = Jp2k(self.jp2file).read(rlevel=1)
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
j.write(data)
|
||||
|
|
@ -578,11 +600,12 @@ class TestJp2k(unittest.TestCase):
|
|||
tfile2.flush()
|
||||
|
||||
jasoc = Jp2k(tfile2.name)
|
||||
self.assertEqual(jasoc.box[3].id, 'asoc')
|
||||
self.assertEqual(jasoc.box[3].box[0].id, 'lbl ')
|
||||
self.assertEqual(jasoc.box[3].box_id, 'asoc')
|
||||
self.assertEqual(jasoc.box[3].box[0].box_id, 'lbl ')
|
||||
self.assertEqual(jasoc.box[3].box[0].label, 'label')
|
||||
self.assertEqual(jasoc.box[3].box[1].id, 'xml ')
|
||||
self.assertEqual(jasoc.box[3].box[1].box_id, 'xml ')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_openjpeg_library_message(self):
|
||||
# Verify the error message produced by the openjpeg library.
|
||||
# This will confirm that the error callback mechanism is working.
|
||||
|
|
@ -610,11 +633,11 @@ class TestJp2k(unittest.TestCase):
|
|||
Invalid\svalues\sfor\scomp\s=\s0\s+
|
||||
:\sdx=1\sdy=0''', re.VERBOSE)
|
||||
if sys.hexversion < 0x03020000:
|
||||
with self.assertRaisesRegexp(IOError, regexp) as ce:
|
||||
d = j.read(reduce=3)
|
||||
with self.assertRaisesRegexp((IOError, OSError), regexp):
|
||||
d = j.read(rlevel=1)
|
||||
else:
|
||||
with self.assertRaisesRegex(IOError, regexp) as ce:
|
||||
d = j.read(reduce=3)
|
||||
with self.assertRaisesRegex((IOError, OSError), regexp):
|
||||
d = j.read(rlevel=1)
|
||||
|
||||
def test_xmp_attribute(self):
|
||||
# Verify that we can read the XMP packet in our shipping example file.
|
||||
|
|
@ -627,6 +650,7 @@ class TestJp2k(unittest.TestCase):
|
|||
attr_value = elt.attrib['{0}CreatorTool'.format(ns1)]
|
||||
self.assertEqual(attr_value, 'glymur')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_unrecognized_exif_tag(self):
|
||||
# An unrecognized exif tag should be handled gracefully.
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
|
|
@ -659,5 +683,72 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertFalse('Make' in exif['Image'].keys())
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjpeg.OPENJPEG is None,
|
||||
"Missing openjpeg library.")
|
||||
class TestJp2k15(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# Monkey patch the package so as to use OPENJPEG instead of OPENJP2
|
||||
cls.openjp2 = glymur.lib.openjp2.OPENJP2
|
||||
glymur.lib.openjp2.OPENJP2 = None
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
# Restore OPENJP2
|
||||
glymur.lib.openjp2.OPENJP2 = cls.openjp2
|
||||
|
||||
def setUp(self):
|
||||
self.jp2file = glymur.data.nemo()
|
||||
self.j2kfile = glymur.data.goodstuff()
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_bands(self):
|
||||
"""Reading individual bands is an advanced maneuver.
|
||||
"""
|
||||
jp2k = Jp2k(self.j2kfile)
|
||||
with self.assertRaises(NotImplementedError):
|
||||
jp2k.read_bands()
|
||||
|
||||
def test_area(self):
|
||||
"""Area option not allowed for 1.5.1.
|
||||
"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
with self.assertRaises(TypeError):
|
||||
j2k.read(area=(0, 0, 100, 100))
|
||||
|
||||
def test_tile(self):
|
||||
"""tile option not allowed for 1.5.1.
|
||||
"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
with self.assertRaises(TypeError):
|
||||
j2k.read(tile=0)
|
||||
|
||||
def test_layer(self):
|
||||
"""layer option not allowed for 1.5.1.
|
||||
"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
with self.assertRaises(TypeError):
|
||||
j2k.read(layer=1)
|
||||
|
||||
def test_basic_jp2(self):
|
||||
"""This test is only useful when openjp2 is not available
|
||||
and OPJ_DATA_ROOT is not set. We need at least one
|
||||
working JP2 test.
|
||||
"""
|
||||
j2k = Jp2k(self.jp2file)
|
||||
j2k.read(rlevel=1)
|
||||
|
||||
def test_basic_j2k(self):
|
||||
"""This test is only useful when openjp2 is not available
|
||||
and OPJ_DATA_ROOT is not set. We need at least one
|
||||
working J2K test.
|
||||
"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
j2k.read()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,6 +2,7 @@
|
|||
The tests here do not correspond directly to the OpenJPEG test suite, but
|
||||
seem like logical negative tests to add.
|
||||
"""
|
||||
#pylint: disable-all
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
|
@ -57,7 +58,7 @@ def read_image(infile):
|
|||
return data
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjp2._OPENJP2 is None,
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
@unittest.skipIf(no_read_backend, no_read_backend_msg)
|
||||
@unittest.skipIf(data_root is None,
|
||||
|
|
@ -65,12 +66,13 @@ def read_image(infile):
|
|||
class TestSuiteNegative(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.jp2file = pkg_resources.resource_filename(glymur.__name__,
|
||||
"data/nemo.jp2")
|
||||
self.jp2file = glymur.data.nemo()
|
||||
self.j2kfile = glymur.data.goodstuff()
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_negative_psnr_with_cratios(self):
|
||||
# Using psnr with cratios options is not allowed.
|
||||
# Not an OpenJPEG test, but close.
|
||||
|
|
@ -94,7 +96,7 @@ class TestSuiteNegative(unittest.TestCase):
|
|||
# Verify that the last segment returned in the codestream is SOD,
|
||||
# not EOC. Codestream parsing should stop when we try to jump to
|
||||
# the end of SOT.
|
||||
self.assertEqual(c.segment[-1].id, 'SOD')
|
||||
self.assertEqual(c.segment[-1].marker_id, 'SOD')
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
|
|
@ -109,7 +111,7 @@ class TestSuiteNegative(unittest.TestCase):
|
|||
# Verify that the last segment returned in the codestream is SOD,
|
||||
# not EOC. Codestream parsing should stop when we try to jump to
|
||||
# the end of SOT.
|
||||
self.assertEqual(c.segment[-1].id, 'SOD')
|
||||
self.assertEqual(c.segment[-1].marker_id, 'SOD')
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
|
|
@ -124,8 +126,9 @@ class TestSuiteNegative(unittest.TestCase):
|
|||
# Verify that the last segment returned in the codestream is SOD,
|
||||
# not EOC. Codestream parsing should stop when we try to jump to
|
||||
# the end of SOT.
|
||||
self.assertEqual(c.segment[-1].id, 'SOD')
|
||||
self.assertEqual(c.segment[-1].marker_id, 'SOD')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_code_block_dimensions(self):
|
||||
# opj_compress doesn't allow the dimensions of a codeblock
|
||||
# to be too small or too big, so neither will we.
|
||||
|
|
@ -154,29 +157,32 @@ class TestSuiteNegative(unittest.TestCase):
|
|||
with self.assertWarns(UserWarning) as cw:
|
||||
j = Jp2k(infile)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_precinct_size_not_multiple_of_two(self):
|
||||
# Seems like precinct sizes should be powers of two.
|
||||
ifile = Jp2k(self.jp2file)
|
||||
data = ifile.read(reduce=3)
|
||||
ifile = Jp2k(self.j2kfile)
|
||||
data = ifile.read(rlevel=2)
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
ofile = Jp2k(tfile.name, 'wb')
|
||||
with self.assertRaises(IOError) as ce:
|
||||
ofile.write(data, psizes=[(13, 13)])
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_codeblock_size_not_multiple_of_two(self):
|
||||
# Seems like code block sizes should be powers of two.
|
||||
ifile = Jp2k(self.jp2file)
|
||||
data = ifile.read(reduce=3)
|
||||
ifile = Jp2k(self.j2kfile)
|
||||
data = ifile.read(rlevel=2)
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
ofile = Jp2k(tfile.name, 'wb')
|
||||
with self.assertRaises(IOError) as ce:
|
||||
ofile.write(data, cbsize=(13, 12))
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_codeblock_size_with_precinct_size(self):
|
||||
# Seems like code block sizes should never exceed half that of
|
||||
# precinct size.
|
||||
ifile = Jp2k(self.jp2file)
|
||||
data = ifile.read(reduce=3)
|
||||
ifile = Jp2k(self.j2kfile)
|
||||
data = ifile.read(rlevel=2)
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
ofile = Jp2k(tfile.name, 'wb')
|
||||
with self.assertRaises(IOError) as ce:
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
The tests defined here roughly correspond to what is in the OpenJPEG test
|
||||
suite.
|
||||
"""
|
||||
#pylint: disable-all
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
|
@ -57,7 +58,8 @@ def read_image(infile):
|
|||
return data
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjp2._OPENJP2 is None,
|
||||
@unittest.skipIf(os.name == "nt", "no write support on windows, period")
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
@unittest.skipIf(no_read_backend, no_read_backend_msg)
|
||||
@unittest.skipIf(data_root is None,
|
||||
|
|
@ -83,50 +85,50 @@ class TestSuiteWrite(unittest.TestCase):
|
|||
|
||||
# SIZ: Image and tile size
|
||||
# Profile: "0" means profile 2
|
||||
self.assertEqual(c.segment[1].Rsiz, 0)
|
||||
self.assertEqual(c.segment[1].rsiz, 0)
|
||||
# Reference grid size
|
||||
self.assertEqual((c.segment[1].Xsiz, c.segment[1].Ysiz),
|
||||
self.assertEqual((c.segment[1].xsiz, c.segment[1].ysiz),
|
||||
(640, 480))
|
||||
# Reference grid offset
|
||||
self.assertEqual((c.segment[1].XOsiz, c.segment[1].YOsiz), (0, 0))
|
||||
self.assertEqual((c.segment[1].xosiz, c.segment[1].yosiz), (0, 0))
|
||||
# Tile size
|
||||
self.assertEqual((c.segment[1].XTsiz, c.segment[1].YTsiz),
|
||||
self.assertEqual((c.segment[1].xtsiz, c.segment[1].ytsiz),
|
||||
(640, 480))
|
||||
# Tile offset
|
||||
self.assertEqual((c.segment[1].XTOsiz, c.segment[1].YTOsiz),
|
||||
self.assertEqual((c.segment[1].xtosiz, c.segment[1].ytosiz),
|
||||
(0, 0))
|
||||
# bitdepth
|
||||
self.assertEqual(c.segment[1]._bitdepth, (8, 8, 8))
|
||||
# signed
|
||||
self.assertEqual(c.segment[1]._signed, (False, False, False))
|
||||
# subsampling
|
||||
self.assertEqual(list(zip(c.segment[1].XRsiz, c.segment[1].YRsiz)),
|
||||
self.assertEqual(list(zip(c.segment[1].xrsiz, c.segment[1].yrsiz)),
|
||||
[(1, 1)] * 3)
|
||||
|
||||
# COD: Coding style default
|
||||
self.assertFalse(c.segment[2].Scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].Scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].SPcod[0], glymur.core.LRCP)
|
||||
self.assertFalse(c.segment[2].scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].spcod[0], glymur.core.LRCP)
|
||||
self.assertEqual(c.segment[2]._layers, 3) # layers = 3
|
||||
self.assertEqual(c.segment[2].SPcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].SPcod[4], 5) # levels
|
||||
self.assertEqual(c.segment[2].spcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].spcod[4], 5) # levels
|
||||
self.assertEqual(tuple(c.segment[2]._code_block_size),
|
||||
(64, 64)) # cblksz
|
||||
# Selective arithmetic coding bypass
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x01)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x01)
|
||||
# Reset context probabilities
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x02)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x02)
|
||||
# Termination on each coding pass
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x04)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x04)
|
||||
# Vertically causal context
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x08)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x08)
|
||||
# Predictable termination
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0010)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0010)
|
||||
# Segmentation symbols
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].SPcod[8],
|
||||
glymur.core.WAVELET_TRANSFORM_5x3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].SPcod), 9)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].spcod[8],
|
||||
glymur.core.WAVELET_XFORM_5X3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].spcod), 9)
|
||||
|
||||
def test_NR_ENC_Bretagne1_ppm_2_encode(self):
|
||||
# NR-ENC-Bretagne1.ppm-2-encode
|
||||
|
|
@ -141,50 +143,50 @@ class TestSuiteWrite(unittest.TestCase):
|
|||
|
||||
# SIZ: Image and tile size
|
||||
# Profile: "0" means profile 2
|
||||
self.assertEqual(c.segment[1].Rsiz, 0)
|
||||
self.assertEqual(c.segment[1].rsiz, 0)
|
||||
# Reference grid size
|
||||
self.assertEqual((c.segment[1].Xsiz, c.segment[1].Ysiz),
|
||||
self.assertEqual((c.segment[1].xsiz, c.segment[1].ysiz),
|
||||
(640, 480))
|
||||
# Reference grid offset
|
||||
self.assertEqual((c.segment[1].XOsiz, c.segment[1].YOsiz), (0, 0))
|
||||
self.assertEqual((c.segment[1].xosiz, c.segment[1].yosiz), (0, 0))
|
||||
# Tile size
|
||||
self.assertEqual((c.segment[1].XTsiz, c.segment[1].YTsiz),
|
||||
self.assertEqual((c.segment[1].xtsiz, c.segment[1].ytsiz),
|
||||
(640, 480))
|
||||
# Tile offset
|
||||
self.assertEqual((c.segment[1].XTOsiz, c.segment[1].YTOsiz),
|
||||
self.assertEqual((c.segment[1].xtosiz, c.segment[1].ytosiz),
|
||||
(0, 0))
|
||||
# bitdepth
|
||||
self.assertEqual(c.segment[1]._bitdepth, (8, 8, 8))
|
||||
# signed
|
||||
self.assertEqual(c.segment[1]._signed, (False, False, False))
|
||||
# subsampling
|
||||
self.assertEqual(list(zip(c.segment[1].XRsiz, c.segment[1].YRsiz)),
|
||||
self.assertEqual(list(zip(c.segment[1].xrsiz, c.segment[1].yrsiz)),
|
||||
[(1, 1)] * 3)
|
||||
|
||||
# COD: Coding style default
|
||||
self.assertFalse(c.segment[2].Scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].Scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].SPcod[0], glymur.core.LRCP)
|
||||
self.assertFalse(c.segment[2].scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].spcod[0], glymur.core.LRCP)
|
||||
self.assertEqual(c.segment[2]._layers, 3) # layers = 3
|
||||
self.assertEqual(c.segment[2].SPcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].SPcod[4], 1) # levels
|
||||
self.assertEqual(c.segment[2].spcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].spcod[4], 1) # levels
|
||||
self.assertEqual(tuple(c.segment[2]._code_block_size),
|
||||
(64, 64)) # cblksz
|
||||
# Selective arithmetic coding bypass
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x01)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x01)
|
||||
# Reset context probabilities
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x02)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x02)
|
||||
# Termination on each coding pass
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x04)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x04)
|
||||
# Vertically causal context
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x08)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x08)
|
||||
# Predictable termination
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0010)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0010)
|
||||
# Segmentation symbols
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].SPcod[8],
|
||||
glymur.core.WAVELET_TRANSFORM_5x3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].SPcod), 9)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].spcod[8],
|
||||
glymur.core.WAVELET_XFORM_5X3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].spcod), 9)
|
||||
|
||||
def test_NR_ENC_Bretagne1_ppm_3_encode(self):
|
||||
# NR-ENC-Bretagne1.ppm-3-encode
|
||||
|
|
@ -200,49 +202,49 @@ class TestSuiteWrite(unittest.TestCase):
|
|||
|
||||
# SIZ: Image and tile size
|
||||
# Profile: "0" means profile 2
|
||||
self.assertEqual(c.segment[1].Rsiz, 0)
|
||||
self.assertEqual(c.segment[1].rsiz, 0)
|
||||
# Reference grid size
|
||||
self.assertEqual((c.segment[1].Xsiz, c.segment[1].Ysiz),
|
||||
self.assertEqual((c.segment[1].xsiz, c.segment[1].ysiz),
|
||||
(640, 480))
|
||||
# Reference grid offset
|
||||
self.assertEqual((c.segment[1].XOsiz, c.segment[1].YOsiz), (0, 0))
|
||||
self.assertEqual((c.segment[1].xosiz, c.segment[1].yosiz), (0, 0))
|
||||
# Tile size
|
||||
self.assertEqual((c.segment[1].XTsiz, c.segment[1].YTsiz),
|
||||
self.assertEqual((c.segment[1].xtsiz, c.segment[1].ytsiz),
|
||||
(640, 480))
|
||||
# Tile offset
|
||||
self.assertEqual((c.segment[1].XTOsiz, c.segment[1].YTOsiz),
|
||||
self.assertEqual((c.segment[1].xtosiz, c.segment[1].ytosiz),
|
||||
(0, 0))
|
||||
# bitdepth
|
||||
self.assertEqual(c.segment[1]._bitdepth, (8, 8, 8))
|
||||
# signed
|
||||
self.assertEqual(c.segment[1]._signed, (False, False, False))
|
||||
# subsampling
|
||||
self.assertEqual(list(zip(c.segment[1].XRsiz, c.segment[1].YRsiz)),
|
||||
self.assertEqual(list(zip(c.segment[1].xrsiz, c.segment[1].yrsiz)),
|
||||
[(1, 1)] * 3)
|
||||
|
||||
# COD: Coding style default
|
||||
self.assertFalse(c.segment[2].Scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].Scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].SPcod[0], glymur.core.LRCP)
|
||||
self.assertFalse(c.segment[2].scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].spcod[0], glymur.core.LRCP)
|
||||
self.assertEqual(c.segment[2]._layers, 3) # layers = 3
|
||||
self.assertEqual(c.segment[2].SPcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].SPcod[4], 5) # levels
|
||||
self.assertEqual(c.segment[2].spcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].spcod[4], 5) # levels
|
||||
self.assertEqual(tuple(c.segment[2]._code_block_size),
|
||||
(16, 16)) # cblksz
|
||||
# Selective arithmetic coding bypass
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x01)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x01)
|
||||
# Reset context probabilities
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x02)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x02)
|
||||
# Termination on each coding pass
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x04)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x04)
|
||||
# Vertically causal context
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x08)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x08)
|
||||
# Predictable termination
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0010)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0010)
|
||||
# Segmentation symbols
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].SPcod[8],
|
||||
glymur.core.WAVELET_TRANSFORM_5x3_REVERSIBLE)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].spcod[8],
|
||||
glymur.core.WAVELET_XFORM_5X3_REVERSIBLE)
|
||||
self.assertEqual(c.segment[2]._precinct_size,
|
||||
[(2, 2), (4, 4), (8, 8), (16, 16), (32, 32),
|
||||
(64, 64)])
|
||||
|
|
@ -263,49 +265,49 @@ class TestSuiteWrite(unittest.TestCase):
|
|||
|
||||
# SIZ: Image and tile size
|
||||
# Profile: "0" means profile 2
|
||||
self.assertEqual(c.segment[1].Rsiz, 0)
|
||||
self.assertEqual(c.segment[1].rsiz, 0)
|
||||
# Reference grid size
|
||||
self.assertEqual((c.segment[1].Xsiz, c.segment[1].Ysiz),
|
||||
self.assertEqual((c.segment[1].xsiz, c.segment[1].ysiz),
|
||||
(data.shape[1], data.shape[0]))
|
||||
# Reference grid offset
|
||||
self.assertEqual((c.segment[1].XOsiz, c.segment[1].YOsiz), (0, 0))
|
||||
self.assertEqual((c.segment[1].xosiz, c.segment[1].yosiz), (0, 0))
|
||||
# Tile size. Reported as XY, not RC.
|
||||
self.assertEqual((c.segment[1].XTsiz, c.segment[1].YTsiz),
|
||||
self.assertEqual((c.segment[1].xtsiz, c.segment[1].ytsiz),
|
||||
(640, 480))
|
||||
# Tile offset
|
||||
self.assertEqual((c.segment[1].XTOsiz, c.segment[1].YTOsiz),
|
||||
self.assertEqual((c.segment[1].xtosiz, c.segment[1].ytosiz),
|
||||
(0, 0))
|
||||
# bitdepth
|
||||
self.assertEqual(c.segment[1]._bitdepth, (8, 8, 8))
|
||||
# signed
|
||||
self.assertEqual(c.segment[1]._signed, (False, False, False))
|
||||
# subsampling
|
||||
self.assertEqual(list(zip(c.segment[1].XRsiz, c.segment[1].YRsiz)),
|
||||
self.assertEqual(list(zip(c.segment[1].xrsiz, c.segment[1].yrsiz)),
|
||||
[(1, 1)] * 3)
|
||||
|
||||
# COD: Coding style default
|
||||
self.assertFalse(c.segment[2].Scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].Scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].SPcod[0], glymur.core.LRCP)
|
||||
self.assertFalse(c.segment[2].scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].spcod[0], glymur.core.LRCP)
|
||||
self.assertEqual(c.segment[2]._layers, 3) # layers = 3
|
||||
self.assertEqual(c.segment[2].SPcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].SPcod[4], 5) # levels
|
||||
self.assertEqual(c.segment[2].spcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].spcod[4], 5) # levels
|
||||
self.assertEqual(tuple(c.segment[2]._code_block_size),
|
||||
(32, 32)) # cblksz
|
||||
# Selective arithmetic coding bypass
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x01)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x01)
|
||||
# Reset context probabilities
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x02)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x02)
|
||||
# Termination on each coding pass
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x04)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x04)
|
||||
# Vertically causal context
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x08)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x08)
|
||||
# Predictable termination
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0010)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0010)
|
||||
# Segmentation symbols
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].SPcod[8],
|
||||
glymur.core.WAVELET_TRANSFORM_5x3_REVERSIBLE)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].spcod[8],
|
||||
glymur.core.WAVELET_XFORM_5X3_REVERSIBLE)
|
||||
self.assertEqual(c.segment[2]._precinct_size,
|
||||
[(16, 16), (32, 32), (64, 64)] + [(128, 128)] * 3)
|
||||
|
||||
|
|
@ -321,50 +323,50 @@ class TestSuiteWrite(unittest.TestCase):
|
|||
|
||||
# SIZ: Image and tile size
|
||||
# Profile: "0" means profile 2
|
||||
self.assertEqual(c.segment[1].Rsiz, 0)
|
||||
self.assertEqual(c.segment[1].rsiz, 0)
|
||||
# Reference grid size
|
||||
self.assertEqual((c.segment[1].Xsiz, c.segment[1].Ysiz),
|
||||
self.assertEqual((c.segment[1].xsiz, c.segment[1].ysiz),
|
||||
(data.shape[1], data.shape[0]))
|
||||
# Reference grid offset
|
||||
self.assertEqual((c.segment[1].XOsiz, c.segment[1].YOsiz), (0, 0))
|
||||
self.assertEqual((c.segment[1].xosiz, c.segment[1].yosiz), (0, 0))
|
||||
# Tile size
|
||||
self.assertEqual((c.segment[1].XTsiz, c.segment[1].YTsiz),
|
||||
self.assertEqual((c.segment[1].xtsiz, c.segment[1].ytsiz),
|
||||
(127, 127))
|
||||
# Tile offset
|
||||
self.assertEqual((c.segment[1].XTOsiz, c.segment[1].YTOsiz),
|
||||
self.assertEqual((c.segment[1].xtosiz, c.segment[1].ytosiz),
|
||||
(0, 0))
|
||||
# bitdepth
|
||||
self.assertEqual(c.segment[1]._bitdepth, (8, 8, 8))
|
||||
# signed
|
||||
self.assertEqual(c.segment[1]._signed, (False, False, False))
|
||||
# subsampling
|
||||
self.assertEqual(list(zip(c.segment[1].XRsiz, c.segment[1].YRsiz)),
|
||||
self.assertEqual(list(zip(c.segment[1].xrsiz, c.segment[1].yrsiz)),
|
||||
[(1, 1)] * 3)
|
||||
|
||||
# COD: Coding style default
|
||||
self.assertFalse(c.segment[2].Scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].Scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].SPcod[0], glymur.core.PCRL)
|
||||
self.assertFalse(c.segment[2].scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].spcod[0], glymur.core.PCRL)
|
||||
self.assertEqual(c.segment[2]._layers, 1) # layers = 1
|
||||
self.assertEqual(c.segment[2].SPcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].SPcod[4], 5) # levels
|
||||
self.assertEqual(c.segment[2].spcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].spcod[4], 5) # levels
|
||||
self.assertEqual(tuple(c.segment[2]._code_block_size),
|
||||
(64, 64)) # cblksz
|
||||
# Selective arithmetic coding bypass
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x01)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x01)
|
||||
# Reset context probabilities
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x02)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x02)
|
||||
# Termination on each coding pass
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x04)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x04)
|
||||
# Vertically causal context
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x08)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x08)
|
||||
# Predictable termination
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0010)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0010)
|
||||
# Segmentation symbols
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].SPcod[8],
|
||||
glymur.core.WAVELET_TRANSFORM_5x3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].SPcod), 9)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].spcod[8],
|
||||
glymur.core.WAVELET_XFORM_5X3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].spcod), 9)
|
||||
|
||||
def test_NR_ENC_Bretagne2_ppm_6_encode(self):
|
||||
# NR-ENC-Bretagne2.ppm-6-encode
|
||||
|
|
@ -378,53 +380,53 @@ class TestSuiteWrite(unittest.TestCase):
|
|||
|
||||
# SIZ: Image and tile size
|
||||
# Profile: "0" means profile 2
|
||||
self.assertEqual(c.segment[1].Rsiz, 0)
|
||||
self.assertEqual(c.segment[1].rsiz, 0)
|
||||
# Reference grid size
|
||||
self.assertEqual((c.segment[1].Xsiz, c.segment[1].Ysiz),
|
||||
self.assertEqual((c.segment[1].xsiz, c.segment[1].ysiz),
|
||||
(5183, 3887))
|
||||
# Reference grid offset
|
||||
self.assertEqual((c.segment[1].XOsiz, c.segment[1].YOsiz), (0, 0))
|
||||
self.assertEqual((c.segment[1].xosiz, c.segment[1].yosiz), (0, 0))
|
||||
# Tile size
|
||||
self.assertEqual((c.segment[1].XTsiz, c.segment[1].YTsiz),
|
||||
self.assertEqual((c.segment[1].xtsiz, c.segment[1].ytsiz),
|
||||
(5183, 3887))
|
||||
# Tile offset
|
||||
self.assertEqual((c.segment[1].XTOsiz, c.segment[1].YTOsiz),
|
||||
self.assertEqual((c.segment[1].xtosiz, c.segment[1].ytosiz),
|
||||
(0, 0))
|
||||
# bitdepth
|
||||
self.assertEqual(c.segment[1]._bitdepth, (8, 8, 8))
|
||||
# signed
|
||||
self.assertEqual(c.segment[1]._signed, (False, False, False))
|
||||
# subsampling
|
||||
self.assertEqual(list(zip(c.segment[1].XRsiz, c.segment[1].YRsiz)),
|
||||
self.assertEqual(list(zip(c.segment[1].xrsiz, c.segment[1].yrsiz)),
|
||||
[(2, 2)] * 3)
|
||||
|
||||
# COD: Coding style default
|
||||
self.assertTrue(c.segment[2].Scod & 2) # sop
|
||||
self.assertFalse(c.segment[2].Scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].SPcod[0], glymur.core.LRCP)
|
||||
self.assertTrue(c.segment[2].scod & 2) # sop
|
||||
self.assertFalse(c.segment[2].scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].spcod[0], glymur.core.LRCP)
|
||||
self.assertEqual(c.segment[2]._layers, 1) # layers = 1
|
||||
self.assertEqual(c.segment[2].SPcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].SPcod[4], 5) # levels
|
||||
self.assertEqual(c.segment[2].spcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].spcod[4], 5) # levels
|
||||
self.assertEqual(tuple(c.segment[2]._code_block_size),
|
||||
(64, 64)) # cblksz
|
||||
# Selective arithmetic coding bypass
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x01)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x01)
|
||||
# Reset context probabilities
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x02)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x02)
|
||||
# Termination on each coding pass
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x04)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x04)
|
||||
# Vertically causal context
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x08)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x08)
|
||||
# Predictable termination
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0010)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0010)
|
||||
# Segmentation symbols
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].SPcod[8],
|
||||
glymur.core.WAVELET_TRANSFORM_5x3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].SPcod), 9)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].spcod[8],
|
||||
glymur.core.WAVELET_XFORM_5X3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].spcod), 9)
|
||||
|
||||
# 18 SOP segments.
|
||||
nsops = [x.Nsop for x in c.segment if x.id == 'SOP']
|
||||
nsops = [x.nsop for x in c.segment if x.marker_id == 'SOP']
|
||||
self.assertEqual(nsops, list(range(18)))
|
||||
|
||||
def test_NR_ENC_Bretagne2_ppm_7_encode(self):
|
||||
|
|
@ -438,53 +440,53 @@ class TestSuiteWrite(unittest.TestCase):
|
|||
|
||||
# SIZ: Image and tile size
|
||||
# Profile: "0" means profile 2
|
||||
self.assertEqual(c.segment[1].Rsiz, 0)
|
||||
self.assertEqual(c.segment[1].rsiz, 0)
|
||||
# Reference grid size
|
||||
self.assertEqual((c.segment[1].Xsiz, c.segment[1].Ysiz),
|
||||
self.assertEqual((c.segment[1].xsiz, c.segment[1].ysiz),
|
||||
(2592, 1944))
|
||||
# Reference grid offset
|
||||
self.assertEqual((c.segment[1].XOsiz, c.segment[1].YOsiz), (0, 0))
|
||||
self.assertEqual((c.segment[1].xosiz, c.segment[1].yosiz), (0, 0))
|
||||
# Tile size
|
||||
self.assertEqual((c.segment[1].XTsiz, c.segment[1].YTsiz),
|
||||
self.assertEqual((c.segment[1].xtsiz, c.segment[1].ytsiz),
|
||||
(2592, 1944))
|
||||
# Tile offset
|
||||
self.assertEqual((c.segment[1].XTOsiz, c.segment[1].YTOsiz),
|
||||
self.assertEqual((c.segment[1].xtosiz, c.segment[1].ytosiz),
|
||||
(0, 0))
|
||||
# bitdepth
|
||||
self.assertEqual(c.segment[1]._bitdepth, (8, 8, 8))
|
||||
# signed
|
||||
self.assertEqual(c.segment[1]._signed, (False, False, False))
|
||||
# subsampling
|
||||
self.assertEqual(list(zip(c.segment[1].XRsiz, c.segment[1].YRsiz)),
|
||||
self.assertEqual(list(zip(c.segment[1].xrsiz, c.segment[1].yrsiz)),
|
||||
[(1, 1)] * 3)
|
||||
|
||||
# COD: Coding style default
|
||||
self.assertFalse(c.segment[2].Scod & 2) # no sop
|
||||
self.assertTrue(c.segment[2].Scod & 4) # eph
|
||||
self.assertEqual(c.segment[2].SPcod[0], glymur.core.LRCP)
|
||||
self.assertFalse(c.segment[2].scod & 2) # no sop
|
||||
self.assertTrue(c.segment[2].scod & 4) # eph
|
||||
self.assertEqual(c.segment[2].spcod[0], glymur.core.LRCP)
|
||||
self.assertEqual(c.segment[2]._layers, 1) # layers = 1
|
||||
self.assertEqual(c.segment[2].SPcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].SPcod[4], 5) # levels
|
||||
self.assertEqual(c.segment[2].spcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].spcod[4], 5) # levels
|
||||
self.assertEqual(tuple(c.segment[2]._code_block_size),
|
||||
(64, 64)) # cblksz
|
||||
# Selective arithmetic coding BYPASS
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x01)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x01)
|
||||
# RESET context probabilities (RESET)
|
||||
self.assertTrue(c.segment[2].SPcod[7] & 0x02)
|
||||
self.assertTrue(c.segment[2].spcod[7] & 0x02)
|
||||
# Termination on each coding pass, RESTART(TERMALL)
|
||||
self.assertTrue(c.segment[2].SPcod[7] & 0x04)
|
||||
self.assertTrue(c.segment[2].spcod[7] & 0x04)
|
||||
# Vertically causal context (VSC)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x08)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x08)
|
||||
# Predictable termination, ERTERM(SEGTERM)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0010)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0010)
|
||||
# Segmentation symbols, SEGMARK(SEGSYSM)
|
||||
self.assertTrue(c.segment[2].SPcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].SPcod[8],
|
||||
glymur.core.WAVELET_TRANSFORM_5x3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].SPcod), 9)
|
||||
self.assertTrue(c.segment[2].spcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].spcod[8],
|
||||
glymur.core.WAVELET_XFORM_5X3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].spcod), 9)
|
||||
|
||||
# 18 EPH segments.
|
||||
ephs = [x for x in c.segment if x.id == 'EPH']
|
||||
ephs = [x for x in c.segment if x.marker_id == 'EPH']
|
||||
self.assertEqual(len(ephs), 18)
|
||||
|
||||
def test_NR_ENC_Bretagne2_ppm_8_encode(self):
|
||||
|
|
@ -498,51 +500,51 @@ class TestSuiteWrite(unittest.TestCase):
|
|||
|
||||
# SIZ: Image and tile size
|
||||
# Profile: "0" means profile 2
|
||||
self.assertEqual(c.segment[1].Rsiz, 0)
|
||||
self.assertEqual(c.segment[1].rsiz, 0)
|
||||
# Reference grid size
|
||||
self.assertEqual((c.segment[1].Xsiz, c.segment[1].Ysiz),
|
||||
self.assertEqual((c.segment[1].xsiz, c.segment[1].ysiz),
|
||||
(2742, 2244))
|
||||
# Reference grid offset
|
||||
self.assertEqual((c.segment[1].XOsiz, c.segment[1].YOsiz),
|
||||
self.assertEqual((c.segment[1].xosiz, c.segment[1].yosiz),
|
||||
(150, 300))
|
||||
# Tile size
|
||||
self.assertEqual((c.segment[1].XTsiz, c.segment[1].YTsiz),
|
||||
self.assertEqual((c.segment[1].xtsiz, c.segment[1].ytsiz),
|
||||
(2742, 2244))
|
||||
# Tile offset
|
||||
self.assertEqual((c.segment[1].XTOsiz, c.segment[1].YTOsiz),
|
||||
self.assertEqual((c.segment[1].xtosiz, c.segment[1].ytosiz),
|
||||
(0, 0))
|
||||
# bitdepth
|
||||
self.assertEqual(c.segment[1]._bitdepth, (8, 8, 8))
|
||||
# signed
|
||||
self.assertEqual(c.segment[1]._signed, (False, False, False))
|
||||
# subsampling
|
||||
self.assertEqual(list(zip(c.segment[1].XRsiz, c.segment[1].YRsiz)),
|
||||
self.assertEqual(list(zip(c.segment[1].xrsiz, c.segment[1].yrsiz)),
|
||||
[(1, 1)] * 3)
|
||||
|
||||
# COD: Coding style default
|
||||
self.assertFalse(c.segment[2].Scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].Scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].SPcod[0], glymur.core.LRCP)
|
||||
self.assertFalse(c.segment[2].scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].spcod[0], glymur.core.LRCP)
|
||||
self.assertEqual(c.segment[2]._layers, 1) # layers = 1
|
||||
self.assertEqual(c.segment[2].SPcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].SPcod[4], 5) # levels
|
||||
self.assertEqual(c.segment[2].spcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].spcod[4], 5) # levels
|
||||
self.assertEqual(tuple(c.segment[2]._code_block_size),
|
||||
(64, 64)) # cblksz
|
||||
# Selective arithmetic coding BYPASS
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x01)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x01)
|
||||
# RESET context probabilities (RESET)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x02)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x02)
|
||||
# Termination on each coding pass, RESTART(TERMALL)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x04)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x04)
|
||||
# Vertically causal context (VSC)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x08)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x08)
|
||||
# Predictable termination, ERTERM(SEGTERM)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0010)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0010)
|
||||
# Segmentation symbols, SEGMARK(SEGSYSM)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].SPcod[8],
|
||||
glymur.core.WAVELET_TRANSFORM_5x3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].SPcod), 9)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].spcod[8],
|
||||
glymur.core.WAVELET_XFORM_5X3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].spcod), 9)
|
||||
|
||||
def test_NR_ENC_Cevennes1_bmp_9_encode(self):
|
||||
infile = os.path.join(data_root, 'input/nonregression/Cevennes1.bmp')
|
||||
|
|
@ -555,50 +557,50 @@ class TestSuiteWrite(unittest.TestCase):
|
|||
|
||||
# SIZ: Image and tile size
|
||||
# Profile: "0" means profile 2
|
||||
self.assertEqual(c.segment[1].Rsiz, 0)
|
||||
self.assertEqual(c.segment[1].rsiz, 0)
|
||||
# Reference grid size
|
||||
self.assertEqual((c.segment[1].Xsiz, c.segment[1].Ysiz),
|
||||
self.assertEqual((c.segment[1].xsiz, c.segment[1].ysiz),
|
||||
(2592, 1944))
|
||||
# Reference grid offset
|
||||
self.assertEqual((c.segment[1].XOsiz, c.segment[1].YOsiz), (0, 0))
|
||||
self.assertEqual((c.segment[1].xosiz, c.segment[1].yosiz), (0, 0))
|
||||
# Tile size
|
||||
self.assertEqual((c.segment[1].XTsiz, c.segment[1].YTsiz),
|
||||
self.assertEqual((c.segment[1].xtsiz, c.segment[1].ytsiz),
|
||||
(2592, 1944))
|
||||
# Tile offset
|
||||
self.assertEqual((c.segment[1].XTOsiz, c.segment[1].YTOsiz),
|
||||
self.assertEqual((c.segment[1].xtosiz, c.segment[1].ytosiz),
|
||||
(0, 0))
|
||||
# bitdepth
|
||||
self.assertEqual(c.segment[1]._bitdepth, (8, 8, 8))
|
||||
# signed
|
||||
self.assertEqual(c.segment[1]._signed, (False, False, False))
|
||||
# subsampling
|
||||
self.assertEqual(list(zip(c.segment[1].XRsiz, c.segment[1].YRsiz)),
|
||||
self.assertEqual(list(zip(c.segment[1].xrsiz, c.segment[1].yrsiz)),
|
||||
[(1, 1)] * 3)
|
||||
|
||||
# COD: Coding style default
|
||||
self.assertFalse(c.segment[2].Scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].Scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].SPcod[0], glymur.core.LRCP)
|
||||
self.assertFalse(c.segment[2].scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].spcod[0], glymur.core.LRCP)
|
||||
self.assertEqual(c.segment[2]._layers, 1) # layers = 1
|
||||
self.assertEqual(c.segment[2].SPcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].SPcod[4], 5) # levels
|
||||
self.assertEqual(c.segment[2].spcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].spcod[4], 5) # levels
|
||||
self.assertEqual(tuple(c.segment[2]._code_block_size),
|
||||
(64, 64)) # cblksz
|
||||
# Selective arithmetic coding BYPASS
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x01)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x01)
|
||||
# RESET context probabilities (RESET)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x02)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x02)
|
||||
# Termination on each coding pass, RESTART(TERMALL)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x04)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x04)
|
||||
# Vertically causal context (VSC)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x08)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x08)
|
||||
# Predictable termination, ERTERM(SEGTERM)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0010)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0010)
|
||||
# Segmentation symbols, SEGMARK(SEGSYSM)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].SPcod[8],
|
||||
glymur.core.WAVELET_TRANSFORM_5x3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].SPcod), 9)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].spcod[8],
|
||||
glymur.core.WAVELET_XFORM_5X3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].spcod), 9)
|
||||
|
||||
def test_NR_ENC_Cevennes2_ppm_10_encode(self):
|
||||
infile = os.path.join(data_root, 'input/nonregression/Cevennes2.ppm')
|
||||
|
|
@ -611,50 +613,50 @@ class TestSuiteWrite(unittest.TestCase):
|
|||
|
||||
# SIZ: Image and tile size
|
||||
# Profile: "0" means profile 2
|
||||
self.assertEqual(c.segment[1].Rsiz, 0)
|
||||
self.assertEqual(c.segment[1].rsiz, 0)
|
||||
# Reference grid size
|
||||
self.assertEqual((c.segment[1].Xsiz, c.segment[1].Ysiz),
|
||||
self.assertEqual((c.segment[1].xsiz, c.segment[1].ysiz),
|
||||
(640, 480))
|
||||
# Reference grid offset
|
||||
self.assertEqual((c.segment[1].XOsiz, c.segment[1].YOsiz), (0, 0))
|
||||
self.assertEqual((c.segment[1].xosiz, c.segment[1].yosiz), (0, 0))
|
||||
# Tile size
|
||||
self.assertEqual((c.segment[1].XTsiz, c.segment[1].YTsiz),
|
||||
self.assertEqual((c.segment[1].xtsiz, c.segment[1].ytsiz),
|
||||
(640, 480))
|
||||
# Tile offset
|
||||
self.assertEqual((c.segment[1].XTOsiz, c.segment[1].YTOsiz),
|
||||
self.assertEqual((c.segment[1].xtosiz, c.segment[1].ytosiz),
|
||||
(0, 0))
|
||||
# bitdepth
|
||||
self.assertEqual(c.segment[1]._bitdepth, (8, 8, 8))
|
||||
# signed
|
||||
self.assertEqual(c.segment[1]._signed, (False, False, False))
|
||||
# subsampling
|
||||
self.assertEqual(list(zip(c.segment[1].XRsiz, c.segment[1].YRsiz)),
|
||||
self.assertEqual(list(zip(c.segment[1].xrsiz, c.segment[1].yrsiz)),
|
||||
[(1, 1)] * 3)
|
||||
|
||||
# COD: Coding style default
|
||||
self.assertFalse(c.segment[2].Scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].Scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].SPcod[0], glymur.core.LRCP)
|
||||
self.assertFalse(c.segment[2].scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].spcod[0], glymur.core.LRCP)
|
||||
self.assertEqual(c.segment[2]._layers, 1) # layers = 1
|
||||
self.assertEqual(c.segment[2].SPcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].SPcod[4], 5) # levels
|
||||
self.assertEqual(c.segment[2].spcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].spcod[4], 5) # levels
|
||||
self.assertEqual(tuple(c.segment[2]._code_block_size),
|
||||
(64, 64)) # cblksz
|
||||
# Selective arithmetic coding BYPASS
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x01)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x01)
|
||||
# RESET context probabilities (RESET)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x02)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x02)
|
||||
# Termination on each coding pass, RESTART(TERMALL)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x04)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x04)
|
||||
# Vertically causal context (VSC)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x08)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x08)
|
||||
# Predictable termination, ERTERM(SEGTERM)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0010)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0010)
|
||||
# Segmentation symbols, SEGMARK(SEGSYSM)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].SPcod[8],
|
||||
glymur.core.WAVELET_TRANSFORM_5x3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].SPcod), 9)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].spcod[8],
|
||||
glymur.core.WAVELET_XFORM_5X3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].spcod), 9)
|
||||
|
||||
def test_NR_ENC_Rome_bmp_11_encode(self):
|
||||
infile = os.path.join(data_root, 'input/nonregression/Rome.bmp')
|
||||
|
|
@ -663,11 +665,11 @@ class TestSuiteWrite(unittest.TestCase):
|
|||
jp2 = Jp2k(tfile.name, 'wb')
|
||||
jp2.write(data, psnr=[30, 35, 50], prog='LRCP', numres=3)
|
||||
|
||||
ids = [box.id for box in jp2.box]
|
||||
ids = [box.box_id for box in jp2.box]
|
||||
lst = ['jP ', 'ftyp', 'jp2h', 'jp2c']
|
||||
self.assertEqual(ids, lst)
|
||||
|
||||
ids = [box.id for box in jp2.box[2].box]
|
||||
ids = [box.box_id for box in jp2.box[2].box]
|
||||
self.assertEqual(ids, ['ihdr', 'colr'])
|
||||
|
||||
# Signature box. Check for corruption.
|
||||
|
|
@ -701,51 +703,51 @@ class TestSuiteWrite(unittest.TestCase):
|
|||
|
||||
# SIZ: Image and tile size
|
||||
# Profile: "0" means profile 2
|
||||
self.assertEqual(c.segment[1].Rsiz, 0)
|
||||
self.assertEqual(c.segment[1].rsiz, 0)
|
||||
# Reference grid size
|
||||
self.assertEqual((c.segment[1].Xsiz, c.segment[1].Ysiz),
|
||||
self.assertEqual((c.segment[1].xsiz, c.segment[1].ysiz),
|
||||
(640, 480))
|
||||
# Reference grid offset
|
||||
self.assertEqual((c.segment[1].XOsiz, c.segment[1].YOsiz),
|
||||
self.assertEqual((c.segment[1].xosiz, c.segment[1].yosiz),
|
||||
(0, 0))
|
||||
# Tile size
|
||||
self.assertEqual((c.segment[1].XTsiz, c.segment[1].YTsiz),
|
||||
self.assertEqual((c.segment[1].xtsiz, c.segment[1].ytsiz),
|
||||
(640, 480))
|
||||
# Tile offset
|
||||
self.assertEqual((c.segment[1].XTOsiz, c.segment[1].YTOsiz),
|
||||
self.assertEqual((c.segment[1].xtosiz, c.segment[1].ytosiz),
|
||||
(0, 0))
|
||||
# bitdepth
|
||||
self.assertEqual(c.segment[1]._bitdepth, (8, 8, 8))
|
||||
# signed
|
||||
self.assertEqual(c.segment[1]._signed, (False, False, False))
|
||||
# subsampling
|
||||
self.assertEqual(list(zip(c.segment[1].XRsiz, c.segment[1].YRsiz)),
|
||||
self.assertEqual(list(zip(c.segment[1].xrsiz, c.segment[1].yrsiz)),
|
||||
[(1, 1)] * 3)
|
||||
|
||||
# COD: Coding style default
|
||||
self.assertFalse(c.segment[2].Scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].Scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].SPcod[0], glymur.core.LRCP)
|
||||
self.assertFalse(c.segment[2].scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].spcod[0], glymur.core.LRCP)
|
||||
self.assertEqual(c.segment[2]._layers, 3) # layers = 3
|
||||
self.assertEqual(c.segment[2].SPcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].SPcod[4], 2) # levels
|
||||
self.assertEqual(c.segment[2].spcod[3], 1) # mct
|
||||
self.assertEqual(c.segment[2].spcod[4], 2) # levels
|
||||
self.assertEqual(tuple(c.segment[2]._code_block_size),
|
||||
(64, 64)) # cblksz
|
||||
# Selective arithmetic coding BYPASS
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x01)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x01)
|
||||
# RESET context probabilities (RESET)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x02)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x02)
|
||||
# Termination on each coding pass, RESTART(TERMALL)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x04)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x04)
|
||||
# Vertically causal context (VSC)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x08)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x08)
|
||||
# Predictable termination, ERTERM(SEGTERM)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0010)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0010)
|
||||
# Segmentation symbols, SEGMARK(SEGSYSM)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].SPcod[8],
|
||||
glymur.core.WAVELET_TRANSFORM_5x3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].SPcod), 9)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].spcod[8],
|
||||
glymur.core.WAVELET_XFORM_5X3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].spcod), 9)
|
||||
|
||||
@unittest.skip("Known failure in openjpeg test suite.")
|
||||
def test_NR_ENC_random_issue_0005_tif_12_encode(self):
|
||||
|
|
@ -762,50 +764,50 @@ class TestSuiteWrite(unittest.TestCase):
|
|||
|
||||
# SIZ: Image and tile size
|
||||
# Profile: "0" means profile 2
|
||||
self.assertEqual(c.segment[1].Rsiz, 0)
|
||||
self.assertEqual(c.segment[1].rsiz, 0)
|
||||
# Reference grid size
|
||||
self.assertEqual((c.segment[1].Xsiz, c.segment[1].Ysiz),
|
||||
self.assertEqual((c.segment[1].xsiz, c.segment[1].ysiz),
|
||||
(1024, 1024))
|
||||
# Reference grid offset
|
||||
self.assertEqual((c.segment[1].XOsiz, c.segment[1].YOsiz), (0, 0))
|
||||
self.assertEqual((c.segment[1].xosiz, c.segment[1].yosiz), (0, 0))
|
||||
# Tile size
|
||||
self.assertEqual((c.segment[1].XTsiz, c.segment[1].YTsiz),
|
||||
self.assertEqual((c.segment[1].xtsiz, c.segment[1].ytsiz),
|
||||
(1024, 1024))
|
||||
# Tile offset
|
||||
self.assertEqual((c.segment[1].XTOsiz, c.segment[1].YTOsiz),
|
||||
self.assertEqual((c.segment[1].xtosiz, c.segment[1].ytosiz),
|
||||
(0, 0))
|
||||
# bitdepth
|
||||
self.assertEqual(c.segment[1]._bitdepth, (16,))
|
||||
# signed
|
||||
self.assertEqual(c.segment[1]._signed, (False,))
|
||||
# subsampling
|
||||
self.assertEqual(list(zip(c.segment[1].XRsiz, c.segment[1].YRsiz)),
|
||||
self.assertEqual(list(zip(c.segment[1].xrsiz, c.segment[1].yrsiz)),
|
||||
[(1, 1)])
|
||||
|
||||
# COD: Coding style default
|
||||
self.assertFalse(c.segment[2].Scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].Scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].SPcod[0], glymur.core.LRCP)
|
||||
self.assertFalse(c.segment[2].scod & 2) # no sop
|
||||
self.assertFalse(c.segment[2].scod & 4) # no eph
|
||||
self.assertEqual(c.segment[2].spcod[0], glymur.core.LRCP)
|
||||
self.assertEqual(c.segment[2]._layers, 1) # layers = 1
|
||||
self.assertEqual(c.segment[2].SPcod[3], 0) # mct
|
||||
self.assertEqual(c.segment[2].SPcod[4], 5) # levels
|
||||
self.assertEqual(c.segment[2].spcod[3], 0) # mct
|
||||
self.assertEqual(c.segment[2].spcod[4], 5) # levels
|
||||
self.assertEqual(tuple(c.segment[2]._code_block_size),
|
||||
(64, 64)) # cblksz
|
||||
# Selective arithmetic coding BYPASS
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x01)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x01)
|
||||
# RESET context probabilities (RESET)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x02)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x02)
|
||||
# Termination on each coding pass, RESTART(TERMALL)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x04)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x04)
|
||||
# Vertically causal context (VSC)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x08)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x08)
|
||||
# Predictable termination, ERTERM(SEGTERM)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0010)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0010)
|
||||
# Segmentation symbols, SEGMARK(SEGSYSM)
|
||||
self.assertFalse(c.segment[2].SPcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].SPcod[8],
|
||||
glymur.core.WAVELET_TRANSFORM_5x3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].SPcod), 9)
|
||||
self.assertFalse(c.segment[2].spcod[7] & 0x0020)
|
||||
self.assertEqual(c.segment[2].spcod[8],
|
||||
glymur.core.WAVELET_XFORM_5X3_REVERSIBLE)
|
||||
self.assertEqual(len(c.segment[2].spcod), 9)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#pylint: disable-all
|
||||
import os
|
||||
import pkg_resources
|
||||
import struct
|
||||
|
|
@ -21,7 +22,8 @@ except:
|
|||
raise
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjp2._OPENJP2 is None,
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestPrintingNeedsLib(unittest.TestCase):
|
||||
"""These tests require the library, mostly in order to just setup the test.
|
||||
|
|
@ -34,7 +36,7 @@ class TestPrintingNeedsLib(unittest.TestCase):
|
|||
with tempfile.NamedTemporaryFile(suffix='.jp2', delete=False) as tfile:
|
||||
cls._plain_nemo_file = tfile.name
|
||||
ijfile = Jp2k(jp2file)
|
||||
data = ijfile.read(reduce=3)
|
||||
data = ijfile.read(rlevel=1)
|
||||
ojfile = Jp2k(cls._plain_nemo_file, 'wb')
|
||||
ojfile.write(data)
|
||||
|
||||
|
|
@ -43,8 +45,9 @@ class TestPrintingNeedsLib(unittest.TestCase):
|
|||
os.unlink(cls._plain_nemo_file)
|
||||
|
||||
def setUp(self):
|
||||
self.jp2file = pkg_resources.resource_filename(glymur.__name__,
|
||||
"data/nemo.jp2")
|
||||
self.jp2file = glymur.data.nemo()
|
||||
self.j2kfile = glymur.data.goodstuff()
|
||||
|
||||
# Save sys.stdout.
|
||||
self.stdout = sys.stdout
|
||||
sys.stdout = StringIO()
|
||||
|
|
@ -57,7 +60,7 @@ class TestPrintingNeedsLib(unittest.TestCase):
|
|||
" Compatibility: ['jp2 ']",
|
||||
'JP2 Header Box (jp2h) @ (32, 45)',
|
||||
' Image Header Box (ihdr) @ (40, 22)',
|
||||
' Size: [182 324 3]',
|
||||
' Size: [728 1296 3]',
|
||||
' Bitdepth: 8',
|
||||
' Signed: False',
|
||||
' Compression: wavelet',
|
||||
|
|
@ -66,15 +69,15 @@ class TestPrintingNeedsLib(unittest.TestCase):
|
|||
' Method: enumerated colorspace',
|
||||
' Precedence: 0',
|
||||
' Colorspace: sRGB',
|
||||
'Contiguous Codestream Box (jp2c) @ (77, 112814)',
|
||||
'Contiguous Codestream Box (jp2c) @ (77, 1632355)',
|
||||
' Main header:',
|
||||
' SOC marker segment @ (85, 0)',
|
||||
' SIZ marker segment @ (87, 47)',
|
||||
' Profile: 2',
|
||||
' Reference Grid Height, Width: (182 x 324)',
|
||||
' Reference Grid Height, Width: (728 x 1296)',
|
||||
' Vertical, Horizontal Reference Grid Offset: '
|
||||
+ '(0 x 0)',
|
||||
' Reference Tile Height, Width: (182 x 324)',
|
||||
' Reference Tile Height, Width: (728 x 1296)',
|
||||
' Vertical, Horizontal Reference Tile Offset: '
|
||||
+ '(0 x 0)',
|
||||
' Bitdepth: (8, 8, 8)',
|
||||
|
|
@ -121,7 +124,7 @@ class TestPrintingNeedsLib(unittest.TestCase):
|
|||
def test_asoc_label_box(self):
|
||||
# Construct a fake file with an asoc and a label box, as
|
||||
# OpenJPEG doesn't have such a file.
|
||||
data = glymur.Jp2k(self.jp2file).read(reduce=3)
|
||||
data = glymur.Jp2k(self.jp2file).read(rlevel=1)
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = glymur.Jp2k(tfile.name, 'wb')
|
||||
j.write(data)
|
||||
|
|
@ -177,7 +180,7 @@ class TestPrintingNeedsLib(unittest.TestCase):
|
|||
lst = actual.split('\n')
|
||||
lst = lst[1:]
|
||||
actual = '\n'.join(lst)
|
||||
|
||||
self.maxDiff = None
|
||||
self.assertEqual(actual, self.expectedPlain)
|
||||
|
||||
def test_entire_file(self):
|
||||
|
|
@ -209,15 +212,15 @@ class TestPrinting(unittest.TestCase):
|
|||
def test_COC_segment(self):
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
codestream = j.get_codestream(header_only=False)
|
||||
print(codestream.segment[5])
|
||||
print(codestream.segment[6])
|
||||
actual = sys.stdout.getvalue().strip()
|
||||
|
||||
lines = ['COC marker segment @ (3233, 9)',
|
||||
lines = ['COC marker segment @ (3260, 9)',
|
||||
' Associated component: 1',
|
||||
' Coding style for this component: '
|
||||
+ 'Entropy coder, PARTITION = 0',
|
||||
' Coding style parameters:',
|
||||
' Number of resolutions: 6',
|
||||
' Number of resolutions: 2',
|
||||
' Code block height, width: (64 x 64)',
|
||||
' Wavelet transform: 5-3 reversible',
|
||||
' Code block context:',
|
||||
|
|
@ -230,6 +233,7 @@ class TestPrinting(unittest.TestCase):
|
|||
' Segmentation symbols: False']
|
||||
|
||||
expected = '\n'.join(lines)
|
||||
self.maxDiff = None
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_COD_segment(self):
|
||||
|
|
@ -245,10 +249,10 @@ class TestPrinting(unittest.TestCase):
|
|||
' EPH marker segments: False',
|
||||
' Coding style parameters:',
|
||||
' Progression order: LRCP',
|
||||
' Number of layers: 3',
|
||||
' Number of layers: 2',
|
||||
' Multiple component transformation usage: '
|
||||
+ 'reversible',
|
||||
' Number of resolutions: 6',
|
||||
' Number of resolutions: 2',
|
||||
' Code block height, width: (64 x 64)',
|
||||
' Wavelet transform: 5-3 reversible',
|
||||
' Precinct size: default, 2^15 x 2^15',
|
||||
|
|
@ -392,7 +396,7 @@ class TestPrinting(unittest.TestCase):
|
|||
print(codestream.segment[-1])
|
||||
actual = sys.stdout.getvalue().strip()
|
||||
|
||||
lines = ['EOC marker segment @ (1136552, 0)']
|
||||
lines = ['EOC marker segment @ (1135421, 0)']
|
||||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
|
|
@ -476,15 +480,13 @@ class TestPrinting(unittest.TestCase):
|
|||
def test_QCC_segment(self):
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
codestream = j.get_codestream(header_only=False)
|
||||
print(codestream.segment[6])
|
||||
print(codestream.segment[7])
|
||||
actual = sys.stdout.getvalue().strip()
|
||||
|
||||
lines = ['QCC marker segment @ (3244, 20)',
|
||||
lines = ['QCC marker segment @ (3271, 8)',
|
||||
' Associated Component: 1',
|
||||
' Quantization style: no quantization, 2 guard bits',
|
||||
' 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)]']
|
||||
' Step size: [(0, 8), (0, 9), (0, 9), (0, 10)]']
|
||||
|
||||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
|
@ -495,11 +497,9 @@ class TestPrinting(unittest.TestCase):
|
|||
print(codestream.segment[3])
|
||||
actual = sys.stdout.getvalue().strip()
|
||||
|
||||
lines = ['QCD marker segment @ (3200, 19)',
|
||||
lines = ['QCD marker segment @ (3200, 7)',
|
||||
' Quantization style: no quantization, 2 guard bits',
|
||||
' 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)]']
|
||||
' Step size: [(0, 8), (0, 9), (0, 9), (0, 10)]']
|
||||
|
||||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
|
@ -514,7 +514,7 @@ class TestPrinting(unittest.TestCase):
|
|||
' Profile: 2',
|
||||
' Reference Grid Height, Width: (1456 x 2592)',
|
||||
' Vertical, Horizontal Reference Grid Offset: (0 x 0)',
|
||||
' Reference Tile Height, Width: (512 x 512)',
|
||||
' Reference Tile Height, Width: (1456 x 2592)',
|
||||
' Vertical, Horizontal Reference Tile Offset: (0 x 0)',
|
||||
' Bitdepth: (8, 8, 8)',
|
||||
' Signed: (False, False, False)',
|
||||
|
|
@ -537,26 +537,27 @@ class TestPrinting(unittest.TestCase):
|
|||
def test_SOD_segment(self):
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
codestream = j.get_codestream(header_only=False)
|
||||
print(codestream.segment[9])
|
||||
print(codestream.segment[10])
|
||||
actual = sys.stdout.getvalue().strip()
|
||||
|
||||
lines = ['SOD marker segment @ (3299, 0)']
|
||||
lines = ['SOD marker segment @ (3302, 0)']
|
||||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_SOT_segment(self):
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
codestream = j.get_codestream(header_only=False)
|
||||
print(codestream.segment[4])
|
||||
print(codestream.segment[5])
|
||||
actual = sys.stdout.getvalue().strip()
|
||||
|
||||
lines = ['SOT marker segment @ (3221, 10)',
|
||||
lines = ['SOT marker segment @ (3248, 10)',
|
||||
' Tile part index: 0',
|
||||
' Tile part length: 78629',
|
||||
' Tile part length: 1132173',
|
||||
' Tile part instance: 0',
|
||||
' Number of tile parts: 1']
|
||||
|
||||
expected = '\n'.join(lines)
|
||||
self.maxDiff = None
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
|
|
@ -606,7 +607,7 @@ class TestPrinting(unittest.TestCase):
|
|||
' Profile: 2',
|
||||
' Reference Grid Height, Width: (1456 x 2592)',
|
||||
' Vertical, Horizontal Reference Grid Offset: (0 x 0)',
|
||||
' Reference Tile Height, Width: (512 x 512)',
|
||||
' Reference Tile Height, Width: (1456 x 2592)',
|
||||
' Vertical, Horizontal Reference Tile Offset: (0 x 0)',
|
||||
' Bitdepth: (8, 8, 8)',
|
||||
' Signed: (False, False, False)',
|
||||
|
|
@ -619,10 +620,10 @@ class TestPrinting(unittest.TestCase):
|
|||
' EPH marker segments: False',
|
||||
' Coding style parameters:',
|
||||
' Progression order: LRCP',
|
||||
' Number of layers: 3',
|
||||
' Number of layers: 2',
|
||||
' Multiple component transformation usage: '
|
||||
+ 'reversible',
|
||||
' Number of resolutions: 6',
|
||||
' Number of resolutions: 2',
|
||||
' Code block height, width: (64 x 64)',
|
||||
' Wavelet transform: 5-3 reversible',
|
||||
' Precinct size: default, 2^15 x 2^15',
|
||||
|
|
@ -634,14 +635,14 @@ class TestPrinting(unittest.TestCase):
|
|||
' Vertically stripe causal context: False',
|
||||
' Predictable termination: False',
|
||||
' Segmentation symbols: False',
|
||||
' QCD marker segment @ (3200, 19)',
|
||||
' QCD marker segment @ (3200, 7)',
|
||||
' Quantization style: no quantization, '
|
||||
+ '2 guard bits',
|
||||
' 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)]']
|
||||
' Step size: [(0, 8), (0, 9), (0, 9), (0, 10)]',
|
||||
' CME marker segment @ (3209, 37)',
|
||||
' "Created by OpenJPEG version 2.0.0"']
|
||||
expected = '\n'.join(lst)
|
||||
self.maxDiff = None
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
|
|
@ -783,6 +784,7 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_less_common_boxes(self):
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
with open(self.jp2file, 'rb') as ifile:
|
||||
|
|
|
|||
30
release.txt
Normal file
30
release.txt
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
| OS | Python 2.7 | Python 3.3 | Notes |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
| Windows | X | | Python(xy) with OpenJPEG 1.5.1. At |
|
||||
| | | | least 155 of 444 tests should pass. |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
| Windows | X | | Python(xy) with OpenJPEG 1.5.1 and |
|
||||
| | | | OpenJPEG svn. At least 282 of 444 |
|
||||
| | | | tests should pass. |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
| Mac | X | | MacPorts with both OpenJPEG 1.5.1 |
|
||||
| | | | and OpenJPEG svn. 370 of 450 tests |
|
||||
| | | | should pass. |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
| Mac | | X | MacPorts with both OpenJPEG 1.5.1 |
|
||||
| | | | and OpenJPEG svn. 390 of 450 |
|
||||
| | | | tests should pass. |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
| Fedora 19 | | X | Ships with 1.5.1. 390 of 450 tests |
|
||||
| | | | should pass. |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
| Fedora 18 | | X | Ships with 1.5.1. 167 of 445 tests |
|
||||
| | | | should pass. |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
| Fedora 17 | X | | Ships with 1.4. Should error out |
|
||||
| | | | gracefully. |
|
||||
+------------+------------+------------+--------------------------------------+
|
||||
|
||||
Pylint on entire package should be at least 0.95.
|
||||
pep8 should be pass cleanly.
|
||||
Coverage should exceed 95%.
|
||||
5
setup.py
5
setup.py
|
|
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||
import sys
|
||||
|
||||
kwargs = {'name': 'Glymur',
|
||||
'version': '0.1.10',
|
||||
'version': '0.2.0',
|
||||
'description': 'Tools for accessing JPEG2000 files',
|
||||
'long_description': open('README.md').read(),
|
||||
'author': 'John Evans',
|
||||
|
|
@ -26,9 +26,10 @@ clssfrs = ["Programming Language :: Python",
|
|||
"Programming Language :: Python :: 3.3",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Operating System :: MacOS",
|
||||
"Operating System :: POSIX :: Linux",
|
||||
"Operating System :: Microsoft :: Windows :: Windows XP",
|
||||
"Intended Audience :: Science/Research",
|
||||
"Intended Audience :: Information Technology",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue