From 87cbf87ed76f7d2000cc6c5381964dbd9f4fb765 Mon Sep 17 00:00:00 2001 From: John Evans Date: Mon, 10 Feb 2014 16:47:09 -0500 Subject: [PATCH] Checking for proper location of jp2h children. #157 Certain boxes can only reside in jp2h or jpch (which is not currently supported for writing purposed). --- glymur/jp2k.py | 16 ++++++++++++++++ glymur/test/test_jp2box.py | 27 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/glymur/jp2k.py b/glymur/jp2k.py index 3ecc96f..55e3766 100644 --- a/glymur/jp2k.py +++ b/glymur/jp2k.py @@ -1198,6 +1198,22 @@ def _validate_jp2_box_sequence(boxes): _jpx_compatibility(boxes, boxes[1].compatibility_list) _check_for_singletons(boxes) _check_top_level(boxes) + _check_jp2h_child_boxes(boxes, 'top-level') + +JP2H_CHILDREN = set(['bpcc', 'cmap', 'ihdr', 'pclr']) +def _check_jp2h_child_boxes(boxes, parent_box_name): + """Certain boxes can only reside in the JP2 header.""" + box_ids = set([box.box_id for box in boxes]) + intersection = box_ids.intersection(JP2H_CHILDREN) + if len(intersection) > 0 and parent_box_name != 'jp2h': + msg = "A '{0}' box can only be nested in a JP2 header box." + raise IOError(msg.format(list(intersection)[0])) + + # Recursively check any contained superboxes. + for box in boxes: + if hasattr(box, 'box'): + _check_jp2h_child_boxes(box.box, box.box_id) + def _collect_box_count(boxes): """Count the occurences of each box type.""" diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py index 23c8e93..ac1b2a3 100644 --- a/glymur/test/test_jp2box.py +++ b/glymur/test/test_jp2box.py @@ -679,6 +679,33 @@ class TestWrap(unittest.TestCase): with self.assertRaises(IOError): j2k.wrap(tfile.name, boxes=boxes) + def test_pclr_not_in_jp2h(self): + """A palette box must reside in a JP2 header box.""" + palette = np.array([[255, 0, 255], [0, 255, 0]], dtype=np.int32) + bps = (8, 8, 8) + signed = (True, False, True) + pclr = glymur.jp2box.PaletteBox(palette=palette, bits_per_component=bps, + signed=(True, False, True)) + + j2k = Jp2k(self.j2kfile) + codestream = j2k.get_codestream() + height = codestream.segment[1].ysiz + width = codestream.segment[1].xsiz + num_components = len(codestream.segment[1].xrsiz) + + jp2b = JPEG2000SignatureBox() + ftyp = FileTypeBox() + jp2h = JP2HeaderBox() + jp2c = ContiguousCodestreamBox() + colr = ColourSpecificationBox(colorspace=glymur.core.SRGB) + ihdr = ImageHeaderBox(height=height, width=width, + num_components=num_components) + jp2h.box = [ihdr, colr] + boxes = [jp2b, ftyp, jp2h, jp2c, pclr] + with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile: + with self.assertRaises(IOError): + j2k.wrap(tfile.name, boxes=boxes) + def test_jp2h_not_preceeding_jp2c(self): """jp2h must precede jp2c""" j2k = Jp2k(self.j2kfile)