Compare commits

...
Sign in to create a new pull request.

2 commits

Author SHA1 Message Date
John Evans
f37da173e3 Releasing 0.5.12.
Fix a few documentation warts.
Added changelog into RST documentation.
Restored glymur.lib.openjp2.*_v3 functions removed in 0.5.11
2014-05-18 18:27:51 -04:00
jevans
5936706f0e Releasing 0.5.11.
Updated to support OpenJPEG versions 1.5.2, 2.0.1, and 2.1.
Updated to support Python 3.4.
Cleaned up and refactored many tests.
Dropped some tests that were always skipped.
2014-05-13 07:28:59 -04:00
29 changed files with 1419 additions and 7044 deletions

View file

@ -3,6 +3,7 @@ python:
- "2.6"
- "2.7"
- "3.3"
- "3.4"
before_install:
- sudo apt-get update -qq
@ -15,12 +16,14 @@ install:
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install --use-mirrors contextlib2 mock ordereddict unittest2; fi
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --use-mirrors contextlib2 mock; fi
- if [[ $TRAVIS_PYTHON_VERSION == '3.3' ]]; then pip install --use-mirrors numpy; fi
- if [[ $TRAVIS_PYTHON_VERSION == '3.4' ]]; then pip install --use-mirrors numpy; fi
# command to run tests
script:
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then unit2 discover; fi
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then python -m unittest discover; fi
- if [[ $TRAVIS_PYTHON_VERSION == '3.3' ]]; then python -m unittest discover; fi
- if [[ $TRAVIS_PYTHON_VERSION == '3.4' ]]; then python -m unittest discover; fi
notifications:
email: "john.g.evans.ne@gmail.com"

View file

@ -1,3 +1,8 @@
May 18, 2014 - v0.5.12 Restored _v3 functions removed in 0.5.11
May 09, 2014 - v0.5.11 Added support for Python 3.4, OpenJPEG 2.0.1, and
OpenJPEG 2.1.0.
Jan 28, 2014 - v0.5.10 Fixed bad warning when reader requirements box mask
length is unsupported.

View file

@ -3,7 +3,6 @@ glymur: a Python interface for JPEG 2000
**glymur** contains a Python interface to the OpenJPEG library which
allows one to read and write JPEG 2000 files. **glymur** works on
Python 2.6, 2.7 and 3.3. Python 3.3 is strongly
recommended.
Python 2.6, 2.7, 3.3, and 3.4.
Please read the docs, https://glymur.readthedocs.org/en/latest/

View file

@ -78,7 +78,7 @@ copyright = u'2013, John Evans'
# The short X.Y version.
version = '0.5'
# The full version, including alpha/beta/rc tags.
release = '0.5.10'
release = '0.5.12'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View file

@ -1,33 +1,25 @@
----------------------------------
Advanced Installation Instructions
----------------------------------
Most users won't need to read this! You've been warned...
''''''''''''''''''''''
Glymur Configuration
''''''''''''''''''''''
The default glymur installation process relies upon OpenJPEG
being properly installed on your system. If you have version 1.5 you can
both read and write JPEG 2000 files, but you may wish to install version 2.0
or the 2.0+ version from OpenJPEG's development trunk for better performance.
If you do that, you should compile it 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 2347 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. ::
The default glymur installation process relies upon OpenJPEG being
properly installed on your system as a shared library. If you have OpenJPEG
installed through your system's package manager on linux or if you use MacPorts
on the mac, you are probably already set to go. But if you have OpenJPEG
installed into a non-standard place or if you use windows, then read on.
$ svn co http://openjpeg.googlecode.com/svn/data
$ export OPJ_DATA_ROOT=`pwd`/data
Glymur uses ctypes to access the openjp2/openjpeg libraries,
and because ctypes accesses libraries in a platform-dependent manner, it is
recommended that you create a configuration file to help Glymur properly find
the openjpeg or openjp2 libraries (linux users don't need to bother with this
if you are using OpenJPEG as provided by your package manager). The
configuration format is the same as used by Python's configparser module,
Glymur uses ctypes to access the openjp2/openjpeg libraries, and
because ctypes accesses libraries in a platform-dependent manner,
it is recommended that if you compile and install OpenJPEG into a
non-standard location, you should then create a configuration file to
help Glymur properly find the openjpeg or openjp2 libraries (linux
users or macports users don't need to bother with this if you are
using OpenJPEG as provided by your package manager). The configuration
format is the same as used by Python's configparser module,
i.e. ::
[library]
@ -35,7 +27,7 @@ i.e. ::
This assumes, of course, that you've installed OpenJPEG into
/opt/openjp2-svn on a linux system. The location of the configuration file
can vary as well (of course). If you use either linux or mac, the path
can vary as well. If you use either linux or mac, the path
to the configuration file would normally be ::
$HOME/.config/glymur/glymurrc
@ -58,78 +50,17 @@ installed in a non-standard place, i.e. ::
[library]
openjpeg: /not/the/usual/location/lib/libopenjpeg.so
''''''''''''''''''''''''''''''
Package Management Suggestions
''''''''''''''''''''''''''''''
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.
Mac OS X
--------
All the necessary packages are available to use glymur with Python 2.6, 2.7,
and 3.3 via MacPorts. For python 3.3, you should install the following set of
ports:
* python33
* py33-numpy
* py33-distribute
* py33-matplotlib (optional, for running certain tests)
* py33-Pillow (optional, for running certain tests)
MacPorts supplies both OpenJPEG 1.5.0 and OpenJPEG 2.0.0.
Linux
-----
For the most part, you only need python and numpy to run glymur, so on
just about all distributions you are already set to go (and you don't
need to mess around with a configuration file, as the openjpeg shared
libraries are found in the usual places thanks to your package manager).
In order to run as many tests as possible, however, the following Python
packages may also need to be installed. Consult your package manager
documentation or use pip.
* setuptools
* matplotlib
* pillow
* contextlib2 (python 2.6, 2.7 only)
* mock (python 2.6, 2.7 only)
* ordereddict (python 2.6 only)
Glymur's been tested on the following linux platforms without any unexpected
difficulties:
* OpenSUSE 12.3
* Fedora 17, 18, 19
* Raspian
* Travis CI (currently Ubuntu 12.04?)
* CentOS 6.4
Windows
-------
32-bit WinPython 2.7.5 seemed to work with OpenJPEG 1.X, 2.0, and the
development version, but still required contextlib2 and mock to be
installed via pip. WinPython 3.3.2, however, seems to have trouble
with OpenJPEG 2.0, so I would suggest using the development version with
that configuration. I no longer have any access to a windows machine,
so I cannot currently offer much guidance here.
'''''''
Testing
'''''''
It is not necessary, but you may wish to download OpenJPEG's test
data for the purpose of configuring and running OpenJPEG's test
suite. Check their instructions on how to do that. You can then
set the **OPJ_DATA_ROOT** environment variable for the purpose of
pointing Glymur to OpenJPEG's test suite. ::
There are two environment variables you may wish to set before running the
tests.
* **OPJ_DATA_ROOT** - points to directory for OpenJPEG test data (see above)
* **FORMAT_CORPUS_DATA_ROOT** - points to directory for format-corpus repository (see https://github.com/openplanets/format-corpus if you wish, but you really don't need to bother with this)
Setting these two environment variables is not required, as any tests using
either of them will be skipped.
$ svn co http://openjpeg.googlecode.com/svn/data
$ export OPJ_DATA_ROOT=`pwd`/data
In order to run the tests, you can either run them from within
python as follows ... ::
@ -141,11 +72,3 @@ or from the command line. ::
$ cd /to/where/you/unpacked/glymur
$ python -m unittest discover
Quite a few tests are currently skipped. These include tests whose
OpenJPEG counterparts are already failing, and others which do pass but
still produce heaps of output on stderr. Rather than let this swamp
the signal (that most of those tests are actually passing), they've been
filtered out for now. There are also more skipped tests on Python 2.7
than on Python 3.3. The important part is whether or not any test
errors are reported at the end.

View file

@ -4,7 +4,7 @@ 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
resolution level. ::
@ -15,7 +15,7 @@ resolution level. ::
>>> thumbnail = j.read(rlevel=-1)
... display metadata?
=================
=====================
There are two ways. From the unix command line, the script *jp2dump* is
available. ::
@ -35,7 +35,7 @@ codestream box, only the main header is printed. It is possible to print
>>> print(j.get_codestream())
... add XML metadata?
=================
=====================
You can append any number of XML boxes to a JP2 file (not to a raw codestream).
Consider the following XML file `data.xml` : ::
@ -67,11 +67,12 @@ The **append** method can add an XML box as shown below::
>>> print(jp2)
... add metadata in a more general fashion?
=======================================
An existing raw codestream (or JP2 file) can be wrapped (re-wrapped) in a
user-defined set of JP2 boxes. To get just a minimal JP2 jacket on the
codestream provided by `goodstuff.j2k` (a file consisting of a raw codestream),
you can use the **wrap** method with no box argument: ::
===========================================
An existing raw codestream or JP2 file can be wrapped (re-wrapped in the case
of JP2) in a user-defined set of JP2 boxes. To get just a minimal
JP2 jacket on the codestream provided by `goodstuff.j2k` (a file
consisting of just a raw codestream), you can use the **wrap** method
with no box argument: ::
>>> import glymur
>>> jfile = glymur.data.goodstuff()
@ -106,10 +107,12 @@ layer (the signature, file type, JP2 header, and contiguous codestream), with
two additional boxes (image header and color specification) contained in the
JP2 header superbox.
XML boxes are not in the minimal set of box requirements for the JP2 format, so
in order to add an XML box into the mix before the codestream box, we'll need to
re-specify all of the boxes. If you already have a JP2 jacket in place, you can just reuse that,
though. Take the following example content in an XML file `favorites.xml` : ::
XML boxes are not in the minimal set of box requirements for the
JP2 format, so in order to add an XML box into the mix before the
codestream box, we'll need to re-specify all of the boxes. If you
already have a JP2 jacket in place, you can just reuse that, though.
Take the following example content in an XML file `favorites.xml`
: ::
<?xml version="1.0"?>
<favorite_things>
@ -158,11 +161,11 @@ while **append** modifies an existing file and is currently limited to XML
boxes.
... create an image with an alpha layer?
====================================
========================================
OpenJPEG can create JP2 files with more than 3 components (requires
the development version of OpenJPEG), but by default, any extra components are
not described as such. In order to do so, we need to rewrap such
OpenJPEG can create JP2 files with more than 3 components (requires version
2.1), but by default any extra components are not described as such by the JP2
boxes created by OpenJPEG. In order to do so, we need to rewrap such
an image in a set of boxes that includes a channel definition box.
This example is based on SciPy example code found at
@ -219,8 +222,8 @@ Here's how the Preview application on the mac shows the RGBA image.
.. image:: goodstuff_alpha.png
work with XMP UUIDs?
====================
... work with XMP UUIDs?
========================
The example JP2 file shipped with glymur has an XMP UUID. ::
>>> import glymur

View file

@ -15,8 +15,10 @@ Contents:
introduction
detailed_installation
how_do_i
roadmap
api
roadmap
whatsnew/index
------------------
Indices and tables

View file

@ -3,7 +3,7 @@ Glymur: a Python interface for JPEG 2000
----------------------------------------
**Glymur** is an interface to the OpenJPEG library
which allows one to read and write JPEG 2000 files from within Python.
which allows one to read and write JPEG 2000 files from Python.
Glymur supports both reading and writing of JPEG 2000 images, but writing
JPEG 2000 images is currently limited to images that can fit in memory
@ -13,14 +13,13 @@ some very limited support for reading JPX metadata. For instance,
**asoc** and **labl** boxes are recognized, so GMLJP2 metadata can
be retrieved from such JPX files.
Glymur works on Python 2.6, 2.7, and 3.3.
Glymur works on Python 2.6, 2.7, 3.3, and 3.4.
OpenJPEG Installation
=====================
Glymur will read JPEG 2000 images with versions 1.3, 1.4, 1.5, 2.0,
and the trunk/development version of OpenJPEG. Writing images is
only supported with the 1.5 or better, however, and the trunk/development
version is strongly recommended. For more information about OpenJPEG,
Glymur will read JPEG 2000 images with versions 1.3, 1.4, 1.5, 2.0, and 2.1 of
OpenJPEG. Writing images is only supported with OpenJPEG 1.5 or better, however,
and version 2.1 is strongly recommended. For more information about OpenJPEG,
please consult http://www.openjpeg.org.
If you use MacPorts or if you have a sufficiently recent version of

View file

@ -0,0 +1,50 @@
=====================
Changes in glymur 0.5
=====================
Changes in 0.5.12
=================
* Minor documentation fixes for grammar and style.
* The functions removed in 0.5.11 due to API changes in OpenJPEG 2.1.0 were
restored for backwards compatibility. They are deprecated, though, and will
be removed in 0.6.0.
* ``glymur.lib.openjp2.stream_create_default_file_stream_v3``
* ``glymur.lib.openjp2.opj.stream_destroy_v3``
Changes in 0.5.11
=================
* Added support for Python 3.4.
* OpenJPEG 1.5.2 and 2.0.1 are officially supported.
* OpenJPEG 2.1.0 is officially supported, but the ABI changes introduced by
OpenJPEG 2.1.0 required corresponding changes to glymur's ctypes interface.
The functions
* ``glymur.lib.openjp2.stream_create_default_file_stream_v3``
* ``glymur.lib.openjp2.opj.stream_destroy_v3``
functions were renamed to
* ``glymur.lib.openjp2.stream_create_default_file_stream``
* ``glymur.lib.openjp2.opj.stream_destroy``
in order to follow OpenJPEG's upstream changes. Unless you were using the
svn version of OpenJPEG, you should not be affected by this.
Changes in 0.5.10
=================
* Fixed bad warning issued when an unsupported reader requirement box mask
length was encountered.
Changes in 0.5.9
================
* Fixed bad library load on linux as a result of botched 0.5.8 release.
This release was primarily aimed at supporting SunPy.

View file

@ -0,0 +1,11 @@
.. _whatsnew:
**********************
"What's new" documents
**********************
These document the changes between minor (or major) versions of glymur.
.. toctree::
0.5

View file

@ -19,6 +19,7 @@ else:
import ctypes
import math
import os
import re
import struct
import warnings
@ -490,16 +491,16 @@ class Jp2k(Jp2kBox):
opj2.setup_encoder(codec, cparams, image)
if _OPENJP2_IS_OFFICIAL_V2:
if re.match("2.0", version.openjpeg_version):
fptr = libc.fopen(self.filename, 'wb')
strm = opj2.stream_create_default_file_stream(fptr, False)
stack.callback(opj2.stream_destroy, strm)
stack.callback(libc.fclose, fptr)
else:
# This routine introduced in 2.0 devel series.
strm = opj2.stream_create_default_file_stream_v3(self.filename,
# This routine introduced in 2.1.
strm = opj2.stream_create_default_file_stream(self.filename,
False)
stack.callback(opj2.stream_destroy_v3, strm)
stack.callback(opj2.stream_destroy, strm)
opj2.start_compress(codec, image, strm)
opj2.encode(codec, strm)
@ -807,17 +808,16 @@ class Jp2k(Jp2kBox):
dparam = self._populate_dparam(layer, rlevel, area, tile)
with ExitStack() as stack:
if hasattr(opj2.OPENJP2,
'opj_stream_create_default_file_stream_v3'):
filename = self.filename
stream = opj2.stream_create_default_file_stream_v3(filename,
True)
stack.callback(opj2.stream_destroy_v3, stream)
else:
if re.match("2.0", version.openjpeg_version):
fptr = libc.fopen(self.filename, 'rb')
stack.callback(libc.fclose, fptr)
stream = opj2.stream_create_default_file_stream(fptr, True)
stack.callback(opj2.stream_destroy, stream)
else:
filename = self.filename
stream = opj2.stream_create_default_file_stream(filename, True)
stack.callback(opj2.stream_destroy, stream)
codec = opj2.create_decompress(self._codec_format)
stack.callback(opj2.destroy_codec, codec)
@ -952,17 +952,15 @@ class Jp2k(Jp2kBox):
dparam = self._populate_dparam(layer, rlevel, area, tile)
with ExitStack() as stack:
if hasattr(opj2.OPENJP2,
'opj_stream_create_default_file_stream_v3'):
filename = self.filename
stream = opj2.stream_create_default_file_stream_v3(filename,
True)
stack.callback(opj2.stream_destroy_v3, stream)
else:
if re.match("2.0", version.openjpeg_version):
fptr = libc.fopen(self.filename, 'rb')
stack.callback(libc.fclose, fptr)
stream = opj2.stream_create_default_file_stream(fptr, True)
stack.callback(opj2.stream_destroy, stream)
else:
filename = self.filename
stream = opj2.stream_create_default_file_stream(filename, True)
stack.callback(opj2.stream_destroy, stream)
codec = opj2.create_decompress(self._codec_format)
stack.callback(opj2.destroy_codec, codec)
@ -1389,7 +1387,7 @@ def _validate_compression_params(img_array, cparams):
msg = "{0}D imagery is not allowed.".format(img_array.ndim)
raise IOError(msg)
if _OPENJP2_IS_OFFICIAL_V2:
if re.match("2.0.0", version.openjpeg_version):
if (((img_array.ndim != 2) and
(img_array.shape[2] != 1 and img_array.shape[2] != 3))):
msg = "Writing images is restricted to single-channel "
@ -1402,14 +1400,6 @@ def _validate_compression_params(img_array, cparams):
msg = "Only uint8 and uint16 images are currently supported."
raise RuntimeError(msg)
# Need to known if openjp2 library is the officially release v2.0.0 or not.
_OPENJP2_IS_OFFICIAL_V2 = False
if opj2.OPENJP2 is not None:
if opj2.version() == '2.0.0':
if not hasattr(opj2.OPENJP2,
'opj_stream_create_default_file_stream_v3'):
_OPENJP2_IS_OFFICIAL_V2 = True
_COLORSPACE_MAP = {'rgb': opj2.CLRSPC_SRGB,
'gray': opj2.CLRSPC_GRAY,
'grey': opj2.CLRSPC_GRAY,

View file

@ -5,11 +5,29 @@ Wraps individual functions in openjp2 library.
# pylint: disable=C0302,R0903,W0201
import ctypes
import re
import sys
from .config import glymur_config
OPENJP2, OPENJPEG = glymur_config()
def version():
"""Wrapper for opj_version library routine."""
try:
OPENJP2.opj_version.restype = ctypes.c_char_p
except AttributeError:
# No library, so the version is zero.
return "0.0.0"
library_version = OPENJP2.opj_version()
if sys.hexversion >= 0x03000000:
return library_version.decode('utf-8')
else:
return library_version
if OPENJP2 is not None:
_MAJOR, _MINOR, _PATH = version().split('.')
else:
_MINOR = 0
ERROR_MSG_LST = []
# Map certain atomic OpenJPEG datatypes to the ctypes equivalents.
@ -353,6 +371,16 @@ class CompressionParametersType(ctypes.Structure):
# based encoding without offset concerning all the components.
("mct_data", ctypes.c_void_p)]
if _MINOR == '1':
# Maximum size (in bytes) for the whole codestream.
# If == 0, codestream size limitation is not considered.
# If it does not comply with tcp_rates, max_cs_size prevails and a
# warning is issued.
_fields_.append(("max_cs_size", ctypes.c_int32))
# To be used to combine OPJ_PROFILE_*, OPJ_EXTENSION_* and (sub)levels
# values.
_fields_.append(("rsiz", ctypes.c_uint16))
class ImageCompType(ctypes.Structure):
"""Defines a single image component.
@ -392,6 +420,9 @@ class ImageCompType(ctypes.Structure):
# image component data
("data", ctypes.POINTER(ctypes.c_int32))]
if _MINOR == '1':
_fields_.append(("alpha", ctypes.c_uint16))
class ImageType(ctypes.Structure):
"""Defines image data and characteristics.
@ -1261,11 +1292,10 @@ def start_compress(codec, image, stream):
OPENJP2.opj_start_compress(codec, image, stream)
def stream_create_default_file_stream(fptr, isa_read_stream):
"""Wraps openjp2 library function opj_stream_create_default_vile_stream.
def _stream_create_default_file_stream_2p0(fptr, isa_read_stream):
"""Wraps openjp2 library function opj_stream_create_default_file_stream.
Sets the stream to be a file stream. This is valid only for version 2.0.0
of OpenJPEG.
Sets the stream to be a file stream.
Parameters
----------
@ -1287,11 +1317,10 @@ def stream_create_default_file_stream(fptr, isa_read_stream):
return stream
def stream_create_default_file_stream_v3(fname, isa_read_stream):
"""Wraps openjp2 library function opj_stream_create_default_vile_stream_v3.
def _stream_create_default_file_stream_2p1(fname, isa_read_stream):
"""Wraps openjp2 library function opj_stream_create_default_file_stream.
Sets the stream to be a file stream. This function is only valid for the
trunk/development 2.0+ version of the openjp2 library.
Sets the stream to be a file stream.
Parameters
----------
@ -1306,15 +1335,14 @@ def stream_create_default_file_stream_v3(fname, isa_read_stream):
An OpenJPEG file stream.
"""
ARGTYPES = [ctypes.c_char_p, ctypes.c_int32]
OPENJP2.opj_stream_create_default_file_stream_v3.argtypes = ARGTYPES
OPENJP2.opj_stream_create_default_file_stream_v3.restype = STREAM_TYPE_P
OPENJP2.opj_stream_create_default_file_stream.argtypes = ARGTYPES
OPENJP2.opj_stream_create_default_file_stream.restype = STREAM_TYPE_P
read_stream = 1 if isa_read_stream else 0
file_argument = ctypes.c_char_p(fname.encode())
stream = OPENJP2.opj_stream_create_default_file_stream_v3(file_argument,
read_stream)
stream = OPENJP2.opj_stream_create_default_file_stream(file_argument,
read_stream)
return stream
def stream_destroy(stream):
"""Wraps openjp2 library function opj_stream_destroy.
@ -1329,21 +1357,51 @@ def stream_destroy(stream):
OPENJP2.opj_stream_destroy.restype = ctypes.c_void_p
OPENJP2.opj_stream_destroy(stream)
if re.match(r'''2.0''', version()):
# We must have the 2.0.x
stream_create_default_file_stream = _stream_create_default_file_stream_2p0
else:
# We must have version 2.1.
stream_create_default_file_stream = _stream_create_default_file_stream_2p1
def stream_destroy_v3(stream):
"""Wraps openjp2 library function opj_stream_destroy_v3.
# The _v3 functions existed only in the SVN version of OpenJPEG, before 2.1.0
# was released
stream_create_default_file_stream_v3 = _stream_create_default_file_stream_2p1
stream_create_default_file_stream_v3.__doc__ = r"""
Wraps openjp2 library function opj_stream_create_default_file_stream_v3.
Destroys the stream created by create_stream_v3.
Sets the stream to be a file stream.
This function is deprecated and will be removed in the 0.6.0 version of
glymur. Please use stream_create_default_file_stream instead.
Parameters
----------
fname : str
Specifies a file.
isa_read_stream: bool
True (read) or False (write)
Returns
-------
stream : stream_t
An OpenJPEG file stream.
"""
stream_destroy_v3 = stream_destroy
stream_destroy_v3.__doc__ = r"""
Wraps openjp2 library function opj_stream_destroy.
Destroys the stream created by create_stream.
This function is deprecated and wil be removed in the 0.6.0 version of
glymur. Please use stream_destroy instead.
Parameters
----------
stream : STREAM_TYPE_P
The file stream.
"""
OPENJP2.opj_stream_destroy_v3.argtypes = [STREAM_TYPE_P]
OPENJP2.opj_stream_destroy_v3.restype = ctypes.c_void_p
OPENJP2.opj_stream_destroy_v3(stream)
def write_tile(codec, tile_index, data, data_size, stream):
"""Wraps openjp2 library function opj_write_tile.
@ -1388,11 +1446,3 @@ def set_error_message(msg):
ERROR_MSG_LST.append(msg)
def version():
"""Wrapper for opj_version library routine."""
OPENJP2.opj_version.restype = ctypes.c_char_p
library_version = OPENJP2.opj_version()
if sys.hexversion >= 0x03000000:
return library_version.decode('utf-8')
else:
return library_version

View file

@ -9,6 +9,7 @@ Tests for libopenjp2 wrapping functions.
# pylint: disable=F0401
import os
import re
import sys
import tempfile
@ -22,17 +23,15 @@ import numpy as np
import glymur
from glymur.lib import openjp2
OPENJP2_IS_V2_OFFICIAL = False
if openjp2.OPENJP2 is not None:
if not hasattr(openjp2.OPENJP2,
'opj_stream_create_default_file_stream_v3'):
OPENJP2_IS_V2_OFFICIAL = True
if re.match("2.0", glymur.version.openjpeg_version):
OPENJP2_IS_V2_OFFICIAL = True
else:
OPENJP2_IS_V2_OFFICIAL = False
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
@unittest.skipIf(openjp2.OPENJP2 is None,
"Missing openjp2 library.")
@unittest.skipIf(OPENJP2_IS_V2_OFFICIAL, "API followed here specific to V2.0+")
@unittest.skipIf(OPENJP2_IS_V2_OFFICIAL, "API followed here specific to V2.1")
class TestOpenJP2(unittest.TestCase):
"""Test openjp2 library functionality.
@ -89,7 +88,7 @@ class TestOpenJP2(unittest.TestCase):
openjp2.set_warning_handler(codec, None)
openjp2.set_error_handler(codec, None)
stream = openjp2.stream_create_default_file_stream_v3(filename, True)
stream = openjp2.stream_create_default_file_stream(filename, True)
openjp2.setup_decoder(codec, dparam)
image = openjp2.read_header(stream, codec)
@ -110,7 +109,7 @@ class TestOpenJP2(unittest.TestCase):
openjp2.end_decompress(codec, stream)
openjp2.destroy_codec(codec)
openjp2.stream_destroy_v3(stream)
openjp2.stream_destroy(stream)
openjp2.image_destroy(image)
def test_tte0(self):
@ -318,15 +317,15 @@ def tile_encoder(**kwargs):
openjp2.setup_encoder(codec, l_param, l_image)
stream = openjp2.stream_create_default_file_stream_v3(kwargs['filename'],
False)
stream = openjp2.stream_create_default_file_stream(kwargs['filename'],
False)
openjp2.start_compress(codec, l_image, stream)
for j in np.arange(num_tiles):
openjp2.write_tile(codec, j, data, tile_size, stream)
openjp2.end_compress(codec, stream)
openjp2.stream_destroy_v3(stream)
openjp2.stream_destroy(stream)
openjp2.destroy_codec(codec)
openjp2.image_destroy(l_image)
@ -335,8 +334,8 @@ def tile_decoder(**kwargs):
Reads a tile. That's all it does.
"""
stream = openjp2.stream_create_default_file_stream_v3(kwargs['filename'],
True)
stream = openjp2.stream_create_default_file_stream(kwargs['filename'],
True)
dparam = openjp2.set_default_decoder_parameters()
dparam.decod_format = kwargs['codec_format']
@ -371,7 +370,7 @@ def tile_decoder(**kwargs):
openjp2.end_decompress(codec, stream)
openjp2.destroy_codec(codec)
openjp2.stream_destroy_v3(stream)
openjp2.stream_destroy(stream)
openjp2.image_destroy(image)
def ttx0_setup(filename):

View file

@ -0,0 +1,443 @@
"""
Tests for functions that wrap SVN version of libopenjp2 (before release of
2.1.0)
"""
# R0904: Seems like pylint is fooled in this situation
# W0142: using kwargs is ok in this context
# pylint: disable=R0904,W0142
# unittest2 is python-2.6 only (pylint/python-2.7)
# pylint: disable=F0401
import os
import re
import sys
import tempfile
if sys.hexversion < 0x02070000:
import unittest2 as unittest
else:
import unittest
import numpy as np
import glymur
from glymur.lib import openjp2
if re.match("2.0", glymur.version.openjpeg_version):
OPENJP2_IS_V2_OFFICIAL = True
else:
OPENJP2_IS_V2_OFFICIAL = False
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
@unittest.skipIf(openjp2.OPENJP2 is None,
"Missing openjp2 library.")
@unittest.skipIf(OPENJP2_IS_V2_OFFICIAL, "API followed here specific to V2.1")
class TestOpenJP2(unittest.TestCase):
"""Test openjp2 library functionality.
Some tests correspond to those in the openjpeg test suite.
"""
def test_default_encoder_parameters(self):
"""Ensure that the encoder structure is clean upon init."""
cparams = openjp2.set_default_encoder_parameters()
self.assertEqual(cparams.res_spec, 0)
self.assertEqual(cparams.cblockw_init, 64)
self.assertEqual(cparams.cblockh_init, 64)
self.assertEqual(cparams.numresolution, 6)
self.assertEqual(cparams.subsampling_dx, 1)
self.assertEqual(cparams.subsampling_dy, 1)
self.assertEqual(cparams.mode, 0)
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)
self.assertEqual(cparams.irreversible, 0)
def test_default_decoder_parameters(self):
"""Tests that the structure is clean upon initialization"""
dparams = openjp2.set_default_decoder_parameters()
self.assertEqual(dparams.DA_x0, 0)
self.assertEqual(dparams.DA_y0, 0)
self.assertEqual(dparams.DA_x1, 0)
self.assertEqual(dparams.DA_y1, 0)
def tile_macro(self, codec, stream, imagep, tidx):
"""called only by j2k_random_tile_access"""
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):
"""fixture called by the test_rtaX methods"""
dparam = openjp2.set_default_decoder_parameters()
infile = filename.encode()
nelts = openjp2.PATH_LEN - len(infile)
infile += b'0' * nelts
dparam.infile = infile
dparam.decod_format = codec_format
codec = openjp2.create_decompress(codec_format)
openjp2.set_info_handler(codec, None)
openjp2.set_warning_handler(codec, None)
openjp2.set_error_handler(codec, None)
stream = openjp2.stream_create_default_file_stream_v3(filename, True)
openjp2.setup_decoder(codec, dparam)
image = openjp2.read_header(stream, codec)
cstr_info = openjp2.get_cstr_info(codec)
tile_ul = 0
tile_ur = cstr_info.contents.tw - 1
tile_lr = cstr_info.contents.tw * cstr_info.contents.th - 1
tile_ll = tile_lr - cstr_info.contents.tw
self.tile_macro(codec, stream, image, tile_ul)
self.tile_macro(codec, stream, image, tile_ur)
self.tile_macro(codec, stream, image, tile_lr)
self.tile_macro(codec, stream, image, tile_ll)
openjp2.destroy_cstr_info(cstr_info)
openjp2.end_decompress(codec, stream)
openjp2.destroy_codec(codec)
openjp2.stream_destroy_v3(stream)
openjp2.image_destroy(image)
def test_tte0(self):
"""Runs test designated tte0 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
ttx0_setup(tfile.name)
self.assertTrue(True)
def test_ttd0(self):
"""Runs test designated ttd0 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
# Produce the tte0 output file for ttd0 input.
ttx0_setup(tfile.name)
kwargs = {'x0': 0,
'y0': 0,
'x1': 1000,
'y1': 1000,
'filename': tfile.name,
'codec_format': openjp2.CODEC_J2K}
tile_decoder(**kwargs)
self.assertTrue(True)
def xtx1_setup(self, filename):
"""Runs tests tte1, rta1."""
kwargs = {'filename': filename,
'codec': openjp2.CODEC_J2K,
'comp_prec': 8,
'irreversible': 1,
'num_comps': 3,
'image_height': 256,
'image_width': 256,
'tile_height': 128,
'tile_width': 128}
tile_encoder(**kwargs)
self.assertTrue(True)
def test_tte1(self):
"""Runs test designated tte1 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
self.xtx1_setup(tfile.name)
def test_ttd1(self):
"""Runs test designated ttd1 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
# Produce the tte0 output file for ttd0 input.
self.xtx1_setup(tfile.name)
kwargs = {'x0': 0,
'y0': 0,
'x1': 128,
'y1': 128,
'filename': tfile.name,
'codec_format': openjp2.CODEC_J2K}
tile_decoder(**kwargs)
self.assertTrue(True)
def test_rta1(self):
"""Runs test designated rta1 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
self.xtx1_setup(tfile.name)
codec_format = openjp2.CODEC_J2K
self.j2k_random_tile_access(tfile.name, codec_format)
self.assertTrue(True)
def test_tte2(self):
"""Runs test designated tte2 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
xtx2_setup(tfile.name)
self.assertTrue(True)
def test_ttd2(self):
"""Runs test designated ttd2 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
# Produce the tte0 output file for ttd0 input.
xtx2_setup(tfile.name)
kwargs = {'x0': 0,
'y0': 0,
'x1': 128,
'y1': 128,
'filename': tfile.name,
'codec_format': openjp2.CODEC_JP2}
tile_decoder(**kwargs)
self.assertTrue(True)
def test_rta2(self):
"""Runs test designated rta2 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
xtx2_setup(tfile.name)
codec_format = openjp2.CODEC_JP2
self.j2k_random_tile_access(tfile.name, codec_format)
def test_tte3(self):
"""Runs test designated tte3 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
xtx3_setup(tfile.name)
self.assertTrue(True)
def test_rta3(self):
"""Runs test designated rta3 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
xtx3_setup(tfile.name)
codec_format = openjp2.CODEC_J2K
self.j2k_random_tile_access(tfile.name, codec_format)
self.assertTrue(True)
def test_tte4(self):
"""Runs test designated tte4 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
xtx4_setup(tfile.name)
self.assertTrue(True)
def test_rta4(self):
"""Runs test designated rta4 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
xtx4_setup(tfile.name)
codec_format = openjp2.CODEC_J2K
self.j2k_random_tile_access(tfile.name, codec_format)
def test_tte5(self):
"""Runs test designated tte5 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
xtx5_setup(tfile.name)
self.assertTrue(True)
def test_rta5(self):
"""Runs test designated rta5 in OpenJPEG test suite."""
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
xtx5_setup(tfile.name)
codec_format = openjp2.CODEC_J2K
self.j2k_random_tile_access(tfile.name, codec_format)
#def tile_encoder(num_comps=None, tile_width=None, tile_height=None,
# filename=None, codec=None, comp_prec=None,
# image_width=None, image_height=None,
# irreversible=None):
def tile_encoder(**kwargs):
"""Fixture used by many tests."""
num_tiles = ((kwargs['image_width'] / kwargs['tile_width']) *
(kwargs['image_height'] / kwargs['tile_height']))
tile_size = ((kwargs['tile_width'] * kwargs['tile_height']) *
(kwargs['num_comps'] * kwargs['comp_prec'] / 8))
data = np.random.random((kwargs['tile_height'],
kwargs['tile_width'],
kwargs['num_comps']))
data = (data * 255).astype(np.uint8)
l_param = openjp2.set_default_encoder_parameters()
l_param.tcp_numlayers = 1
l_param.cp_fixed_quality = 1
l_param.tcp_distoratio[0] = 20
# position of the tile grid aligned with the image
l_param.cp_tx0 = 0
l_param.cp_ty0 = 0
# tile size, we are using tile based encoding
l_param.tile_size_on = 1
l_param.cp_tdx = kwargs['tile_width']
l_param.cp_tdy = kwargs['tile_height']
# use irreversible encoding
l_param.irreversible = kwargs['irreversible']
l_param.numresolution = 6
l_param.prog_order = glymur.core.LRCP
l_params = (openjp2.ImageComptParmType * kwargs['num_comps'])()
for j in range(kwargs['num_comps']):
l_params[j].dx = 1
l_params[j].dy = 1
l_params[j].h = kwargs['image_height']
l_params[j].w = kwargs['image_width']
l_params[j].sgnd = 0
l_params[j].prec = kwargs['comp_prec']
l_params[j].x0 = 0
l_params[j].y0 = 0
codec = openjp2.create_compress(kwargs['codec'])
openjp2.set_info_handler(codec, None)
openjp2.set_warning_handler(codec, None)
openjp2.set_error_handler(codec, None)
cspace = openjp2.CLRSPC_SRGB
l_image = openjp2.image_tile_create(l_params, cspace)
l_image.contents.x0 = 0
l_image.contents.y0 = 0
l_image.contents.x1 = kwargs['image_width']
l_image.contents.y1 = kwargs['image_height']
l_image.contents.color_space = openjp2.CLRSPC_SRGB
openjp2.setup_encoder(codec, l_param, l_image)
stream = openjp2.stream_create_default_file_stream_v3(kwargs['filename'],
False)
openjp2.start_compress(codec, l_image, stream)
for j in np.arange(num_tiles):
openjp2.write_tile(codec, j, data, tile_size, stream)
openjp2.end_compress(codec, stream)
openjp2.stream_destroy_v3(stream)
openjp2.destroy_codec(codec)
openjp2.image_destroy(l_image)
def tile_decoder(**kwargs):
"""Fixture called with various configurations by many tests.
Reads a tile. That's all it does.
"""
stream = openjp2.stream_create_default_file_stream_v3(kwargs['filename'],
True)
dparam = openjp2.set_default_decoder_parameters()
dparam.decod_format = kwargs['codec_format']
# Do not use layer decoding limitation.
dparam.cp_layer = 0
# do not use resolution reductions.
dparam.cp_reduce = 0
codec = openjp2.create_decompress(kwargs['codec_format'])
openjp2.set_info_handler(codec, None)
openjp2.set_warning_handler(codec, None)
openjp2.set_error_handler(codec, None)
openjp2.setup_decoder(codec, dparam)
image = openjp2.read_header(stream, codec)
openjp2.set_decode_area(codec, image,
kwargs['x0'], kwargs['y0'],
kwargs['x1'], kwargs['y1'])
data = np.zeros((1150, 2048, 3), dtype=np.uint8)
while True:
rargs = openjp2.read_tile_header(codec, stream)
tidx = rargs[0]
size = rargs[1]
go_on = rargs[-1]
if not go_on:
break
openjp2.decode_tile_data(codec, tidx, data, size, stream)
openjp2.end_decompress(codec, stream)
openjp2.destroy_codec(codec)
openjp2.stream_destroy_v3(stream)
openjp2.image_destroy(image)
def ttx0_setup(filename):
"""Runs tests tte0, tte0."""
kwargs = {'filename': filename,
'codec': openjp2.CODEC_J2K,
'comp_prec': 8,
'irreversible': 1,
'num_comps': 3,
'image_height': 200,
'image_width': 200,
'tile_height': 100,
'tile_width': 100}
tile_encoder(**kwargs)
def xtx2_setup(filename):
"""Runs tests rta2, tte2, ttd2."""
kwargs = {'filename': filename,
'codec': openjp2.CODEC_JP2,
'comp_prec': 8,
'irreversible': 1,
'num_comps': 3,
'image_height': 256,
'image_width': 256,
'tile_height': 128,
'tile_width': 128}
tile_encoder(**kwargs)
def xtx3_setup(filename):
"""Runs tests tte3, rta3."""
kwargs = {'filename': filename,
'codec': openjp2.CODEC_J2K,
'comp_prec': 8,
'irreversible': 1,
'num_comps': 1,
'image_height': 256,
'image_width': 256,
'tile_height': 128,
'tile_width': 128}
tile_encoder(**kwargs)
def xtx4_setup(filename):
"""Runs tests rta4, tte4."""
kwargs = {'filename': filename,
'codec': openjp2.CODEC_J2K,
'comp_prec': 8,
'irreversible': 0,
'num_comps': 1,
'image_height': 256,
'image_width': 256,
'tile_height': 128,
'tile_width': 128}
tile_encoder(**kwargs)
def xtx5_setup(filename):
"""Runs tests rta5, tte5."""
kwargs = {'filename': filename,
'codec': openjp2.CODEC_J2K,
'comp_prec': 8,
'irreversible': 0,
'num_comps': 1,
'image_height': 512,
'image_width': 512,
'tile_height': 256,
'tile_width': 256}
tile_encoder(**kwargs)
if __name__ == "__main__":
unittest.main()

View file

@ -167,3 +167,252 @@ def read_pgx_header(pgx_file):
header = header.rstrip()
return header, pos
text_gbr_27 = """Colour Specification Box (colr) @ (179, 1339)
Method: any ICC profile
Precedence: 2
Approximation: accurately represents correct colorspace definition
ICC Profile:
{'Color Space': 'RGB',
'Connection Space': 'XYZ',
'Creator': u'appl',
'Datetime': datetime.datetime(2009, 2, 25, 11, 26, 11),
'Device Attributes': 'reflective, glossy, positive media polarity, color media',
'Device Class': 'display device profile',
'Device Manufacturer': u'appl',
'Device Model': '',
'File Signature': u'acsp',
'Flags': 'not embedded, can be used independently',
'Illuminant': array([ 0.96420288, 1. , 0.8249054 ]),
'Platform': u'APPL',
'Preferred CMM Type': 1634758764,
'Rendering Intent': 'perceptual',
'Size': 1328,
'Version': '2.2.0'}"""
text_gbr_33 = """Colour Specification Box (colr) @ (179, 1339)
Method: any ICC profile
Precedence: 2
Approximation: accurately represents correct colorspace definition
ICC Profile:
{'Size': 1328,
'Preferred CMM Type': 1634758764,
'Version': '2.2.0',
'Device Class': 'display device profile',
'Color Space': 'RGB',
'Connection Space': 'XYZ',
'Datetime': datetime.datetime(2009, 2, 25, 11, 26, 11),
'File Signature': 'acsp',
'Platform': 'APPL',
'Flags': 'not embedded, can be used independently',
'Device Manufacturer': 'appl',
'Device Model': '',
'Device Attributes': 'reflective, glossy, positive media polarity, color media',
'Rendering Intent': 'perceptual',
'Illuminant': array([ 0.96420288, 1. , 0.8249054 ]),
'Creator': 'appl'}"""
text_gbr_34 = """Colour Specification Box (colr) @ (179, 1339)
Method: any ICC profile
Precedence: 2
Approximation: accurately represents correct colorspace definition
ICC Profile:
{'Size': 1328,
'Preferred CMM Type': 1634758764,
'Version': '2.2.0',
'Device Class': 'display device profile',
'Color Space': 'RGB',
'Connection Space': 'XYZ',
'Datetime': datetime.datetime(2009, 2, 25, 11, 26, 11),
'File Signature': 'acsp',
'Platform': 'APPL',
'Flags': 'not embedded, can be used independently',
'Device Manufacturer': 'appl',
'Device Model': '',
'Device Attributes': 'reflective, glossy, positive media polarity, color '
'media',
'Rendering Intent': 'perceptual',
'Illuminant': array([ 0.96420288, 1. , 0.8249054 ]),
'Creator': 'appl'}"""
# Metadata dump of nemo.
nemo_dump_full_opj2 = r'''JPEG 2000 Signature Box (jP ) @ (0, 12)
Signature: 0d0a870a
File Type Box (ftyp) @ (12, 20)
Brand: jp2
Compatibility: ['jp2 ']
JP2 Header Box (jp2h) @ (32, 45)
Image Header Box (ihdr) @ (40, 22)
Size: [1456 2592 3]
Bitdepth: 8
Signed: False
Compression: wavelet
Colorspace Unknown: False
Colour Specification Box (colr) @ (62, 15)
Method: enumerated colorspace
Precedence: 0
Colorspace: sRGB
UUID Box (uuid) @ (77, 638)
UUID: 4a706754-6966-6645-7869-662d3e4a5032 (Exif)
UUID Data:
{'Image': {'Make': 'HTC',
'Model': 'HTC Glacier',
'XResolution': 72.0,
'YResolution': 72.0,
'ResolutionUnit': 2,
'YCbCrPositioning': 1,
'ExifTag': 138,
'GPSTag': 354},
'Photo': {'ISOSpeedRatings': 76,
'ExifVersion': (48, 50, 50, 48),
'DateTimeOriginal': '2013:02:09 14:47:53',
'DateTimeDigitized': '2013:02:09 14:47:53',
'ComponentsConfiguration': (1, 2, 3, 0),
'FocalLength': 3.53,
'FlashpixVersion': (48, 49, 48, 48),
'ColorSpace': 1,
'PixelXDimension': 2528,
'PixelYDimension': 1424,
'InteroperabilityTag': 324},
'GPSInfo': {'GPSVersionID': (2, 2, 0),
'GPSLatitudeRef': 'N',
'GPSLatitude': [42.0, 20.0, 33.61],
'GPSLongitudeRef': 'W',
'GPSLongitude': [71.0, 5.0, 17.32],
'GPSAltitudeRef': 0,
'GPSAltitude': 0.0,
'GPSTimeStamp': [19.0, 47.0, 53.0],
'GPSMapDatum': 'WGS-84',
'GPSProcessingMethod': (65,
83,
67,
73,
73,
0,
0,
0,
78,
69,
84,
87,
79,
82,
75),
'GPSDateStamp': '2013:02:09'},
'Iop': None}
UUID Box (uuid) @ (715, 2412)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
UUID Data:
<ns0:xmpmeta xmlns:ns0="adobe:ns:meta/" xmlns:ns2="http://ns.adobe.com/xap/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ns0:xmptk="XMP Core 4.4.0-Exiv2">
<rdf:RDF>
<rdf:Description ns2:CreatorTool="glymur" rdf:about="" />
</rdf:RDF>
</ns0:xmpmeta>
Contiguous Codestream Box (jp2c) @ (3127, 1132296)
Main header:
SOC marker segment @ (3135, 0)
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: (1456 x 2592)
Vertical, Horizontal Reference Tile Offset: (0 x 0)
Bitdepth: (8, 8, 8)
Signed: (False, False, False)
Vertical, Horizontal Subsampling: ((1, 1), (1, 1), (1, 1))
COD marker segment @ (3186, 12)
Coding style:
Entropy coder, without partitions
SOP marker segments: False
EPH marker segments: False
Coding style parameters:
Progression order: LRCP
Number of layers: 2
Multiple component transformation usage: reversible
Number of resolutions: 2
Code block height, width: (64 x 64)
Wavelet transform: 5-3 reversible
Precinct size: default, 2^15 x 2^15
Code block context:
Selective arithmetic coding bypass: False
Reset context probabilities on coding pass boundaries: False
Termination on each coding pass: False
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False
QCD marker segment @ (3200, 7)
Quantization style: no quantization, 2 guard bits
Step size: [(0, 8), (0, 9), (0, 9), (0, 10)]
CME marker segment @ (3209, 37)
"Created by OpenJPEG version 2.0.0"'''
nemo_dump_full_p27 = r'''JPEG 2000 Signature Box (jP ) @ (0, 12)
Signature: 0d0a870a
File Type Box (ftyp) @ (12, 20)
Brand: jp2
Compatibility: ['jp2 ']
JP2 Header Box (jp2h) @ (32, 45)
Image Header Box (ihdr) @ (40, 22)
Size: [1456 2592 3]
Bitdepth: 8
Signed: False
Compression: wavelet
Colorspace Unknown: False
Colour Specification Box (colr) @ (62, 15)
Method: enumerated colorspace
Precedence: 0
Colorspace: sRGB
UUID Box (uuid) @ (77, 638)
UUID: 4a706754-6966-6645-7869-662d3e4a5032 (Exif)
UUID Data:
{'GPSInfo': OrderedDict([('GPSVersionID', (2, 2, 0)), ('GPSLatitudeRef', 'N'), ('GPSLatitude', [42.0, 20.0, 33.61]), ('GPSLongitudeRef', 'W'), ('GPSLongitude', [71.0, 5.0, 17.32]), ('GPSAltitudeRef', 0), ('GPSAltitude', 0.0), ('GPSTimeStamp', [19.0, 47.0, 53.0]), ('GPSMapDatum', 'WGS-84'), ('GPSProcessingMethod', (65, 83, 67, 73, 73, 0, 0, 0, 78, 69, 84, 87, 79, 82, 75)), ('GPSDateStamp', '2013:02:09')]),
'Image': OrderedDict([('Make', 'HTC'), ('Model', 'HTC Glacier'), ('XResolution', 72.0), ('YResolution', 72.0), ('ResolutionUnit', 2), ('YCbCrPositioning', 1), ('ExifTag', 138), ('GPSTag', 354)]),
'Iop': None,
'Photo': OrderedDict([('ISOSpeedRatings', 76), ('ExifVersion', (48, 50, 50, 48)), ('DateTimeOriginal', '2013:02:09 14:47:53'), ('DateTimeDigitized', '2013:02:09 14:47:53'), ('ComponentsConfiguration', (1, 2, 3, 0)), ('FocalLength', 3.53), ('FlashpixVersion', (48, 49, 48, 48)), ('ColorSpace', 1), ('PixelXDimension', 2528), ('PixelYDimension', 1424), ('InteroperabilityTag', 324)])}
UUID Box (uuid) @ (715, 2412)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
UUID Data:
<ns0:xmpmeta xmlns:ns0="adobe:ns:meta/" xmlns:ns2="http://ns.adobe.com/xap/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ns0:xmptk="XMP Core 4.4.0-Exiv2">
<rdf:RDF>
<rdf:Description ns2:CreatorTool="glymur" rdf:about="" />
</rdf:RDF>
</ns0:xmpmeta>
Contiguous Codestream Box (jp2c) @ (3127, 1132296)
Main header:
SOC marker segment @ (3135, 0)
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: (1456 x 2592)
Vertical, Horizontal Reference Tile Offset: (0 x 0)
Bitdepth: (8, 8, 8)
Signed: (False, False, False)
Vertical, Horizontal Subsampling: ((1, 1), (1, 1), (1, 1))
COD marker segment @ (3186, 12)
Coding style:
Entropy coder, without partitions
SOP marker segments: False
EPH marker segments: False
Coding style parameters:
Progression order: LRCP
Number of layers: 2
Multiple component transformation usage: reversible
Number of resolutions: 2
Code block height, width: (64 x 64)
Wavelet transform: 5-3 reversible
Precinct size: default, 2^15 x 2^15
Code block context:
Selective arithmetic coding bypass: False
Reset context probabilities on coding pass boundaries: False
Termination on each coding pass: False
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False
QCD marker segment @ (3200, 7)
Quantization style: no quantization, 2 guard bits
Step size: [(0, 8), (0, 9), (0, 9), (0, 10)]
CME marker segment @ (3209, 37)
"Created by OpenJPEG version 2.0.0"'''

View file

@ -15,6 +15,7 @@ import os
import struct
import sys
import tempfile
import warnings
if sys.hexversion < 0x02070000:
import unittest2 as unittest
@ -98,8 +99,10 @@ class TestCodestream(unittest.TestCase):
tfile.write(read_buffer)
tfile.flush()
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
codestream = Jp2k(tfile.name).get_codestream()
self.assertEqual(len(w), 1)
self.assertEqual(codestream.segment[2].marker_id, '0xff79')
self.assertEqual(codestream.segment[2].length, 3)

View file

@ -15,6 +15,7 @@ import imp
import os
import sys
import tempfile
import warnings
if sys.hexversion < 0x02070000:
import unittest2 as unittest
@ -87,8 +88,10 @@ class TestSuite(unittest.TestCase):
with patch.dict('os.environ', {'XDG_CONFIG_HOME': tdir}):
# Misconfigured new configuration file should
# be rejected.
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
imp.reload(glymur.lib.openjp2)
self.assertEqual(len(w), 1)
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None and

View file

@ -14,6 +14,7 @@ import os
from os.path import join
import re
import sys
import warnings
if sys.hexversion < 0x02070000:
import unittest2 as unittest
@ -36,8 +37,6 @@ except KeyError:
@unittest.skipIf(FORMAT_CORPUS_DATA_ROOT is None,
"FORMAT_CORPUS_DATA_ROOT environment variable not set")
@unittest.skipIf(sys.hexversion < 0x03020000,
"Requires features introduced in 3.2 (assertWarns)")
class TestSuiteFormatCorpus(unittest.TestCase):
"""Test suite for files in format corpus repository."""
@ -49,32 +48,16 @@ class TestSuiteFormatCorpus(unittest.TestCase):
jfile = os.path.join(FORMAT_CORPUS_DATA_ROOT,
'jp2k-test/byteCorruption/balloon_trunc1.jp2')
j2k = Jp2k(jfile)
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
codestream = j2k.get_codestream(header_only=False)
self.assertEqual(len(w), 1)
# The last segment is truncated, so there should not be an EOC marker.
self.assertNotEqual(codestream.segment[-1].marker_id, 'EOC')
# The codestream is not as long as claimed.
with self.assertRaises(OSError):
j2k.read(rlevel=-1)
@unittest.skipIf(re.match(r"""1\.[01234]""",
glymur.version.openjpeg_version) is not None,
"Needs 1.4+ to catch this.")
def test_balloon_trunc2(self):
"""Shortened by 5000 bytes."""
jfile = os.path.join(FORMAT_CORPUS_DATA_ROOT,
'jp2k-test/byteCorruption/balloon_trunc2.jp2')
j2k = Jp2k(jfile)
with self.assertWarns(UserWarning):
codestream = j2k.get_codestream(header_only=False)
# The last segment is truncated, so there should not be an EOC marker.
self.assertNotEqual(codestream.segment[-1].marker_id, 'EOC')
# The codestream is not as long as claimed.
with self.assertRaises(OSError):
with self.assertRaises((OSError, IOError)):
j2k.read(rlevel=-1)
def test_balloon_trunc3(self):
@ -82,8 +65,10 @@ class TestSuiteFormatCorpus(unittest.TestCase):
jfile = os.path.join(FORMAT_CORPUS_DATA_ROOT,
'jp2k-test/byteCorruption/balloon_trunc3.jp2')
j2k = Jp2k(jfile)
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
codestream = j2k.get_codestream(header_only=False)
self.assertEqual(len(w), 1)
# The last segment is truncated, so there should not be an EOC marker.
self.assertNotEqual(codestream.segment[-1].marker_id, 'EOC')
@ -97,8 +82,10 @@ class TestSuiteFormatCorpus(unittest.TestCase):
jfile = os.path.join(FORMAT_CORPUS_DATA_ROOT,
'jp2k-test', 'icc',
'balloon_eciRGBv2_ps_adobeplugin.jpf')
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
Jp2k(jfile)
self.assertEqual(len(w), 1)
def test_jp2_brand_iccpr_mult_colr(self):
"""Has colr box, one that conforms, one that does not."""
@ -109,14 +96,14 @@ class TestSuiteFormatCorpus(unittest.TestCase):
# ("Input Device") changed relative to original profile.
jfile = join(FORMAT_CORPUS_DATA_ROOT, 'jp2k-test', 'icc',
'balloon_eciRGBv2_ps_adobeplugin_jp2compatible.jpf')
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
Jp2k(jfile)
self.assertEqual(len(w), 1)
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
@unittest.skipIf(sys.hexversion < 0x03020000,
"Requires features introduced in 3.2 (assertWarns)")
class TestSuiteOpj(unittest.TestCase):
"""Test suite for files in openjpeg repository."""
@ -130,8 +117,10 @@ class TestSuiteOpj(unittest.TestCase):
"""If 'jp2 ', then the method cannot be any icc profile."""
filename = os.path.join(OPJ_DATA_ROOT,
'input/nonregression/text_GBR.jp2')
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
Jp2k(filename)
self.assertEqual(len(w), 1)
if __name__ == "__main__":
unittest.main()

View file

@ -11,6 +11,7 @@ ICC profile tests.
import datetime
import os
import sys
import warnings
if sys.hexversion < 0x02070000:
import unittest2 as unittest
@ -65,16 +66,16 @@ class TestICC(unittest.TestCase):
self.assertEqual(profile['Creator'], 'JPEG')
@unittest.skipIf(sys.hexversion < 0x03020000,
"Uses features introduced in 3.2.")
def test_invalid_profile_header(self):
"""invalid ICC header data should cause UserWarning"""
jfile = opj_data_file('input/nonregression/orb-blue10-lin-jp2.jp2')
# assertWarns in Python 3.3 (python2.7/pylint issue)
# pylint: disable=E1101
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
Jp2k(jfile)
self.assertEqual(len(w), 1)
if __name__ == "__main__":
unittest.main()

View file

@ -18,6 +18,7 @@ Test suite specifically targeting JP2 box layout.
import doctest
import os
import re
import shutil
import struct
import sys
@ -57,7 +58,7 @@ def load_tests(loader, tests, ignore):
return tests
@unittest.skipIf(glymur.version.openjpeg_version_tuple[0] < 2 or
OPENJP2_IS_V2_OFFICIAL,
re.match(r'''2.0.0''', glymur.version.openjpeg_version),
"Not supported until 2.0+.")
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
class TestChannelDefinition(unittest.TestCase):

View file

@ -53,8 +53,10 @@ class TestReaderRequirements(unittest.TestCase):
tfile.write(nemof.read())
tfile.flush()
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
j = Jp2k(tfile.name)
self.assertEqual(len(w), 1)
self.assertEqual(j.box[2].box_id, 'rreq')
self.assertEqual(type(j.box[2]),
glymur.jp2box.ReaderRequirementsBox)

View file

@ -23,6 +23,7 @@ import sys
import tempfile
import warnings
import xml.etree.cElementTree as ET
import warnings
if sys.hexversion < 0x03000000:
from StringIO import StringIO
@ -212,18 +213,12 @@ class TestJp2kBadXmlFile(unittest.TestCase):
def tearDown(self):
pass
@unittest.skipIf(sys.hexversion < 0x03020000,
"Uses features introduced in 3.2.")
def test_invalid_xml_box_warning(self):
"""Should warn in case of bad XML"""
with self.assertWarns(UserWarning):
Jp2k(self._bad_xml_file)
def test_invalid_xml_box(self):
"""Should be able to recover info from xml box with bad xml."""
with warnings.catch_warnings():
warnings.simplefilter("ignore")
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
jp2k = Jp2k(self._bad_xml_file)
self.assertEqual(len(w), 1)
self.assertEqual(jp2k.box[3].box_id, 'xml ')
self.assertEqual(jp2k.box[3].offset, 77)
@ -276,8 +271,10 @@ class TestBadButRecoverableXmlFile(unittest.TestCase):
"Uses features introduced in 3.2.")
def test_bad_xml_box_warning(self):
"""Should warn in case of bad XML"""
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
Jp2k(self._bad_xml_file)
self.assertEqual(len(w), 1)
def test_recover_from_bad_xml(self):
"""Should be able to recover info from xml box with bad xml."""

View file

@ -1,9 +1,6 @@
"""
Tests for general glymur functionality.
"""
# E1101: assertWarns introduced in python 3.2
# pylint: disable=E1101
# R0904: Not too many methods in unittest.
# pylint: disable=R0904
@ -384,13 +381,9 @@ class TestJp2k(unittest.TestCase):
# Verify that a warning is issued, but only on python3.
# On python2, just suppress the warning.
if sys.hexversion < 0x03030000:
with warnings.catch_warnings():
warnings.simplefilter("ignore")
j = Jp2k(tfile.name)
else:
with self.assertWarns(UserWarning):
j = Jp2k(tfile.name)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
j = Jp2k(tfile.name)
exif = j.box[3].data
# Were the tag == 271, 'Make' would be in the keys instead.
@ -590,8 +583,8 @@ class TestJp2k_1_x(unittest.TestCase):
j2k.read(layer=1)
@unittest.skipIf(not OPENJP2_IS_V2_OFFICIAL,
"Tests only to be run on 2.0 official.")
@unittest.skipIf(re.match("2.0.0", glymur.version.openjpeg_version) is None,
"Tests only to be run on 2.0.0.")
class TestJp2k_2_0_official(unittest.TestCase):
"""Test suite to only be run on v2.0 official."""

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,407 @@
"""
The tests defined here roughly correspond to what is in the OpenJPEG test
suite.
"""
# Some test names correspond with openjpeg tests. Long names are ok in this
# case.
# pylint: disable=C0103
# All of these tests correspond to tests in openjpeg, so no docstring is really
# needed.
# pylint: disable=C0111
# This module is very long, cannot be helped.
# pylint: disable=C0302
# unittest fools pylint with "too many public methods"
# pylint: disable=R0904
# Some tests use numpy test infrastructure, which means the tests never
# reference "self", so pylint claims it should be a function. No, no, no.
# pylint: disable=R0201
# Many tests are pretty long and that can't be helped.
# pylint: disable=R0915
# asserWarns introduced in python 3.2 (python2.7/pylint issue)
# pylint: disable=E1101
# unittest2 is python2.6 only (pylint/python-2.7)
# pylint: disable=F0401
import re
import sys
if sys.hexversion < 0x02070000:
import unittest2 as unittest
else:
import unittest
import warnings
import numpy as np
from glymur import Jp2k
import glymur
from .fixtures import OPENJP2_IS_V2_OFFICIAL, OPJ_DATA_ROOT
from .fixtures import mse, peak_tolerance, read_pgx, opj_data_file
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
@unittest.skipIf(re.match(r'''2.0.0''', glymur.version.openjpeg_version),
"Tests not introduced until 2.0.1")
@unittest.skipIf(glymur.version.openjpeg_version_tuple[0] == 1,
"Tests not introduced until 2.1")
class TestSuite2point1(unittest.TestCase):
"""Runs tests introduced in version 2.0+ or that pass only in 2.0+"""
def setUp(self):
pass
def tearDown(self):
pass
def test_NR_DEC_text_GBR_jp2_29_decode(self):
jfile = opj_data_file('input/nonregression/text_GBR.jp2')
with warnings.catch_warnings():
# brand is 'jp2 ', but has any icc profile.
warnings.simplefilter("ignore")
jp2 = Jp2k(jfile)
jp2.read()
self.assertTrue(True)
def test_NR_DEC_kodak_2layers_lrcp_j2c_31_decode(self):
jfile = opj_data_file('input/nonregression/kodak_2layers_lrcp.j2c')
Jp2k(jfile).read()
self.assertTrue(True)
def test_NR_DEC_kodak_2layers_lrcp_j2c_32_decode(self):
jfile = opj_data_file('input/nonregression/kodak_2layers_lrcp.j2c')
Jp2k(jfile).read(layer=2)
self.assertTrue(True)
def test_NR_DEC_issue104_jpxstream_jp2_33_decode(self):
jfile = opj_data_file('input/nonregression/issue104_jpxstream.jp2')
Jp2k(jfile).read()
self.assertTrue(True)
def test_NR_DEC_mem_b2b86b74_2753_jp2_35_decode(self):
jfile = opj_data_file('input/nonregression/mem-b2b86b74-2753.jp2')
Jp2k(jfile).read()
self.assertTrue(True)
def test_NR_DEC_gdal_fuzzer_unchecked_num_resolutions_jp2_36_decode(self):
f = 'input/nonregression/gdal_fuzzer_unchecked_numresolutions.jp2'
jfile = opj_data_file(f)
with warnings.catch_warnings():
# Invalid number of resolutions.
warnings.simplefilter("ignore")
j = Jp2k(jfile)
with self.assertRaises(IOError):
j.read()
def test_NR_DEC_gdal_fuzzer_check_number_of_tiles_jp2_38_decode(self):
relpath = 'input/nonregression/gdal_fuzzer_check_number_of_tiles.jp2'
jfile = opj_data_file(relpath)
with warnings.catch_warnings():
# Invalid number of tiles.
warnings.simplefilter("ignore")
j = Jp2k(jfile)
with self.assertRaises(IOError):
j.read()
def test_NR_DEC_gdal_fuzzer_check_comp_dx_dy_jp2_39_decode(self):
relpath = 'input/nonregression/gdal_fuzzer_check_comp_dx_dy.jp2'
jfile = opj_data_file(relpath)
with warnings.catch_warnings():
# Invalid subsampling value
warnings.simplefilter("ignore")
with self.assertRaises(IOError):
Jp2k(jfile).read()
def test_NR_DEC_file_409752_jp2_40_decode(self):
jfile = opj_data_file('input/nonregression/file409752.jp2')
with self.assertRaises(RuntimeError):
Jp2k(jfile).read()
def test_NR_DEC_issue188_beach_64bitsbox_jp2_41_decode(self):
# Has an 'XML ' box instead of 'xml '. Yes that is pedantic, but it
# really does deserve a warning.
relpath = 'input/nonregression/issue188_beach_64bitsbox.jp2'
jfile = opj_data_file(relpath)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
Jp2k(jfile).read()
self.assertEqual(len(w), 1)
def test_NR_DEC_issue206_image_000_jp2_42_decode(self):
jfile = opj_data_file('input/nonregression/issue206_image-000.jp2')
Jp2k(jfile).read()
self.assertTrue(True)
def test_NR_DEC_p1_04_j2k_43_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(0, 0, 1024, 1024))
odata = jp2k.read()
np.testing.assert_array_equal(ssdata, odata)
def test_NR_DEC_p1_04_j2k_44_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(640, 512, 768, 640))
odata = jp2k.read()
np.testing.assert_array_equal(ssdata, odata[640:768, 512:640])
def test_NR_DEC_p1_04_j2k_45_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(896, 896, 1024, 1024))
odata = jp2k.read()
np.testing.assert_array_equal(ssdata, odata[896:1024, 896:1024])
def test_NR_DEC_p1_04_j2k_46_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(500, 100, 800, 300))
odata = jp2k.read()
np.testing.assert_array_equal(ssdata, odata[500:800, 100:300])
def test_NR_DEC_p1_04_j2k_47_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(520, 260, 600, 360))
odata = jp2k.read()
np.testing.assert_array_equal(ssdata, odata[520:600, 260:360])
def test_NR_DEC_p1_04_j2k_48_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(520, 260, 660, 360))
odata = jp2k.read()
np.testing.assert_array_equal(ssdata, odata[520:660, 260:360])
def test_NR_DEC_p1_04_j2k_49_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(520, 360, 600, 400))
odata = jp2k.read()
np.testing.assert_array_equal(ssdata, odata[520:600, 360:400])
def test_NR_DEC_p1_04_j2k_50_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(0, 0, 1024, 1024), rlevel=2)
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(ssdata, odata[0:256, 0:256])
def test_NR_DEC_p1_04_j2k_51_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(640, 512, 768, 640), rlevel=2)
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(ssdata, odata[160:192, 128:160])
def test_NR_DEC_p1_04_j2k_52_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(896, 896, 1024, 1024), rlevel=2)
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(ssdata, odata[224:352, 224:352])
def test_NR_DEC_p1_04_j2k_53_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(500, 100, 800, 300), rlevel=2)
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(ssdata, odata[125:200, 25:75])
def test_NR_DEC_p1_04_j2k_54_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(520, 260, 600, 360), rlevel=2)
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(ssdata, odata[130:150, 65:90])
def test_NR_DEC_p1_04_j2k_55_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(520, 260, 660, 360), rlevel=2)
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(ssdata, odata[130:165, 65:90])
def test_NR_DEC_p1_04_j2k_56_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(520, 360, 600, 400), rlevel=2)
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(ssdata, odata[130:150, 90:100])
def test_NR_DEC_p1_04_j2k_57_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
tdata = jp2k.read(tile=63) # last tile
odata = jp2k.read()
np.testing.assert_array_equal(tdata, odata[896:1024, 896:1024])
def test_NR_DEC_p1_04_j2k_58_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
tdata = jp2k.read(tile=63, rlevel=2) # last tile
odata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(tdata, odata[224:256, 224:256])
def test_NR_DEC_p1_04_j2k_59_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
tdata = jp2k.read(tile=12) # 2nd row, 5th column
odata = jp2k.read()
np.testing.assert_array_equal(tdata, odata[128:256, 512:640])
def test_NR_DEC_p1_04_j2k_60_decode(self):
jfile = opj_data_file('input/conformance/p1_04.j2k')
jp2k = Jp2k(jfile)
tdata = jp2k.read(tile=12, rlevel=1) # 2nd row, 5th column
odata = jp2k.read(rlevel=1)
np.testing.assert_array_equal(tdata, odata[64:128, 256:320])
def test_NR_DEC_jp2_36_decode(self):
lst = ('input',
'nonregression',
'gdal_fuzzer_assert_in_opj_j2k_read_SQcd_SQcc.patch.jp2')
jfile = opj_data_file('/'.join(lst))
with warnings.catch_warnings():
# Invalid component number.
warnings.simplefilter("ignore")
j = Jp2k(jfile)
with self.assertRaises(IOError):
j.read()
def test_NR_DEC_p1_06_j2k_70_decode(self):
jfile = opj_data_file('input/conformance/p1_06.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(9, 9, 12, 12), rlevel=1)
self.assertEqual(ssdata.shape, (1, 1, 3))
def test_NR_DEC_p1_06_j2k_71_decode(self):
jfile = opj_data_file('input/conformance/p1_06.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(10, 4, 12, 10), rlevel=1)
self.assertEqual(ssdata.shape, (1, 3, 3))
def test_NR_DEC_p1_06_j2k_72_decode(self):
jfile = opj_data_file('input/conformance/p1_06.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(3, 3, 9, 9), rlevel=1)
self.assertEqual(ssdata.shape, (3, 3, 3))
def test_NR_DEC_p1_06_j2k_73_decode(self):
jfile = opj_data_file('input/conformance/p1_06.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(4, 4, 7, 7), rlevel=1)
self.assertEqual(ssdata.shape, (2, 2, 3))
def test_NR_DEC_p1_06_j2k_74_decode(self):
jfile = opj_data_file('input/conformance/p1_06.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(4, 4, 5, 5), rlevel=1)
self.assertEqual(ssdata.shape, (1, 1, 3))
def test_NR_DEC_p1_06_j2k_75_decode(self):
# Image size would be 0 x 0.
jfile = opj_data_file('input/conformance/p1_06.j2k')
jp2k = Jp2k(jfile)
with self.assertRaises((IOError, OSError)):
jp2k.read(area=(9, 9, 12, 12), rlevel=2)
def test_NR_DEC_p0_04_j2k_85_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(0, 0, 256, 256))
fulldata = jp2k.read()
np.testing.assert_array_equal(fulldata[0:256, 0:256], ssdata)
def test_NR_DEC_p0_04_j2k_86_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(0, 128, 128, 256))
fulldata = jp2k.read()
np.testing.assert_array_equal(fulldata[0:128, 128:256], ssdata)
def test_NR_DEC_p0_04_j2k_87_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(10, 50, 200, 120))
fulldata = jp2k.read()
np.testing.assert_array_equal(fulldata[10:200, 50:120], ssdata)
def test_NR_DEC_p0_04_j2k_88_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(150, 10, 210, 190))
fulldata = jp2k.read()
np.testing.assert_array_equal(fulldata[150:210, 10:190], ssdata)
def test_NR_DEC_p0_04_j2k_89_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(80, 100, 150, 200))
fulldata = jp2k.read()
np.testing.assert_array_equal(fulldata[80:150, 100:200], ssdata)
def test_NR_DEC_p0_04_j2k_90_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(20, 150, 50, 200))
fulldata = jp2k.read()
np.testing.assert_array_equal(fulldata[20:50, 150:200], ssdata)
def test_NR_DEC_p0_04_j2k_91_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(0, 0, 256, 256), rlevel=2)
fulldata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(fulldata[0:64, 0:64], ssdata)
def test_NR_DEC_p0_04_j2k_92_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(0, 128, 128, 256), rlevel=2)
fulldata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(fulldata[0:32, 32:64], ssdata)
def test_NR_DEC_p0_04_j2k_93_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(10, 50, 200, 120), rlevel=2)
fulldata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(fulldata[3:50, 13:30], ssdata)
def test_NR_DEC_p0_04_j2k_94_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(150, 10, 210, 190), rlevel=2)
fulldata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(fulldata[38:53, 3:48], ssdata)
def test_NR_DEC_p0_04_j2k_95_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(80, 100, 150, 200), rlevel=2)
fulldata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(fulldata[20:38, 25:50], ssdata)
def test_NR_DEC_p0_04_j2k_96_decode(self):
jfile = opj_data_file('input/conformance/p0_04.j2k')
jp2k = Jp2k(jfile)
ssdata = jp2k.read(area=(20, 150, 50, 200), rlevel=2)
fulldata = jp2k.read(rlevel=2)
np.testing.assert_array_equal(fulldata[5:13, 38:50], ssdata)
if __name__ == "__main__":
unittest.main()

View file

@ -2,9 +2,6 @@
The tests here do not correspond directly to the OpenJPEG test suite, but
seem like logical negative tests to add.
"""
# E1101: assertWarns introduced in python 3.2
# pylint: disable=E1101
# R0904: Not too many methods in unittest.
# pylint: disable=R0904
@ -15,6 +12,7 @@ import os
import re
import sys
import tempfile
import warnings
if sys.hexversion < 0x02070000:
import unittest2 as unittest
@ -64,15 +62,15 @@ class TestSuiteNegative(unittest.TestCase):
jp2k.get_codestream(header_only=False)
self.assertTrue(True)
@unittest.skipIf(sys.hexversion < 0x03020000,
"Uses features introduced in 3.2.")
def test_nr_illegalclrtransform(self):
"""EOC marker is bad"""
relpath = 'input/nonregression/illegalcolortransform.j2k'
jfile = opj_data_file(relpath)
jp2k = Jp2k(jfile)
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
codestream = jp2k.get_codestream(header_only=False)
self.assertEqual(len(w), 1)
# Verify that the last segment returned in the codestream is SOD,
# not EOC. Codestream parsing should stop when we try to jump to
@ -106,8 +104,6 @@ class TestSuiteNegative(unittest.TestCase):
with self.assertRaises(IOError):
j.write(data, cbsize=(2, 2048))
@unittest.skipIf(sys.hexversion < 0x03020000,
"Uses features introduced in 3.2.")
def test_exceeded_box(self):
"""should warn if reading past end of a box"""
# Verify that a warning is issued if we read past the end of a box
@ -115,7 +111,8 @@ class TestSuiteNegative(unittest.TestCase):
# short.
infile = os.path.join(OPJ_DATA_ROOT,
'input/nonregression/mem-b2ace68c-1381.jp2')
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("ignore")
Jp2k(infile)
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")

View file

@ -794,7 +794,6 @@ class TestSuiteWrite(unittest.TestCase):
glymur.core.WAVELET_XFORM_5X3_REVERSIBLE)
self.assertEqual(len(codestream.segment[2].spcod), 9)
@unittest.skip("Known failure in openjpeg test suite.")
def test_NR_ENC_random_issue_0005_tif_12_encode(self):
"""NR-ENC-random-issue-0005.tif-12-encode"""
# opj_decompress has trouble reading it, but that is not an issue here.

View file

@ -35,7 +35,9 @@ else:
import glymur
from glymur import Jp2k
from . import fixtures
from .fixtures import OPJ_DATA_ROOT, opj_data_file
from .fixtures import text_gbr_27, text_gbr_33, text_gbr_34
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
@ -185,31 +187,23 @@ class TestPrintingNeedsLib(unittest.TestCase):
expected = '\n'.join(lines)
self.assertEqual(actual, expected)
@unittest.skipIf(sys.hexversion < 0x02070000, "Do not bother with 2.6")
def test_jp2dump(self):
"""basic jp2dump test"""
with patch('sys.stdout', new=StringIO()) as fake_out:
glymur.jp2dump(self._plain_nemo_file)
glymur.jp2dump(glymur.data.nemo())
actual = fake_out.getvalue().strip()
# Get rid of the filename line, as it is not set in stone.
lst = actual.split('\n')
lst = lst[1:]
actual = '\n'.join(lst)
self.assertEqual(actual, self.expected_plain)
def test_entire_file(self):
"""verify output from printing entire file"""
j = glymur.Jp2k(self._plain_nemo_file)
with patch('sys.stdout', new=StringIO()) as fake_out:
print(j)
actual = fake_out.getvalue().strip()
# Get rid of the filename line, as it is not set in stone.
lst = actual.split('\n')
lst = lst[1:]
actual = '\n'.join(lst)
self.assertEqual(actual, self.expected_plain)
self.maxDiff = None
if sys.hexversion < 0x02080000:
# Ordered dicts are different in 2.7
self.assertEqual(actual, fixtures.nemo_dump_full_p27)
else:
self.assertEqual(actual, fixtures.nemo_dump_full_opj2)
class TestPrinting(unittest.TestCase):
@ -287,70 +281,25 @@ class TestPrinting(unittest.TestCase):
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
def test_icc_profile(self):
"""verify printing of colr box with ICC profile"""
"""verify icc profile printing with a jpx"""
# ICC profiles may be used in JP2, but the approximation field should
# be zero unless we have jpx. This file does both.
filename = opj_data_file('input/nonregression/text_GBR.jp2')
with warnings.catch_warnings():
# brand is 'jp2 ', but has any icc profile.
warnings.simplefilter("ignore")
jp2 = Jp2k(filename)
with patch('sys.stdout', new=StringIO()) as fake_out:
print(jp2.box[3].box[1])
actual = fake_out.getvalue().strip()
lin27 = ["Colour Specification Box (colr) @ (179, 1339)",
" Method: any ICC profile",
" Precedence: 2",
" Approximation: accurately represents correct "
+ "colorspace definition",
" ICC Profile:",
" {'Color Space': 'RGB',",
" 'Connection Space': 'XYZ',",
" 'Creator': u'appl',",
" 'Datetime': "
+ "datetime.datetime(2009, 2, 25, 11, 26, 11),",
" 'Device Attributes': 'reflective, glossy, "
+ "positive media polarity, color media',",
" 'Device Class': 'display device profile',",
" 'Device Manufacturer': u'appl',",
" 'Device Model': '',",
" 'File Signature': u'acsp',",
" 'Flags': "
+ "'not embedded, can be used independently',",
" 'Illuminant': "
+ "array([ 0.96420288, 1. , 0.8249054 ]),",
" 'Platform': u'APPL',",
" 'Preferred CMM Type': 1634758764,",
" 'Rendering Intent': 'perceptual',",
" 'Size': 1328,",
" 'Version': '2.2.0'}"]
lin33 = ["Colour Specification Box (colr) @ (179, 1339)",
" Method: any ICC profile",
" Precedence: 2",
" Approximation: accurately represents correct "
+ "colorspace definition",
" ICC Profile:",
" {'Size': 1328,",
" 'Preferred CMM Type': 1634758764,",
" 'Version': '2.2.0',",
" 'Device Class': 'display device profile',",
" 'Color Space': 'RGB',",
" 'Connection Space': 'XYZ',",
" 'Datetime': "
+ "datetime.datetime(2009, 2, 25, 11, 26, 11),",
" 'File Signature': 'acsp',",
" 'Platform': 'APPL',",
" 'Flags': 'not embedded, can be used "
+ "independently',",
" 'Device Manufacturer': 'appl',",
" 'Device Model': '',",
" 'Device Attributes': 'reflective, glossy, "
+ "positive media polarity, color media',",
" 'Rendering Intent': 'perceptual',",
" 'Illuminant': "
+ "array([ 0.96420288, 1. , 0.8249054 ]),",
" 'Creator': 'appl'}"]
if sys.hexversion < 0x03000000:
expected = text_gbr_27
elif sys.hexversion < 0x03040000:
expected = text_gbr_33
else:
expected = text_gbr_34
lines = lin27 if sys.hexversion < 0x03000000 else lin33
expected = '\n'.join(lines)
self.assertEqual(actual, expected)
@unittest.skipIf(OPJ_DATA_ROOT is None,
@ -980,7 +929,7 @@ class TestPrinting(unittest.TestCase):
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
def test_jpx_approx_icc_profile(self):
"""verify jpx with approx field equal to zero"""
"""verify icc profile printing with a jpx"""
# ICC profiles may be used in JP2, but the approximation field should
# be zero unless we have jpx. This file does both.
filename = opj_data_file('input/nonregression/text_GBR.jp2')
@ -992,34 +941,13 @@ class TestPrinting(unittest.TestCase):
with patch('sys.stdout', new=StringIO()) as fake_out:
print(jp2.box[3].box[1])
actual = fake_out.getvalue().strip()
lines = ["Colour Specification Box (colr) @ (179, 1339)",
" Method: any ICC profile",
" Precedence: 2",
" Approximation: accurately represents "
+ "correct colorspace definition",
" ICC Profile:",
" {'Size': 1328,",
" 'Preferred CMM Type': 1634758764,",
" 'Version': '2.2.0',",
" 'Device Class': 'display device profile',",
" 'Color Space': 'RGB',",
" 'Connection Space': 'XYZ',",
" 'Datetime': "
+ "datetime.datetime(2009, 2, 25, 11, 26, 11),",
" 'File Signature': 'acsp',",
" 'Platform': 'APPL',",
" 'Flags': 'not embedded, "
+ "can be used independently',",
" 'Device Manufacturer': 'appl',",
" 'Device Model': '',",
" 'Device Attributes': 'reflective, glossy, "
+ "positive media polarity, color media',",
" 'Rendering Intent': 'perceptual',",
" 'Illuminant': array([ 0.96420288, 1. ,"
+ " 0.8249054 ]),",
" 'Creator': 'appl'}"]
if sys.hexversion < 0x03000000:
expected = text_gbr_27
elif sys.hexversion < 0x03040000:
expected = text_gbr_33
else:
expected = text_gbr_34
expected = '\n'.join(lines)
self.assertEqual(actual, expected)
@unittest.skipIf(OPJ_DATA_ROOT is None,

View file

@ -15,7 +15,7 @@ from .lib import openjp2 as opj2
# Do not change the format of this next line! Doing so risks breaking
# setup.py
version = "0.5.10"
version = "0.5.12"
_sv = LooseVersion(version)
version_tuple = _sv.version