From 11eed0f513b707ee940751132584f6b183496592 Mon Sep 17 00:00:00 2001 From: jevans Date: Mon, 22 Jul 2013 17:49:50 -0400 Subject: [PATCH 01/12] Prepping for 0.2.5 release. --- CHANGES.txt | 3 +++ docs/source/conf.py | 2 +- setup.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index f80b04b..410f243 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,6 @@ +Jul 23, 2013 - v0.2.5 Fixed inconsistency in XML handling, now all instances + are always ElementTree objects (issue82). + Jul 21, 2013 - v0.2.4 Fixed markdown bug for Fedora 17 information, fixed out-of-date windows information (issue79). Fixed incorrect interpretation of Psot parameter (issue78). diff --git a/docs/source/conf.py b/docs/source/conf.py index bd59b1b..d9f833e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -78,7 +78,7 @@ copyright = u'2013, John Evans' # The short X.Y version. version = '0.1' # The full version, including alpha/beta/rc tags. -release = '0.2.4' +release = '0.2.5' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 95e778b..4f33418 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages import sys kwargs = {'name': 'Glymur', - 'version': '0.2.4', + 'version': '0.2.5rc1', 'description': 'Tools for accessing JPEG2000 files', 'long_description': open('README.md').read(), 'author': 'John Evans', From e75cdcf68665c1a1ef47220ba32205241e2ff38b Mon Sep 17 00:00:00 2001 From: jevans Date: Mon, 22 Jul 2013 18:00:44 -0400 Subject: [PATCH 02/12] The XMP uuid data is an ElementTree instance, not an Element instance. --- docs/source/how_do_i.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/source/how_do_i.rst b/docs/source/how_do_i.rst index 8abb693..9ffaee5 100644 --- a/docs/source/how_do_i.rst +++ b/docs/source/how_do_i.rst @@ -185,9 +185,8 @@ Work with XMP UUIDs? ==================== The example JP2 file shipped with glymur has an XMP UUID. :: - >>> from glymur import Jp2k - >>> file = glymur.data.nemo() - >>> j = Jp2k(file) + >>> import glymur + >>> j = glymur.Jp2k(glymur.data.nemo()) >>> print(j.box[4]) UUID Box (uuid) @ (715, 2412) UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP) @@ -198,7 +197,7 @@ The example JP2 file shipped with glymur has an XMP UUID. :: -Since the UUID data in this case is returned as an ElementTree Element, one can +Since the UUID data in this case is returned as an ElementTree instance, one can use ElementTree to access the data. For example, to extract the **CreatorTool** attribute value, the following would work:: From 49634552986dc25c4c731ed00cad88fb4ff7741f Mon Sep 17 00:00:00 2001 From: jevans Date: Mon, 22 Jul 2013 18:07:17 -0400 Subject: [PATCH 03/12] Finalizing 0.2.5 version info. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4f33418..8d88a3a 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages import sys kwargs = {'name': 'Glymur', - 'version': '0.2.5rc1', + 'version': '0.2.5', 'description': 'Tools for accessing JPEG2000 files', 'long_description': open('README.md').read(), 'author': 'John Evans', From 83f17b218114c637eefec1c51a1ac55bc7b62f8a Mon Sep 17 00:00:00 2001 From: jevans Date: Mon, 22 Jul 2013 19:03:59 -0400 Subject: [PATCH 04/12] Checking for the codestream markers to always occupy two bytes. --- docs/source/detailed_installation.rst | 13 +++++-- glymur/codestream.py | 9 ++++- glymur/test/test_format_corpus.py | 51 +++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 glymur/test/test_format_corpus.py diff --git a/docs/source/detailed_installation.rst b/docs/source/detailed_installation.rst index 06c6b79..b737843 100644 --- a/docs/source/detailed_installation.rst +++ b/docs/source/detailed_installation.rst @@ -137,8 +137,17 @@ platforms. Testing ''''''' -If you wish to run the tests (strongly recommended :-), you can either run them -from within python as follows ... :: +There are two environment variables you may wish to set before running the +tests. + + * **OPJ_DATA_ROOT** - points to directory for OpenJPEG test data + * **FORMAT_CORPUS_ROOT** - points to directory for format-corpus repository (see https://github.com/openplanets/format-corpus) + +Setting these two environment variables is not required, as any tests using +either of them will be skipped. + +In order to run the tests, you can either run them from within +python as follows ... :: >>> import glymur >>> glymur.runtests() diff --git a/glymur/codestream.py b/glymur/codestream.py index df1575c..c4d8b4b 100644 --- a/glymur/codestream.py +++ b/glymur/codestream.py @@ -102,7 +102,14 @@ class Codestream(object): while True: read_buffer = fptr.read(2) - marker_id, = struct.unpack('>H', read_buffer) + try: + marker_id, = struct.unpack('>H', read_buffer) + except struct.error: + # Treat this as a warning. + msg = "Marker had length {0} instead of expected length of 2 " + msg += "bytes. Codestream parsing terminated." + warnings.warn(msg.format(len(read_buffer))) + break if marker_id == 0xff90 and header_only: # Start-of-tile (SOT) means that we are out of the main header diff --git a/glymur/test/test_format_corpus.py b/glymur/test/test_format_corpus.py new file mode 100644 index 0000000..2f7347b --- /dev/null +++ b/glymur/test/test_format_corpus.py @@ -0,0 +1,51 @@ +""" +These tests deal with JPX/JP2/J2K images in the format-corpus repository. +""" +#pylint: disable-all + +import os +import sys + +if sys.hexversion < 0x02070000: + import unittest2 as unittest +else: + import unittest + +import warnings + +from glymur import Jp2k +import glymur + +try: + data_root = os.environ['FORMAT_CORPUS_ROOT'] +except KeyError: + data_root = None +except: + raise + + +@unittest.skipIf(sys.hexversion < 0x03020000, + "Requires features introduced in 3.2 (assertWarns)") +@unittest.skipIf(data_root is None, + "FORMAT_CORPUS_ROOT environment variable not set") +class TestSuite(unittest.TestCase): + + def setUp(self): + pass + + def tearDown(self): + pass + + def test_balloon_trunc1(self): + # Has one byte shaved off of EOC marker. + jfile = os.path.join(data_root, + 'jp2k-test/byteCorruption/balloon_trunc1.jp2') + j2k = Jp2k(jfile) + with self.assertWarns(UserWarning): + c = j2k.get_codestream(header_only=False) + + # The last segment is truncated, so there should not be an EOC marker. + self.assertNotEqual(c.segment[-1].marker_id, 'EOC') + +if __name__ == "__main__": + unittest.main() From 15cd084df132aef5245066d80105f950043cbd5a Mon Sep 17 00:00:00 2001 From: jevans Date: Mon, 22 Jul 2013 19:03:59 -0400 Subject: [PATCH 05/12] Checking for the codestream markers to always occupy two bytes. #77 --- docs/source/detailed_installation.rst | 13 +++++-- glymur/codestream.py | 9 ++++- glymur/test/test_format_corpus.py | 51 +++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 glymur/test/test_format_corpus.py diff --git a/docs/source/detailed_installation.rst b/docs/source/detailed_installation.rst index 06c6b79..b737843 100644 --- a/docs/source/detailed_installation.rst +++ b/docs/source/detailed_installation.rst @@ -137,8 +137,17 @@ platforms. Testing ''''''' -If you wish to run the tests (strongly recommended :-), you can either run them -from within python as follows ... :: +There are two environment variables you may wish to set before running the +tests. + + * **OPJ_DATA_ROOT** - points to directory for OpenJPEG test data + * **FORMAT_CORPUS_ROOT** - points to directory for format-corpus repository (see https://github.com/openplanets/format-corpus) + +Setting these two environment variables is not required, as any tests using +either of them will be skipped. + +In order to run the tests, you can either run them from within +python as follows ... :: >>> import glymur >>> glymur.runtests() diff --git a/glymur/codestream.py b/glymur/codestream.py index df1575c..c4d8b4b 100644 --- a/glymur/codestream.py +++ b/glymur/codestream.py @@ -102,7 +102,14 @@ class Codestream(object): while True: read_buffer = fptr.read(2) - marker_id, = struct.unpack('>H', read_buffer) + try: + marker_id, = struct.unpack('>H', read_buffer) + except struct.error: + # Treat this as a warning. + msg = "Marker had length {0} instead of expected length of 2 " + msg += "bytes. Codestream parsing terminated." + warnings.warn(msg.format(len(read_buffer))) + break if marker_id == 0xff90 and header_only: # Start-of-tile (SOT) means that we are out of the main header diff --git a/glymur/test/test_format_corpus.py b/glymur/test/test_format_corpus.py new file mode 100644 index 0000000..2f7347b --- /dev/null +++ b/glymur/test/test_format_corpus.py @@ -0,0 +1,51 @@ +""" +These tests deal with JPX/JP2/J2K images in the format-corpus repository. +""" +#pylint: disable-all + +import os +import sys + +if sys.hexversion < 0x02070000: + import unittest2 as unittest +else: + import unittest + +import warnings + +from glymur import Jp2k +import glymur + +try: + data_root = os.environ['FORMAT_CORPUS_ROOT'] +except KeyError: + data_root = None +except: + raise + + +@unittest.skipIf(sys.hexversion < 0x03020000, + "Requires features introduced in 3.2 (assertWarns)") +@unittest.skipIf(data_root is None, + "FORMAT_CORPUS_ROOT environment variable not set") +class TestSuite(unittest.TestCase): + + def setUp(self): + pass + + def tearDown(self): + pass + + def test_balloon_trunc1(self): + # Has one byte shaved off of EOC marker. + jfile = os.path.join(data_root, + 'jp2k-test/byteCorruption/balloon_trunc1.jp2') + j2k = Jp2k(jfile) + with self.assertWarns(UserWarning): + c = j2k.get_codestream(header_only=False) + + # The last segment is truncated, so there should not be an EOC marker. + self.assertNotEqual(c.segment[-1].marker_id, 'EOC') + +if __name__ == "__main__": + unittest.main() From 67032f504071c2a491836180401af6ad0c0b4177 Mon Sep 17 00:00:00 2001 From: jevans Date: Mon, 22 Jul 2013 19:13:26 -0400 Subject: [PATCH 06/12] Added test for error on truncated EOC file. --- glymur/test/test_format_corpus.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/glymur/test/test_format_corpus.py b/glymur/test/test_format_corpus.py index 2f7347b..fdf042c 100644 --- a/glymur/test/test_format_corpus.py +++ b/glymur/test/test_format_corpus.py @@ -47,5 +47,9 @@ class TestSuite(unittest.TestCase): # The last segment is truncated, so there should not be an EOC marker. self.assertNotEqual(c.segment[-1].marker_id, 'EOC') + # The codestream is not as long as claimed. + with self.assertRaises(OSError): + j2k.read(rlevel=-1) + if __name__ == "__main__": unittest.main() From 292f806bfeb78936692008b65be69d72ab3d9c51 Mon Sep 17 00:00:00 2001 From: jevans Date: Mon, 22 Jul 2013 19:28:51 -0400 Subject: [PATCH 07/12] Added test for file shortened by 5000 bytes. --- glymur/test/test_format_corpus.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/glymur/test/test_format_corpus.py b/glymur/test/test_format_corpus.py index fdf042c..14c0830 100644 --- a/glymur/test/test_format_corpus.py +++ b/glymur/test/test_format_corpus.py @@ -51,5 +51,20 @@ class TestSuite(unittest.TestCase): with self.assertRaises(OSError): j2k.read(rlevel=-1) + def test_balloon_trunc2(self): + # Shortened by 5000 bytes. + jfile = os.path.join(data_root, + 'jp2k-test/byteCorruption/balloon_trunc2.jp2') + j2k = Jp2k(jfile) + with self.assertWarns(UserWarning): + c = j2k.get_codestream(header_only=False) + + # The last segment is truncated, so there should not be an EOC marker. + self.assertNotEqual(c.segment[-1].marker_id, 'EOC') + + # The codestream is not as long as claimed. + with self.assertRaises(OSError): + j2k.read(rlevel=-1) + if __name__ == "__main__": unittest.main() From 83b53c5f9be71139ad2320edab53ee26d8110639 Mon Sep 17 00:00:00 2001 From: John Evans Date: Tue, 23 Jul 2013 06:36:36 -0400 Subject: [PATCH 08/12] Added warning test for image with last truncated tile, #77 --- glymur/test/test_format_corpus.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/glymur/test/test_format_corpus.py b/glymur/test/test_format_corpus.py index 14c0830..28e1d4d 100644 --- a/glymur/test/test_format_corpus.py +++ b/glymur/test/test_format_corpus.py @@ -66,5 +66,20 @@ class TestSuite(unittest.TestCase): with self.assertRaises(OSError): j2k.read(rlevel=-1) + def test_balloon_trunc3(self): + # Most of last tile is missing. + jfile = os.path.join(data_root, + 'jp2k-test/byteCorruption/balloon_trunc3.jp2') + j2k = Jp2k(jfile) + with self.assertWarns(UserWarning): + c = j2k.get_codestream(header_only=False) + + # The last segment is truncated, so there should not be an EOC marker. + self.assertNotEqual(c.segment[-1].marker_id, 'EOC') + + # Should error out, it does not. + #with self.assertRaises(OSError): + # j2k.read(rlevel=-1) + if __name__ == "__main__": unittest.main() From de7e6e1f0fef2585e128ca9f5ba5ea195c410179 Mon Sep 17 00:00:00 2001 From: John Evans Date: Tue, 23 Jul 2013 17:22:21 -0400 Subject: [PATCH 09/12] Added validation step for jp2 brand / any icc profile mismatch. #77 text_GBR.jp2 also shows this issue. --- glymur/__init__.py | 2 +- glymur/jp2k.py | 18 ++++++++++++++++++ glymur/test/test_format_corpus.py | 11 +++++++++++ glymur/test/test_opj_suite.py | 11 +++++++++-- glymur/test/test_printing.py | 22 ++++++++++++++++------ 5 files changed, 55 insertions(+), 9 deletions(-) diff --git a/glymur/__init__.py b/glymur/__init__.py index a69d28f..fb37ef0 100644 --- a/glymur/__init__.py +++ b/glymur/__init__.py @@ -6,7 +6,7 @@ from .jp2k import Jp2k from .jp2dump import jp2dump from . import data -from . import test +#from . import test def runtests(): diff --git a/glymur/jp2k.py b/glymur/jp2k.py index 5baebac..4efcb77 100644 --- a/glymur/jp2k.py +++ b/glymur/jp2k.py @@ -22,6 +22,7 @@ from .codestream import Codestream from .core import SRGB from .core import GREYSCALE from .core import PROGRESSION_ORDER +from .core import ENUMERATED_COLORSPACE, RESTRICTED_ICC_PROFILE from .jp2box import Jp2kBox from .jp2box import JPEG2000SignatureBox from .jp2box import FileTypeBox @@ -159,6 +160,23 @@ class Jp2k(Jp2kBox): # boxes) here. fptr.seek(0) self.box = self.parse_superbox(fptr) + self._validate() + + def _validate(self): + """Validate the JPEG 2000 outermost superbox. + """ + # A jp2-branded file cannot contain an "any ICC profile + ftyp = self.box[1] + jp2h = [box for box in self.box if box.box_id == 'jp2h'][0] + colr = [box for box in jp2h.box if box.box_id == 'colr'][0] + if (((ftyp.brand == 'jp2 ') and + (colr.method not in (ENUMERATED_COLORSPACE, + RESTRICTED_ICC_PROFILE)))): + msg = "Color Specification box method must specify either an " + msg += "enumerated colorspace or a restricted ICC profile if the " + msg += "file type box brand is 'jp2 '." + warnings.warn(msg) + # pylint: disable-msg=W0221 def write(self, img_array, cratios=None, eph=False, psnr=None, numres=None, diff --git a/glymur/test/test_format_corpus.py b/glymur/test/test_format_corpus.py index 28e1d4d..93af29d 100644 --- a/glymur/test/test_format_corpus.py +++ b/glymur/test/test_format_corpus.py @@ -81,5 +81,16 @@ class TestSuite(unittest.TestCase): #with self.assertRaises(OSError): # j2k.read(rlevel=-1) + def test_jp2_brand_vs_any_icc_profile(self): + # If 'jp2 ', then the method cannot be any icc profile. + jfile = os.path.join(data_root, + 'jp2k-test/icc/balloon_eciRGBv2_ps_adobeplugin.jpf') + with self.assertWarns(UserWarning): + j2k = Jp2k(jfile) + + # Should error out, it does not. + #with self.assertRaises(OSError): + # j2k.read(rlevel=-1) + if __name__ == "__main__": unittest.main() diff --git a/glymur/test/test_opj_suite.py b/glymur/test/test_opj_suite.py index 4aab788..4699b06 100644 --- a/glymur/test/test_opj_suite.py +++ b/glymur/test/test_opj_suite.py @@ -990,7 +990,11 @@ class TestSuite(unittest.TestCase): def test_NR_DEC_text_GBR_jp2_29_decode(self): jfile = os.path.join(data_root, 'input/nonregression/text_GBR.jp2') - data = Jp2k(jfile).read() + with warnings.catch_warnings(): + # brand is 'jp2 ', but has any icc profile. + warnings.simplefilter("ignore") + jp2 = Jp2k(jfile) + data = jp2.read() self.assertTrue(True) def test_NR_DEC_pacs_ge_j2k_30_decode(self): @@ -7260,7 +7264,10 @@ class TestSuiteDump(unittest.TestCase): def test_NR_text_GBR_dump(self): jfile = os.path.join(data_root, 'input/nonregression/text_GBR.jp2') - jp2 = Jp2k(jfile) + with warnings.catch_warnings(): + # brand is 'jp2 ', but has any icc profile. + 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_printing.py b/glymur/test/test_printing.py index 09f828c..79a12e1 100644 --- a/glymur/test/test_printing.py +++ b/glymur/test/test_printing.py @@ -4,6 +4,7 @@ import pkg_resources import struct import sys import tempfile +import warnings if sys.hexversion < 0x02070000: import unittest2 as unittest @@ -277,9 +278,12 @@ class TestPrinting(unittest.TestCase): "OPJ_DATA_ROOT environment variable not set") def test_icc_profile(self): filename = os.path.join(data_root, 'input/nonregression/text_GBR.jp2') - j = glymur.Jp2k(filename) + 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(j.box[3].box[1]) + print(jp2.box[3].box[1]) actual = fake_out.getvalue().strip() lin27 = ["Colour Specification Box (colr) @ (179, 1339)", " Method: any ICC profile", @@ -902,10 +906,13 @@ class TestPrinting(unittest.TestCase): # ICC profiles may be used in JP2, but the approximation field should # be zero unless we have jpx. This file does both. filename = os.path.join(data_root, 'input/nonregression/text_GBR.jp2') - j = glymur.Jp2k(filename) + 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(j.box[3].box[1]) + print(jp2.box[3].box[1]) actual = fake_out.getvalue().strip() lines = ["Colour Specification Box (colr) @ (179, 1339)", " Method: any ICC profile", @@ -942,10 +949,13 @@ class TestPrinting(unittest.TestCase): def test_uuid(self): # UUID box filename = os.path.join(data_root, 'input/nonregression/text_GBR.jp2') - j = glymur.Jp2k(filename) + 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(j.box[4]) + print(jp2.box[4]) actual = fake_out.getvalue().strip() lines = ['UUID Box (uuid) @ (1544, 25)', ' UUID: 3a0d0218-0ae9-4115-b376-4bca41ce0e71', From 6fd8f6c3b839665a65d822b2d6e40733f6f371f5 Mon Sep 17 00:00:00 2001 From: jevans Date: Tue, 23 Jul 2013 18:27:09 -0400 Subject: [PATCH 10/12] text_GBR also has a jp2 brand any icc profile mismatch. #77 --- glymur/test/test_format_corpus.py | 56 ++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/glymur/test/test_format_corpus.py b/glymur/test/test_format_corpus.py index 93af29d..f9b94e9 100644 --- a/glymur/test/test_format_corpus.py +++ b/glymur/test/test_format_corpus.py @@ -17,18 +17,23 @@ from glymur import Jp2k import glymur try: - data_root = os.environ['FORMAT_CORPUS_ROOT'] + format_corpus_data_root = os.environ['FORMAT_CORPUS_DATA_ROOT'] except KeyError: - data_root = None + format_corpus_data_root = None +except: + raise + +try: + opj_data_root = os.environ['OPJ_DATA_ROOT'] +except KeyError: + opj_corpus_data_root = None except: raise @unittest.skipIf(sys.hexversion < 0x03020000, "Requires features introduced in 3.2 (assertWarns)") -@unittest.skipIf(data_root is None, - "FORMAT_CORPUS_ROOT environment variable not set") -class TestSuite(unittest.TestCase): +class TestSuiteFormatCorpus(unittest.TestCase): def setUp(self): pass @@ -36,9 +41,11 @@ class TestSuite(unittest.TestCase): def tearDown(self): pass + @unittest.skipIf(format_corpus_data_root is None, + "FORMAT_CORPUS_DATA_ROOT environment variable not set") def test_balloon_trunc1(self): # Has one byte shaved off of EOC marker. - jfile = os.path.join(data_root, + jfile = os.path.join(format_corpus_data_root, 'jp2k-test/byteCorruption/balloon_trunc1.jp2') j2k = Jp2k(jfile) with self.assertWarns(UserWarning): @@ -51,9 +58,11 @@ class TestSuite(unittest.TestCase): with self.assertRaises(OSError): j2k.read(rlevel=-1) + @unittest.skipIf(format_corpus_data_root is None, + "FORMAT_CORPUS_DATA_ROOT environment variable not set") def test_balloon_trunc2(self): # Shortened by 5000 bytes. - jfile = os.path.join(data_root, + jfile = os.path.join(format_corpus_data_root, 'jp2k-test/byteCorruption/balloon_trunc2.jp2') j2k = Jp2k(jfile) with self.assertWarns(UserWarning): @@ -66,9 +75,11 @@ class TestSuite(unittest.TestCase): with self.assertRaises(OSError): j2k.read(rlevel=-1) + @unittest.skipIf(format_corpus_data_root is None, + "FORMAT_CORPUS_DATA_ROOT environment variable not set") def test_balloon_trunc3(self): # Most of last tile is missing. - jfile = os.path.join(data_root, + jfile = os.path.join(format_corpus_data_root, 'jp2k-test/byteCorruption/balloon_trunc3.jp2') j2k = Jp2k(jfile) with self.assertWarns(UserWarning): @@ -81,16 +92,35 @@ class TestSuite(unittest.TestCase): #with self.assertRaises(OSError): # j2k.read(rlevel=-1) + @unittest.skipIf(format_corpus_data_root is None, + "FORMAT_CORPUS_DATA_ROOT environment variable not set") def test_jp2_brand_vs_any_icc_profile(self): # If 'jp2 ', then the method cannot be any icc profile. - jfile = os.path.join(data_root, - 'jp2k-test/icc/balloon_eciRGBv2_ps_adobeplugin.jpf') + jfile = os.path.join(format_corpus_data_root, + 'jp2k-test', 'icc', + 'balloon_eciRGBv2_ps_adobeplugin.jpf') with self.assertWarns(UserWarning): j2k = Jp2k(jfile) - # Should error out, it does not. - #with self.assertRaises(OSError): - # j2k.read(rlevel=-1) +@unittest.skipIf(sys.hexversion < 0x03020000, + "Requires features introduced in 3.2 (assertWarns)") +class TestSuiteOpj(unittest.TestCase): + + def setUp(self): + pass + + def tearDown(self): + pass + + @unittest.skipIf(opj_data_root is None, + "OPJ_DATA_ROOT environment variable not set") + def test_jp2_brand_vs_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): + j2k = Jp2k(filename) + if __name__ == "__main__": unittest.main() From 097549fd667305f4b9e3c03fc0a208b615742541 Mon Sep 17 00:00:00 2001 From: jevans Date: Tue, 23 Jul 2013 18:39:42 -0400 Subject: [PATCH 11/12] Renamed, files other than those from format-corpus. #77 --- glymur/test/{test_format_corpus.py => test_conformance.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename glymur/test/{test_format_corpus.py => test_conformance.py} (100%) diff --git a/glymur/test/test_format_corpus.py b/glymur/test/test_conformance.py similarity index 100% rename from glymur/test/test_format_corpus.py rename to glymur/test/test_conformance.py From ee2b3b9c0e61097fa68502f86874611366267fda Mon Sep 17 00:00:00 2001 From: John Evans Date: Wed, 24 Jul 2013 06:01:46 -0400 Subject: [PATCH 12/12] Validation check now allows for multiple colr boxes. Closes #77 jp2h superboxes can contain multiple colr boxes, so we need to check each one for validity. --- glymur/jp2k.py | 19 ++++++++++--------- glymur/test/test_conformance.py | 29 ++++++++++++++++++----------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/glymur/jp2k.py b/glymur/jp2k.py index 4efcb77..319bf46 100644 --- a/glymur/jp2k.py +++ b/glymur/jp2k.py @@ -167,15 +167,16 @@ class Jp2k(Jp2kBox): """ # A jp2-branded file cannot contain an "any ICC profile ftyp = self.box[1] - jp2h = [box for box in self.box if box.box_id == 'jp2h'][0] - colr = [box for box in jp2h.box if box.box_id == 'colr'][0] - if (((ftyp.brand == 'jp2 ') and - (colr.method not in (ENUMERATED_COLORSPACE, - RESTRICTED_ICC_PROFILE)))): - msg = "Color Specification box method must specify either an " - msg += "enumerated colorspace or a restricted ICC profile if the " - msg += "file type box brand is 'jp2 '." - warnings.warn(msg) + if ftyp.brand == 'jp2 ': + jp2h = [box for box in self.box if box.box_id == 'jp2h'][0] + colrs = [box for box in jp2h.box if box.box_id == 'colr'] + for colr in colrs: + if colr.method not in (ENUMERATED_COLORSPACE, + RESTRICTED_ICC_PROFILE): + msg = "Color Specification box method must specify either " + msg += "an enumerated colorspace or a restricted ICC " + msg += "profile if the file type box brand is 'jp2 '." + warnings.warn(msg) # pylint: disable-msg=W0221 diff --git a/glymur/test/test_conformance.py b/glymur/test/test_conformance.py index f9b94e9..ec179c2 100644 --- a/glymur/test/test_conformance.py +++ b/glymur/test/test_conformance.py @@ -26,11 +26,13 @@ except: try: opj_data_root = os.environ['OPJ_DATA_ROOT'] except KeyError: - opj_corpus_data_root = None + opj_data_root = None except: raise +@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): @@ -41,8 +43,6 @@ class TestSuiteFormatCorpus(unittest.TestCase): def tearDown(self): pass - @unittest.skipIf(format_corpus_data_root is None, - "FORMAT_CORPUS_DATA_ROOT environment variable not set") def test_balloon_trunc1(self): # Has one byte shaved off of EOC marker. jfile = os.path.join(format_corpus_data_root, @@ -58,8 +58,6 @@ class TestSuiteFormatCorpus(unittest.TestCase): with self.assertRaises(OSError): j2k.read(rlevel=-1) - @unittest.skipIf(format_corpus_data_root is None, - "FORMAT_CORPUS_DATA_ROOT environment variable not set") def test_balloon_trunc2(self): # Shortened by 5000 bytes. jfile = os.path.join(format_corpus_data_root, @@ -75,8 +73,6 @@ class TestSuiteFormatCorpus(unittest.TestCase): with self.assertRaises(OSError): j2k.read(rlevel=-1) - @unittest.skipIf(format_corpus_data_root is None, - "FORMAT_CORPUS_DATA_ROOT environment variable not set") def test_balloon_trunc3(self): # Most of last tile is missing. jfile = os.path.join(format_corpus_data_root, @@ -92,8 +88,6 @@ class TestSuiteFormatCorpus(unittest.TestCase): #with self.assertRaises(OSError): # j2k.read(rlevel=-1) - @unittest.skipIf(format_corpus_data_root is None, - "FORMAT_CORPUS_DATA_ROOT environment variable not set") def test_jp2_brand_vs_any_icc_profile(self): # If 'jp2 ', then the method cannot be any icc profile. jfile = os.path.join(format_corpus_data_root, @@ -102,7 +96,22 @@ class TestSuiteFormatCorpus(unittest.TestCase): with self.assertWarns(UserWarning): j2k = Jp2k(jfile) + def test_jp2_brand_vs_any_icc_profile_multiple_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. + lst = [format_corpus_data_root, 'jp2k-test', 'icc', + 'balloon_eciRGBv2_ps_adobeplugin_jp2compatible.jpf'] + jfile = os.path.join(*lst) + with self.assertWarns(UserWarning): + j2k = 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): @@ -113,8 +122,6 @@ class TestSuiteOpj(unittest.TestCase): def tearDown(self): pass - @unittest.skipIf(opj_data_root is None, - "OPJ_DATA_ROOT environment variable not set") def test_jp2_brand_vs_any_icc_profile(self): # If 'jp2 ', then the method cannot be any icc profile. filename = os.path.join(opj_data_root,