Merge branch 'issue78' into devel
This commit is contained in:
commit
7d3329db0f
6 changed files with 84 additions and 52 deletions
|
|
@ -58,7 +58,12 @@ class Codestream(object):
|
|||
|
||||
Attributes
|
||||
----------
|
||||
segment : list of marker segments
|
||||
segment : iterable
|
||||
list of marker segments
|
||||
offset : int
|
||||
Offset of the codestream from start of the file in bytes.
|
||||
length : int
|
||||
Length of the codestream in bytes.
|
||||
|
||||
Raises
|
||||
------
|
||||
|
|
@ -71,17 +76,22 @@ class Codestream(object):
|
|||
15444-1:2004 - Information technology -- JPEG 2000 image coding system:
|
||||
Core coding system
|
||||
"""
|
||||
def __init__(self, fptr, header_only=True):
|
||||
def __init__(self, fptr, length, header_only=True):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
fptr : file
|
||||
Open file object.
|
||||
length : int
|
||||
Length of the codestream in bytes.
|
||||
header_only : bool, optional
|
||||
If True, only marker segments in the main header are parsed.
|
||||
Supplying False may impose a large performance penalty.
|
||||
"""
|
||||
|
||||
self.offset = fptr.tell()
|
||||
self.length = length
|
||||
|
||||
# Number of components. Must be kept track of for the processing of
|
||||
# many segments.
|
||||
self._csiz = -1
|
||||
|
|
@ -107,9 +117,9 @@ class Codestream(object):
|
|||
|
||||
try:
|
||||
segment = self._process_marker_segment(fptr, marker_id)
|
||||
except InconsistentStartOfTileError as isote:
|
||||
except Exception as error:
|
||||
# Treat this as a warning.
|
||||
msg = str(isote)
|
||||
msg = str(error)
|
||||
warnings.warn(msg)
|
||||
break
|
||||
|
||||
|
|
@ -202,7 +212,11 @@ class Codestream(object):
|
|||
segment = _parse_sot_segment(fptr)
|
||||
if segment.offset not in self._tile_offset:
|
||||
self._tile_offset.append(segment.offset)
|
||||
self._tile_length.append(segment.psot)
|
||||
if segment.psot == 0:
|
||||
tile_part_length = self.offset + self.length - segment.offset - 2
|
||||
else:
|
||||
tile_part_length = segment.psot
|
||||
self._tile_length.append(tile_part_length)
|
||||
else:
|
||||
msg = "Inconsistent start-of-tile (SOT) marker segment "
|
||||
msg += "encountered in tile with index {0}. "
|
||||
|
|
|
|||
|
|
@ -644,7 +644,7 @@ class ContiguousCodestreamBox(Jp2kBox):
|
|||
-------
|
||||
ContiguousCodestreamBox instance
|
||||
"""
|
||||
main_header = Codestream(fptr, header_only=True)
|
||||
main_header = Codestream(fptr, length, header_only=True)
|
||||
box = ContiguousCodestreamBox(main_header, length=length,
|
||||
offset=offset)
|
||||
return box
|
||||
|
|
|
|||
|
|
@ -1033,7 +1033,8 @@ class Jp2k(Jp2kBox):
|
|||
"""
|
||||
with open(self.filename, 'rb') as fptr:
|
||||
if self._codec_format == _opj2.CODEC_J2K:
|
||||
codestream = Codestream(fptr, header_only=header_only)
|
||||
codestream = Codestream(fptr, self.length,
|
||||
header_only=header_only)
|
||||
else:
|
||||
box = [x for x in self.box if x.box_id == 'jp2c']
|
||||
if len(box) != 1:
|
||||
|
|
@ -1042,9 +1043,15 @@ class Jp2k(Jp2kBox):
|
|||
fptr.seek(box[0].offset)
|
||||
read_buffer = fptr.read(8)
|
||||
(box_length, _) = struct.unpack('>I4s', read_buffer)
|
||||
if box_length == 1:
|
||||
if box_length == 0:
|
||||
# The length of the box is presumed to last until the end
|
||||
# of the file. Compute the effective length of the box.
|
||||
box_length = os.path.getsize(fptr.name) - fptr.tell() + 8
|
||||
elif box_length == 1:
|
||||
# Seek past the XL field.
|
||||
read_buffer = fptr.read(8)
|
||||
codestream = Codestream(fptr, header_only=header_only)
|
||||
box_length, = struct.unpack('>Q', read_buffer)
|
||||
codestream = Codestream(fptr, box_length - 8,
|
||||
header_only=header_only)
|
||||
|
||||
return codestream
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@ except:
|
|||
class TestCodestream(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.jp2file = pkg_resources.resource_filename(glymur.__name__,
|
||||
"data/nemo.jp2")
|
||||
self.jp2file = glymur.data.nemo()
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
|
@ -95,5 +94,16 @@ class TestCodestream(unittest.TestCase):
|
|||
self.assertEqual(c.segment[2].length, 3)
|
||||
self.assertEqual(c.segment[2]._data, b'\x00')
|
||||
|
||||
def test_psot_is_zero(self):
|
||||
# Psot=0 in SOT is perfectly legal. Issue #78.
|
||||
filename = os.path.join(data_root,
|
||||
'input/nonregression/123.j2c')
|
||||
j = Jp2k(filename)
|
||||
c = j.get_codestream(header_only=False)
|
||||
|
||||
# The codestream is valid, so we should be able to get the entire
|
||||
# codestream, so the last one is EOC.
|
||||
self.assertEqual(c.segment[-1].marker_id, 'EOC')
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -823,12 +823,16 @@ class TestSuite(unittest.TestCase):
|
|||
self.assertTrue(True)
|
||||
|
||||
def test_NR_DEC_broken2_jp2_5_decode(self):
|
||||
jfile = os.path.join(data_root,
|
||||
'input/nonregression/broken2.jp2')
|
||||
# Null pointer access
|
||||
jfile = os.path.join(data_root, 'input/nonregression/broken2.jp2')
|
||||
with self.assertRaises(IOError):
|
||||
data = Jp2k(jfile).read()
|
||||
with warnings.catch_warnings():
|
||||
# Library warning, invalid number of subbands.
|
||||
warnings.simplefilter("ignore")
|
||||
data = Jp2k(jfile).read()
|
||||
self.assertTrue(True)
|
||||
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
def test_NR_DEC_broken3_jp2_6_decode(self):
|
||||
|
|
@ -845,7 +849,10 @@ class TestSuite(unittest.TestCase):
|
|||
jfile = os.path.join(data_root,
|
||||
'input/nonregression/broken4.jp2')
|
||||
with self.assertRaises(IOError):
|
||||
data = Jp2k(jfile).read()
|
||||
with warnings.catch_warnings():
|
||||
# Library warning, invalid number of subbands.
|
||||
warnings.simplefilter("ignore")
|
||||
data = Jp2k(jfile).read()
|
||||
self.assertTrue(True)
|
||||
|
||||
@unittest.skip("fprintf stderr output in r2343.")
|
||||
|
|
@ -6003,13 +6010,16 @@ class TestSuiteDump(unittest.TestCase):
|
|||
self.assertEqual(c.segment[6]._exponent,
|
||||
[8] + [9, 9, 10] * 5)
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2, 'assertWarns'.")
|
||||
def test_NR_broken2_jp2_dump(self):
|
||||
# Invalid marker ID on codestream.
|
||||
jfile = os.path.join(data_root,
|
||||
'input/nonregression/broken2.jp2')
|
||||
with self.assertRaises(IOError):
|
||||
jfile = os.path.join(data_root, 'input/nonregression/broken2.jp2')
|
||||
with self.assertWarns(UserWarning):
|
||||
jp2 = Jp2k(jfile)
|
||||
|
||||
self.assertEqual(jp2.box[-1].main_header.segment[-1].marker_id, 'QCC')
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
def test_NR_broken3_jp2_dump(self):
|
||||
|
|
@ -6137,12 +6147,16 @@ class TestSuiteDump(unittest.TestCase):
|
|||
self.assertEqual(c.segment[6]._exponent,
|
||||
[8] + [9, 9, 10] * 5)
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2, 'assertWarns'")
|
||||
def test_NR_broken4_jp2_dump(self):
|
||||
jfile = os.path.join(data_root,
|
||||
'input/nonregression/broken4.jp2')
|
||||
with self.assertRaises(IOError):
|
||||
# Has an invalid marker in the main header
|
||||
jfile = os.path.join(data_root, 'input/nonregression/broken4.jp2')
|
||||
with self.assertWarns(UserWarning):
|
||||
jp2 = Jp2k(jfile)
|
||||
|
||||
self.assertEqual(jp2.box[-1].main_header.segment[-1].marker_id, 'QCC')
|
||||
|
||||
def test_NR_file409752(self):
|
||||
jfile = os.path.join(data_root,
|
||||
'input/nonregression/file409752.jp2')
|
||||
|
|
@ -7800,17 +7814,19 @@ class TestSuite15(unittest.TestCase):
|
|||
self.assertTrue(True)
|
||||
|
||||
def test_NR_DEC_broken2_jp2_5_decode(self):
|
||||
jfile = os.path.join(data_root,
|
||||
'input/nonregression/broken2.jp2')
|
||||
with self.assertRaises(IOError):
|
||||
data = Jp2k(jfile).read()
|
||||
# Null pointer access
|
||||
jfile = os.path.join(data_root, 'input/nonregression/broken2.jp2')
|
||||
with self.assertRaises(ValueError):
|
||||
with warnings.catch_warnings():
|
||||
# Library warning, invalid number of subbands.
|
||||
warnings.simplefilter("ignore")
|
||||
data = Jp2k(jfile).read()
|
||||
self.assertTrue(True)
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
def test_NR_DEC_broken3_jp2_6_decode(self):
|
||||
jfile = os.path.join(data_root,
|
||||
'input/nonregression/broken3.jp2')
|
||||
jfile = os.path.join(data_root, 'input/nonregression/broken3.jp2')
|
||||
with self.assertWarns(UserWarning) as cw:
|
||||
# colr box has bad length.
|
||||
j = Jp2k(jfile)
|
||||
|
|
@ -7819,10 +7835,13 @@ class TestSuite15(unittest.TestCase):
|
|||
d = j.read()
|
||||
|
||||
def test_NR_DEC_broken4_jp2_7_decode(self):
|
||||
jfile = os.path.join(data_root,
|
||||
'input/nonregression/broken4.jp2')
|
||||
with self.assertRaises(IOError):
|
||||
data = Jp2k(jfile).read()
|
||||
# Null pointer access
|
||||
jfile = os.path.join(data_root, 'input/nonregression/broken4.jp2')
|
||||
with self.assertRaises(ValueError):
|
||||
with warnings.catch_warnings():
|
||||
# Library warning, invalid number of subbands.
|
||||
warnings.simplefilter("ignore")
|
||||
data = Jp2k(jfile).read()
|
||||
self.assertTrue(True)
|
||||
|
||||
@unittest.skip("fprintf stderr output in r2343.")
|
||||
|
|
|
|||
|
|
@ -73,25 +73,16 @@ class TestSuiteNegative(unittest.TestCase):
|
|||
with self.assertRaises(RuntimeError):
|
||||
j.write(data, psnr=[30, 35, 40], cratios=[2, 3, 4])
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
def test_NR_MarkerIsNotCompliant_j2k_dump(self):
|
||||
# SOT marker gives bad offset.
|
||||
relpath = 'input/nonregression/MarkerIsNotCompliant.j2k'
|
||||
jfile = os.path.join(data_root, relpath)
|
||||
jp2k = Jp2k(jfile)
|
||||
with self.assertWarns(UserWarning) as cw:
|
||||
c = jp2k.get_codestream(header_only=False)
|
||||
|
||||
# Verify that the last segment returned in the codestream is SOD,
|
||||
# not EOC. Codestream parsing should stop when we try to jump to
|
||||
# the end of SOT.
|
||||
self.assertEqual(c.segment[-1].marker_id, 'SOD')
|
||||
c = jp2k.get_codestream(header_only=False)
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
def test_NR_illegalcolortransform_dump(self):
|
||||
# SOT marker gives bad offset.
|
||||
# EOC marker is bad
|
||||
relpath = 'input/nonregression/illegalcolortransform.j2k'
|
||||
jfile = os.path.join(data_root, relpath)
|
||||
jp2k = Jp2k(jfile)
|
||||
|
|
@ -103,20 +94,11 @@ class TestSuiteNegative(unittest.TestCase):
|
|||
# the end of SOT.
|
||||
self.assertEqual(c.segment[-1].marker_id, 'SOD')
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
def test_NR_Cannotreaddatawithnosizeknown_j2k(self):
|
||||
# SOT marker gives bad offset.
|
||||
relpath = 'input/nonregression/Cannotreaddatawithnosizeknown.j2k'
|
||||
jfile = os.path.join(data_root, relpath)
|
||||
jp2k = Jp2k(jfile)
|
||||
with self.assertWarns(UserWarning) as cw:
|
||||
c = jp2k.get_codestream(header_only=False)
|
||||
|
||||
# Verify that the last segment returned in the codestream is SOD,
|
||||
# not EOC. Codestream parsing should stop when we try to jump to
|
||||
# the end of SOT.
|
||||
self.assertEqual(c.segment[-1].marker_id, 'SOD')
|
||||
c = jp2k.get_codestream(header_only=False)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_code_block_dimensions(self):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue