parent
d7a3c4df27
commit
528fb3492d
4 changed files with 92 additions and 0 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
Mar 18, 2015 - Added support for JP2 bits per component box.
|
||||||
|
|
||||||
Jan 10, 2015 - v0.8.0 Reduced number of steps required for writing
|
Jan 10, 2015 - v0.8.0 Reduced number of steps required for writing
|
||||||
images. Deprecated old read and write methods in favor of
|
images. Deprecated old read and write methods in favor of
|
||||||
array-style slicing. Added ignore_pclr_cmap_cdef, verbose,
|
array-style slicing. Added ignore_pclr_cmap_cdef, verbose,
|
||||||
|
|
|
||||||
|
|
@ -1830,6 +1830,79 @@ class AssociationBox(Jp2kBox):
|
||||||
self._write_superbox(fptr, b'asoc')
|
self._write_superbox(fptr, b'asoc')
|
||||||
|
|
||||||
|
|
||||||
|
class BitsPerComponentBox(Jp2kBox):
|
||||||
|
"""Container for bits per component 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.
|
||||||
|
bpc : list
|
||||||
|
bits per component for each component
|
||||||
|
signed : list
|
||||||
|
True if signed, false if not, for each component
|
||||||
|
"""
|
||||||
|
box_id = 'bpcc'
|
||||||
|
longname = 'Bits Per Component'
|
||||||
|
|
||||||
|
def __init__(self, bpc, signed, length=0, offset=-1):
|
||||||
|
Jp2kBox.__init__(self)
|
||||||
|
self.length = length
|
||||||
|
self.offset = offset
|
||||||
|
self.bpc = bpc
|
||||||
|
self.signed = signed
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
msg = "glymur.jp2box.BitsPerComponentBox(box={0})".format(self.box)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
title = Jp2kBox.__str__(self)
|
||||||
|
if _printoptions['short'] is True:
|
||||||
|
return title
|
||||||
|
|
||||||
|
body = 'Bits per component: ['
|
||||||
|
body += ', '.join(str(x) for x in self.bpc)
|
||||||
|
body += ']'
|
||||||
|
body += '\n'
|
||||||
|
body += 'Signed: [' + ', '.join(str(x) for x in self.signed) + ']'
|
||||||
|
|
||||||
|
body = self._indent(body)
|
||||||
|
|
||||||
|
text = '\n'.join([title, body])
|
||||||
|
return text
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def parse(cls, fptr, offset, length):
|
||||||
|
"""Parse bits per component 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
|
||||||
|
"""
|
||||||
|
nbytes = length - 8
|
||||||
|
data = fptr.read(nbytes)
|
||||||
|
bpc = tuple(((x & 0x7f) + 1) for x in data)
|
||||||
|
signed = tuple(((x & 0x80) > 0) for x in data)
|
||||||
|
|
||||||
|
return cls(bpc, signed, length=length, offset=offset)
|
||||||
|
|
||||||
|
|
||||||
class JP2HeaderBox(Jp2kBox):
|
class JP2HeaderBox(Jp2kBox):
|
||||||
"""Container for JP2 header box information.
|
"""Container for JP2 header box information.
|
||||||
|
|
||||||
|
|
@ -3404,6 +3477,7 @@ class UUIDBox(Jp2kBox):
|
||||||
# Map each box ID to the corresponding class.
|
# Map each box ID to the corresponding class.
|
||||||
_BOX_WITH_ID = {
|
_BOX_WITH_ID = {
|
||||||
b'asoc': AssociationBox,
|
b'asoc': AssociationBox,
|
||||||
|
b'bpcc': BitsPerComponentBox,
|
||||||
b'cdef': ChannelDefinitionBox,
|
b'cdef': ChannelDefinitionBox,
|
||||||
b'cgrp': ColourGroupBox,
|
b'cgrp': ColourGroupBox,
|
||||||
b'cmap': ComponentMappingBox,
|
b'cmap': ComponentMappingBox,
|
||||||
|
|
|
||||||
|
|
@ -1092,3 +1092,8 @@ goodstuff_with_full_header = r"""Codestream:
|
||||||
Step size: [(0, 8), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10)]
|
Step size: [(0, 8), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10)]
|
||||||
SOD marker segment @ (164, 0)
|
SOD marker segment @ (164, 0)
|
||||||
EOC marker segment @ (115218, 0)"""
|
EOC marker segment @ (115218, 0)"""
|
||||||
|
|
||||||
|
bpcc = """Bits Per Component Box (bpcc) @ (62, 12)
|
||||||
|
Bits per component: [5, 5, 5, 1]
|
||||||
|
Signed: [False, False, False, False]"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -618,6 +618,17 @@ class TestPrintingOpjDataRoot(unittest.TestCase):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def test_bpcc(self):
|
||||||
|
"""BPCC boxes are rare :-)"""
|
||||||
|
self.maxDiff = None
|
||||||
|
filename = opj_data_file('input/nonregression/issue458.jp2')
|
||||||
|
jp2 = Jp2k(filename)
|
||||||
|
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||||
|
box = jp2.box[2].box[1]
|
||||||
|
print(box)
|
||||||
|
actual = fake_out.getvalue().strip()
|
||||||
|
self.assertEqual(actual, fixtures.bpcc)
|
||||||
|
|
||||||
def test_cinema_profile(self):
|
def test_cinema_profile(self):
|
||||||
"""Should print Cinema 2K when the profile is 3."""
|
"""Should print Cinema 2K when the profile is 3."""
|
||||||
filename = opj_data_file('input/nonregression/_00042.j2k')
|
filename = opj_data_file('input/nonregression/_00042.j2k')
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue