Merge branch 'issue145' into devel

This commit is contained in:
jevans 2014-02-01 18:00:07 -05:00
commit f08b89fc64
3 changed files with 164 additions and 4 deletions

View file

@ -1,6 +1,7 @@
Feb 01, 2014 - Added read support for JPX FreeBox, NumberListBox, Data Reference
Box. Palette box now a 2D numpy array instead of a list of 1D arrays.
JP2 super box constructors now take optional box list argument.
Feb 01, 2014 - Added read support for JPX free, number list, data reference,
fragment table, and fragment list boxes. Palette box now a 2D numpy array
instead of a list of 1D arrays. JP2 super box constructors now take
optional box list argument.
Jan 28, 2014 - v0.5.10 Fixed bad warning when reader requirements box mask
length is unsupported.

View file

@ -835,7 +835,7 @@ class DataReferenceBox(Jp2kBox):
def __str__(self):
msg = Jp2kBox.__str__(self)
for box in enumerate(self.DR):
for box in self.DR:
msg += '\n ' + str(box)
return msg
@ -984,6 +984,134 @@ class FileTypeBox(Jp2kBox):
return box
class FragmentListBox(Jp2kBox):
"""Container for JPX fragment 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.
"""
def __init__(self, fragment_offset, fragment_length, data_reference,
length=0, offset=-1):
Jp2kBox.__init__(self, box_id='flst', longname='Fragment List')
self.fragment_offset = fragment_offset
self.fragment_length = fragment_length
self.data_reference = data_reference
self.length = length
self.offset = offset
def __repr__(self):
msg = "glymur.jp2box.FragmentListBox()"
return msg
def __str__(self):
msg = Jp2kBox.__str__(self)
for j in range(len(self.fragment_offset)):
msg += "\n Offset {0}: {1}"
msg += "\n Fragment Length {2}: {3}"
msg += "\n Data Reference {4}: {5}"
msg = msg.format(j, self.fragment_offset[j],
j, self.fragment_length[j],
j, self.data_reference[j])
return msg
@staticmethod
def parse(fptr, offset, length):
"""Parse JPX free box.
Parameters
----------
f : file
Open file object.
offset : int
Start position of box in bytes.
length : int
Length of the box in bytes.
Returns
-------
FreeBox instance
"""
read_buffer = fptr.read(2)
nf, = struct.unpack('>H', read_buffer)
read_buffer = fptr.read(nf * 14)
lst = struct.unpack('>' + 'QIH' * nf, read_buffer)
frag_offset = lst[0::3]
frag_len = lst[1::3]
data_reference = lst[2::3]
return FragmentListBox(frag_offset, frag_len, data_reference,
length=length, offset=offset)
class FragmentTableBox(Jp2kBox):
"""Container for JPX fragment table 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.
"""
def __init__(self, length=0, offset=-1):
Jp2kBox.__init__(self, box_id='ftbl', longname='Fragment Table')
self.length = length
self.offset = offset
def __repr__(self):
msg = "glymur.jp2box.FragmentTableBox()"
return msg
def __str__(self):
msg = Jp2kBox.__str__(self)
for box in self.box:
boxstr = str(box)
# Add indentation.
strs = [('\n ' + x) for x in boxstr.split('\n')]
msg += ''.join(strs)
return msg
@staticmethod
def parse(fptr, offset, length):
"""Parse JPX fragment table superbox box.
Parameters
----------
f : file
Open file object.
offset : int
Start position of box in bytes.
length : int
Length of the box in bytes.
Returns
-------
FreeBox instance
"""
box = FragmentTableBox(length=length, offset=offset)
# The FragmentTable box is a superbox, so go ahead and parse its child
# boxes.
box.box = box.parse_superbox(fptr)
return box
class FreeBox(Jp2kBox):
"""Container for JPX free box information.
@ -2999,6 +3127,8 @@ _BOX_WITH_ID = {
'jplh': CompositingLayerHeaderBox,
'jp2c': ContiguousCodestreamBox,
'free': FreeBox,
'flst': FragmentListBox,
'ftbl': FragmentTableBox,
'jp2h': JP2HeaderBox,
'lbl ': LabelBox,
'nlst': NumberListBox,

View file

@ -82,6 +82,35 @@ class TestJPXOther(unittest.TestCase):
self.assertEqual(len(jpx.box[-1].DR), 2)
def test_ftbl(self):
"""Verify that we can interpret Fragment Table boxes."""
# Copy the existing JPX file, add a fragment table box onto the end.
with tempfile.NamedTemporaryFile(suffix='.jpx') as tfile:
with open(self.jpxfile, 'rb') as ifile:
tfile.write(ifile.read())
write_buffer = struct.pack('>I4s', 32, b'ftbl')
tfile.write(write_buffer)
# Just one fragment list box
write_buffer = struct.pack('>I4s', 24, b'flst')
tfile.write(write_buffer)
# Simple offset, length, reference
write_buffer = struct.pack('>HQIH', 1, 4237, 170246, 3)
tfile.write(write_buffer)
tfile.flush()
with self.assertWarns(UserWarning):
jpx = Jp2k(tfile.name)
self.assertEqual(jpx.box[-1].box_id, 'ftbl')
self.assertEqual(jpx.box[-1].box[0].box_id, 'flst')
self.assertEqual(jpx.box[-1].box[0].fragment_offset, (4237,))
self.assertEqual(jpx.box[-1].box[0].fragment_length, (170246,))
self.assertEqual(jpx.box[-1].box[0].data_reference, (3,))
def test_nlst(self):
"""Verify that we can handle a free box."""
with warnings.catch_warnings():