diff --git a/glymur/jp2k.py b/glymur/jp2k.py
index 6f20ae9..d755cb0 100644
--- a/glymur/jp2k.py
+++ b/glymur/jp2k.py
@@ -468,6 +468,19 @@ class Jp2k(Jp2kBox):
msg = "The jp2 header box must contain a color definition box."
raise IOError(msg)
+ # Any cdef box must be in the jp2 header following the image header.
+ cdef_lst = [j for (j, box) in enumerate(boxes) if box.id == 'cdef']
+ if len(cdef_lst) != 0:
+ msg = "Any channel defintion box must be in the JP2 header "
+ msg += "following the image header."
+ raise IOError(msg)
+
+ cdef_lst = [j for (j, box) in enumerate(jp2h.box) if box.id == 'cdef']
+ if len(cdef_lst) > 1:
+ msg = "Only one channel definition box is allowed in the "
+ msg += "JP2 header."
+ raise IOError(msg)
+
with open(filename, 'wb') as ofile:
for box in boxes:
if box.id != 'jp2c':
diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py
index 4b929cd..d39cc64 100644
--- a/glymur/test/test_jp2box.py
+++ b/glymur/test/test_jp2box.py
@@ -17,17 +17,61 @@ def load_tests(loader, tests, ignore):
return tests
-@unittest.skipIf(glymur.lib.openjp2._OPENJP2 is None,
- "Missing openjp2 library.")
class TestChannelDefinition(unittest.TestCase):
def setUp(self):
self.jp2file = glymur.data.nemo()
self.j2kfile = glymur.data.goodstuff()
+ j2k = Jp2k(self.j2kfile)
+ c = j2k.get_codestream()
+ height = c.segment[1].Ysiz
+ width = c.segment[1].Xsiz
+ num_components = len(c.segment[1].XRsiz)
+
+ self.jP = JPEG2000SignatureBox()
+ self.ftyp = FileTypeBox()
+ self.jp2h = JP2HeaderBox()
+ self.jp2c = ContiguousCodestreamBox()
+ self.ihdr = ImageHeaderBox(height=height, width=width,
+ num_components=num_components)
+ self.colr_rgb = ColourSpecificationBox(colorspace=glymur.core.SRGB)
+
def tearDown(self):
pass
+ def test_only_one_cdef_in_jp2_header(self):
+ """There can only be one channel definition box in the jp2 header."""
+ j2k = Jp2k(self.j2kfile)
+
+ cdef = glymur.jp2box.ChannelDefinitionBox(index=[0, 1, 2],
+ channel_type=[0, 0, 0],
+ association=[0, 1, 2])
+
+ boxes = [self.ihdr, cdef, self.colr_rgb, cdef]
+ self.jp2h.box = boxes
+
+ boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
+
+ with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
+ with self.assertRaises(IOError):
+ j2k.wrap(tfile.name, boxes=boxes)
+
+ def test_not_in_jp2_header(self):
+ j2k = Jp2k(self.j2kfile)
+ boxes = [self.ihdr, self.colr_rgb]
+ self.jp2h.box = boxes
+
+ cdef = glymur.jp2box.ChannelDefinitionBox(index=[0, 1, 2],
+ channel_type=[0, 0, 0],
+ association=[0, 1, 2])
+
+ boxes = [self.jP, self.ftyp, self.jp2h, cdef, self.jp2c]
+
+ with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
+ with self.assertRaises(IOError):
+ j2k.wrap(tfile.name, boxes=boxes)
+
def test_bad_type(self):
# Channel types are limited to 0, 1, 2, 65535
# Should reject if not all of index, channel_type, association the
@@ -45,6 +89,93 @@ class TestChannelDefinition(unittest.TestCase):
channel_type=[0, 0],
association=[0, 1, 2])
+class TestXML(unittest.TestCase):
+
+ def setUp(self):
+ self.jp2file = glymur.data.nemo()
+ self.j2kfile = glymur.data.goodstuff()
+
+ j2k = Jp2k(self.j2kfile)
+ c = j2k.get_codestream()
+ height = c.segment[1].Ysiz
+ width = c.segment[1].Xsiz
+ num_components = len(c.segment[1].XRsiz)
+
+ self.jP = JPEG2000SignatureBox()
+ self.ftyp = FileTypeBox()
+ self.jp2h = JP2HeaderBox()
+ self.jp2c = ContiguousCodestreamBox()
+ self.ihdr = ImageHeaderBox(height=height, width=width,
+ num_components=num_components)
+ self.colr = ColourSpecificationBox(colorspace=glymur.core.SRGB)
+
+ def tearDown(self):
+ pass
+
+ def test_basic_xml(self):
+ j2k = Jp2k(self.j2kfile)
+
+ self.jp2h.box = [self.ihdr, self.colr]
+
+ the_xml = ET.fromstring('0')
+ xml = glymur.jp2box.XMLBox(xml=the_xml)
+ boxes = [self.jP, self.ftyp, self.jp2h, xml, self.jp2c]
+
+ with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
+ j2k.wrap(tfile.name, boxes=boxes)
+ jp2 = Jp2k(tfile.name)
+ self.assertEqual(jp2.box[3].id, 'xml ')
+
+ def test_xml_from_file(self):
+ raw_xml = b"""
+
+
+ 1
+ 2008
+ 141100
+
+
+
+
+ 4
+ 2011
+ 59900
+
+
+
+ 68
+ 2011
+ 13600
+
+
+
+ """
+ with tempfile.NamedTemporaryFile(suffix=".xml") as tfile:
+ tfile.write(raw_xml)
+ tfile.flush()
+
+ j2k = Jp2k(self.j2kfile)
+
+ self.jp2h.box = [self.ihdr, self.colr]
+
+ xmlb = glymur.jp2box.XMLBox(filename=tfile.name)
+ boxes = [self.jP, self.ftyp, self.jp2h, xmlb, self.jp2c]
+ with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
+ j2k.wrap(tfile.name, boxes=boxes)
+ jp2 = Jp2k(tfile.name)
+
+ output_boxes = [box.id for box in jp2.box]
+ self.assertEqual(output_boxes, ['jP ', 'ftyp', 'jp2h', 'xml ',
+ 'jp2c'])
+
+ elts = jp2.box[3].xml.findall('country')
+ self.assertEqual(len(elts), 3)
+
+ neighbor = elts[1].find('neighbor')
+ self.assertEqual(neighbor.attrib['name'], 'Malaysia')
+ self.assertEqual(neighbor.attrib['direction'], 'N')
+
+
@unittest.skipIf(glymur.lib.openjp2._OPENJP2 is None,
"Missing openjp2 library.")
class TestJp2Boxes(unittest.TestCase):
@@ -370,84 +501,5 @@ class TestJp2Boxes(unittest.TestCase):
with self.assertRaises(IOError):
j2k.wrap(tfile.name, boxes=boxes)
- def test_basic_xml(self):
- j2k = Jp2k(self.raw_codestream)
- c = j2k.get_codestream()
- height = c.segment[1].Ysiz
- width = c.segment[1].Xsiz
- num_components = len(c.segment[1].XRsiz)
-
- jP = JPEG2000SignatureBox()
- ftyp = FileTypeBox()
- jp2h = JP2HeaderBox()
- jp2c = ContiguousCodestreamBox()
- ihdr = ImageHeaderBox(height=height, width=width,
- num_components=num_components)
- colr = ColourSpecificationBox(colorspace=glymur.core.SRGB)
- jp2h.box = [ihdr, colr]
-
- the_xml = ET.fromstring('0')
- xml = glymur.jp2box.XMLBox(xml=the_xml)
- boxes = [jP, ftyp, jp2h, xml, jp2c]
- with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
- j2k.wrap(tfile.name, boxes=boxes)
- jp2 = Jp2k(tfile.name)
- self.assertEqual(jp2.box[3].id, 'xml ')
-
- def test_xml_from_file(self):
- raw_xml = b"""
-
-
- 1
- 2008
- 141100
-
-
-
-
- 4
- 2011
- 59900
-
-
-
- 68
- 2011
- 13600
-
-
-
- """
- with tempfile.NamedTemporaryFile(suffix=".xml") as tfile:
- tfile.write(raw_xml)
- tfile.flush()
-
- j2k = Jp2k(self.raw_codestream)
- c = j2k.get_codestream()
- height = c.segment[1].Ysiz
- width = c.segment[1].Xsiz
- num_components = len(c.segment[1].XRsiz)
-
- jP = JPEG2000SignatureBox()
- ftyp = FileTypeBox()
- jp2h = JP2HeaderBox()
- jp2c = ContiguousCodestreamBox()
- ihdr = ImageHeaderBox(height=height, width=width,
- num_components=num_components)
- colr = ColourSpecificationBox(colorspace=glymur.core.SRGB)
- jp2h.box = [ihdr, colr]
-
- xmlb = glymur.jp2box.XMLBox(filename=tfile.name)
- boxes = [jP, ftyp, jp2h, xmlb, jp2c]
- with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
- j2k.wrap(tfile.name, boxes=boxes)
- jp2 = Jp2k(tfile.name)
-
- output_boxes = [box.id for box in jp2.box]
- self.assertEqual(output_boxes, ['jP ', 'ftyp', 'jp2h', 'xml ',
- 'jp2c'])
- self.assertIsNotNone(jp2.box[3].xml)
-
-
if __name__ == "__main__":
unittest.main()