Starting write support for ftbl and flst boxes. #175
This commit is contained in:
parent
5e76d1cf39
commit
cd606e1f9d
2 changed files with 120 additions and 3 deletions
|
|
@ -148,7 +148,8 @@ class Jp2kBox(object):
|
|||
box = UnknownBox(box_id, offset=start, length=num_bytes,
|
||||
longname='Unknown')
|
||||
|
||||
if fptr.tell() != start + 8:
|
||||
cpos = fptr.tell()
|
||||
if not ((cpos == start + 8) or (cpos == start + 16)):
|
||||
# If the file pointer has advanced, then the KeyError
|
||||
# ocurred during the parsing of the box.
|
||||
pass
|
||||
|
|
@ -1122,6 +1123,18 @@ class FragmentListBox(Jp2kBox):
|
|||
self.length = length
|
||||
self.offset = offset
|
||||
|
||||
def _validate(self):
|
||||
"""Validate internal correctness."""
|
||||
if (((len(self.fragment_offset) != len(self.fragment_length)) or
|
||||
(len(self.fragment_length) != len(self.data_reference)))):
|
||||
msg = "The lengths of the fragment offsets, fragment lengths, and "
|
||||
msg += "data reference items must be the same."
|
||||
raise IOError(msg)
|
||||
if any([x <= 0 for x in self.fragment_offset]):
|
||||
raise IOError("Fragment offsets must all be positive.")
|
||||
if any([x <= 0 for x in self.fragment_length]):
|
||||
raise IOError("Fragment lengths must all be positive.")
|
||||
|
||||
def __repr__(self):
|
||||
msg = "glymur.jp2box.FragmentListBox()"
|
||||
return msg
|
||||
|
|
@ -1141,6 +1154,22 @@ class FragmentListBox(Jp2kBox):
|
|||
|
||||
return msg
|
||||
|
||||
def write(self, fptr):
|
||||
"""Write a fragment list box to file.
|
||||
"""
|
||||
self._validate()
|
||||
num_items = len(self.fragment_offset)
|
||||
length = 8 + 2 + num_items * 14
|
||||
fptr.write(struct.pack('>I', length))
|
||||
fptr.write(self.box_id.encode())
|
||||
fptr.write(struct.pack('>H', num_items))
|
||||
for j in range(num_items):
|
||||
write_buffer = struct.pack('>QIH',
|
||||
self.fragment_offset[j],
|
||||
self.fragment_length[j],
|
||||
self.data_reference[j])
|
||||
fptr.write(write_buffer)
|
||||
|
||||
@staticmethod
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse JPX free box.
|
||||
|
|
@ -1184,10 +1213,11 @@ class FragmentTableBox(Jp2kBox):
|
|||
longname : str
|
||||
more verbose description of the box.
|
||||
"""
|
||||
def __init__(self, length=0, offset=-1):
|
||||
def __init__(self, box=None, length=0, offset=-1):
|
||||
Jp2kBox.__init__(self, box_id='ftbl', longname='Fragment Table')
|
||||
self.length = length
|
||||
self.offset = offset
|
||||
self.box = box if box is not None else []
|
||||
|
||||
def __repr__(self):
|
||||
msg = "glymur.jp2box.FragmentTableBox()"
|
||||
|
|
@ -1212,7 +1242,7 @@ class FragmentTableBox(Jp2kBox):
|
|||
|
||||
Returns
|
||||
-------
|
||||
FreeBox instance
|
||||
FragmentTableBox instance
|
||||
"""
|
||||
box = FragmentTableBox(length=length, offset=offset)
|
||||
|
||||
|
|
@ -1222,6 +1252,20 @@ class FragmentTableBox(Jp2kBox):
|
|||
|
||||
return box
|
||||
|
||||
def _validate(self):
|
||||
"""Self-validate the box before writing."""
|
||||
box_ids = [box.box_id for box in self.box]
|
||||
if len(box_ids) != 1 or box_ids[0] != 'flst':
|
||||
msg = "Fragment table boxes must have a single fragment list "
|
||||
msg += "box as a child box."
|
||||
raise IOError(msg)
|
||||
|
||||
def write(self, fptr):
|
||||
"""Write a fragment table box to file.
|
||||
"""
|
||||
self._validate()
|
||||
self._write_superbox(fptr)
|
||||
|
||||
|
||||
|
||||
class FreeBox(Jp2kBox):
|
||||
|
|
|
|||
|
|
@ -41,6 +41,34 @@ class TestJPXWrap(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
os.unlink(self.xmlfile)
|
||||
|
||||
def test_ftbl(self):
|
||||
"""Write a fragment table box."""
|
||||
# Add a negative test where offset < 0
|
||||
# Add a negative test where length < 0
|
||||
# Add a negative test where ref > 0 but no data reference box.
|
||||
# Add a negative test where more than one flst
|
||||
# Add negative test where ftbl contained in a superbox.
|
||||
jp2 = Jp2k(self.jp2file)
|
||||
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
|
||||
|
||||
# The ftyp box must be modified to jpx.
|
||||
boxes[1].brand = 'jpx '
|
||||
boxes[1].compatibility_list = ['jp2 ', 'jpxb']
|
||||
|
||||
offset = [89]
|
||||
length = [1132288]
|
||||
reference = [0]
|
||||
flst = glymur.jp2box.FragmentListBox(offset, length, reference)
|
||||
ftbl = glymur.jp2box.FragmentTableBox(box=[flst])
|
||||
boxes.append(ftbl)
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix=".jpx") as tfile:
|
||||
jpx = jp2.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
self.assertEqual(jpx.box[1].compatibility_list, ['jp2 ', 'jpxb'])
|
||||
self.assertEqual(jpx.box[-1].box_id, 'ftbl')
|
||||
self.assertEqual(jpx.box[-1].box[0].box_id, 'flst')
|
||||
|
||||
def test_jpxb_compatibility(self):
|
||||
"""Wrap JP2 to JPX, state jpxb compatibility"""
|
||||
jp2 = Jp2k(self.jp2file)
|
||||
|
|
@ -194,6 +222,51 @@ class TestJPX(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_flst_lens_not_the_same(self):
|
||||
"""A fragment list box items must be the same length."""
|
||||
offset = [89]
|
||||
length = [1132288]
|
||||
reference = [0, 0]
|
||||
flst = glymur.jp2box.FragmentListBox(offset, length, reference)
|
||||
with self.assertRaises(IOError):
|
||||
with tempfile.TemporaryFile() as tfile:
|
||||
flst.write(tfile)
|
||||
|
||||
def test_flst_offsets_not_positive(self):
|
||||
"""A fragment list box offsets must be positive."""
|
||||
offset = [0]
|
||||
length = [1132288]
|
||||
reference = [0]
|
||||
flst = glymur.jp2box.FragmentListBox(offset, length, reference)
|
||||
with self.assertRaises(IOError):
|
||||
with tempfile.TemporaryFile() as tfile:
|
||||
flst.write(tfile)
|
||||
|
||||
def test_flst_lengths_not_positive(self):
|
||||
"""A fragment list box lengths must be positive."""
|
||||
offset = [89]
|
||||
length = [0]
|
||||
reference = [0]
|
||||
flst = glymur.jp2box.FragmentListBox(offset, length, reference)
|
||||
with self.assertRaises(IOError):
|
||||
with tempfile.TemporaryFile() as tfile:
|
||||
flst.write(tfile)
|
||||
|
||||
def test_ftbl_boxes_empty(self):
|
||||
"""A fragment table box must have at least one child box."""
|
||||
ftbl = glymur.jp2box.FragmentTableBox()
|
||||
with self.assertRaises(IOError):
|
||||
with tempfile.TemporaryFile() as tfile:
|
||||
ftbl.write(tfile)
|
||||
|
||||
def test_ftbl_child_not_flst(self):
|
||||
"""A fragment table box can only contain a fragment list."""
|
||||
free = glymur.jp2box.FreeBox()
|
||||
ftbl = glymur.jp2box.FragmentTableBox(box=[free])
|
||||
with self.assertRaises(IOError):
|
||||
with tempfile.TemporaryFile() as tfile:
|
||||
ftbl.write(tfile)
|
||||
|
||||
def test_jpx_rreq_mask_length_3(self):
|
||||
"""There are some JPX files with rreq mask length of 3."""
|
||||
jpx = Jp2k(self.jpxfile)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue