diff --git a/glymur/codestream.py b/glymur/codestream.py index cf21ec5..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 diff --git a/glymur/test/fixtures.py b/glymur/test/fixtures.py index b47f211..8e8deb8 100644 --- a/glymur/test/fixtures.py +++ b/glymur/test/fixtures.py @@ -587,3 +587,26 @@ 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 ce03ef7..28ea0f8 100644 --- a/glymur/test/test_codestream.py +++ b/glymur/test/test_codestream.py @@ -29,8 +29,39 @@ class TestCodestream(unittest.TestCase): def tearDown(self): pass - @unittest.skipIf(OPJ_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') @@ -43,8 +74,6 @@ class TestCodestream(unittest.TestCase): Jp2k(filename) - @unittest.skipIf(OPJ_DATA_ROOT is None, - "OPJ_DATA_ROOT environment variable not set") @unittest.skipIf(os.name == "nt", "Temporary file issue on window.") def test_reserved_marker_segment(self): """Reserved marker segments are ok.""" @@ -76,8 +105,6 @@ class TestCodestream(unittest.TestCase): self.assertEqual(codestream.segment[2].length, 3) self.assertEqual(codestream.segment[2].data, b'\x00') - @unittest.skipIf(OPJ_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.") @@ -109,8 +136,6 @@ class TestCodestream(unittest.TestCase): self.assertEqual(codestream.segment[2].length, 3) self.assertEqual(codestream.segment[2].data, b'\x00') - @unittest.skipIf(OPJ_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(OPJ_DATA_ROOT, @@ -123,19 +148,6 @@ 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(OPJ_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(OPJ_DATA_ROOT, 'input/conformance/p0_03.j2k') diff --git a/glymur/test/test_jp2box_xml.py b/glymur/test/test_jp2box_xml.py index 9194a49..8650895 100644 --- a/glymur/test/test_jp2box_xml.py +++ b/glymur/test/test_jp2box_xml.py @@ -94,6 +94,8 @@ class TestXML(unittest.TestCase): def tearDown(self): os.unlink(self.xmlfile) + @unittest.skipIf(OPJ_DATA_ROOT is None, + "OPJ_DATA_ROOT environment variable not set") def test_invalid_utf8(self): """Bad byte sequence that cannot be parsed.""" filename = opj_data_file(os.path.join('input', diff --git a/glymur/test/test_printing.py b/glymur/test/test_printing.py index 6a819ac..554e6de 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,8 +588,316 @@ 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") + @unittest.skipIf(sys.hexversion < 0x03000000, + "Ordered dicts not printing well in 2.7") + def test_exif_uuid(self): + """Verify printing of exif information""" + with tempfile.NamedTemporaryFile(suffix='.jp2', mode='wb') as tfile: + + with open(self.jp2file, 'rb') as ifptr: + tfile.write(ifptr.read()) + + # Write L, T, UUID identifier. + tfile.write(struct.pack('>I4s', 76, b'uuid')) + tfile.write(b'JpgTiffExif->JP2') + + tfile.write(b'Exif\x00\x00') + xbuffer = struct.pack(' (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 @@ -885,8 +920,6 @@ class TestPrinting(unittest.TestCase): 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') @@ -932,46 +965,6 @@ class TestPrinting(unittest.TestCase): actual = fake_out.getvalue().strip() self.assertEqual(actual, fixtures.issue_183_colr) - @unittest.skipIf(sys.hexversion < 0x03000000, - "Ordered dicts not printing well in 2.7") - def test_exif_uuid(self): - """Verify printing of exif information""" - with tempfile.NamedTemporaryFile(suffix='.jp2', mode='wb') as tfile: - - with open(self.jp2file, 'rb') as ifptr: - tfile.write(ifptr.read()) - - # Write L, T, UUID identifier. - tfile.write(struct.pack('>I4s', 76, b'uuid')) - tfile.write(b'JpgTiffExif->JP2') - - tfile.write(b'Exif\x00\x00') - xbuffer = struct.pack('