From 2755e8edd439765acedc7fb11cac7bbfeeae9591 Mon Sep 17 00:00:00 2001 From: jevans Date: Mon, 5 Jan 2015 20:23:52 -0500 Subject: [PATCH] Jp2dump tests passing, more need to be written --- glymur/command_line.py | 16 +++++++++---- glymur/jp2box.py | 45 ++++++++++++++++++++++++++++-------- glymur/test/test_printing.py | 40 ++++++++++++++++++++------------ 3 files changed, 72 insertions(+), 29 deletions(-) diff --git a/glymur/command_line.py b/glymur/command_line.py index 0836108..4cd080d 100644 --- a/glymur/command_line.py +++ b/glymur/command_line.py @@ -60,11 +60,19 @@ def main(): # JP2 metadata can be extensive, so don't print any warnings until we # are done with the metadata. jp2 = Jp2k(filename) - if (((jp2._codec_format == lib.openjp2.CODEC_J2K) and - (codestream_level == 0))): - print('File: {0}'.format(os.path.basename(filename))) + if jp2._codec_format == lib.openjp2.CODEC_J2K: + if codestream_level == 0: + print('File: {0}'.format(os.path.basename(filename))) + elif codestream_level == 1: + print(jp2) + elif codestream_level == 2: + print('File: {0}'.format(os.path.basename(filename))) + print(jp2.get_codestream(header_only=False)) elif print_full_codestream: - print(jp2.get_codestream(header_only=False)) + for box in jp2.box: + if box.box_id == 'jp2c': + box._get_codestream(header_only=False) + print(jp2) else: print(jp2) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index 4307f48..bd60c30 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -1001,18 +1001,19 @@ class ContiguousCodestreamBox(Jp2kBox): offset of the box from the start of the file. longname : str more verbose description of the box. - main_header : Codestream object - contains list of main header marker/segments + codestream : Codestream object + Contains list of codestream marker/segments. By default, only the main + header is retrieved. main_header_offset : int offset of main header from start of file """ box_id = 'jp2c' longname = 'Contiguous Codestream' - def __init__(self, main_header=None, main_header_offset=None, length=0, + def __init__(self, codestream=None, main_header_offset=None, length=0, offset=-1): Jp2kBox.__init__(self) - self._main_header = main_header + self._codestream = codestream self.length = length self.offset = offset self.main_header_offset = main_header_offset @@ -1021,16 +1022,16 @@ class ContiguousCodestreamBox(Jp2kBox): self._filename = None @property - def main_header(self): - if self._main_header is None: + def codestream(self): + if self._codestream is None: if self._filename is not None: with open(self._filename, 'rb') as fptr: fptr.seek(self.main_header_offset) - main_header = Codestream(fptr, + codestream = Codestream(fptr, self._length, header_only=True) - self._main_header = main_header - return self._main_header + self._codestream = codestream + return self._codestream def __repr__(self): msg = "glymur.jp2box.ContiguousCodeStreamBox(main_header={0})" @@ -1043,7 +1044,7 @@ class ContiguousCodestreamBox(Jp2kBox): if _printoptions['codestream'] is False: return msg - for segment in self.main_header.segment: + for segment in self.codestream.segment: msg += '\n' + self._indent(str(segment), indent_level=4) return msg @@ -1076,6 +1077,30 @@ class ContiguousCodestreamBox(Jp2kBox): box._length = length return box + def _get_codestream(self, header_only=True): + """retrieve codestream + + Parameters + ---------- + header_only : bool, optional + If True, only marker segments in the main header are parsed. + Supplying False may impose a large performance penalty. + """ + with open(self.filename, 'rb') as fptr: + fptr.seek(self.offset) + read_buffer = fptr.read(8) + (box_length, _) = struct.unpack('>I4s', read_buffer) + if box_length == 0: + # The length of the box is presumed to last until the end + # of the file. Compute the effective length of the box. + box_length = os.path.getsize(fptr.name) - fptr.tell() + 8 + elif box_length == 1: + # Seek past the XL field. + read_buffer = fptr.read(8) + box_length, = struct.unpack('>Q', read_buffer) + self._codestream = Codestream(fptr, box_length - 8, + header_only=header_only) + class DataReferenceBox(Jp2kBox): """Container for Data Reference box information. diff --git a/glymur/test/test_printing.py b/glymur/test/test_printing.py index 55e3018..bef59ad 100644 --- a/glymur/test/test_printing.py +++ b/glymur/test/test_printing.py @@ -1055,25 +1055,44 @@ class TestJp2dump(unittest.TestCase): return actual def test_default_nemo(self): - """Should be able to dump a JP2 file's metadata with no codestream.""" + """by default one should get the main header""" actual = self.run_jp2dump(['', self.jp2file]) - self.assertEqual(actual, fixtures.nemo_dump_no_codestream) + # shave off the non-main-header segments + lines = fixtures.nemo.split('\n') + expected = lines[0:140] + expected = '\n'.join(expected) + self.assertEqual(actual, expected) - def test_codestream_0(self): + @unittest.skipIf(sys.hexversion < 0x03000000, "assertRegex not in 2.7") + + def test_jp2_codestream_0(self): """Verify dumping with -c 0, supressing all codestream details.""" actual = self.run_jp2dump(['', '-c', '0', self.jp2file]) expected = fixtures.nemo_dump_no_codestream self.assertEqual(actual, expected) - def test_codestream_1(self): + def test_jp2_codestream_1(self): """Verify dumping with -c 1, print just the header.""" actual = self.run_jp2dump(['', '-c', '1', self.jp2file]) - self.assertEqual(actual, fixtures.nemo_with_codestream_header) + # shave off the non-main-header segments + lines = fixtures.nemo.split('\n') + expected = lines[0:140] + expected = '\n'.join(expected) + self.assertEqual(actual, expected) - def test_codestream_2(self): + @unittest.skipIf(sys.hexversion < 0x03000000, "assertRegex not in 2.7") + def test_j2k_codestream_0(self): + """-c 0 should print just a single line when used on a codestream.""" + sys.argv = ['', '-c', '0', self.j2kfile] + with patch('sys.stdout', new=StringIO()) as fake_out: + command_line.main() + actual = fake_out.getvalue().strip() + self.assertRegex(actual, "File: .*") + + def test_j2k_codestream_2(self): """Verify dumping with -c 2, full details.""" with patch('sys.stdout', new=StringIO()) as fake_out: sys.argv = ['', '-c', '2', self.j2kfile] @@ -1104,12 +1123,3 @@ class TestJp2dump(unittest.TestCase): expected.extend(lines[104:140]) expected = '\n'.join(expected) self.assertEqual(actual, expected) - - @unittest.skipIf(sys.hexversion < 0x03000000, "assertRegex not in 2.7") - def test_codestream_0_with_j2k_file(self): - """-c 0 should print just a single line when used on a codestream.""" - sys.argv = ['', '-c', '0', self.j2kfile] - with patch('sys.stdout', new=StringIO()) as fake_out: - command_line.main() - actual = fake_out.getvalue().strip() - self.assertRegex(actual, "File: .*")