Merge branch 'master' into devel

This commit is contained in:
John Evans 2014-08-17 18:17:11 -04:00
commit a854123bca
32 changed files with 6558 additions and 6467 deletions

View file

@ -2,6 +2,7 @@ language: python
python:
- "2.7"
- "3.3"
- "3.4"
before_install:
- sudo apt-get update -qq
@ -13,6 +14,7 @@ before_install:
install:
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install lxml contextlib2 mock; fi
- if [[ $TRAVIS_PYTHON_VERSION == '3.3' ]]; then pip install lxml numpy; fi
- if [[ $TRAVIS_PYTHON_VERSION == '3.4' ]]; then pip install lxml numpy; fi
# command to run tests
script:

View file

@ -1,46 +0,0 @@
---------
ChangeLog
---------
0.6.0 (pending)
===============
* Added Cinema2K, Cinema4K write support.
* Added lxml requirement.
* added set_printoptions, get_printoptions function
* dropped support for Python 2.6, added support for Python 3.4
* dropped support for OpenJPEG versions 1.3 and 1.4
* dropped windows support (it might work, it might not, I don't much care)
* added write support for JP2 UUID, dataEntryURL, palette, and component mapping boxes
* added read/write support for JPX free, number list, and data reference boxes
* Added read support for JPX fragment list and fragment table boxes
* incompatible change to channel definition box constructor, channel_type and association are no longer keyword arguments
* incompatible change to palette box constructor, it now takes a 2D numpy array instead of a list of 1D arrays
0.5.0 (September 16, 2013)
==========================
* added write support when using OpenJPEG version 1.5
* added version module
0.4.0 (August 18, 2013)
==========================
* added append method
0.3.0 (July 31, 2013)
==========================
* added support for OpenJPEG library version 2.0.0
0.2.0 (July 11, 2013)
==========================
* added Python 2.6, Python 2.7 on windows
* read/write using OpenJPEG library version 2.0.0
* read using OpenJPEG 1.4
0.1.0 (May 27, 2013)
====================
* first release using development version (2.x) of OpenJPEG

View file

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

View file

@ -1,34 +1,27 @@
----------------------------------
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 r2691 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,
i.e. ::
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]
openjp2: /opt/openjp2-svn/lib/libopenjp2.so
@ -45,78 +38,30 @@ the path will be ::
$XDG_CONFIG_HOME/glymur/glymurrc
On windows, the path to the configuration file can be determined by starting
up Python and typing ::
import os
os.path.join(os.path.expanduser('~', 'glymur', 'glymurrc')
You may also include a line for the version 1.x openjpeg library if you have it
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 MacPorts.
For python 3.3, you should install the following set of ports:
* python33
* py33-numpy
* py33-lxml
* py33-distribute
* 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
* python-lxml
* matplotlib
* pillow
* contextlib2 (2.7 only)
* mock (2.7 only)
Glymur 0.6 been tested on the following linux platforms without any unexpected
difficulties:
* OpenSUSE 13.1
* Fedora 19
* Raspian
* Travis CI (currently Ubuntu 12.04?)
Windows
-------
The 0.6.x series of Glymur is untested on windows and I make no promises here.
I suggest that windows users check the 0.5.x series.
'''''''
Testing
'''''''
There are two environment variables you may wish to set before running the
tests.
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. ::
* **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 ... ::
@ -128,11 +73,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 Python3. The important part is whether or not any test
errors are reported at the end.

View file

@ -11,13 +11,13 @@ take a shortcut by supplying -1 as the
resolution level. ::
>>> import glymur
>>> file = glymur.data.nemo()
>>> jp2 = glymur.Jp2k(file)
>>> jp2file = glymur.data.nemo()
>>> jp2 = glymur.Jp2k(jp2file)
>>> thumbnail = jp2.read(rlevel=-1)
... display metadata?
=====================
There are two ways. From the unix command line, the script *jp2dump* is
There are two ways. From the unix command line, the script **jp2dump** is
available. ::
$ jp2dump /path/to/glymur/installation/data/nemo.jp2
@ -25,8 +25,8 @@ available. ::
From within Python, it is as simple as printing the Jp2k object, i.e. ::
>>> import glymur
>>> file = glymur.data.nemo()
>>> jp2 = glymur.Jp2k(file)
>>> jp2file = glymur.data.nemo()
>>> jp2 = glymur.Jp2k(jp2file)
>>> print(jp2)
File: nemo.jp2
JPEG 2000 Signature Box (jP ) @ (0, 12)
@ -241,8 +241,8 @@ you can use the :py:meth:`wrap` method with no box argument: ::
>>> import glymur
>>> glymur.set_printoptions(codestream=False)
>>> jfile = glymur.data.goodstuff()
>>> j2k = glymur.Jp2k(jfile)
>>> jp2file = glymur.data.goodstuff()
>>> j2k = glymur.Jp2k(jp2file)
>>> jp2 = j2k.wrap("newfile.jp2")
>>> print(jp2)
File: newfile.jp2
@ -524,8 +524,8 @@ You can also build up XMP metadata from scratch. For instance, if we try to
wrap `goodstuff.j2k` again::
>>> import glymur
>>> jfile = glymur.data.goodstuff()
>>> j2k = glymur.Jp2k(jfile)
>>> j2kfile = glymur.data.goodstuff()
>>> j2k = glymur.Jp2k(j2kfile)
>>> jp2 = j2k.wrap("goodstuff.jp2")
Now build up the metadata piece-by-piece. It would help to have the XMP

View file

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

View file

@ -3,13 +3,13 @@ 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
In regards to metadata, most JP2 boxes are properly interpreted.
Certain optional JP2 boxes can also be written, including XML boxes and
XMP UUIDs. There is some very limited support for reading JPX metadata.
XMP UUIDs. There is incomplete support for reading JPX metadata.
Glymur 0.6 works on Python versions 2.7, 3.3 and 3.4. If you have Python 2.6,
you should use the 0.5 series of Glymur.
@ -21,16 +21,16 @@ Glymur Installation
You can retrieve the source for Glymur from either of
* https://pypi.python.org/pypi/Glymur/ (stable releases)
* http://github.com/quintusdias/glymur (bleeding edge)
* http://github.com/quintusdias/glymur (bleeding edge, use the devel branch)
but you should also be able to install Glymur via pip ::
$ pip install glymur
This will install the **jp2dump** script that can be used from the unix command
line, so you should adjust your **$PATH**
to take advantage of it. For example, if you install with pip's
`--user` option on linux ::
This will install a script **jp2dump** that can be used from the unix command
line for dumping JP2 metadata, so you should adjust your **$PATH**
environment variable to take advantage of it. For example, if you install
with pip's `--user` option on linux ::
$ export PATH=$HOME/.local/bin:$PATH

View file

@ -1,3 +1,11 @@
------------
Known Issues
------------
* Creating a Jp2 file with the irreversible option does not work
on windows.
* Eval-ing a :py:meth:`repr` string does not work on windows.
-------
Roadmap
-------

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,23 @@
=====================
Changes in glymur 0.6
=====================
Changes in 0.6.0
=================
* Added Cinema2K, Cinema4K write support.
* Added irreversible 9-7 transform write support.
* Added set_printoptions, get_printoptions functions.
* Added write support for JP2 UUID, data entry URL, palette, and component
mapping boxes.
* Added read/write support for JPX free, number list, and data reference boxes
* Added read support for JPX fragment list and fragment table boxes
* Incompatible change to channel definition box constructor, channel_type and
association are no longer keyword arguments
* Incompatible change to palette box constructor, it now takes a 2D numpy array
instead of a list of 1D arrays
* Dropped support for 1.3 and 1.4.
* Dropped support for Python 2.6.
* Dropped windows support. It might still work, I don't have access to a windows
box with which to test it.
* Added lxml as a package dependency, replacing ElementTree.

View file

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

View file

@ -37,7 +37,9 @@ def tiff_header(read_buffer):
# big endian
endian = '>'
else:
msg = "Bad byte order indication: {0}".format(read_buffer[6:8])
msg = "The byte order indication in the TIFF header ({0}) is invalid. "
msg += "It should be either {1} or {2}."
msg = msg.format(read_buffer[6:8], bytes([73, 73]), bytes([77, 77]))
raise IOError(msg)
_, offset = struct.unpack(endian + 'HI', read_buffer[8:14])
@ -99,8 +101,12 @@ class _Ifd(object):
def parse_tag(self, dtype, count, offset_buf):
"""Interpret an Exif image tag data payload.
"""
fmt = self.datatype2fmt[dtype][0] * count
payload_size = self.datatype2fmt[dtype][1] * count
try:
fmt = self.datatype2fmt[dtype][0] * count
payload_size = self.datatype2fmt[dtype][1] * count
except KeyError:
msg = 'Invalid TIFF tag datatype ({0}).'.format(dtype)
raise IOError(msg)
if payload_size <= 4:
# Interpret the payload from the 4 bytes in the tag entry.

View file

@ -1241,8 +1241,10 @@ class FileTypeBox(Jp2kBox):
def _validate(self, writing=False):
"""Validate the box before writing to file."""
if self.brand not in ['jp2 ', 'jpx ']:
msg = "The file type brand must be either 'jp2 ' or 'jpx '."
self._dispatch_validation_error(msg, writing=writing)
msg = "The file type brand was '{0}'. "
msg += "It should be either 'jp2 ' or 'jpx '."
self._dispatch_validation_error(msg.format(self.brand),
writing=writing)
valid_cls = ['jp2 ', 'jpx ', 'jpxb']
for item in self.compatibility_list:
if item not in valid_cls:
@ -2740,12 +2742,7 @@ class XMLBox(Jp2kBox):
def write(self, fptr):
"""Write an XML box to file.
"""
try:
read_buffer = ET.tostring(self.xml, encoding='utf-8')
except (AttributeError, AssertionError):
# AssertionError on 2.6
read_buffer = ET.tostring(self.xml.getroot(), encoding='utf-8')
read_buffer = ET.tostring(self.xml, encoding='utf-8')
fptr.write(struct.pack('>I4s', len(read_buffer) + 8, b'xml '))
fptr.write(read_buffer)

View file

@ -180,9 +180,9 @@ class Jp2k(Jp2kBox):
if re.match("2.0", version.openjpeg_version) is not None:
# 2.0 API
if fps == 24:
cparams.cp_cinema = core.OPJ_CINEMA_2K_24
cparams.cp_cinema = core.OPJ_CINEMA2K_24
else:
cparams.cp_cinema = core.OPJ_CINEMA_2K_48
cparams.cp_cinema = core.OPJ_CINEMA2K_48
else:
# 2.1 API
if fps == 24:
@ -198,7 +198,7 @@ class Jp2k(Jp2kBox):
# cinema4k
if re.match("2.0", version.openjpeg_version) is not None:
# 2.0 API
cparams.cp_cinema = core.OPJ_CINEMA_4K_24
cparams.cp_cinema = core.OPJ_CINEMA4K_24
else:
# 2.1 API
cparams.rsiz = core.OPJ_PROFILE_CINEMA_4K
@ -271,6 +271,9 @@ class Jp2k(Jp2kBox):
cparams.tcp_numlayers = 1
cparams.cp_disto_alloc = 1
if 'irreversible' in kwargs and kwargs['irreversible'] is True:
cparams.irreversible = 1
if 'cinema2k' in kwargs:
self._set_cinema_params(cparams, 'cinema2k', kwargs['cinema2k'])
return cparams
@ -416,6 +419,8 @@ class Jp2k(Jp2kBox):
If true, write SOP marker after each header packet.
grid_offset : tuple, optional
Offset (DY, DX) of the origin of the image in the reference grid.
irreversible : bool, optional
If true, use the irreversible DWT 9-7 transform.
mct : bool, optional
Specifies usage of the multi component transform. If not
specified, defaults to True if the colorspace is RGB.

View file

@ -51,51 +51,6 @@ class TestCodestreamOpjData(unittest.TestCase):
def tearDown(self):
pass
def test_bad_rsiz(self):
"""Should warn if RSIZ is bad. Issue196"""
filename = opj_data_file('input/nonregression/edf_c2_1002767.jp2')
if sys.hexversion < 0x03000000:
with warnings.catch_warnings():
warnings.simplefilter("ignore")
j = Jp2k(filename)
else:
with self.assertWarns(UserWarning):
j = Jp2k(filename)
def test_bad_wavelet_transform(self):
"""Should warn if wavelet transform is bad. Issue195"""
filename = opj_data_file('input/nonregression/edf_c2_10025.jp2')
if sys.hexversion < 0x03000000:
with warnings.catch_warnings():
warnings.simplefilter("ignore")
j = Jp2k(filename)
else:
with self.assertWarns(UserWarning):
j = Jp2k(filename)
def test_invalid_progression_order(self):
"""Should still be able to parse even if prog order is invalid."""
jfile = opj_data_file('input/nonregression/2977.pdf.asan.67.2198.jp2')
if sys.hexversion < 0x03000000:
with warnings.catch_warnings():
warnings.simplefilter("ignore")
Jp2k(jfile)
else:
with self.assertWarns(UserWarning):
Jp2k(jfile)
def test_tile_height_is_zero(self):
"""Zero tile height should not cause an exception."""
filename = opj_data_file('input/nonregression/2539.pdf.SIGFPE.706.1712.jp2')
if sys.hexversion < 0x03000000:
with warnings.catch_warnings():
warnings.simplefilter("ignore")
Jp2k(filename)
else:
with self.assertWarns(UserWarning):
Jp2k(filename)
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_reserved_marker_segment(self):
"""Reserved marker segments are ok."""
@ -127,37 +82,6 @@ class TestCodestreamOpjData(unittest.TestCase):
self.assertEqual(codestream.segment[2].length, 3)
self.assertEqual(codestream.segment[2].data, b'\x00')
@unittest.skipIf(sys.hexversion < 0x03020000,
"Uses features introduced in 3.2.")
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_unknown_marker_segment(self):
"""Should warn for an unknown marker."""
# Let's inject a marker segment whose marker does not appear to
# be valid. We still parse the file, but warn about the offending
# marker.
filename = os.path.join(OPJ_DATA_ROOT, 'input/conformance/p0_01.j2k')
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
with open(filename, 'rb') as ifile:
# Everything up until the first QCD marker.
read_buffer = ifile.read(45)
tfile.write(read_buffer)
# Write the new marker segment, 0xff79 = 65401
read_buffer = struct.pack('>HHB', int(65401), int(3), int(0))
tfile.write(read_buffer)
# Get the rest of the input file.
read_buffer = ifile.read()
tfile.write(read_buffer)
tfile.flush()
with self.assertWarns(UserWarning):
codestream = Jp2k(tfile.name).get_codestream()
self.assertEqual(codestream.segment[2].marker_id, '0xff79')
self.assertEqual(codestream.segment[2].length, 3)
self.assertEqual(codestream.segment[2].data, b'\x00')
def test_psot_is_zero(self):
"""Psot=0 in SOT is perfectly legal. Issue #78."""
filename = os.path.join(OPJ_DATA_ROOT,

View file

@ -0,0 +1,100 @@
"""
Test suite for codestream parsing.
"""
# unittest doesn't work well with R0904.
# pylint: disable=R0904
# tempfile.TemporaryDirectory, unittest.assertWarns introduced in 3.2
# pylint: disable=E1101
import os
import struct
import sys
import tempfile
import unittest
import warnings
from glymur import Jp2k
import glymur
from .fixtures import opj_data_file, OPJ_DATA_ROOT
@unittest.skipIf(sys.platform.startswith('linux'), 'warnings failing on linux')
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
class TestCodestreamOpjDataWarnings(unittest.TestCase):
"""Test suite for unusual codestream cases. Uses OPJ_DATA_ROOT"""
def test_bad_rsiz(self):
"""Should warn if RSIZ is bad. Issue196"""
filename = opj_data_file('input/nonregression/edf_c2_1002767.jp2')
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
j = Jp2k(filename)
self.assertEqual(len(w), 3)
self.assertTrue(issubclass(w[0].category, UserWarning))
self.assertTrue('Invalid profile' in str(w[0].message))
def test_bad_wavelet_transform(self):
"""Should warn if wavelet transform is bad. Issue195"""
filename = opj_data_file('input/nonregression/edf_c2_10025.jp2')
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
j = Jp2k(filename)
self.assertTrue(issubclass(w[0].category, UserWarning))
self.assertTrue('Invalid wavelet transform' in str(w[0].message))
def test_invalid_progression_order(self):
"""Should still be able to parse even if prog order is invalid."""
jfile = opj_data_file('input/nonregression/2977.pdf.asan.67.2198.jp2')
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
Jp2k(jfile)
self.assertTrue(issubclass(w[0].category, UserWarning))
self.assertTrue('Invalid progression order' in str(w[0].message))
def test_tile_height_is_zero(self):
"""Zero tile height should not cause an exception."""
filename = opj_data_file('input/nonregression/2539.pdf.SIGFPE.706.1712.jp2')
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
Jp2k(filename)
self.assertTrue(issubclass(w[0].category, UserWarning))
self.assertTrue('Invalid tile dimensions' in str(w[0].message))
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_unknown_marker_segment(self):
"""Should warn for an unknown marker."""
# Let's inject a marker segment whose marker does not appear to
# be valid. We still parse the file, but warn about the offending
# marker.
filename = os.path.join(OPJ_DATA_ROOT, 'input/conformance/p0_01.j2k')
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
with open(filename, 'rb') as ifile:
# Everything up until the first QCD marker.
read_buffer = ifile.read(45)
tfile.write(read_buffer)
# Write the new marker segment, 0xff79 = 65401
read_buffer = struct.pack('>HHB', int(65401), int(3), int(0))
tfile.write(read_buffer)
# Get the rest of the input file.
read_buffer = ifile.read()
tfile.write(read_buffer)
tfile.flush()
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
codestream = Jp2k(tfile.name).get_codestream()
self.assertTrue(issubclass(w[0].category, UserWarning))
self.assertTrue('Unrecognized marker' in str(w[0].message))
self.assertEqual(codestream.segment[2].marker_id, '0xff79')
self.assertEqual(codestream.segment[2].length, 3)
self.assertEqual(codestream.segment[2].data, b'\x00')
if __name__ == "__main__":
unittest.main()

View file

@ -16,6 +16,7 @@ import os
import sys
import tempfile
import unittest
import warnings
if sys.hexversion <= 0x03030000:
from mock import patch
@ -83,8 +84,11 @@ 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.assertTrue(issubclass(w[0].category,UserWarning))
self.assertTrue('could not be loaded' in str(w[0].message))
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None and

View file

@ -62,16 +62,18 @@ class TestICC(unittest.TestCase):
self.assertEqual(profile['Creator'], 'JPEG')
@unittest.skipIf(sys.hexversion < 0x03020000,
"Uses features introduced in 3.2.")
@unittest.skipIf(sys.platform.startswith('linux'), 'Failing on linux')
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.assertTrue(issubclass(w[0].category,UserWarning))
self.assertTrue('ICC profile header is corrupt' in str(w[0].message))
if __name__ == "__main__":
unittest.main()

View file

@ -357,7 +357,6 @@ class TestChannelDefinition(unittest.TestCase):
with self.assertRaises((IOError, OSError)):
j2k.wrap(tfile.name, boxes=boxes)
@unittest.skipIf(sys.hexversion < 0x03000000, "Needs unittest in 3.x.")
def test_bad_type(self):
"""Channel types are limited to 0, 1, 2, 65535
Should reject if not all of index, channel_type, association the
@ -365,20 +364,26 @@ class TestChannelDefinition(unittest.TestCase):
"""
channel_type = (COLOR, COLOR, 3)
association = (RED, GREEN, BLUE)
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
self.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[0].category, UserWarning))
@unittest.skipIf(sys.hexversion < 0x03000000, "Needs unittest in 3.x.")
def test_wrong_lengths(self):
"""Should reject if not all of index, channel_type, association the
same length.
"""
channel_type = (COLOR, COLOR)
association = (RED, GREEN, BLUE)
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
self.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[0].category, UserWarning))
class TestFileTypeBox(unittest.TestCase):
@ -474,32 +479,41 @@ class TestColourSpecificationBox(unittest.TestCase):
self.assertEqual(colr.colorspace, glymur.core.SRGB)
self.assertIsNone(colr.icc_profile)
@unittest.skipIf(sys.hexversion < 0x03030000, "Requires 3.3+")
def test_colr_with_cspace_and_icc(self):
"""Colour specification boxes can't have both."""
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
colorspace = glymur.core.SRGB
rawb = b'\x01\x02\x03\x04'
glymur.jp2box.ColourSpecificationBox(colorspace=colorspace,
icc_profile=rawb)
self.assertTrue(issubclass(w[0].category,UserWarning))
msg = 'Colorspace and icc_profile cannot both be set'
self.assertTrue(msg in str(w[0].message))
@unittest.skipIf(sys.hexversion < 0x03030000, "Requires 3.3+")
def test_colr_with_bad_method(self):
"""colr must have a valid method field"""
colorspace = glymur.core.SRGB
method = -1
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
glymur.jp2box.ColourSpecificationBox(colorspace=colorspace,
method=method)
self.assertTrue(issubclass(w[0].category,UserWarning))
msg = 'Invalid method'
self.assertTrue(msg in str(w[0].message))
@unittest.skipIf(sys.hexversion < 0x03030000, "Requires 3.3+")
def test_colr_with_bad_approx(self):
"""colr should have a valid approximation field"""
colorspace = glymur.core.SRGB
approx = -1
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
glymur.jp2box.ColourSpecificationBox(colorspace=colorspace,
approximation=approx)
self.assertTrue(issubclass(w[0].category,UserWarning))
msg = 'Invalid approximation'
self.assertTrue(msg in str(w[0].message))
def test_colr_with_bad_color(self):
"""colr must have a valid color, strange as though that may sound."""
@ -523,25 +537,29 @@ class TestPaletteBox(unittest.TestCase):
def tearDown(self):
pass
@unittest.skipIf(sys.hexversion < 0x03000000, "Needs unittest in 3.x.")
def test_mismatched_bitdepth_signed(self):
"""bitdepth and signed arguments must have equal length"""
palette = np.array([[255, 0, 255], [0, 255, 0]], dtype=np.uint8)
bps = (8, 8, 8)
signed = (False, False)
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
pclr = glymur.jp2box.PaletteBox(palette, bits_per_component=bps,
signed=signed)
self.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[0].category, UserWarning))
@unittest.skipIf(sys.hexversion < 0x03000000, "Needs unittest in 3.x.")
def test_mismatched_signed_palette(self):
"""bitdepth and signed arguments must have equal length"""
palette = np.array([[255, 0, 255], [0, 255, 0]], dtype=np.uint8)
bps = (8, 8, 8, 8)
signed = (False, False, False, False)
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
pclr = glymur.jp2box.PaletteBox(palette, bits_per_component=bps,
signed=signed)
self.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[0].category, UserWarning))
def test_writing_with_different_bitdepths(self):
"""Bitdepths must be the same when writing."""
@ -554,6 +572,8 @@ class TestPaletteBox(unittest.TestCase):
with self.assertRaises(IOError):
pclr.write(tfile)
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
class TestAppend(unittest.TestCase):
"""Tests for append method."""
@ -1274,8 +1294,8 @@ class TestRepr(unittest.TestCase):
box = glymur.jp2box.XMLBox(xml=tree)
regexp = r"""glymur.jp2box.XMLBox"""
regexp += r"""\(xml=<lxml.etree._ElementTree object """
regexp += """at 0x([a-f0-9]*)>\)"""
regexp += r"""[(]xml=<lxml.etree._ElementTree\sobject\s"""
regexp += """at\s0x([a-fA-F0-9]*)>[)]"""
if sys.hexversion < 0x03000000:
self.assertRegexpMatches(repr(box), regexp)
@ -1314,7 +1334,6 @@ class TestRepr(unittest.TestCase):
else:
self.assertRegex(repr(box), regexp)
@unittest.skipIf(sys.hexversion < 0x02070000, "Requires 2.7+")
def test_uuid_box_xmp(self):
"""Verify uuid repr method for XMP UUID box."""
jp2file = glymur.data.nemo()
@ -1340,8 +1359,8 @@ class TestRepr(unittest.TestCase):
# Difficult to eval(repr()) this, so just match the general pattern.
regexp = "glymur.jp2box.ContiguousCodeStreamBox"
regexp += "\(main_header=<glymur.codestream.Codestream\sobject\s"
regexp += "at\s0x([a-f0-9]*)>\)"
regexp += "[(]main_header=<glymur.codestream.Codestream\sobject\s"
regexp += "at\s0x([a-fA-F0-9]*)>[)]"
if sys.hexversion < 0x03000000:
self.assertRegexpMatches(repr(box), regexp)

View file

@ -305,15 +305,17 @@ class TestJPXWrap(unittest.TestCase):
with self.assertRaises(IOError):
jp2.wrap(tfile.name, boxes=boxes)
@unittest.skipIf(sys.hexversion < 0x03000000, "Needs unittest in 3.x.")
def test_deurl_child_of_dtbl(self):
"""Data reference boxes can only contain data entry url boxes."""
jp2 = Jp2k(self.jp2file)
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
ftyp = glymur.jp2box.FileTypeBox()
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
dref = glymur.jp2box.DataReferenceBox([ftyp])
self.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[0].category, UserWarning))
# Try to get around it by appending the ftyp box after creation.
dref = glymur.jp2box.DataReferenceBox()
@ -484,25 +486,6 @@ class TestJPX(unittest.TestCase):
with tempfile.TemporaryFile() as tfile:
ftbl.write(tfile)
@unittest.skip("Requires unnecessarily complicated code")
def test_unknown_superbox(self):
"""Verify that we can handle an unknown superbox."""
with tempfile.NamedTemporaryFile(suffix='.jpx') as tfile:
with open(self.jpxfile, 'rb') as ifile:
tfile.write(ifile.read())
# Add the header for an unknwon superbox.
write_buffer = struct.pack('>I4s', 20, 'grp '.encode())
tfile.write(write_buffer)
write_buffer = struct.pack('>I4sI', 12, 'free'.encode(), 0)
tfile.write(write_buffer)
tfile.flush()
with self.assertWarns(UserWarning):
jpx = Jp2k(tfile.name)
self.assertEqual(jpx.box[-1].box_id, b'grp ')
self.assertEqual(jpx.box[-1].box[0].box_id, 'free')
def test_data_reference_requires_dtbl(self):
"""The existance of a data reference box requires a ftbl box as well."""
flag = 0

View file

@ -45,6 +45,7 @@ from glymur import Jp2k
from .fixtures import OPJ_DATA_ROOT, opj_data_file, SimpleRDF
@unittest.skipIf(os.name == "nt", "Unexplained failure on windows")
class TestUUIDXMP(unittest.TestCase):
"""Tests for UUIDs of XMP type."""
@ -74,6 +75,7 @@ class TestUUIDXMP(unittest.TestCase):
self.assertTrue(isinstance(jp2.box[-1].data,
lxml.etree._ElementTree))
@unittest.skipIf(os.name == "nt", "Unexplained failure on windows")
class TestUUIDExif(unittest.TestCase):
"""Tests for UUIDs of Exif type."""
@ -83,7 +85,6 @@ class TestUUIDExif(unittest.TestCase):
def tearDown(self):
pass
@unittest.skipIf(sys.hexversion < 0x03000000, "Requires assertWarns, 3.2+")
def test_unrecognized_exif_tag(self):
"""Verify warning in case of unrecognized tag."""
with tempfile.NamedTemporaryFile(suffix='.jp2', mode='wb') as tfile:
@ -106,10 +107,13 @@ class TestUUIDExif(unittest.TestCase):
tfile.write(struct.pack('<HHI4s', 171, 2, 3, b'HTC\x00'))
tfile.flush()
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
j = glymur.Jp2k(tfile.name)
self.assertTrue(issubclass(w[0].category, UserWarning))
msg = 'Unrecognized Exif tag'
self.assertTrue(msg in str(w[0].message))
@unittest.skipIf(sys.hexversion < 0x03000000, "Requires assertWarns, 3.2+")
def test_bad_tag_datatype(self):
"""Only certain datatypes are allowable"""
with tempfile.NamedTemporaryFile(suffix='.jp2', mode='wb') as tfile:
@ -132,12 +136,15 @@ class TestUUIDExif(unittest.TestCase):
tfile.write(struct.pack('<HHI4s', 271, 2000, 3, b'HTC\x00'))
tfile.flush()
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
j = glymur.Jp2k(tfile.name)
self.assertTrue(issubclass(w[0].category, UserWarning))
msg = 'Invalid TIFF tag'
self.assertTrue(msg in str(w[0].message))
self.assertEqual(j.box[-1].box_id, 'uuid')
@unittest.skipIf(sys.hexversion < 0x03000000, "Requires assertWarns, 3.2+")
def test_bad_tiff_header_byte_order_indication(self):
"""Only b'II' and b'MM' are allowed."""
with tempfile.NamedTemporaryFile(suffix='.jp2', mode='wb') as tfile:
@ -160,8 +167,18 @@ class TestUUIDExif(unittest.TestCase):
tfile.write(struct.pack('<HHI4s', 271, 2, 3, b'HTC\x00'))
tfile.flush()
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
j = glymur.Jp2k(tfile.name)
self.assertTrue(issubclass(w[0].category, UserWarning))
msg = 'The byte order indication in the TIFF header '
if sys.hexversion < 0x03000000:
msg += "(JI) is invalid. "
msg += "It should be either [73, 73] or [77, 77]."
else:
msg += "(b'JI') is invalid. "
msg += "It should be either b'II' or b'MM'."
self.assertTrue(msg in str(w[0].message))
self.assertEqual(j.box[-1].box_id, 'uuid')

View file

@ -207,18 +207,14 @@ 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.assertTrue(issubclass(w[0].category, UserWarning))
msg = 'No XML was retrieved'
self.assertTrue(msg in str(w[0].message))
self.assertEqual(jp2k.box[3].box_id, 'xml ')
self.assertEqual(jp2k.box[3].offset, 77)
@ -267,12 +263,14 @@ class TestBadButRecoverableXmlFile(unittest.TestCase):
def tearDownClass(cls):
os.unlink(cls._bad_xml_file)
@unittest.skipIf(sys.hexversion < 0x03020000,
"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.assertTrue(issubclass(w[0].category, UserWarning))
msg = 'A UnicodeDecodeError was encountered parsing an XML box'
self.assertTrue(msg in str(w[0].message))
def test_recover_from_bad_xml(self):
"""Should be able to recover info from xml box with bad xml."""
@ -292,18 +290,19 @@ class TestBadButRecoverableXmlFile(unittest.TestCase):
class TestXML_OpjDataRoot(unittest.TestCase):
"""Test suite for XML boxes, requires OPJ_DATA_ROOT."""
@unittest.skipIf(sys.platform.startswith('linux'), 'Failing on linux')
def test_bom(self):
"""Byte order markers are illegal in UTF-8. Issue 185"""
filename = opj_data_file(os.path.join('input',
'nonregression',
'issue171.jp2'))
if sys.hexversion < 0x03000000:
with warnings.catch_warnings():
warnings.simplefilter("ignore")
jp2 = Jp2k(filename)
else:
with self.assertWarns(UserWarning):
jp2 = Jp2k(filename)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
jp2 = Jp2k(filename)
self.assertTrue(issubclass(w[0].category, UserWarning))
msg = 'An illegal BOM (byte order marker) was detected and removed'
self.assertTrue(msg in str(w[0].message))
self.assertIsNotNone(jp2.box[3].xml)
@ -312,13 +311,10 @@ class TestXML_OpjDataRoot(unittest.TestCase):
filename = opj_data_file(os.path.join('input',
'nonregression',
'26ccf3651020967f7778238ef5af08af.SIGFPE.d25.527.jp2'))
if sys.hexversion < 0x03000000:
with warnings.catch_warnings():
warnings.simplefilter("ignore")
jp2 = Jp2k(filename)
else:
with self.assertWarns(UserWarning):
jp2 = Jp2k(filename)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
jp2 = Jp2k(filename)
self.assertTrue(issubclass(w[0].category, UserWarning))
self.assertIsNone(jp2.box[3].box[1].box[1].xml)

View file

@ -63,6 +63,25 @@ class TestJp2k(unittest.TestCase):
def tearDown(self):
pass
@unittest.skipIf(os.name == "nt", "Unexplained failure on windows")
def test_irreversible(self):
"""Irreversible"""
j = Jp2k(self.jp2file)
expdata = j.read()
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
j2 = Jp2k(tfile.name, 'wb')
j2.write(expdata, irreversible=True)
codestream = j2.get_codestream()
self.assertEqual(codestream.segment[2].spcod[8],
glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE)
actdata = j2.read()
self.assertTrue(fixtures.mse(actdata[0], expdata[0]) < 0.38)
@unittest.skipIf(re.match('1.5.(1|2)',
glymur.version.openjpeg_version) is not None,
"Mysteriously fails in 1.5.1 and 1.5.2")
def test_no_cxform_pclr_jpx(self):
"""Indices for pclr jpxfile if no color transform"""
j = Jp2k(self.jpxfile)
@ -81,6 +100,7 @@ class TestJp2k(unittest.TestCase):
rgb_from_idx[r, c] = palette[idx[r, c]]
np.testing.assert_array_equal(rgb, rgb_from_idx)
@unittest.skipIf(os.name == "nt", "Unexplained failure on windows")
def test_repr(self):
"""Verify that results of __repr__ are eval-able."""
j = Jp2k(self.j2kfile)
@ -390,6 +410,7 @@ class TestJp2k(unittest.TestCase):
self.assertEqual(data.shape, (1024, 1024, 3))
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
class TestJp2k_write(unittest.TestCase):
"""Write tests, can be run by versions 1.5+"""
@ -400,8 +421,6 @@ class TestJp2k_write(unittest.TestCase):
def tearDown(self):
pass
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
def test_cblkh_different_than_width(self):
"""Verify that we can set a code block size where height does not equal
width.
@ -418,7 +437,6 @@ class TestJp2k_write(unittest.TestCase):
# Code block size is reported as XY in the codestream.
self.assertEqual(tuple(codestream.segment[2].spcod[5:7]), (3, 2))
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
def test_too_many_dimensions(self):
"""OpenJP2 only allows 2D or 3D images."""
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
@ -427,7 +445,6 @@ class TestJp2k_write(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_2d_rgb(self):
"""RGB must have at least 3 components."""
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
@ -436,7 +453,6 @@ class TestJp2k_write(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:
@ -445,7 +461,6 @@ class TestJp2k_write(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):
"""specify RGB explicitly"""
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
@ -454,7 +469,6 @@ class TestJp2k_write(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):
"""test gray explicitly specified (that's GRAY, not GREY)"""
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
@ -464,7 +478,6 @@ class TestJp2k_write(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):
"""test grey explicitly specified"""
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
@ -474,7 +487,6 @@ class TestJp2k_write(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_comps(self):
"""should be able to write gray + two extra components"""
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
@ -495,7 +507,6 @@ class TestJp2k_write(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_write_with_jp2_in_caps(self):
"""should be able to write with JP2 suffix."""
j2k = Jp2k(self.j2kfile)
@ -506,7 +517,6 @@ class TestJp2k_write(unittest.TestCase):
actdata = ofile.read()
np.testing.assert_array_equal(actdata, expdata)
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
def test_write_srgb_without_mct(self):
"""should be able to write RGB without specifying mct"""
j2k = Jp2k(self.j2kfile)
@ -520,7 +530,6 @@ class TestJp2k_write(unittest.TestCase):
codestream = ofile.get_codestream()
self.assertEqual(codestream.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)
@ -530,7 +539,6 @@ class TestJp2k_write(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):
"""Must be able to write a CPRL progression order file"""
# Issue 17
@ -757,7 +765,7 @@ class TestJp2k_2_1(unittest.TestCase):
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
class TestParsing(unittest.TestCase):
"""Tests for verifying how paring may be altered."""
"""Tests for verifying how parsing may be altered."""
def setUp(self):
self.jp2file = glymur.data.nemo()
# Reset parseoptions for every test.
@ -766,6 +774,7 @@ class TestParsing(unittest.TestCase):
def tearDown(self):
pass
@unittest.skipIf(sys.platform.startswith('linux'), 'Failing on linux')
def test_bad_rsiz(self):
"""Should not warn if RSIZ when parsing is turned off."""
# Actually there are three warning triggered by this codestream.
@ -776,11 +785,11 @@ class TestParsing(unittest.TestCase):
self.assertEqual(len(w), 0)
glymur.set_parseoptions(codestream=True)
if sys.hexversion >= 0x03000000:
with self.assertWarns(UserWarning):
jp2 = Jp2k(filename)
with warnings.catch_warnings(record=True) as w:
jp2 = Jp2k(filename)
self.assertTrue(issubclass(w[0].category, UserWarning))
self.assertTrue('Invalid profile' in str(w[0].message))
#@unittest.skip("blah")
def test_main_header(self):
"""Verify that the main header is not loaded when parsing turned off."""
# The hidden _main_header attribute should show up after accessing it.
@ -793,44 +802,80 @@ class TestParsing(unittest.TestCase):
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
class TestJp2kOpjDataRoot(unittest.TestCase):
class TestJp2kOpjDataRootWarnings(unittest.TestCase):
"""These tests should be run by just about all configuration."""
def test_undecodeable_box_id(self):
"""Should warn in case of undecodeable box ID but not error out."""
filename = opj_data_file('input/nonregression/edf_c2_1013627.jp2')
if sys.hexversion < 0x03000000:
with warnings.catch_warnings():
warnings.simplefilter("ignore")
jp2 = Jp2k(filename)
else:
with self.assertWarns(UserWarning):
jp2 = Jp2k(filename)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
jp2 = Jp2k(filename)
self.assertTrue(issubclass(w[0].category, UserWarning))
self.assertTrue('Unrecognized box' in str(w[0].message))
# Now make sure we got all of the boxes. Ignore the last, which was
# bad.
box_ids = [box.box_id for box in jp2.box[:-1]]
self.assertEqual(box_ids, ['jP ', 'ftyp', 'jp2h', 'jp2c'])
def test_invalid_approximation(self):
def test_bad_ftyp_brand(self):
"""Should warn in case of bad ftyp brand."""
filename = opj_data_file('input/nonregression/edf_c2_1000290.jp2')
with self.assertWarns(UserWarning):
jp2 = Jp2k(filename)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
jp2 = Jp2k(filename)
self.assertTrue(issubclass(w[0].category, UserWarning))
@unittest.skipIf(sys.hexversion < 0x03000000, "Test requires Python 3.3+")
def test_invalid_approximation(self):
"""Should warn in case of invalid approximation."""
filename = opj_data_file('input/nonregression/edf_c2_1015644.jp2')
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
jp2 = Jp2k(filename)
self.assertTrue(issubclass(w[0].category, UserWarning))
self.assertTrue('Invalid approximation' in str(w[0].message))
@unittest.skipIf(sys.hexversion < 0x03000000, "Test requires Python 3.3+")
@unittest.skipIf(sys.platform.startswith('linux'), 'Failing on linux')
def test_invalid_colorspace(self):
"""Should warn in case of invalid colorspace."""
filename = opj_data_file('input/nonregression/edf_c2_1103421.jp2')
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
jp2 = Jp2k(filename)
self.assertTrue(issubclass(w[1].category, UserWarning))
self.assertTrue('Unrecognized colorspace' in str(w[1].message))
def test_stupid_windows_eol_at_end(self):
"""Garbage characters at the end of the file."""
filename = opj_data_file('input/nonregression/issue211.jp2')
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
jp2 = Jp2k(filename)
self.assertTrue(issubclass(w[1].category, UserWarning))
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
class TestJp2kOpjDataRoot(unittest.TestCase):
"""These tests should be run by just about all configuration."""
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
def test_irreversible(self):
"""Irreversible"""
filename = opj_data_file('input/nonregression/issue141.rawl')
expdata = np.fromfile(filename, dtype=np.uint16)
expdata.resize((2816, 2048))
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
j = Jp2k(tfile.name, 'wb')
j.write(expdata, irreversible=True)
codestream = j.get_codestream()
self.assertEqual(codestream.segment[2].spcod[8],
glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE)
actdata = j.read()
self.assertTrue(fixtures.mse(actdata, expdata) < 250)
def test_no_cxform_pclr_jp2(self):
"""Indices for pclr jpxfile if no color transform"""
@ -850,17 +895,6 @@ class TestJp2kOpjDataRoot(unittest.TestCase):
rgb_from_idx[r, c] = palette[idx[r, c]]
np.testing.assert_array_equal(rgb, rgb_from_idx)
def test_stupid_windows_eol_at_end(self):
"""Garbage characters at the end of the file."""
filename = opj_data_file('input/nonregression/issue211.jp2')
if sys.hexversion < 0x03000000:
with warnings.catch_warnings():
warnings.simplefilter("ignore")
jp2 = Jp2k(filename)
else:
with self.assertWarns(UserWarning):
jp2 = Jp2k(filename)
def test_read_differing_subsamples(self):
"""should error out with read used on differently subsampled images"""
# Verify that we error out appropriately if we use the read method

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,389 @@
"""
The tests defined here roughly correspond to what is in the OpenJPEG test
suite.
"""
# Some test names correspond with openjpeg tests. Long names are ok in this
# case.
# pylint: disable=C0103
# All of these tests correspond to tests in openjpeg, so no docstring is really
# needed.
# pylint: disable=C0111
# This module is very long, cannot be helped.
# pylint: disable=C0302
# unittest fools pylint with "too many public methods"
# pylint: disable=R0904
# Some tests use numpy test infrastructure, which means the tests never
# reference "self", so pylint claims it should be a function. No, no, no.
# pylint: disable=R0201
# Many tests are pretty long and that can't be helped.
# pylint: disable=R0915
# asserWarns introduced in python 3.2 (python2.7/pylint issue)
# pylint: disable=E1101
import re
import sys
import unittest
import warnings
import numpy as np
from glymur import Jp2k
import glymur
from .fixtures import 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'''(1|2.0.0)''',
glymur.version.openjpeg_version) is not None,
"Only supported in 2.0.1 or higher")
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_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()

File diff suppressed because it is too large Load diff

View file

@ -13,6 +13,7 @@ import re
import sys
import tempfile
import unittest
import warnings
import numpy as np
@ -77,14 +78,13 @@ 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('ignore')
codestream = jp2k.get_codestream(header_only=False)
# Verify that the last segment returned in the codestream is SOD,
@ -119,8 +119,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
@ -128,7 +126,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

@ -0,0 +1,376 @@
"""
The tests defined here roughly correspond to what is in the OpenJPEG test
suite.
"""
# Some test names correspond with openjpeg tests. Long names are ok in this
# case.
# pylint: disable=C0103
# All of these tests correspond to tests in openjpeg, so no docstring is really
# needed.
# pylint: disable=C0111
# This module is very long, cannot be helped.
# pylint: disable=C0302
# unittest fools pylint with "too many public methods"
# pylint: disable=R0904
# Some tests use numpy test infrastructure, which means the tests never
# reference "self", so pylint claims it should be a function. No, no, no.
# pylint: disable=R0201
# Many tests are pretty long and that can't be helped.
# pylint: disable=R0915
# asserWarns introduced in python 3.2 (python2.7/pylint issue)
# pylint: disable=E1101
import re
import sys
import unittest
import warnings
import numpy as np
from glymur import Jp2k
import glymur
from .fixtures import 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")
class TestSuiteDumpWarnings(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_NR_broken_jp2_dump(self):
jfile = opj_data_file('input/nonregression/broken.jp2')
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('ignore')
# colr box has bad length.
jp2 = Jp2k(jfile)
ids = [box.box_id for box in jp2.box]
self.assertEqual(ids, ['jP ', 'ftyp', 'jp2h', 'jp2c'])
ids = [box.box_id for box in jp2.box[2].box]
self.assertEqual(ids, ['ihdr', 'colr'])
# Signature box. Check for corruption.
self.assertEqual(jp2.box[0].signature, (13, 10, 135, 10))
# File type box.
self.assertEqual(jp2.box[1].brand, 'jp2 ')
self.assertEqual(jp2.box[1].minor_version, 0)
self.assertEqual(jp2.box[1].compatibility_list[0], 'jp2 ')
# Jp2 Header
# Image header
self.assertEqual(jp2.box[2].box[0].height, 152)
self.assertEqual(jp2.box[2].box[0].width, 203)
self.assertEqual(jp2.box[2].box[0].num_components, 3)
self.assertEqual(jp2.box[2].box[0].bits_per_component, 8)
self.assertEqual(jp2.box[2].box[0].signed, False)
self.assertEqual(jp2.box[2].box[0].compression, 7) # wavelet
self.assertEqual(jp2.box[2].box[0].colorspace_unknown, False)
self.assertEqual(jp2.box[2].box[0].ip_provided, False)
# Jp2 Header
# Colour specification
self.assertEqual(jp2.box[2].box[1].method,
glymur.core.ENUMERATED_COLORSPACE)
self.assertEqual(jp2.box[2].box[1].precedence, 0)
self.assertEqual(jp2.box[2].box[1].approximation, 0) # not allowed?
self.assertEqual(jp2.box[2].box[1].colorspace, glymur.core.SRGB)
c = jp2.box[3].main_header
ids = [x.marker_id for x in c.segment]
expected = ['SOC', 'SIZ', 'CME', 'COD', 'QCD', 'QCC', 'QCC']
self.assertEqual(ids, expected)
# SIZ: Image and tile size
# Profile:
self.assertEqual(c.segment[1].rsiz, 0)
# Reference grid size
self.assertEqual(c.segment[1].xsiz, 203)
self.assertEqual(c.segment[1].ysiz, 152)
# Reference grid offset
self.assertEqual((c.segment[1].xosiz, c.segment[1].yosiz), (0, 0))
# Tile size
self.assertEqual((c.segment[1].xtsiz, c.segment[1].ytsiz), (203, 152))
# Tile offset
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)),
[(1, 1)] * 3)
# COM: comment
# Registration
self.assertEqual(c.segment[2].rcme, glymur.core.RCME_ISO_8859_1)
# Comment value
self.assertEqual(c.segment[2].ccme.decode('latin-1'),
"Creator: JasPer Version 1.701.0")
# COD: Coding style default
self.assertFalse(c.segment[3].scod & 2) # no sop
self.assertFalse(c.segment[3].scod & 4) # no eph
self.assertEqual(c.segment[3].spcod[0], glymur.core.LRCP)
self.assertEqual(c.segment[3].layers, 1) # layers = 1
self.assertEqual(c.segment[3].spcod[3], 1) # mct
self.assertEqual(c.segment[3].spcod[4], 5) # level
self.assertEqual(tuple(c.segment[3].code_block_size),
(64, 64)) # cblk
# Selective arithmetic coding bypass
self.assertFalse(c.segment[3].spcod[7] & 0x01)
# Reset context probabilities
self.assertFalse(c.segment[3].spcod[7] & 0x02)
# Termination on each coding pass
self.assertFalse(c.segment[3].spcod[7] & 0x04)
# Vertically causal context
self.assertFalse(c.segment[3].spcod[7] & 0x08)
# Predictable termination
self.assertFalse(c.segment[3].spcod[7] & 0x0010)
# Segmentation symbols
self.assertFalse(c.segment[3].spcod[7] & 0x0020)
self.assertEqual(c.segment[3].spcod[8],
glymur.core.WAVELET_XFORM_5X3_REVERSIBLE)
self.assertEqual(len(c.segment[3].spcod), 9)
# QCD: Quantization default
self.assertEqual(c.segment[4].sqcd & 0x1f, 0)
self.assertEqual(c.segment[4].guard_bits, 2)
self.assertEqual(c.segment[4].mantissa, [0] * 16)
self.assertEqual(c.segment[4].exponent,
[8] + [9, 9, 10] * 5)
# QCC: Quantization component
# associated component
self.assertEqual(c.segment[5].cqcc, 1)
self.assertEqual(c.segment[5].guard_bits, 2)
# quantization type
self.assertEqual(c.segment[5].sqcc & 0x1f, 0) # none
self.assertEqual(c.segment[5].mantissa, [0] * 16)
self.assertEqual(c.segment[5].exponent,
[8] + [9, 9, 10] * 5)
# QCC: Quantization component
# associated component
self.assertEqual(c.segment[6].cqcc, 2)
self.assertEqual(c.segment[6].guard_bits, 2)
# quantization type
self.assertEqual(c.segment[6].sqcc & 0x1f, 0) # none
self.assertEqual(c.segment[6].mantissa, [0] * 16)
self.assertEqual(c.segment[6].exponent,
[8] + [9, 9, 10] * 5)
def test_NR_broken2_jp2_dump(self):
# Invalid marker ID on codestream.
jfile = opj_data_file('input/nonregression/broken2.jp2')
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('ignore')
jp2 = Jp2k(jfile)
self.assertEqual(jp2.box[-1].main_header.segment[-1].marker_id, 'QCC')
@unittest.skipIf(sys.maxsize < 2**32, 'Do not run on 32-bit platforms')
def test_NR_broken3_jp2_dump(self):
"""
NR_broken3_jp2_dump
The file in question here has a colr box with an erroneous box
length of over 1GB. Don't run it on 32-bit platforms.
"""
jfile = opj_data_file('input/nonregression/broken3.jp2')
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('ignore')
jp2 = Jp2k(jfile)
ids = [box.box_id for box in jp2.box]
self.assertEqual(ids, ['jP ', 'ftyp', 'jp2h', 'jp2c'])
ids = [box.box_id for box in jp2.box[2].box]
self.assertEqual(ids, ['ihdr', 'colr'])
# Signature box. Check for corruption.
self.assertEqual(jp2.box[0].signature, (13, 10, 135, 10))
# File type box.
self.assertEqual(jp2.box[1].brand, 'jp2 ')
self.assertEqual(jp2.box[1].minor_version, 0)
self.assertEqual(jp2.box[1].compatibility_list[0], 'jp2 ')
# Jp2 Header
# Image header
self.assertEqual(jp2.box[2].box[0].height, 152)
self.assertEqual(jp2.box[2].box[0].width, 203)
self.assertEqual(jp2.box[2].box[0].num_components, 3)
self.assertEqual(jp2.box[2].box[0].bits_per_component, 8)
self.assertEqual(jp2.box[2].box[0].signed, False)
self.assertEqual(jp2.box[2].box[0].compression, 7) # wavelet
self.assertEqual(jp2.box[2].box[0].colorspace_unknown, False)
self.assertEqual(jp2.box[2].box[0].ip_provided, False)
# Jp2 Header
# Colour specification
self.assertEqual(jp2.box[2].box[1].method,
glymur.core.ENUMERATED_COLORSPACE)
self.assertEqual(jp2.box[2].box[1].precedence, 0)
self.assertEqual(jp2.box[2].box[1].approximation, 0) # JP2
self.assertEqual(jp2.box[2].box[1].colorspace, glymur.core.SRGB)
c = jp2.box[3].main_header
ids = [x.marker_id for x in c.segment]
expected = ['SOC', 'SIZ', 'CME', 'COD', 'QCD', 'QCC', 'QCC']
self.assertEqual(ids, expected)
# SIZ: Image and tile size
# Profile:
self.assertEqual(c.segment[1].rsiz, 0)
# Reference grid size
self.assertEqual(c.segment[1].xsiz, 203)
self.assertEqual(c.segment[1].ysiz, 152)
# Reference grid offset
self.assertEqual((c.segment[1].xosiz, c.segment[1].yosiz), (0, 0))
# Tile size
self.assertEqual((c.segment[1].xtsiz, c.segment[1].ytsiz), (203, 152))
# Tile offset
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)),
[(1, 1)] * 3)
# COM: comment
# Registration
self.assertEqual(c.segment[2].rcme, glymur.core.RCME_ISO_8859_1)
# Comment value
self.assertEqual(c.segment[2].ccme.decode('latin-1'),
"Creator: JasPer Vers)on 1.701.0")
# COD: Coding style default
self.assertFalse(c.segment[3].scod & 2) # no sop
self.assertFalse(c.segment[3].scod & 4) # no eph
self.assertEqual(c.segment[3].spcod[0], glymur.core.LRCP)
self.assertEqual(c.segment[3].layers, 1) # layers = 1
self.assertEqual(c.segment[3].spcod[3], 1) # mct
self.assertEqual(c.segment[3].spcod[4], 5) # level
self.assertEqual(tuple(c.segment[3].code_block_size),
(64, 64)) # cblk
# Selective arithmetic coding bypass
self.assertFalse(c.segment[3].spcod[7] & 0x01)
# Reset context probabilities
self.assertFalse(c.segment[3].spcod[7] & 0x02)
# Termination on each coding pass
self.assertFalse(c.segment[3].spcod[7] & 0x04)
# Vertically causal context
self.assertFalse(c.segment[3].spcod[7] & 0x08)
# Predictable termination
self.assertFalse(c.segment[3].spcod[7] & 0x0010)
# Segmentation symbols
self.assertFalse(c.segment[3].spcod[7] & 0x0020)
self.assertEqual(c.segment[3].spcod[8],
glymur.core.WAVELET_XFORM_5X3_REVERSIBLE)
self.assertEqual(len(c.segment[3].spcod), 9)
# QCD: Quantization default
self.assertEqual(c.segment[4].sqcd & 0x1f, 0)
self.assertEqual(c.segment[4].guard_bits, 2)
self.assertEqual(c.segment[4].mantissa, [0] * 16)
self.assertEqual(c.segment[4].exponent,
[8] + [9, 9, 10] * 5)
# QCC: Quantization component
# associated component
self.assertEqual(c.segment[5].cqcc, 1)
self.assertEqual(c.segment[5].guard_bits, 2)
# quantization type
self.assertEqual(c.segment[5].sqcc & 0x1f, 0) # none
self.assertEqual(c.segment[5].mantissa, [0] * 16)
self.assertEqual(c.segment[5].exponent,
[8] + [9, 9, 10] * 5)
# QCC: Quantization component
# associated component
self.assertEqual(c.segment[6].cqcc, 2)
self.assertEqual(c.segment[6].guard_bits, 2)
# quantization type
self.assertEqual(c.segment[6].sqcc & 0x1f, 0) # none
self.assertEqual(c.segment[6].mantissa, [0] * 16)
self.assertEqual(c.segment[6].exponent,
[8] + [9, 9, 10] * 5)
def test_NR_broken4_jp2_dump(self):
# Has an invalid marker in the main header
jfile = opj_data_file('input/nonregression/broken4.jp2')
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('ignore')
jp2 = Jp2k(jfile)
self.assertEqual(jp2.box[-1].main_header.segment[-1].marker_id, 'QCC')
def test_NR_gdal_fuzzer_assert_in_opj_j2k_read_SQcd_SQcc_patch_jp2(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(record=True) as w:
warnings.simplefilter('ignore')
Jp2k(jfile)
def test_NR_gdal_fuzzer_check_comp_dx_dy_jp2_dump(self):
lst = ['input', 'nonregression', 'gdal_fuzzer_check_comp_dx_dy.jp2']
jfile = opj_data_file('/'.join(lst))
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('ignore')
Jp2k(jfile)
def test_NR_gdal_fuzzer_check_number_of_tiles(self):
# Has an impossible tiling setup.
lst = ['input', 'nonregression',
'gdal_fuzzer_check_number_of_tiles.jp2']
jfile = opj_data_file('/'.join(lst))
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('ignore')
Jp2k(jfile)
def test_NR_gdal_fuzzer_unchecked_numresolutions_dump(self):
# Has an invalid number of resolutions.
lst = ['input', 'nonregression',
'gdal_fuzzer_unchecked_numresolutions.jp2']
jfile = opj_data_file('/'.join(lst))
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('ignore')
Jp2k(jfile)
@unittest.skipIf(re.match("1.5|2.0.0", glymur.version.openjpeg_version),
"Test not passing on 1.5.x, not introduced until 2.x")
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('ignore')
j = Jp2k(jfile)
d = j.read()
if __name__ == "__main__":
unittest.main()

View file

@ -13,6 +13,8 @@ import tempfile
import unittest
import warnings
import numpy as np
try:
import skimage.io
skimage.io.use_plugin('freeimage', 'imread')
@ -271,6 +273,19 @@ class TestSuiteWrite(unittest.TestCase):
def tearDown(self):
pass
def test_NR_ENC_issue141_rawl_23_encode(self):
filename = opj_data_file('input/nonregression/issue141.rawl')
expdata = np.fromfile(filename, dtype=np.uint16)
expdata.resize((2816, 2048))
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
j = Jp2k(tfile.name, 'wb')
j.write(expdata, irreversible=True)
codestream = j.get_codestream()
self.assertEqual(codestream.segment[2].spcod[8],
glymur.core.WAVELET_XFORM_9X7_IRREVERSIBLE)
def test_NR_ENC_Bretagne1_ppm_1_encode(self):
"""NR-ENC-Bretagne1.ppm-1-encode"""
infile = opj_data_file('input/nonregression/Bretagne1.ppm')
@ -1020,7 +1035,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

@ -70,7 +70,6 @@ class TestPrinting(unittest.TestCase):
self.assertTrue(True)
@unittest.skipIf(sys.hexversion < 0x03000000, "Needs unittest in 3.x.")
def test_unknown_superbox(self):
"""Verify that we can handle an unknown superbox."""
with tempfile.NamedTemporaryFile(suffix='.jpx') as tfile:
@ -87,14 +86,19 @@ class TestPrinting(unittest.TestCase):
tfile.write(write_buffer)
tfile.flush()
with self.assertWarns(UserWarning):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
jpx = Jp2k(tfile.name)
self.assertTrue(len(w), 1)
glymur.set_printoptions(short=True)
with patch('sys.stdout', new=StringIO()) as fake_out:
print(jpx.box[-1])
actual = fake_out.getvalue().strip()
lines = ["Unknown Box (b'grp ') @ (1399071, 20)"]
expected = '\n'.join(lines)
if sys.hexversion < 0x03000000:
expected = "Unknown Box (grp ) @ (1399071, 20)"
else:
expected = "Unknown Box (b'grp ') @ (1399071, 20)"
self.assertEqual(actual, expected)
def test_printoptions_bad_argument(self):
@ -721,6 +725,8 @@ class TestPrintingOpjDataRoot(unittest.TestCase):
# Reset printoptions for every test.
glymur.set_printoptions(short=False, xml=True, codestream=True)
warnings.resetwarnings()
def tearDown(self):
pass
@ -767,7 +773,7 @@ class TestPrintingOpjDataRoot(unittest.TestCase):
with warnings.catch_warnings():
warnings.simplefilter("ignore")
jp2 = Jp2k(jfile)
codestream = jp2.get_codestream()
codestream = jp2.get_codestream()
with patch('sys.stdout', new=StringIO()) as fake_out:
print(codestream.segment[2])
actual = fake_out.getvalue().strip()

View file

@ -19,7 +19,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.6.0"
_sv = LooseVersion(version)
version_tuple = _sv.version

View file

@ -25,6 +25,7 @@ kwargs['install_requires'] = instllrqrs
clssfrs = ["Programming Language :: Python",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: Implementation :: CPython",
"License :: OSI Approved :: MIT License",
"Development Status :: 5 - Production/Stable",