diff --git a/.travis.yml b/.travis.yml
index c055dce..6a57264 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,8 +11,8 @@ before_install:
# command to install dependencies
install:
- - if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --use-mirrors lxml contextlib2 mock; fi
- - if [[ $TRAVIS_PYTHON_VERSION == '3.3' ]]; then pip install --use-mirrors lxml numpy; fi
+ - 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
# command to run tests
script:
diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst
index 7a96571..c3eae6c 100644
--- a/docs/source/changelog.rst
+++ b/docs/source/changelog.rst
@@ -9,6 +9,7 @@ ChangeLog
* 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
diff --git a/docs/source/introduction.rst b/docs/source/introduction.rst
index 38193eb..10df117 100644
--- a/docs/source/introduction.rst
+++ b/docs/source/introduction.rst
@@ -14,17 +14,7 @@ XMP UUIDs. There is some very limited 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.
-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 of OpenJPEG 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
-Linux, your package manager should already provide you with a version of
-OpenJPEG 1.X which glymur can already use.
+For more information about OpenJPEG, please consult http://www.openjpeg.org.
Glymur Installation
===================
diff --git a/glymur/codestream.py b/glymur/codestream.py
index 4259788..35e3fee 100644
--- a/glymur/codestream.py
+++ b/glymur/codestream.py
@@ -17,6 +17,7 @@ codestreams.
# the base Segment class.
# pylint: disable=R0903
+import collections
import math
import struct
import sys
@@ -30,12 +31,26 @@ from .core import WAVELET_XFORM_5X3_REVERSIBLE
from .core import _CAPABILITIES_DISPLAY
from .lib import openjp2 as opj2
-_PROGRESSION_ORDER_DISPLAY = {
- LRCP: 'LRCP',
- RLCP: 'RLCP',
- RPCL: 'RPCL',
- PCRL: 'PCRL',
- CPRL: 'CPRL'}
+class _keydefaultdict(collections.defaultdict):
+ """Unlisted keys help form their own error message.
+
+ Normally defaultdict uses a factory function with no input arguments, but
+ that's not quite the behavior we want.
+ """
+ def __missing__(self, key):
+ if self.default_factory is None:
+ raise KeyError(key)
+ else:
+ ret = self[key] = self.default_factory(key)
+ return ret
+
+_factory = lambda x: '{0} (invalid)'.format(x)
+_PROGRESSION_ORDER_DISPLAY = _keydefaultdict(_factory,
+ { LRCP: 'LRCP',
+ RLCP: 'RLCP',
+ RPCL: 'RPCL',
+ PCRL: 'PCRL',
+ CPRL: 'CPRL'})
_WAVELET_TRANSFORM_DISPLAY = {
WAVELET_XFORM_9X7_IRREVERSIBLE: '9-7 irreversible',
@@ -371,6 +386,9 @@ class Codestream(object):
numbytes = offset + 2 + length - fptr.tell()
spcod = fptr.read(numbytes)
spcod = np.frombuffer(spcod, dtype=np.uint8)
+ if spcod[0] not in [LRCP, RLCP, RPCL, PCRL, CPRL]:
+ msg = "Invalid progression order in COD segment: {0}."
+ warnings.warn(msg.format(spcod[0]))
sop = (scod & 2) > 0
eph = (scod & 4) > 0
@@ -673,6 +691,18 @@ class Codestream(object):
msg = msg.format(j, subsampling[0], subsampling[1])
warnings.warn(msg)
+ try:
+ num_tiles_x = (xysiz[0] - xyosiz[0]) / (xytsiz[0] - xytosiz[0])
+ num_tiles_y = (xysiz[1] - xyosiz[1]) / (xytsiz[1] - xytosiz[1])
+ except ZeroDivisionError as err:
+ warnings.warn("Invalid tile dimensions.")
+ else:
+ numtiles = math.ceil(num_tiles_x) * math.ceil(num_tiles_y)
+ if numtiles > 65535:
+ msg = "Invalid number of tiles ({0}).".format(numtiles)
+ warnings.warn(msg)
+
+
kwargs = {'rsiz': rsiz,
'xysiz': xysiz,
'xyosiz': xyosiz,
@@ -1514,14 +1544,6 @@ class SIZsegment(Segment):
lst.append(bitdepth - 1)
self.ssiz = tuple(lst)
- num_tiles_x = (self.xsiz - self.xosiz) / (self.xtsiz - self.xtosiz)
- num_tiles_y = (self.ysiz - self.yosiz) / (self.ytsiz - self.ytosiz)
- numtiles = math.ceil(num_tiles_x) * math.ceil(num_tiles_y)
- if numtiles > 65535:
- msg = "Invalid number of tiles ({0}).".format(numtiles)
- warnings.warn(msg)
-
-
def __repr__(self):
msg = "glymur.codestream.SIZsegment(rsiz={rsiz}, xysiz={xysiz}, "
msg += "xyosiz={xyosiz}, xytsiz={xytsiz}, xytosiz={xytosiz}, "
diff --git a/glymur/jp2box.py b/glymur/jp2box.py
index 6db6c87..578ef36 100644
--- a/glymur/jp2box.py
+++ b/glymur/jp2box.py
@@ -220,7 +220,13 @@ class Jp2kBox(object):
break
read_buffer = fptr.read(8)
- (box_length, box_id) = struct.unpack('>I4s', read_buffer)
+ try:
+ (box_length, box_id) = struct.unpack('>I4s', read_buffer)
+ except Exception as err:
+ msg = "Extra bytes at end of file ignored."
+ warnings.warn(msg)
+ return superbox
+
if sys.hexversion >= 0x03000000:
box_id = box_id.decode('utf-8')
@@ -359,13 +365,16 @@ class ColourSpecificationBox(Jp2kBox):
else:
# 2.7 has trouble pretty-printing ordered dicts so we just have
# to print as a regular dict in this case.
- if sys.hexversion < 0x03000000:
- icc_profile = dict(self.icc_profile)
+ if self.icc_profile is None:
+ msg += '\n ICC Profile: None'
else:
- icc_profile = self.icc_profile
- dispvalue = pprint.pformat(icc_profile)
- lines = [' ' * 8 + y for y in dispvalue.split('\n')]
- msg += '\n ICC Profile:\n{0}'.format('\n'.join(lines))
+ if sys.hexversion < 0x03000000:
+ icc_profile = dict(self.icc_profile)
+ else:
+ icc_profile = self.icc_profile
+ dispvalue = pprint.pformat(icc_profile)
+ lines = [' ' * 8 + y for y in dispvalue.split('\n')]
+ msg += '\n ICC Profile:\n{0}'.format('\n'.join(lines))
return msg
@@ -829,7 +838,7 @@ class ComponentMappingBox(Jp2kBox):
msg = msg.format(self.component_index[k],
self.palette_index[k])
else:
- msg += '\n Component %d ==> %d'
+ msg += '\n Component {0} ==> {1}'
msg = msg.format(self.component_index[k], k)
return msg
@@ -2628,26 +2637,39 @@ class XMLBox(Jp2kBox):
read_buffer = fptr.read(num_bytes)
try:
text = read_buffer.decode('utf-8')
- except UnicodeDecodeError as ude:
+ except UnicodeDecodeError as err:
# Possibly bad string of bytes to begin with.
# Try to search for -1:
- text = read_buffer[decl_start:].decode('utf-8')
- else:
- raise
+ if decl_start <= -1:
+ msg = 'A problem was encountered while parsing an XML box:'
+ msg += '\n\n\t"{0}"\n\nNo XML was retrieved.'
+ warnings.warn(msg.format(str(err)))
+ return XMLBox(xml=None, length=length, offset=offset)
+
+ text = read_buffer[decl_start:].decode('utf-8')
# Let the user know that the XML box was problematic.
msg = 'A UnicodeDecodeError was encountered parsing an XML box at '
msg += 'byte position {0} ({1}), but the XML was still recovered.'
- msg = msg.format(offset, ude.reason)
+ msg = msg.format(offset, err.reason)
warnings.warn(msg, UserWarning)
# Strip out any trailing nulls, as they can foul up XML parsing.
+ # Remove any byte order markers.
text = text.rstrip(chr(0))
+ if u'\ufeff' in text:
+ msg = 'An illegal BOM (byte order marker) was detected and '
+ msg += 'removed from the XML contents in the box starting at byte '
+ msg += 'offset {0}'.format(offset)
+ warnings.warn(msg)
+ text = text.replace(u'\ufeff', '')
+ # Remove any encoding declaration.
+ if text.startswith(''):
+ text = text[38:]
try:
- elt = ET.fromstring(text.encode('utf-8'))
+ elt = ET.fromstring(text)
xml = ET.ElementTree(elt)
except ET.ParseError as err:
msg = 'A problem was encountered while parsing an XML box:'
diff --git a/glymur/jp2k.py b/glymur/jp2k.py
index 7522d35..1239821 100644
--- a/glymur/jp2k.py
+++ b/glymur/jp2k.py
@@ -695,6 +695,8 @@ class Jp2k(Jp2kBox):
(first_row, first_col, last_row, last_col)
tile : int, optional
Number of tile to decode.
+ no_cxform : bool
+ Whether or not to apply intended color transforms.
verbose : bool, optional
Print informational messages produced by the OpenJPEG library.
@@ -749,7 +751,7 @@ class Jp2k(Jp2kBox):
msg += "the read_bands method instead."
raise RuntimeError(msg)
- def _read_openjpeg(self, rlevel=0, verbose=False):
+ def _read_openjpeg(self, rlevel=0, no_cxform=False, verbose=False):
"""Read a JPEG 2000 image using libopenjpeg.
Parameters
@@ -757,6 +759,8 @@ class Jp2k(Jp2kBox):
rlevel : int, optional
Factor by which to rlevel output resolution. Use -1 to get the
lowest resolution thumbnail.
+ no_cxform : bool
+ Whether or not to apply intended color transforms.
verbose : bool, optional
Print informational messages produced by the OpenJPEG library.
@@ -772,24 +776,30 @@ class Jp2k(Jp2kBox):
"""
self._subsampling_sanity_check()
+ # Must check the specified rlevel against the maximum.
if rlevel != 0:
# Must check the specified rlevel against the maximum.
- # OpenJPEG 1.3 will segfault if rlevel is too high.
codestream = self.get_codestream()
max_rlevel = codestream.segment[2].spcod[4]
if rlevel == -1:
# -1 is shorthand for the largest rlevel
rlevel = max_rlevel
- if rlevel < -1 or rlevel > max_rlevel:
- msg = "rlevel must be in the range [-1, {0}] for this image."
- msg = msg.format(max_rlevel)
- raise IOError(msg)
+ elif rlevel < -1 or rlevel > max_rlevel:
+ msg = "rlevel must be in the range [-1, {0}] for this image."
+ msg = msg.format(max_rlevel)
+ raise IOError(msg)
with ExitStack() as stack:
try:
# Set decoding parameters.
+ # TODO: look to refactor, use _populate_dparam
dparameters = opj.DecompressionParametersType()
opj.set_default_decoder_parameters(ctypes.byref(dparameters))
+
+ if no_cxform is True:
+ # Return raw codestream components.
+ dparameters.flags |= 1
+
dparameters.cp_reduce = rlevel
dparameters.decod_format = self._codec_format
@@ -834,7 +844,7 @@ class Jp2k(Jp2kBox):
return data
def _read_openjp2(self, rlevel=0, layer=0, area=None, tile=None,
- verbose=False):
+ verbose=False, no_cxform=False):
"""Read a JPEG 2000 image using libopenjp2.
Parameters
@@ -864,7 +874,7 @@ class Jp2k(Jp2kBox):
"""
self._subsampling_sanity_check()
- dparam = self._populate_dparam(layer, rlevel, area, tile)
+ dparam = self._populate_dparam(layer, rlevel, area, tile, no_cxform)
with ExitStack() as stack:
if hasattr(opj2.OPENJP2,
@@ -908,20 +918,22 @@ class Jp2k(Jp2kBox):
return img_array
- def _populate_dparam(self, layer, rlevel, area, tile):
+ def _populate_dparam(self, layer, rlevel, area, tile, no_cxform):
"""Populate decompression structure with appropriate input parameters.
Parameters
----------
- layer : int, optional
+ layer : int
Number of quality layer to decode.
- rlevel : int, optional
+ rlevel : int
Factor by which to rlevel output resolution.
- area : tuple, optional
+ area : tuple
Specifies decoding image area,
(first_row, first_col, last_row, last_col)
- tile : int, optional
+ tile : int
Number of tile to decode.
+ no_cxform : bool
+ Whether or not to apply intended color transforms.
Returns
-------
@@ -959,10 +971,14 @@ class Jp2k(Jp2kBox):
dparam.tile_index = tile
dparam.nb_tile_to_decode = 1
+ if no_cxform is True:
+ # Return raw codestream components.
+ dparam.flags |= 1
+
return dparam
def read_bands(self, rlevel=0, layer=0, area=None, tile=None,
- verbose=False):
+ verbose=False, no_cxform=False):
"""Read a JPEG 2000 image.
The only time you should use this method is when the image has
@@ -980,6 +996,8 @@ class Jp2k(Jp2kBox):
(first_row, first_col, last_row, last_col)
tile : int, optional
Number of tile to decode.
+ no_cxform : bool
+ Whether or not to apply intended color transforms.
verbose : bool, optional
Print informational messages produced by the OpenJPEG library.
@@ -1009,7 +1027,7 @@ class Jp2k(Jp2kBox):
"of OpenJP2 installed before using "
"this functionality.")
- dparam = self._populate_dparam(layer, rlevel, area, tile)
+ dparam = self._populate_dparam(layer, rlevel, area, tile, no_cxform)
with ExitStack() as stack:
if hasattr(opj2.OPENJP2,
diff --git a/glymur/lib/openjp2.py b/glymur/lib/openjp2.py
index 5430110..39dd5a4 100644
--- a/glymur/lib/openjp2.py
+++ b/glymur/lib/openjp2.py
@@ -395,7 +395,7 @@ class ImageCompType(ctypes.Structure):
# alpha channel
# TODO: exclude for 2.0, 1.5
- ("alpha", ctypes.POINTER(ctypes.c_uint16))]
+ ("alpha", ctypes.c_uint16)]
class ImageType(ctypes.Structure):
diff --git a/glymur/test/fixtures.py b/glymur/test/fixtures.py
index 2004d2b..8e8deb8 100644
--- a/glymur/test/fixtures.py
+++ b/glymur/test/fixtures.py
@@ -577,3 +577,36 @@ file1_xml = """XML Box (xml ) @ (36, 439)
\t\tProfessional 120 Image
\t
"""
+
+issue_182_cmap = """Component Mapping Box (cmap) @ (130, 24)
+ Component 0 ==> palette column 0
+ Component 1 ==> palette column 0
+ Component 2 ==> 2"""
+
+issue_183_colr = """Colour Specification Box (colr) @ (62, 12)
+ Method: restricted ICC profile
+ Precedence: 0
+ ICC Profile: None"""
+
+
+# Progression order is invalid.
+issue_186_progression_order = """COD marker segment @ (174, 12)
+ Coding style:
+ Entropy coder, without partitions
+ SOP marker segments: False
+ EPH marker segments: False
+ Coding style parameters:
+ Progression order: 33 (invalid)
+ Number of layers: 1
+ Multiple component transformation usage: reversible
+ Number of resolutions: 6
+ Code block height, width: (32 x 32)
+ Wavelet transform: 9-7 irreversible
+ 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"""
diff --git a/glymur/test/test_codestream.py b/glymur/test/test_codestream.py
index 5edd144..28ea0f8 100644
--- a/glymur/test/test_codestream.py
+++ b/glymur/test/test_codestream.py
@@ -13,17 +13,12 @@ import struct
import sys
import tempfile
import unittest
+import warnings
from glymur import Jp2k
import glymur
-try:
- DATA_ROOT = os.environ['OPJ_DATA_ROOT']
-except KeyError:
- DATA_ROOT = None
-except:
- raise
-
+from .fixtures import opj_data_file, OPJ_DATA_ROOT
class TestCodestream(unittest.TestCase):
"""Test suite for unusual codestream cases."""
@@ -34,8 +29,51 @@ class TestCodestream(unittest.TestCase):
def tearDown(self):
pass
- @unittest.skipIf(DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
+ def test_siz_segment_ssiz_unsigned(self):
+ """ssiz attribute to be removed in future release"""
+ j = Jp2k(self.jp2file)
+ codestream = j.get_codestream()
+
+ # The ssiz attribute was simply a tuple of raw bytes.
+ # The first 7 bits are interpreted as the bitdepth, the MSB determines
+ # whether or not it is signed.
+ self.assertEqual(codestream.segment[1].ssiz, (7, 7, 7))
+
+
+@unittest.skipIf(OPJ_DATA_ROOT is None,
+ "OPJ_DATA_ROOT environment variable not set")
+class TestCodestreamOpjData(unittest.TestCase):
+ """Test suite for unusual codestream cases. Uses OPJ_DATA_ROOT"""
+
+ def setUp(self):
+ self.jp2file = glymur.data.nemo()
+
+ def tearDown(self):
+ pass
+
+ 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."""
@@ -45,7 +83,7 @@ class TestCodestream(unittest.TestCase):
#
# Let's inject a reserved marker segment into a file that
# we know something about to make sure we can still parse it.
- filename = os.path.join(DATA_ROOT, 'input/conformance/p0_01.j2k')
+ 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.
@@ -67,8 +105,6 @@ class TestCodestream(unittest.TestCase):
self.assertEqual(codestream.segment[2].length, 3)
self.assertEqual(codestream.segment[2].data, b'\x00')
- @unittest.skipIf(DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
@unittest.skipIf(sys.hexversion < 0x03020000,
"Uses features introduced in 3.2.")
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
@@ -77,7 +113,7 @@ class TestCodestream(unittest.TestCase):
# 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(DATA_ROOT, 'input/conformance/p0_01.j2k')
+ 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.
@@ -100,11 +136,9 @@ class TestCodestream(unittest.TestCase):
self.assertEqual(codestream.segment[2].length, 3)
self.assertEqual(codestream.segment[2].data, b'\x00')
- @unittest.skipIf(DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
def test_psot_is_zero(self):
"""Psot=0 in SOT is perfectly legal. Issue #78."""
- filename = os.path.join(DATA_ROOT,
+ filename = os.path.join(OPJ_DATA_ROOT,
'input/nonregression/123.j2c')
j = Jp2k(filename)
codestream = j.get_codestream(header_only=False)
@@ -114,22 +148,9 @@ class TestCodestream(unittest.TestCase):
self.assertEqual(codestream.segment[-1].marker_id, 'EOC')
- def test_siz_segment_ssiz_unsigned(self):
- """ssiz attribute to be removed in future release"""
- j = Jp2k(self.jp2file)
- codestream = j.get_codestream()
-
- # The ssiz attribute was simply a tuple of raw bytes.
- # The first 7 bits are interpreted as the bitdepth, the MSB determines
- # whether or not it is signed.
- self.assertEqual(codestream.segment[1].ssiz, (7, 7, 7))
-
-
- @unittest.skipIf(DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
def test_siz_segment_ssiz_signed(self):
"""ssiz attribute to be removed in future release"""
- filename = os.path.join(DATA_ROOT, 'input/conformance/p0_03.j2k')
+ filename = os.path.join(OPJ_DATA_ROOT, 'input/conformance/p0_03.j2k')
j = Jp2k(filename)
codestream = j.get_codestream()
diff --git a/glymur/test/test_conformance.py b/glymur/test/test_conformance.py
deleted file mode 100644
index 765f2f6..0000000
--- a/glymur/test/test_conformance.py
+++ /dev/null
@@ -1,148 +0,0 @@
-"""
-These tests deal with JPX/JP2/J2K images in the format-corpus repository.
-"""
-# R0904: Not too many methods in unittest.
-# pylint: disable=R0904
-
-# E1101: assertWarns introduced in python 3.2
-# pylint: disable=E1101
-
-import os
-from os.path import join
-import re
-import sys
-import tempfile
-import unittest
-
-import glymur
-from glymur import Jp2k
-
-try:
- FORMAT_CORPUS_DATA_ROOT = os.environ['FORMAT_CORPUS_DATA_ROOT']
-except KeyError:
- FORMAT_CORPUS_DATA_ROOT = None
-
-try:
- OPJ_DATA_ROOT = os.environ['OPJ_DATA_ROOT']
-except KeyError:
- OPJ_DATA_ROOT = None
-
-
-@unittest.skipIf(sys.hexversion < 0x03020000,
- "Requires features introduced in 3.2 (assertWarns)")
-class TestSuiteConformance(unittest.TestCase):
- """Test suite for conformance."""
-
- def setUp(self):
- self.j2kfile = glymur.data.goodstuff()
-
- def tearDown(self):
- pass
-
- @unittest.skipIf(re.match(r"""1\.[0123]""",
- glymur.version.openjpeg_version) is not None,
- "Needs 1.3+ to catch this.")
- def test_truncated_eoc(self):
- """Has one byte shaved off of EOC marker."""
- with open(self.j2kfile, 'rb') as ifile:
- data = ifile.read()
- with tempfile.NamedTemporaryFile(suffix='.j2k') as ofile:
- ofile.write(data[:-1])
- ofile.flush()
-
- j2k = Jp2k(ofile.name)
- 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):
- j2k.read(rlevel=-1)
-
-
-@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."""
-
- @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):
- j2k.read(rlevel=-1)
-
- def test_balloon_trunc3(self):
- """Most of last tile is missing."""
- jfile = os.path.join(FORMAT_CORPUS_DATA_ROOT,
- 'jp2k-test/byteCorruption/balloon_trunc3.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')
-
- # Should error out, it does not.
- #with self.assertRaises(OSError):
- # j2k.read(rlevel=-1)
-
- def test_jp2_brand_any_icc_profile(self):
- """If 'jp2 ', then the method cannot be any icc profile."""
- jfile = os.path.join(FORMAT_CORPUS_DATA_ROOT,
- 'jp2k-test', 'icc',
- 'balloon_eciRGBv2_ps_adobeplugin.jpf')
- with self.assertWarns(UserWarning):
- Jp2k(jfile)
-
- def test_jp2_brand_iccpr_mult_colr(self):
- """Has colr box, one that conforms, one that does not."""
-
- # Wrong 'brand' field; contains two versions of ICC profile: one
- # embedded using "Any ICC" method; other embedded using "Restricted
- # ICC" method, with description ("Modified eciRGB v2") and profileClass
- # ("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):
- Jp2k(jfile)
-
-
-@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."""
-
- def setUp(self):
- pass
-
- def tearDown(self):
- pass
-
- def test_jp2_brand_any_icc_profile(self):
- """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):
- Jp2k(filename)
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/glymur/test/test_jp2box_xml.py b/glymur/test/test_jp2box_xml.py
index facc4df..2531f0d 100644
--- a/glymur/test/test_jp2box_xml.py
+++ b/glymur/test/test_jp2box_xml.py
@@ -39,6 +39,7 @@ from glymur.jp2box import ColourSpecificationBox, ContiguousCodestreamBox
from glymur.jp2box import FileTypeBox, ImageHeaderBox, JP2HeaderBox
from glymur.jp2box import JPEG2000SignatureBox
+from .fixtures import OPJ_DATA_ROOT, opj_data_file
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
class TestXML(unittest.TestCase):
@@ -286,3 +287,40 @@ class TestBadButRecoverableXmlFile(unittest.TestCase):
b'this is a test')
+@unittest.skipIf(OPJ_DATA_ROOT is None,
+ "OPJ_DATA_ROOT environment variable not set")
+class TestXML_OpjDataRoot(unittest.TestCase):
+ """Test suite for XML boxes, requires OPJ_DATA_ROOT."""
+
+ 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)
+ self.assertIsNotNone(jp2.box[3].xml)
+
+
+ def test_invalid_utf8(self):
+ """Bad byte sequence that cannot be parsed."""
+ 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)
+
+ self.assertIsNone(jp2.box[3].box[1].box[1].xml)
+
+
+
diff --git a/glymur/test/test_jp2k.py b/glymur/test/test_jp2k.py
index dd55299..f6eb691 100644
--- a/glymur/test/test_jp2k.py
+++ b/glymur/test/test_jp2k.py
@@ -37,7 +37,6 @@ if HAS_PYTHON_XMP_TOOLKIT:
from .fixtures import OPJ_DATA_ROOT, opj_data_file
from . import fixtures
-
# Doc tests should be run as well.
def load_tests(loader, tests, ignore):
# W0613: "loader" and "ignore" are necessary for the protocol
@@ -54,9 +53,7 @@ def load_tests(loader, tests, ignore):
class TestJp2k(unittest.TestCase):
- """Test suite for openjpeg software starting at 1.3"""
-
- # These tests should be run by just about all configuration.
+ """These tests should be run by just about all configuration."""
def setUp(self):
self.jp2file = glymur.data.nemo()
@@ -95,6 +92,23 @@ class TestJp2k(unittest.TestCase):
with self.assertRaises(IOError):
Jp2k(filename)
+ def test_no_cxform_pclr_jpx(self):
+ """Indices for pclr jpxfile if no color transform"""
+ j = Jp2k(self.jpxfile)
+ rgb = j.read()
+ idx = j.read(no_cxform=True)
+ self.assertEqual(rgb.shape, (1024, 1024, 3))
+ self.assertEqual(idx.shape, (1024, 1024))
+
+ # Should be able to manually reconstruct the RGB image from the palette
+ # and indices.
+ palette = j.box[3].box[2].palette
+ rgb_from_idx = np.zeros(rgb.shape, dtype=np.uint8)
+ for r in np.arange(1024):
+ for c in np.arange(1024):
+ rgb_from_idx[r, c] = palette[idx[r, c]]
+ np.testing.assert_array_equal(rgb, rgb_from_idx)
+
def test_file_not_present(self):
"""Should error out if reading from a file that does not exist"""
# Verify that we error out appropriately if not given an existing file
@@ -248,19 +262,6 @@ class TestJp2k(unittest.TestCase):
j2k = Jp2k(self.j2kfile)
j2k.read()
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- 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
- # on an image with differing subsamples
- #
- # Issue 86.
- filename = opj_data_file('input/conformance/p0_05.j2k')
- j = Jp2k(filename)
- with self.assertRaises(RuntimeError):
- j.read()
-
def test_empty_box_with_j2k(self):
"""Verify that the list of boxes in a J2C/J2K file is present, but
empty.
@@ -386,15 +387,9 @@ class TestJp2k(unittest.TestCase):
# The file in question has multiple codestreams.
jpx = Jp2k(self.jpxfile)
data = jpx.read()
- if re.match(r"""1\.[0123]""", glymur.version.openjpeg_version):
- # openjpeg 1.3 doesn't apply the palette, so it's a 2D image here
- self.assertEqual(data.shape, (1024, 1024))
- else:
- self.assertEqual(data.shape, (1024, 1024, 3))
+ self.assertEqual(data.shape, (1024, 1024, 3))
-@unittest.skipIf(re.match(r"""1\.[01234]""", glymur.version.openjpeg_version),
- "Requires at least version 1.5")
class TestJp2k_write(unittest.TestCase):
"""Write tests, can be run by versions 1.5+"""
@@ -758,6 +753,67 @@ class TestJp2k_2_1(unittest.TestCase):
with self.assertRaisesRegex((IOError, OSError), regexp):
j.read(rlevel=1)
+@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."""
+
+ def test_no_cxform_pclr_jp2(self):
+ """Indices for pclr jpxfile if no color transform"""
+ filename = opj_data_file('input/conformance/file9.jp2')
+ j = Jp2k(filename)
+ rgb = j.read()
+ idx = j.read(no_cxform=True)
+ self.assertEqual(rgb.shape, (512, 768, 3))
+ self.assertEqual(idx.shape, (512, 768))
+
+ # Should be able to manually reconstruct the RGB image from the palette
+ # and indices.
+ palette = j.box[2].box[1].palette
+ rgb_from_idx = np.zeros(rgb.shape, dtype=np.uint8)
+ for r in np.arange(rgb.shape[0]):
+ for c in np.arange(rgb.shape[1]):
+ 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
+ # on an image with differing subsamples
+ #
+ # Issue 86.
+ filename = opj_data_file('input/conformance/p0_05.j2k')
+ j = Jp2k(filename)
+ with self.assertRaises(RuntimeError):
+ j.read()
+
+ def test_no_cxform_cmap(self):
+ """Bands as physically ordered, not as physically intended"""
+ # This file has the components physically reversed. The cmap box
+ # tells the decoder how to order them, but this flag prevents that.
+ filename = opj_data_file('input/conformance/file2.jp2')
+ j = Jp2k(filename)
+ ycbcr = j.read()
+ crcby = j.read(no_cxform=True)
+
+ expected = np.zeros(ycbcr.shape, ycbcr.dtype)
+ for k in range(crcby.shape[2]):
+ expected[:,:,crcby.shape[2] - k - 1] = crcby[:,:,k]
+
+ np.testing.assert_array_equal(ycbcr, expected)
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/glymur/test/test_opj_suite.py b/glymur/test/test_opj_suite.py
index be85de9..5cc9250 100644
--- a/glymur/test/test_opj_suite.py
+++ b/glymur/test/test_opj_suite.py
@@ -381,11 +381,7 @@ class TestSuite(unittest.TestCase):
jfile = opj_data_file('input/conformance/file9.jp2')
jp2k = Jp2k(jfile)
jpdata = jp2k.read()
- if re.match(r"""1\.3""", glymur.version.openjpeg_version):
- # Version 1.3 reads the indexed image as indices, not as RGB.
- self.assertEqual(jpdata.shape, (512, 768))
- else:
- self.assertEqual(jpdata.shape, (512, 768, 3))
+ self.assertEqual(jpdata.shape, (512, 768, 3))
def test_NR_DEC_Bretagne2_j2k_1_decode(self):
jfile = opj_data_file('input/nonregression/Bretagne2.j2k')
@@ -6307,11 +6303,16 @@ class TestSuiteDump(unittest.TestCase):
[8, 9, 9, 10, 9, 9, 10, 9, 9, 10, 9, 9, 10, 9, 9, 10])
def test_NR_text_GBR_dump(self):
+ # brand is 'jp2 ', but has any icc profile.
+ # Verify the warning on python3, but ignore it otherwise.
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)
+ if sys.hexversion > 0x03030000:
+ with self.assertWarns(UserWarning):
+ jp2 = Jp2k(jfile)
+ else:
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ jp2 = Jp2k(jfile)
ids = [box.box_id for box in jp2.box]
lst = ['jP ', 'ftyp', 'rreq', 'jp2h',
diff --git a/glymur/test/test_opj_suite_neg.py b/glymur/test/test_opj_suite_neg.py
index d31ea48..c9a7e8c 100644
--- a/glymur/test/test_opj_suite_neg.py
+++ b/glymur/test/test_opj_suite_neg.py
@@ -23,33 +23,6 @@ from glymur import Jp2k
import glymur
-@unittest.skipIf(re.match(r"""1\.[01234]""", glymur.version.openjpeg_version),
- "Functionality not implemented for 1.3, 1.4")
-@unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_OPJ_DATA_ROOT environment variable not set")
-class TestSuiteNegative2pointzero(unittest.TestCase):
- """Feature set not supported for versions less than 2.0"""
-
- def setUp(self):
- self.jp2file = glymur.data.nemo()
- self.j2kfile = glymur.data.goodstuff()
-
- def tearDown(self):
- pass
-
- @unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
- def test_cinema_mode(self):
- """Cinema mode not supported for less than 2.0.1."""
- infile = opj_data_file('input/nonregression/Bretagne1.ppm')
- data = read_image(infile)
- with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
- j = Jp2k(tfile.name, 'wb')
- with self.assertRaises(IOError):
- j.write(data, psnr=[30, 35, 40], cratios=[2, 3, 4])
-
-
-@unittest.skipIf(re.match(r"""1\.[01234]""", glymur.version.openjpeg_version),
- "Functionality not implemented for 1.3, 1.4")
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_OPJ_DATA_ROOT environment variable not set")
class TestSuiteNegative(unittest.TestCase):
diff --git a/glymur/test/test_opj_suite_write.py b/glymur/test/test_opj_suite_write.py
index 220115c..91afd8d 100644
--- a/glymur/test/test_opj_suite_write.py
+++ b/glymur/test/test_opj_suite_write.py
@@ -223,8 +223,10 @@ class TestSuiteWriteCinema(unittest.TestCase):
self.check_cinema2k_codestream(codestream, (1998, 1080))
+@unittest.skipIf(not _HAS_SKIMAGE_FREEIMAGE_SUPPORT,
+ "Cannot read input image without scikit-image/freeimage")
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
-@unittest.skipIf(re.match(r"""2\.0""", glymur.version.openjpeg_version),
+@unittest.skipIf(not re.match("(1.5|2.0)", glymur.version.openjpeg_version),
"Functionality implemented for 2.1")
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_OPJ_DATA_ROOT environment variable not set")
@@ -249,9 +251,6 @@ class TestSuiteNegative2pointzero(unittest.TestCase):
@unittest.skipIf(os.name == "nt", "no write support on windows, period")
-@unittest.skipIf(re.match(r"""1\.[01234]\.\d""",
- glymur.version.openjpeg_version) is not None,
- "Writing only supported with openjpeg version 1.5+.")
@unittest.skipIf(NO_READ_BACKEND, NO_READ_BACKEND_MSG)
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
diff --git a/glymur/test/test_printing.py b/glymur/test/test_printing.py
index 0deaebd..fe09583 100644
--- a/glymur/test/test_printing.py
+++ b/glymur/test/test_printing.py
@@ -289,69 +289,6 @@ class TestPrinting(unittest.TestCase):
expected = '\n'.join(lines)
self.assertEqual(actual, expected)
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_crg(self):
- """verify printing of CRG segment"""
- filename = opj_data_file('input/conformance/p0_03.j2k')
- j = glymur.Jp2k(filename)
- codestream = j.get_codestream()
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(codestream.segment[-5])
- actual = fake_out.getvalue().strip()
- lines = ['CRG marker segment @ (87, 6)',
- ' Vertical, Horizontal offset: (0.50, 1.00)']
- expected = '\n'.join(lines)
- self.assertEqual(actual, expected)
-
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_rgn(self):
- """verify printing of RGN segment"""
- filename = opj_data_file('input/conformance/p0_03.j2k')
- j = glymur.Jp2k(filename)
- codestream = j.get_codestream(header_only=False)
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(codestream.segment[12])
- actual = fake_out.getvalue().strip()
- lines = ['RGN marker segment @ (310, 5)',
- ' Associated component: 0',
- ' ROI style: 0',
- ' Parameter: 7']
- expected = '\n'.join(lines)
- self.assertEqual(actual, expected)
-
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_sop(self):
- """verify printing of SOP segment"""
- filename = opj_data_file('input/conformance/p0_03.j2k')
- j = glymur.Jp2k(filename)
- codestream = j.get_codestream(header_only=False)
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(codestream.segment[-2])
- actual = fake_out.getvalue().strip()
- lines = ['SOP marker segment @ (12836, 4)',
- ' Nsop: 15']
- expected = '\n'.join(lines)
- self.assertEqual(actual, expected)
-
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_cme(self):
- """Test printing a CME or comment marker segment."""
- filename = opj_data_file('input/conformance/p0_02.j2k')
- j = glymur.Jp2k(filename)
- codestream = j.get_codestream()
- # 2nd to last segment in the main header
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(codestream.segment[-2])
- actual = fake_out.getvalue().strip()
- lines = ['CME marker segment @ (85, 45)',
- ' "Creator: AV-J2K (c) 2000,2001 Algo Vision"']
- expected = '\n'.join(lines)
- self.assertEqual(actual, expected)
-
def test_eoc_segment(self):
"""verify printing of eoc segment"""
j = glymur.Jp2k(self.jp2file)
@@ -364,91 +301,6 @@ class TestPrinting(unittest.TestCase):
expected = '\n'.join(lines)
self.assertEqual(actual, expected)
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_plt_segment(self):
- """verify printing of PLT segment"""
- filename = opj_data_file('input/conformance/p0_07.j2k')
- j = glymur.Jp2k(filename)
- codestream = j.get_codestream(header_only=False)
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(codestream.segment[49935])
- actual = fake_out.getvalue().strip()
-
- lines = ['PLT marker segment @ (7871146, 38)',
- ' Index: 0',
- ' Iplt: [9, 122, 19, 30, 27, 9, 41, 62, 18, 29, 261,'
- + ' 55, 82, 299, 93, 941, 951, 687, 1729, 1443, 1008, 2168,'
- + ' 2188, 2223]']
- expected = '\n'.join(lines)
- self.assertEqual(actual, expected)
-
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_pod_segment(self):
- """verify printing of POD segment"""
- filename = opj_data_file('input/conformance/p0_13.j2k')
- j = glymur.Jp2k(filename)
- codestream = j.get_codestream()
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(codestream.segment[8])
- actual = fake_out.getvalue().strip()
-
- lines = ['POD marker segment @ (878, 20)',
- ' Progression change 0:',
- ' Resolution index start: 0',
- ' Component index start: 0',
- ' Layer index end: 1',
- ' Resolution index end: 33',
- ' Component index end: 128',
- ' Progression order: RLCP',
- ' Progression change 1:',
- ' Resolution index start: 0',
- ' Component index start: 128',
- ' Layer index end: 1',
- ' Resolution index end: 33',
- ' Component index end: 257',
- ' Progression order: CPRL']
-
- expected = '\n'.join(lines)
- self.assertEqual(actual, expected)
-
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_ppm_segment(self):
- """verify printing of PPM segment"""
- filename = opj_data_file('input/conformance/p1_03.j2k')
- j = glymur.Jp2k(filename)
- codestream = j.get_codestream()
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(codestream.segment[9])
- actual = fake_out.getvalue().strip()
-
- lines = ['PPM marker segment @ (213, 43712)',
- ' Index: 0',
- ' Data: 43709 uninterpreted bytes']
-
- expected = '\n'.join(lines)
- self.assertEqual(actual, expected)
-
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_ppt_segment(self):
- """verify printing of ppt segment"""
- filename = opj_data_file('input/conformance/p1_06.j2k')
- j = glymur.Jp2k(filename)
- codestream = j.get_codestream(header_only=False)
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(codestream.segment[6])
- actual = fake_out.getvalue().strip()
-
- lines = ['PPT marker segment @ (155, 109)',
- ' Index: 0',
- ' Packet headers: 106 uninterpreted bytes']
-
- expected = '\n'.join(lines)
- self.assertEqual(actual, expected)
-
def test_qcc_segment(self):
"""verify printing of qcc segment"""
j = glymur.Jp2k(self.jp2file)
@@ -543,25 +395,6 @@ class TestPrinting(unittest.TestCase):
expected = '\n'.join(lines)
self.assertEqual(actual, expected)
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_tlm_segment(self):
- """verify printing of TLM segment"""
- filename = opj_data_file('input/conformance/p0_15.j2k')
- j = glymur.Jp2k(filename)
- codestream = j.get_codestream()
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(codestream.segment[10])
- actual = fake_out.getvalue().strip()
-
- lines = ['TLM marker segment @ (268, 28)',
- ' Index: 0',
- ' Tile number: (0, 1, 2, 3)',
- ' Length: (4267, 2117, 4080, 2081)']
-
- expected = '\n'.join(lines)
- self.assertEqual(actual, expected)
-
def test_xmp(self):
"""Verify the printing of a UUID/XMP box."""
j = glymur.Jp2k(self.jp2file)
@@ -621,17 +454,6 @@ class TestPrinting(unittest.TestCase):
expected = '\n'.join(lst)
self.assertEqual(actual, expected)
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_xml(self):
- """verify printing of XML box"""
- filename = opj_data_file('input/conformance/file1.jp2')
- j = glymur.Jp2k(filename)
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(j.box[2])
- actual = fake_out.getvalue().strip()
- self.assertEqual(actual, fixtures.file1_xml)
-
@unittest.skipIf(sys.hexversion < 0x03000000,
"Only trusting python3 for printing non-ascii chars")
def test_xml_latin1(self):
@@ -689,101 +511,6 @@ class TestPrinting(unittest.TestCase):
expected = '\n'.join(lines)
self.assertEqual(actual, expected)
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_channel_definition(self):
- """verify printing of cdef box"""
- filename = opj_data_file('input/conformance/file2.jp2')
- j = glymur.Jp2k(filename)
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(j.box[2].box[2])
- actual = fake_out.getvalue().strip()
- lines = ['Channel Definition Box (cdef) @ (81, 28)',
- ' Channel 0 (color) ==> (3)',
- ' Channel 1 (color) ==> (2)',
- ' Channel 2 (color) ==> (1)']
- expected = '\n'.join(lines)
- self.assertEqual(actual, expected)
-
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_component_mapping(self):
- """verify printing of cmap box"""
- filename = opj_data_file('input/conformance/file9.jp2')
- j = glymur.Jp2k(filename)
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(j.box[2].box[2])
- actual = fake_out.getvalue().strip()
- lines = ['Component Mapping Box (cmap) @ (848, 20)',
- ' Component 0 ==> palette column 0',
- ' Component 0 ==> palette column 1',
- ' Component 0 ==> palette column 2']
- expected = '\n'.join(lines)
- self.assertEqual(actual, expected)
-
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_palette7(self):
- """verify printing of pclr box"""
- filename = opj_data_file('input/conformance/file9.jp2')
- j = glymur.Jp2k(filename)
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(j.box[2].box[1])
- actual = fake_out.getvalue().strip()
- lines = ['Palette Box (pclr) @ (66, 782)',
- ' Size: (256 x 3)']
- expected = '\n'.join(lines)
- self.assertEqual(actual, expected)
-
- @unittest.skip("file7 no longer has a rreq")
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_rreq(self):
- """verify printing of reader requirements box"""
- filename = opj_data_file('input/nonregression/text_GBR.jp2')
- j = glymur.Jp2k(filename)
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(j.box[2])
- actual = fake_out.getvalue().strip()
- self.assertEqual(actual, fixtures.text_GBR_rreq)
-
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_differing_subsamples(self):
- """verify printing of SIZ with different subsampling... Issue 86."""
- filename = opj_data_file('input/conformance/p0_05.j2k')
- j = glymur.Jp2k(filename)
- codestream = j.get_codestream()
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(codestream.segment[1])
- actual = fake_out.getvalue().strip()
- lines = ['SIZ marker segment @ (2, 50)',
- ' Profile: 0',
- ' Reference Grid Height, Width: (1024 x 1024)',
- ' Vertical, Horizontal Reference Grid Offset: (0 x 0)',
- ' Reference Tile Height, Width: (1024 x 1024)',
- ' Vertical, Horizontal Reference Tile Offset: (0 x 0)',
- ' Bitdepth: (8, 8, 8, 8)',
- ' Signed: (False, False, False, False)',
- ' Vertical, Horizontal Subsampling: '
- + '((1, 1), (1, 1), (2, 2), (2, 2))']
- expected = '\n'.join(lines)
- self.assertEqual(actual, expected)
-
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_palette_box(self):
- """Verify that palette (pclr) boxes are printed without error."""
- filename = opj_data_file('input/conformance/file9.jp2')
- j = glymur.Jp2k(filename)
- with patch('sys.stdout', new=StringIO()) as fake_out:
- print(j.box[2].box[1])
- actual = fake_out.getvalue().strip()
- lines = ['Palette Box (pclr) @ (66, 782)',
- ' Size: (256 x 3)']
- expected = '\n'.join(lines)
- self.assertEqual(actual, expected)
-
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_less_common_boxes(self):
"""verify uinf, ulst, url, res, resd, resc box printing"""
@@ -861,50 +588,6 @@ class TestPrinting(unittest.TestCase):
expected = '\n'.join(lines)
self.assertEqual(actual, expected)
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_icc_profile(self):
- """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()
- if sys.hexversion < 0x03000000:
- expected = text_gbr_27
- elif sys.hexversion < 0x03040000:
- expected = text_gbr_33
- else:
- expected = text_gbr_34
-
- self.assertEqual(actual, expected)
-
- @unittest.skipIf(OPJ_DATA_ROOT is None,
- "OPJ_DATA_ROOT environment variable not set")
- def test_uuid(self):
- """verify printing of UUID box"""
- 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[4])
- actual = fake_out.getvalue().strip()
- lines = ['UUID Box (uuid) @ (1544, 25)',
- ' UUID: 3a0d0218-0ae9-4115-b376-4bca41ce0e71 (unknown)',
- ' UUID Data: 1 bytes']
-
- expected = '\n'.join(lines)
- self.assertEqual(actual, expected)
-
@unittest.skipIf(sys.hexversion < 0x03000000,
"Ordered dicts not printing well in 2.7")
def test_exif_uuid(self):
@@ -946,5 +629,355 @@ class TestPrinting(unittest.TestCase):
self.assertEqual(actual, expected)
+@unittest.skipIf(OPJ_DATA_ROOT is None,
+ "OPJ_DATA_ROOT environment variable not set")
+@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
+class TestPrintingOpjDataRoot(unittest.TestCase):
+ """Tests for verifying printing. restricted to OPJ_DATA_ROOT files."""
+ def setUp(self):
+ self.jpxfile = glymur.data.jpxfile()
+ self.jp2file = glymur.data.nemo()
+ self.j2kfile = glymur.data.goodstuff()
+
+ # Reset printoptions for every test.
+ glymur.set_printoptions(short=False, xml=True, codestream=True)
+
+ def tearDown(self):
+ pass
+
+ def test_invalid_progression_order(self):
+ """Should still be able to print even if prog order is invalid."""
+ jfile = opj_data_file('input/nonregression/2977.pdf.asan.67.2198.jp2')
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ jp2 = Jp2k(jfile)
+ codestream = jp2.get_codestream()
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(codestream.segment[2])
+ actual = fake_out.getvalue().strip()
+ self.assertEqual(actual, fixtures.issue_186_progression_order)
+
+ def test_crg(self):
+ """verify printing of CRG segment"""
+ filename = opj_data_file('input/conformance/p0_03.j2k')
+ j = glymur.Jp2k(filename)
+ codestream = j.get_codestream()
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(codestream.segment[-5])
+ actual = fake_out.getvalue().strip()
+ lines = ['CRG marker segment @ (87, 6)',
+ ' Vertical, Horizontal offset: (0.50, 1.00)']
+ expected = '\n'.join(lines)
+ self.assertEqual(actual, expected)
+
+ def test_rgn(self):
+ """verify printing of RGN segment"""
+ filename = opj_data_file('input/conformance/p0_03.j2k')
+ j = glymur.Jp2k(filename)
+ codestream = j.get_codestream(header_only=False)
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(codestream.segment[12])
+ actual = fake_out.getvalue().strip()
+ lines = ['RGN marker segment @ (310, 5)',
+ ' Associated component: 0',
+ ' ROI style: 0',
+ ' Parameter: 7']
+ expected = '\n'.join(lines)
+ self.assertEqual(actual, expected)
+
+ def test_sop(self):
+ """verify printing of SOP segment"""
+ filename = opj_data_file('input/conformance/p0_03.j2k')
+ j = glymur.Jp2k(filename)
+ codestream = j.get_codestream(header_only=False)
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(codestream.segment[-2])
+ actual = fake_out.getvalue().strip()
+ lines = ['SOP marker segment @ (12836, 4)',
+ ' Nsop: 15']
+ expected = '\n'.join(lines)
+ self.assertEqual(actual, expected)
+
+ def test_cme(self):
+ """Test printing a CME or comment marker segment."""
+ filename = opj_data_file('input/conformance/p0_02.j2k')
+ j = glymur.Jp2k(filename)
+ codestream = j.get_codestream()
+ # 2nd to last segment in the main header
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(codestream.segment[-2])
+ actual = fake_out.getvalue().strip()
+ lines = ['CME marker segment @ (85, 45)',
+ ' "Creator: AV-J2K (c) 2000,2001 Algo Vision"']
+ expected = '\n'.join(lines)
+ self.assertEqual(actual, expected)
+
+ def test_plt_segment(self):
+ """verify printing of PLT segment"""
+ filename = opj_data_file('input/conformance/p0_07.j2k')
+ j = glymur.Jp2k(filename)
+ codestream = j.get_codestream(header_only=False)
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(codestream.segment[49935])
+ actual = fake_out.getvalue().strip()
+
+ lines = ['PLT marker segment @ (7871146, 38)',
+ ' Index: 0',
+ ' Iplt: [9, 122, 19, 30, 27, 9, 41, 62, 18, 29, 261,'
+ + ' 55, 82, 299, 93, 941, 951, 687, 1729, 1443, 1008, 2168,'
+ + ' 2188, 2223]']
+ expected = '\n'.join(lines)
+ self.assertEqual(actual, expected)
+
+ def test_pod_segment(self):
+ """verify printing of POD segment"""
+ filename = opj_data_file('input/conformance/p0_13.j2k')
+ j = glymur.Jp2k(filename)
+ codestream = j.get_codestream()
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(codestream.segment[8])
+ actual = fake_out.getvalue().strip()
+
+ lines = ['POD marker segment @ (878, 20)',
+ ' Progression change 0:',
+ ' Resolution index start: 0',
+ ' Component index start: 0',
+ ' Layer index end: 1',
+ ' Resolution index end: 33',
+ ' Component index end: 128',
+ ' Progression order: RLCP',
+ ' Progression change 1:',
+ ' Resolution index start: 0',
+ ' Component index start: 128',
+ ' Layer index end: 1',
+ ' Resolution index end: 33',
+ ' Component index end: 257',
+ ' Progression order: CPRL']
+
+ expected = '\n'.join(lines)
+ self.assertEqual(actual, expected)
+
+ def test_ppm_segment(self):
+ """verify printing of PPM segment"""
+ filename = opj_data_file('input/conformance/p1_03.j2k')
+ j = glymur.Jp2k(filename)
+ codestream = j.get_codestream()
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(codestream.segment[9])
+ actual = fake_out.getvalue().strip()
+
+ lines = ['PPM marker segment @ (213, 43712)',
+ ' Index: 0',
+ ' Data: 43709 uninterpreted bytes']
+
+ expected = '\n'.join(lines)
+ self.assertEqual(actual, expected)
+
+ def test_ppt_segment(self):
+ """verify printing of ppt segment"""
+ filename = opj_data_file('input/conformance/p1_06.j2k')
+ j = glymur.Jp2k(filename)
+ codestream = j.get_codestream(header_only=False)
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(codestream.segment[6])
+ actual = fake_out.getvalue().strip()
+
+ lines = ['PPT marker segment @ (155, 109)',
+ ' Index: 0',
+ ' Packet headers: 106 uninterpreted bytes']
+
+ expected = '\n'.join(lines)
+ self.assertEqual(actual, expected)
+
+ def test_tlm_segment(self):
+ """verify printing of TLM segment"""
+ filename = opj_data_file('input/conformance/p0_15.j2k')
+ j = glymur.Jp2k(filename)
+ codestream = j.get_codestream()
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(codestream.segment[10])
+ actual = fake_out.getvalue().strip()
+
+ lines = ['TLM marker segment @ (268, 28)',
+ ' Index: 0',
+ ' Tile number: (0, 1, 2, 3)',
+ ' Length: (4267, 2117, 4080, 2081)']
+
+ expected = '\n'.join(lines)
+ self.assertEqual(actual, expected)
+
+ def test_xml(self):
+ """verify printing of XML box"""
+ filename = opj_data_file('input/conformance/file1.jp2')
+ j = glymur.Jp2k(filename)
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(j.box[2])
+ actual = fake_out.getvalue().strip()
+ self.assertEqual(actual, fixtures.file1_xml)
+
+ def test_channel_definition(self):
+ """verify printing of cdef box"""
+ filename = opj_data_file('input/conformance/file2.jp2')
+ j = glymur.Jp2k(filename)
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(j.box[2].box[2])
+ actual = fake_out.getvalue().strip()
+ lines = ['Channel Definition Box (cdef) @ (81, 28)',
+ ' Channel 0 (color) ==> (3)',
+ ' Channel 1 (color) ==> (2)',
+ ' Channel 2 (color) ==> (1)']
+ expected = '\n'.join(lines)
+ self.assertEqual(actual, expected)
+
+ def test_component_mapping(self):
+ """verify printing of cmap box"""
+ filename = opj_data_file('input/conformance/file9.jp2')
+ j = glymur.Jp2k(filename)
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(j.box[2].box[2])
+ actual = fake_out.getvalue().strip()
+ lines = ['Component Mapping Box (cmap) @ (848, 20)',
+ ' Component 0 ==> palette column 0',
+ ' Component 0 ==> palette column 1',
+ ' Component 0 ==> palette column 2']
+ expected = '\n'.join(lines)
+ self.assertEqual(actual, expected)
+
+ def test_palette7(self):
+ """verify printing of pclr box"""
+ filename = opj_data_file('input/conformance/file9.jp2')
+ j = glymur.Jp2k(filename)
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(j.box[2].box[1])
+ actual = fake_out.getvalue().strip()
+ lines = ['Palette Box (pclr) @ (66, 782)',
+ ' Size: (256 x 3)']
+ expected = '\n'.join(lines)
+ self.assertEqual(actual, expected)
+
+ @unittest.skip("file7 no longer has a rreq")
+ def test_rreq(self):
+ """verify printing of reader requirements box"""
+ filename = opj_data_file('input/nonregression/text_GBR.jp2')
+ j = glymur.Jp2k(filename)
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(j.box[2])
+ actual = fake_out.getvalue().strip()
+ self.assertEqual(actual, fixtures.text_GBR_rreq)
+
+ def test_differing_subsamples(self):
+ """verify printing of SIZ with different subsampling... Issue 86."""
+ filename = opj_data_file('input/conformance/p0_05.j2k')
+ j = glymur.Jp2k(filename)
+ codestream = j.get_codestream()
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(codestream.segment[1])
+ actual = fake_out.getvalue().strip()
+ lines = ['SIZ marker segment @ (2, 50)',
+ ' Profile: 0',
+ ' Reference Grid Height, Width: (1024 x 1024)',
+ ' Vertical, Horizontal Reference Grid Offset: (0 x 0)',
+ ' Reference Tile Height, Width: (1024 x 1024)',
+ ' Vertical, Horizontal Reference Tile Offset: (0 x 0)',
+ ' Bitdepth: (8, 8, 8, 8)',
+ ' Signed: (False, False, False, False)',
+ ' Vertical, Horizontal Subsampling: '
+ + '((1, 1), (1, 1), (2, 2), (2, 2))']
+ expected = '\n'.join(lines)
+ self.assertEqual(actual, expected)
+
+ def test_palette_box(self):
+ """Verify that palette (pclr) boxes are printed without error."""
+ filename = opj_data_file('input/conformance/file9.jp2')
+ j = glymur.Jp2k(filename)
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(j.box[2].box[1])
+ actual = fake_out.getvalue().strip()
+ lines = ['Palette Box (pclr) @ (66, 782)',
+ ' Size: (256 x 3)']
+ expected = '\n'.join(lines)
+ self.assertEqual(actual, expected)
+
+ def test_icc_profile(self):
+ """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()
+ if sys.hexversion < 0x03000000:
+ expected = text_gbr_27
+ elif sys.hexversion < 0x03040000:
+ expected = text_gbr_33
+ else:
+ expected = text_gbr_34
+
+ self.assertEqual(actual, expected)
+
+ def test_uuid(self):
+ """verify printing of UUID box"""
+ 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[4])
+ actual = fake_out.getvalue().strip()
+ lines = ['UUID Box (uuid) @ (1544, 25)',
+ ' UUID: 3a0d0218-0ae9-4115-b376-4bca41ce0e71 (unknown)',
+ ' UUID Data: 1 bytes']
+
+ expected = '\n'.join(lines)
+ self.assertEqual(actual, expected)
+
+ def test_issue182(self):
+ """Should not show the format string in output."""
+ # The cmap box is wildly broken, but printing was still wrong.
+ # Format strings like %d were showing up in the output.
+ filename = opj_data_file('input/nonregression/mem-b2ace68c-1381.jp2')
+
+ with warnings.catch_warnings():
+ # Ignore warning about bad pclr box.
+ warnings.simplefilter("ignore")
+ jp2 = Jp2k(filename)
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(jp2.box[3].box[3])
+ actual = fake_out.getvalue().strip()
+ self.assertEqual(actual, fixtures.issue_182_cmap)
+
+ def test_issue183(self):
+ filename = opj_data_file('input/nonregression/orb-blue10-lin-jp2.jp2')
+
+ with warnings.catch_warnings():
+ # Ignore warning about bad pclr box.
+ warnings.simplefilter("ignore")
+ jp2 = Jp2k(filename)
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ print(jp2.box[2].box[1])
+ actual = fake_out.getvalue().strip()
+ self.assertEqual(actual, fixtures.issue_183_colr)
+
+ 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'))
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ jp2 = Jp2k(filename)
+ with patch('sys.stdout', new=StringIO()) as fake_out:
+ # No need to verify, it's enough that we don't error out.
+ print(jp2)
+
+ self.assertTrue(True)
+
if __name__ == "__main__":
unittest.main()