Merge branch 'issue165' into devel

This commit is contained in:
John Evans 2014-02-11 16:16:48 -05:00
commit 1a4d6a54c6
4 changed files with 77 additions and 34 deletions

View file

@ -1837,10 +1837,10 @@ class ReaderRequirementsBox(Jp2kBox):
Jp2kBox.__init__(self, box_id='rreq', longname='Reader Requirements')
self.fuam = fuam
self.dcm = dcm
self.standard_flag = standard_flag
self.standard_mask = standard_mask
self.vendor_feature = vendor_feature
self.vendor_mask = vendor_mask
self.standard_flag = tuple(standard_flag)
self.standard_mask = tuple(standard_mask)
self.vendor_feature = tuple(vendor_feature)
self.vendor_mask = tuple(vendor_mask)
self.length = length
self.offset = offset
@ -1902,6 +1902,9 @@ class ReaderRequirementsBox(Jp2kBox):
read_buffer = fptr.read(1)
mask_length, = struct.unpack('>B', read_buffer)
if mask_length == 3:
return _parse_rreq3(fptr, length, offset)
# Fully Understands Aspect Mask
# Decodes Completely Mask
read_buffer = fptr.read(2 * mask_length)
@ -1911,6 +1914,7 @@ class ReaderRequirementsBox(Jp2kBox):
# The mask length tells us the format string to use when unpacking
# from the buffer read from file.
try:
mask_format = {1: 'B', 2: 'H', 4: 'I', 8: 'Q'}[mask_length]
fuam, dcm = struct.unpack('>' + mask_format * 2, read_buffer)
@ -1931,6 +1935,62 @@ class ReaderRequirementsBox(Jp2kBox):
return box
def _parse_rreq3(fptr, length, offset):
"""Parse a reader requirements box. Special case when mask length is 3."""
# Fully Understands Aspect Mask
# Decodes Completely Mask
read_buffer = fptr.read(2 * 3)
fuam = dcm = standard_flag = standard_mask = []
vendor_feature = vendor_mask = []
# The mask length tells us the format string to use when unpacking
# from the buffer read from file.
lst = struct.unpack('>BBBBBB', read_buffer)
fuam = lst[0] << 16 | lst[1] << 8 | lst[2]
dcm = lst[3] << 16 | lst[4] << 8 | lst[5]
read_buffer = fptr.read(2)
num_standard_features, = struct.unpack('>H', read_buffer)
fmt = '>' + 'HBBB' * num_standard_features
read_buffer = fptr.read(num_standard_features * 5)
lst = struct.unpack(fmt, read_buffer)
standard_flag = lst[0::4]
standard_mask = []
for j in range(num_standard_features):
items = lst[slice(j * 4 + 1, j * 4 + 4)]
mask = items[0] << 16 | items[1] << 8 | items[2]
standard_mask.append(mask)
read_buffer = fptr.read(2)
num_vendor_features, = struct.unpack('>H', read_buffer)
fmt = '>' + 'HBBB' * num_vendor_features
read_buffer = fptr.read(num_vendor_features * 5)
lst = struct.unpack(fmt, read_buffer)
# Each vendor feature consists of a 16-byte UUID plus a mask whose
# length is specified by, you guessed it, "mask_length".
entry_length = 16 + 3
read_buffer = fptr.read(num_vendor_features * entry_length)
vendor_feature = []
vendor_mask = []
for j in range(num_vendor_features):
ubuffer = read_buffer[j * entry_length:(j + 1) * entry_length]
vendor_feature.append(uuid.UUID(bytes=ubuffer[0:16]))
lst = struct.unpack('>BBB', ubuffer[16:])
vmask = lst[0] << 16 | lst[1] << 8 | lst[2]
vendor_mask.append(vmask)
box = ReaderRequirementsBox(fuam, dcm, standard_flag, standard_mask,
vendor_feature, vendor_mask,
length=length, offset=offset)
return box
def _parse_standard_flag(fptr, mask_length):
"""Construct standard flag, standard mask data from the file.

View file

@ -580,10 +580,7 @@ class TestWrap(unittest.TestCase):
def test_jpx_to_jp2(self):
"""basic test for rewrapping a jpx file"""
with warnings.catch_warnings():
# This file has a rreq mask length that we do not recognize.
warnings.simplefilter("ignore")
jpx = Jp2k(self.jpxfile)
jpx = Jp2k(self.jpxfile)
idx = [0, 1, 3, 6]
boxes = [jpx.box[idx] for idx in [0, 1, 3, 6]]
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:

View file

@ -135,7 +135,6 @@ class TestJPXWrap(unittest.TestCase):
jpx = jp2.wrap(tfile.name, boxes=boxes)
@unittest.skipIf(sys.hexversion < 0x03000000, "Warning assert on 2.x.")
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
class TestJPX(unittest.TestCase):
"""Test suite for other JPX boxes."""
@ -146,22 +145,18 @@ class TestJPX(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]),
def test_jpx_rreq_mask_length_3(self):
"""There are some JPX files with rreq mask length of 3."""
jpx = Jp2k(self.jpxfile)
self.assertEqual(jpx.box[2].box_id, 'rreq')
self.assertEqual(type(jpx.box[2]),
glymur.jp2box.ReaderRequirementsBox)
self.assertEqual(jpx.box[2].standard_flag,
(5, 42, 45, 2, 18, 19, 1, 8, 12, 31, 20))
def test_free_box(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)
j = Jp2k(self.jpxfile)
self.assertEqual(j.box[16].box[0].box_id, 'free')
self.assertEqual(type(j.box[16].box[0]), glymur.jp2box.FreeBox)
@ -183,10 +178,7 @@ class TestJPX(unittest.TestCase):
tfile.flush()
with warnings.catch_warnings():
# This file has a rreq mask length that we do not recognize.
warnings.simplefilter("ignore")
jpx = Jp2k(tfile.name)
jpx = Jp2k(tfile.name)
self.assertEqual(jpx.box[-1].box_id, 'dtbl')
self.assertEqual(len(jpx.box[-1].DR), 2)
@ -212,8 +204,7 @@ class TestJPX(unittest.TestCase):
tfile.flush()
with self.assertWarns(UserWarning):
jpx = Jp2k(tfile.name)
jpx = Jp2k(tfile.name)
self.assertEqual(jpx.box[-1].box_id, 'ftbl')
self.assertEqual(jpx.box[-1].box[0].box_id, 'flst')
@ -223,10 +214,7 @@ class TestJPX(unittest.TestCase):
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)
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)

View file

@ -379,9 +379,7 @@ class TestJp2k(unittest.TestCase):
def test_jpx_mult_codestreams_jp2_brand(self):
"""Read JPX codestream when jp2-compatible."""
# The file in question has multiple codestreams.
with warnings.catch_warnings():
warnings.simplefilter("ignore")
jpx = Jp2k(self.jpxfile)
jpx = Jp2k(self.jpxfile)
data = jpx.read()
if re.match(r"""1\.[0123]""", glymur.version.openjpeg_version):
# openjpeg 1.3 doesn't apply the palette, so it's a 2D image here