Merge branch 'issue143' into devel
This commit is contained in:
commit
ff668a4967
2 changed files with 97 additions and 40 deletions
|
|
@ -1903,6 +1903,72 @@ class LabelBox(Jp2kBox):
|
||||||
return box
|
return box
|
||||||
|
|
||||||
|
|
||||||
|
class NumberListBox(Jp2kBox):
|
||||||
|
"""Container for Number List box information.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
box_id : str
|
||||||
|
4-character identifier for the box.
|
||||||
|
length : int
|
||||||
|
length of the box in bytes.
|
||||||
|
offset : int
|
||||||
|
offset of the box from the start of the file.
|
||||||
|
longname : str
|
||||||
|
more verbose description of the box.
|
||||||
|
AN : list
|
||||||
|
Descriptors of an entity with which the data contained within the same
|
||||||
|
Association box is associated.
|
||||||
|
"""
|
||||||
|
def __init__(self, associations, length=0, offset=-1):
|
||||||
|
Jp2kBox.__init__(self, box_id='nlst', longname='Number List')
|
||||||
|
self.associations = associations
|
||||||
|
self.length = length
|
||||||
|
self.offset = offset
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
msg = Jp2kBox.__str__(self)
|
||||||
|
for j, association in enumerate(self.associations):
|
||||||
|
if association == 0:
|
||||||
|
msg += '\n Association[{0}]: the rendered result'.format(j)
|
||||||
|
elif (association >> 24) == 1:
|
||||||
|
idx = association & 0x00FFFFFF
|
||||||
|
msg += '\n Association[{0}]: Codestream {0} '.format(idx)
|
||||||
|
elif (association >> 24) == 2:
|
||||||
|
idx = association & 0x00FFFFFF
|
||||||
|
msg += '\n Association[{0}]: Compositing Layer {0}'
|
||||||
|
msg = msg.format(idx)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
msg = 'glymur.jp2box.NumberListBox()'
|
||||||
|
return msg
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse(fptr, offset, length):
|
||||||
|
"""Parse Label box.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
fptr : file
|
||||||
|
Open file object.
|
||||||
|
offset : int
|
||||||
|
Start position of box in bytes.
|
||||||
|
length : int
|
||||||
|
Length of the box in bytes.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
LabelBox instance
|
||||||
|
"""
|
||||||
|
num_bytes = offset + length - fptr.tell()
|
||||||
|
raw_data = fptr.read(num_bytes)
|
||||||
|
num_associations = int(len(raw_data) / 4)
|
||||||
|
lst = struct.unpack('>' + 'I' * num_associations, raw_data)
|
||||||
|
box = NumberListBox(lst, length=length, offset=offset)
|
||||||
|
return box
|
||||||
|
|
||||||
|
|
||||||
class XMLBox(Jp2kBox):
|
class XMLBox(Jp2kBox):
|
||||||
"""Container for XML box information.
|
"""Container for XML box information.
|
||||||
|
|
||||||
|
|
@ -2865,6 +2931,7 @@ _BOX_WITH_ID = {
|
||||||
'free': FreeBox,
|
'free': FreeBox,
|
||||||
'jp2h': JP2HeaderBox,
|
'jp2h': JP2HeaderBox,
|
||||||
'lbl ': LabelBox,
|
'lbl ': LabelBox,
|
||||||
|
'nlst': NumberListBox,
|
||||||
'pclr': PaletteBox,
|
'pclr': PaletteBox,
|
||||||
'res ': ResolutionBox,
|
'res ': ResolutionBox,
|
||||||
'resc': CaptureResolutionBox,
|
'resc': CaptureResolutionBox,
|
||||||
|
|
|
||||||
|
|
@ -20,46 +20,6 @@ from glymur import Jp2k
|
||||||
from glymur.jp2box import ReaderRequirementsBox
|
from glymur.jp2box import ReaderRequirementsBox
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(sys.hexversion < 0x03000000, "Warning assert on 2.x.")
|
|
||||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
|
||||||
class TestReaderRequirements(unittest.TestCase):
|
|
||||||
"""Test suite for XML boxes."""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.jp2file = glymur.data.nemo()
|
|
||||||
pass
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def test_mask_length_is_3(self):
|
|
||||||
"""The standard says that the mask length should be 1, 2, 4, or 8."""
|
|
||||||
# Rewrite nemo to include this kind of rreq box.
|
|
||||||
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
|
|
||||||
with open(self.jp2file, 'rb') as nemof:
|
|
||||||
# Read the jP and ftyp boxes as-is.
|
|
||||||
write_buffer = nemof.read(32)
|
|
||||||
tfile.write(write_buffer)
|
|
||||||
|
|
||||||
# Fake a rreq box with ML = 3.
|
|
||||||
write_buffer = struct.pack('>I4sB', 74, b'rreq', 3)
|
|
||||||
tfile.write(write_buffer)
|
|
||||||
|
|
||||||
# pad the rest with zeros
|
|
||||||
write_buffer = struct.pack('>65s', b'\x00' * 65)
|
|
||||||
tfile.write(write_buffer)
|
|
||||||
|
|
||||||
# Write the rest of nemo.
|
|
||||||
tfile.write(nemof.read())
|
|
||||||
tfile.flush()
|
|
||||||
|
|
||||||
with self.assertWarns(UserWarning):
|
|
||||||
j = Jp2k(tfile.name)
|
|
||||||
self.assertEqual(j.box[2].box_id, 'rreq')
|
|
||||||
self.assertEqual(type(j.box[2]),
|
|
||||||
glymur.jp2box.ReaderRequirementsBox)
|
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(sys.hexversion < 0x03000000, "Warning assert on 2.x.")
|
@unittest.skipIf(sys.hexversion < 0x03000000, "Warning assert on 2.x.")
|
||||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||||
class TestJPXOther(unittest.TestCase):
|
class TestJPXOther(unittest.TestCase):
|
||||||
|
|
@ -72,6 +32,16 @@ class TestJPXOther(unittest.TestCase):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def test_rreq_box_strange_mask_length(self):
|
||||||
|
"""The standard says that the mask length should be 1, 2, 4, or 8."""
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
# This file has a rreq mask length that we do not recognize.
|
||||||
|
warnings.simplefilter("ignore")
|
||||||
|
j = Jp2k(self.jpxfile)
|
||||||
|
self.assertEqual(j.box[2].box_id, 'rreq')
|
||||||
|
self.assertEqual(type(j.box[2]),
|
||||||
|
glymur.jp2box.ReaderRequirementsBox)
|
||||||
|
|
||||||
def test_free_box(self):
|
def test_free_box(self):
|
||||||
"""Verify that we can handle a free box."""
|
"""Verify that we can handle a free box."""
|
||||||
with warnings.catch_warnings():
|
with warnings.catch_warnings():
|
||||||
|
|
@ -81,3 +51,23 @@ class TestJPXOther(unittest.TestCase):
|
||||||
self.assertEqual(j.box[16].box[0].box_id, 'free')
|
self.assertEqual(j.box[16].box[0].box_id, 'free')
|
||||||
self.assertEqual(type(j.box[16].box[0]), glymur.jp2box.FreeBox)
|
self.assertEqual(type(j.box[16].box[0]), glymur.jp2box.FreeBox)
|
||||||
|
|
||||||
|
def test_nlst(self):
|
||||||
|
"""Verify that we can handle a free box."""
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
# This file has a rreq mask length that we do not recognize.
|
||||||
|
warnings.simplefilter("ignore")
|
||||||
|
j = Jp2k(self.jpxfile)
|
||||||
|
self.assertEqual(j.box[16].box[1].box[0].box_id, 'nlst')
|
||||||
|
self.assertEqual(type(j.box[16].box[1].box[0]),
|
||||||
|
glymur.jp2box.NumberListBox)
|
||||||
|
|
||||||
|
# Two associations.
|
||||||
|
self.assertEqual(len(j.box[16].box[1].box[0].associations), 2)
|
||||||
|
|
||||||
|
# Codestream 0
|
||||||
|
self.assertEqual(j.box[16].box[1].box[0].associations[0], 1 << 24)
|
||||||
|
|
||||||
|
# Compositing Layer 0
|
||||||
|
self.assertEqual(j.box[16].box[1].box[0].associations[1], 2 << 24)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue