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
|
||||
|
||||
|
||||
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):
|
||||
"""Container for XML box information.
|
||||
|
||||
|
|
@ -2865,6 +2931,7 @@ _BOX_WITH_ID = {
|
|||
'free': FreeBox,
|
||||
'jp2h': JP2HeaderBox,
|
||||
'lbl ': LabelBox,
|
||||
'nlst': NumberListBox,
|
||||
'pclr': PaletteBox,
|
||||
'res ': ResolutionBox,
|
||||
'resc': CaptureResolutionBox,
|
||||
|
|
|
|||
|
|
@ -20,46 +20,6 @@ from glymur import Jp2k
|
|||
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(os.name == "nt", "Temporary file issue on window.")
|
||||
class TestJPXOther(unittest.TestCase):
|
||||
|
|
@ -72,6 +32,16 @@ class TestJPXOther(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
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):
|
||||
"""Verify that we can handle a free box."""
|
||||
with warnings.catch_warnings():
|
||||
|
|
@ -81,3 +51,23 @@ class TestJPXOther(unittest.TestCase):
|
|||
self.assertEqual(j.box[16].box[0].box_id, 'free')
|
||||
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