Merge branch 'issue84' into devel
This commit is contained in:
commit
181b31ff94
5 changed files with 232 additions and 18 deletions
|
|
@ -6,7 +6,6 @@ from .jp2k import Jp2k
|
|||
from .jp2dump import jp2dump
|
||||
|
||||
from . import data
|
||||
#from . import test
|
||||
|
||||
|
||||
def runtests():
|
||||
|
|
|
|||
195
glymur/jp2box.py
195
glymur/jp2box.py
|
|
@ -520,6 +520,195 @@ class ChannelDefinitionBox(Jp2kBox):
|
|||
return box
|
||||
|
||||
|
||||
class CodestreamHeaderBox(Jp2kBox):
|
||||
"""Container for codestream header 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.
|
||||
box : list
|
||||
List of boxes contained in this superbox.
|
||||
"""
|
||||
def __init__(self, length=0, offset=-1):
|
||||
Jp2kBox.__init__(self, box_id='jpch', longname='Codestream Header')
|
||||
self.length = length
|
||||
self.offset = offset
|
||||
self.box = []
|
||||
|
||||
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 codestream header box.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fptr : file
|
||||
Open file object.
|
||||
offset : int
|
||||
Start position of box in bytes.
|
||||
length : int
|
||||
Length of the box in bytes.
|
||||
|
||||
Returns
|
||||
-------
|
||||
AssociationBox instance
|
||||
"""
|
||||
box = CodestreamHeaderBox(length=length, offset=offset)
|
||||
|
||||
# The codestream header box is a superbox, so go ahead and parse its
|
||||
# child boxes.
|
||||
box.box = box.parse_superbox(fptr)
|
||||
|
||||
return box
|
||||
|
||||
|
||||
class CompositingLayerHeaderBox(Jp2kBox):
|
||||
"""Container for compositing layer header 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.
|
||||
box : list
|
||||
List of boxes contained in this superbox.
|
||||
"""
|
||||
def __init__(self, length=0, offset=-1):
|
||||
Jp2kBox.__init__(self, box_id='jplh',
|
||||
longname='Compositing Layer Header')
|
||||
self.length = length
|
||||
self.offset = offset
|
||||
self.box = []
|
||||
|
||||
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 compositing layer header box.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fptr : file
|
||||
Open file object.
|
||||
offset : int
|
||||
Start position of box in bytes.
|
||||
length : int
|
||||
Length of the box in bytes.
|
||||
|
||||
Returns
|
||||
-------
|
||||
AssociationBox instance
|
||||
"""
|
||||
box = CompositingLayerHeaderBox(length=length, offset=offset)
|
||||
|
||||
# This box is a superbox, so go ahead and parse its # child boxes.
|
||||
box.box = box.parse_superbox(fptr)
|
||||
|
||||
return box
|
||||
|
||||
|
||||
class JP2HeaderBox(Jp2kBox):
|
||||
"""Container for JP2 header 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.
|
||||
box : list
|
||||
List of boxes contained in this superbox.
|
||||
"""
|
||||
def __init__(self, length=0, offset=-1):
|
||||
Jp2kBox.__init__(self, box_id='jp2h', longname='JP2 Header')
|
||||
self.length = length
|
||||
self.offset = offset
|
||||
self.box = []
|
||||
|
||||
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
|
||||
|
||||
def write(self, fptr):
|
||||
"""Write a JP2 Header box to file.
|
||||
"""
|
||||
# Write the contained boxes, then come back and write the length.
|
||||
orig_pos = fptr.tell()
|
||||
fptr.write(struct.pack('>I', 0))
|
||||
fptr.write('jp2h'.encode())
|
||||
for box in self.box:
|
||||
box.write(fptr)
|
||||
|
||||
end_pos = fptr.tell()
|
||||
fptr.seek(orig_pos)
|
||||
fptr.write(struct.pack('>I', end_pos - orig_pos))
|
||||
fptr.seek(end_pos)
|
||||
|
||||
@staticmethod
|
||||
def parse(fptr, offset, length):
|
||||
"""Parse JPEG 2000 header box.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fptr : file
|
||||
Open file object.
|
||||
offset : int
|
||||
Start position of box in bytes.
|
||||
length : int
|
||||
Length of the box in bytes.
|
||||
|
||||
Returns
|
||||
-------
|
||||
JP2HeaderBox instance
|
||||
"""
|
||||
box = JP2HeaderBox(length=length, offset=offset)
|
||||
|
||||
# The JP2 header box is a superbox, so go ahead and parse its child
|
||||
# boxes.
|
||||
box.box = box.parse_superbox(fptr)
|
||||
|
||||
return box
|
||||
|
||||
|
||||
class ComponentMappingBox(Jp2kBox):
|
||||
"""Container for channel identification information.
|
||||
|
||||
|
|
@ -2509,11 +2698,13 @@ _BOX_WITH_ID = {
|
|||
'cdef': ChannelDefinitionBox,
|
||||
'cmap': ComponentMappingBox,
|
||||
'colr': ColourSpecificationBox,
|
||||
'jP ': JPEG2000SignatureBox,
|
||||
'ftyp': FileTypeBox,
|
||||
'ihdr': ImageHeaderBox,
|
||||
'jp2h': JP2HeaderBox,
|
||||
'jP ': JPEG2000SignatureBox,
|
||||
'jpch': CodestreamHeaderBox,
|
||||
'jplh': CompositingLayerHeaderBox,
|
||||
'jp2c': ContiguousCodestreamBox,
|
||||
'jp2h': JP2HeaderBox,
|
||||
'lbl ': LabelBox,
|
||||
'pclr': PaletteBox,
|
||||
'res ': ResolutionBox,
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
from .test_callbacks import TestCallbacks as callbacks
|
||||
from .test_codestream import TestCodestream as codestream
|
||||
from .test_config import TestSuite as config
|
||||
from .test_jp2k import TestJp2k as jp2k
|
||||
from .test_icc import TestICC as icc
|
||||
from .test_printing import TestPrinting as printing
|
||||
from .test_opj_suite import TestSuite as suite
|
||||
from .test_opj_suite import TestSuiteDump as suitedump
|
||||
from .test_opj_suite_write import TestSuiteWrite as suitew
|
||||
from .test_opj_suite_neg import TestSuiteNegative as suiteneg
|
||||
from .test_jp2box import TestJp2Boxes as box
|
||||
|
|
@ -20,15 +20,11 @@ try:
|
|||
format_corpus_data_root = os.environ['FORMAT_CORPUS_DATA_ROOT']
|
||||
except KeyError:
|
||||
format_corpus_data_root = None
|
||||
except:
|
||||
raise
|
||||
|
||||
try:
|
||||
opj_data_root = os.environ['OPJ_DATA_ROOT']
|
||||
except KeyError:
|
||||
opj_data_root = None
|
||||
except:
|
||||
raise
|
||||
|
||||
|
||||
@unittest.skipIf(format_corpus_data_root is None,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@ from glymur.jp2box import *
|
|||
from glymur.core import COLOR, OPACITY
|
||||
from glymur.core import RED, GREEN, BLUE, GREY, WHOLE_IMAGE
|
||||
|
||||
try:
|
||||
format_corpus_data_root = os.environ['FORMAT_CORPUS_DATA_ROOT']
|
||||
except KeyError:
|
||||
format_corpus_data_root = None
|
||||
|
||||
|
||||
# Doc tests should be run as well.
|
||||
def load_tests(loader, tests, ignore):
|
||||
|
|
@ -673,5 +678,39 @@ class TestJp2Boxes(unittest.TestCase):
|
|||
with self.assertRaises(IOError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
|
||||
class TestJpxBoxes(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
@unittest.skipIf(format_corpus_data_root is None,
|
||||
"FORMAT_CORPUS_DATA_ROOT environment variable not set")
|
||||
def test_codestream_header(self):
|
||||
# Should recognize codestream header box.
|
||||
jfile = os.path.join(format_corpus_data_root,
|
||||
'jp2k-formats/balloon.jpf')
|
||||
jpx = Jp2k(jfile)
|
||||
|
||||
# This superbox just happens to be empty.
|
||||
self.assertEqual(jpx.box[4].box_id, 'jpch')
|
||||
self.assertEqual(len(jpx.box[4].box), 0)
|
||||
|
||||
@unittest.skipIf(format_corpus_data_root is None,
|
||||
"FORMAT_CORPUS_DATA_ROOT environment variable not set")
|
||||
def test_compositing_layer_header(self):
|
||||
# Should recognize compositing layer header box.
|
||||
jfile = os.path.join(format_corpus_data_root,
|
||||
'jp2k-formats/balloon.jpf')
|
||||
jpx = Jp2k(jfile)
|
||||
|
||||
# This superbox just happens to be empty.
|
||||
self.assertEqual(jpx.box[5].box_id, 'jplh')
|
||||
self.assertEqual(len(jpx.box[5].box), 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue