From d82c9b465e8d2027f1531e111c332390705c7237 Mon Sep 17 00:00:00 2001 From: John Evans Date: Thu, 13 Mar 2014 19:41:05 -0400 Subject: [PATCH] Less than 8 bytes at end of file indicates corruption. #187 --- glymur/jp2box.py | 8 +++- glymur/test/test_jp2k.py | 84 ++++++++++++++++++++++------------------ 2 files changed, 54 insertions(+), 38 deletions(-) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index 5dba568..971818f 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') diff --git a/glymur/test/test_jp2k.py b/glymur/test/test_jp2k.py index 3046422..16a1b80 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,26 +92,6 @@ class TestJp2k(unittest.TestCase): with self.assertRaises(IOError): Jp2k(filename) - @unittest.skipIf(OPJ_DATA_ROOT is None, - "OPJ_DATA_ROOT environment variable not set") - 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_no_cxform_pclr_jpx(self): """Indices for pclr jpxfile if no color transform""" j = Jp2k(self.jpxfile) @@ -300,19 +277,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. @@ -804,6 +768,52 @@ 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() + + if __name__ == "__main__": unittest.main()