Merge branch 'issue145' into devel
This commit is contained in:
commit
f08b89fc64
3 changed files with 164 additions and 4 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
Feb 01, 2014 - Added read support for JPX FreeBox, NumberListBox, Data Reference
|
Feb 01, 2014 - Added read support for JPX free, number list, data reference,
|
||||||
Box. Palette box now a 2D numpy array instead of a list of 1D arrays.
|
fragment table, and fragment list boxes. Palette box now a 2D numpy array
|
||||||
JP2 super box constructors now take optional box list argument.
|
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
|
Jan 28, 2014 - v0.5.10 Fixed bad warning when reader requirements box mask
|
||||||
length is unsupported.
|
length is unsupported.
|
||||||
|
|
|
||||||
132
glymur/jp2box.py
132
glymur/jp2box.py
|
|
@ -835,7 +835,7 @@ class DataReferenceBox(Jp2kBox):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
msg = Jp2kBox.__str__(self)
|
msg = Jp2kBox.__str__(self)
|
||||||
for box in enumerate(self.DR):
|
for box in self.DR:
|
||||||
msg += '\n ' + str(box)
|
msg += '\n ' + str(box)
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
|
@ -984,6 +984,134 @@ class FileTypeBox(Jp2kBox):
|
||||||
return box
|
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):
|
class FreeBox(Jp2kBox):
|
||||||
"""Container for JPX free box information.
|
"""Container for JPX free box information.
|
||||||
|
|
||||||
|
|
@ -2999,6 +3127,8 @@ _BOX_WITH_ID = {
|
||||||
'jplh': CompositingLayerHeaderBox,
|
'jplh': CompositingLayerHeaderBox,
|
||||||
'jp2c': ContiguousCodestreamBox,
|
'jp2c': ContiguousCodestreamBox,
|
||||||
'free': FreeBox,
|
'free': FreeBox,
|
||||||
|
'flst': FragmentListBox,
|
||||||
|
'ftbl': FragmentTableBox,
|
||||||
'jp2h': JP2HeaderBox,
|
'jp2h': JP2HeaderBox,
|
||||||
'lbl ': LabelBox,
|
'lbl ': LabelBox,
|
||||||
'nlst': NumberListBox,
|
'nlst': NumberListBox,
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,35 @@ class TestJPXOther(unittest.TestCase):
|
||||||
self.assertEqual(len(jpx.box[-1].DR), 2)
|
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):
|
def test_nlst(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():
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue