Added validation step for jp2 brand / any icc profile mismatch. #77
text_GBR.jp2 also shows this issue.
This commit is contained in:
parent
83b53c5f9b
commit
de7e6e1f0f
5 changed files with 55 additions and 9 deletions
|
|
@ -6,7 +6,7 @@ from .jp2k import Jp2k
|
||||||
from .jp2dump import jp2dump
|
from .jp2dump import jp2dump
|
||||||
|
|
||||||
from . import data
|
from . import data
|
||||||
from . import test
|
#from . import test
|
||||||
|
|
||||||
|
|
||||||
def runtests():
|
def runtests():
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ from .codestream import Codestream
|
||||||
from .core import SRGB
|
from .core import SRGB
|
||||||
from .core import GREYSCALE
|
from .core import GREYSCALE
|
||||||
from .core import PROGRESSION_ORDER
|
from .core import PROGRESSION_ORDER
|
||||||
|
from .core import ENUMERATED_COLORSPACE, RESTRICTED_ICC_PROFILE
|
||||||
from .jp2box import Jp2kBox
|
from .jp2box import Jp2kBox
|
||||||
from .jp2box import JPEG2000SignatureBox
|
from .jp2box import JPEG2000SignatureBox
|
||||||
from .jp2box import FileTypeBox
|
from .jp2box import FileTypeBox
|
||||||
|
|
@ -159,6 +160,23 @@ class Jp2k(Jp2kBox):
|
||||||
# boxes) here.
|
# boxes) here.
|
||||||
fptr.seek(0)
|
fptr.seek(0)
|
||||||
self.box = self.parse_superbox(fptr)
|
self.box = self.parse_superbox(fptr)
|
||||||
|
self._validate()
|
||||||
|
|
||||||
|
def _validate(self):
|
||||||
|
"""Validate the JPEG 2000 outermost superbox.
|
||||||
|
"""
|
||||||
|
# A jp2-branded file cannot contain an "any ICC profile
|
||||||
|
ftyp = self.box[1]
|
||||||
|
jp2h = [box for box in self.box if box.box_id == 'jp2h'][0]
|
||||||
|
colr = [box for box in jp2h.box if box.box_id == 'colr'][0]
|
||||||
|
if (((ftyp.brand == 'jp2 ') and
|
||||||
|
(colr.method not in (ENUMERATED_COLORSPACE,
|
||||||
|
RESTRICTED_ICC_PROFILE)))):
|
||||||
|
msg = "Color Specification box method must specify either an "
|
||||||
|
msg += "enumerated colorspace or a restricted ICC profile if the "
|
||||||
|
msg += "file type box brand is 'jp2 '."
|
||||||
|
warnings.warn(msg)
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable-msg=W0221
|
# pylint: disable-msg=W0221
|
||||||
def write(self, img_array, cratios=None, eph=False, psnr=None, numres=None,
|
def write(self, img_array, cratios=None, eph=False, psnr=None, numres=None,
|
||||||
|
|
|
||||||
|
|
@ -81,5 +81,16 @@ class TestSuite(unittest.TestCase):
|
||||||
#with self.assertRaises(OSError):
|
#with self.assertRaises(OSError):
|
||||||
# j2k.read(rlevel=-1)
|
# j2k.read(rlevel=-1)
|
||||||
|
|
||||||
|
def test_jp2_brand_vs_any_icc_profile(self):
|
||||||
|
# If 'jp2 ', then the method cannot be any icc profile.
|
||||||
|
jfile = os.path.join(data_root,
|
||||||
|
'jp2k-test/icc/balloon_eciRGBv2_ps_adobeplugin.jpf')
|
||||||
|
with self.assertWarns(UserWarning):
|
||||||
|
j2k = Jp2k(jfile)
|
||||||
|
|
||||||
|
# Should error out, it does not.
|
||||||
|
#with self.assertRaises(OSError):
|
||||||
|
# j2k.read(rlevel=-1)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
|
|
@ -990,7 +990,11 @@ class TestSuite(unittest.TestCase):
|
||||||
def test_NR_DEC_text_GBR_jp2_29_decode(self):
|
def test_NR_DEC_text_GBR_jp2_29_decode(self):
|
||||||
jfile = os.path.join(data_root,
|
jfile = os.path.join(data_root,
|
||||||
'input/nonregression/text_GBR.jp2')
|
'input/nonregression/text_GBR.jp2')
|
||||||
data = Jp2k(jfile).read()
|
with warnings.catch_warnings():
|
||||||
|
# brand is 'jp2 ', but has any icc profile.
|
||||||
|
warnings.simplefilter("ignore")
|
||||||
|
jp2 = Jp2k(jfile)
|
||||||
|
data = jp2.read()
|
||||||
self.assertTrue(True)
|
self.assertTrue(True)
|
||||||
|
|
||||||
def test_NR_DEC_pacs_ge_j2k_30_decode(self):
|
def test_NR_DEC_pacs_ge_j2k_30_decode(self):
|
||||||
|
|
@ -7260,7 +7264,10 @@ class TestSuiteDump(unittest.TestCase):
|
||||||
def test_NR_text_GBR_dump(self):
|
def test_NR_text_GBR_dump(self):
|
||||||
jfile = os.path.join(data_root,
|
jfile = os.path.join(data_root,
|
||||||
'input/nonregression/text_GBR.jp2')
|
'input/nonregression/text_GBR.jp2')
|
||||||
jp2 = Jp2k(jfile)
|
with warnings.catch_warnings():
|
||||||
|
# brand is 'jp2 ', but has any icc profile.
|
||||||
|
warnings.simplefilter("ignore")
|
||||||
|
jp2 = Jp2k(jfile)
|
||||||
|
|
||||||
ids = [box.box_id for box in jp2.box]
|
ids = [box.box_id for box in jp2.box]
|
||||||
lst = ['jP ', 'ftyp', 'rreq', 'jp2h',
|
lst = ['jP ', 'ftyp', 'rreq', 'jp2h',
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import pkg_resources
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import warnings
|
||||||
|
|
||||||
if sys.hexversion < 0x02070000:
|
if sys.hexversion < 0x02070000:
|
||||||
import unittest2 as unittest
|
import unittest2 as unittest
|
||||||
|
|
@ -277,9 +278,12 @@ class TestPrinting(unittest.TestCase):
|
||||||
"OPJ_DATA_ROOT environment variable not set")
|
"OPJ_DATA_ROOT environment variable not set")
|
||||||
def test_icc_profile(self):
|
def test_icc_profile(self):
|
||||||
filename = os.path.join(data_root, 'input/nonregression/text_GBR.jp2')
|
filename = os.path.join(data_root, 'input/nonregression/text_GBR.jp2')
|
||||||
j = glymur.Jp2k(filename)
|
with warnings.catch_warnings():
|
||||||
|
# brand is 'jp2 ', but has any icc profile.
|
||||||
|
warnings.simplefilter("ignore")
|
||||||
|
jp2 = Jp2k(filename)
|
||||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||||
print(j.box[3].box[1])
|
print(jp2.box[3].box[1])
|
||||||
actual = fake_out.getvalue().strip()
|
actual = fake_out.getvalue().strip()
|
||||||
lin27 = ["Colour Specification Box (colr) @ (179, 1339)",
|
lin27 = ["Colour Specification Box (colr) @ (179, 1339)",
|
||||||
" Method: any ICC profile",
|
" Method: any ICC profile",
|
||||||
|
|
@ -902,10 +906,13 @@ class TestPrinting(unittest.TestCase):
|
||||||
# ICC profiles may be used in JP2, but the approximation field should
|
# ICC profiles may be used in JP2, but the approximation field should
|
||||||
# be zero unless we have jpx. This file does both.
|
# be zero unless we have jpx. This file does both.
|
||||||
filename = os.path.join(data_root, 'input/nonregression/text_GBR.jp2')
|
filename = os.path.join(data_root, 'input/nonregression/text_GBR.jp2')
|
||||||
j = glymur.Jp2k(filename)
|
with warnings.catch_warnings():
|
||||||
|
# brand is 'jp2 ', but has any icc profile.
|
||||||
|
warnings.simplefilter("ignore")
|
||||||
|
jp2 = Jp2k(filename)
|
||||||
|
|
||||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||||
print(j.box[3].box[1])
|
print(jp2.box[3].box[1])
|
||||||
actual = fake_out.getvalue().strip()
|
actual = fake_out.getvalue().strip()
|
||||||
lines = ["Colour Specification Box (colr) @ (179, 1339)",
|
lines = ["Colour Specification Box (colr) @ (179, 1339)",
|
||||||
" Method: any ICC profile",
|
" Method: any ICC profile",
|
||||||
|
|
@ -942,10 +949,13 @@ class TestPrinting(unittest.TestCase):
|
||||||
def test_uuid(self):
|
def test_uuid(self):
|
||||||
# UUID box
|
# UUID box
|
||||||
filename = os.path.join(data_root, 'input/nonregression/text_GBR.jp2')
|
filename = os.path.join(data_root, 'input/nonregression/text_GBR.jp2')
|
||||||
j = glymur.Jp2k(filename)
|
with warnings.catch_warnings():
|
||||||
|
# brand is 'jp2 ', but has any icc profile.
|
||||||
|
warnings.simplefilter("ignore")
|
||||||
|
jp2 = Jp2k(filename)
|
||||||
|
|
||||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||||
print(j.box[4])
|
print(jp2.box[4])
|
||||||
actual = fake_out.getvalue().strip()
|
actual = fake_out.getvalue().strip()
|
||||||
lines = ['UUID Box (uuid) @ (1544, 25)',
|
lines = ['UUID Box (uuid) @ (1544, 25)',
|
||||||
' UUID: 3a0d0218-0ae9-4115-b376-4bca41ce0e71',
|
' UUID: 3a0d0218-0ae9-4115-b376-4bca41ce0e71',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue