More negative tests. Incompatible change to ChannelDefinitionBox. #175
This commit is contained in:
parent
4caa13a955
commit
f8ced317db
5 changed files with 73 additions and 30 deletions
21
CHANGES.txt
21
CHANGES.txt
|
|
@ -1,13 +1,14 @@
|
|||
Feb 09, 2014 - Removed support for Python 2.6. Added write support for JP2
|
||||
UUID, DataEntryURL, Palette and Component Mapping boxes, JPX
|
||||
Association, NumberList and DataReference boxes. Added read
|
||||
support for JPX free, number list, data reference, fragment
|
||||
table, and fragment list boxes. Improved JPX Reader Requirements box
|
||||
support. Added get_printoptions, set_printoptions functions.
|
||||
Palette box now a 2D numpy array instead of a list of 1D arrays.
|
||||
JP2 super box constructors now take optional box list argument.
|
||||
Fixed bug where JPX files with more than one codestream but
|
||||
advertising jp2 compatibility were not being read.
|
||||
Feb 09, 2014 - Changed constructor for ChannelDefinition box. Removed support
|
||||
for Python 2.6. Added write support for JP2 UUID, DataEntryURL,
|
||||
Palette and Component Mapping boxes, JPX Association, NumberList
|
||||
and DataReference boxes. Added read support for JPX free,
|
||||
number list, data reference, fragment table, and fragment list
|
||||
boxes. Improved JPX Reader Requirements box support. Added
|
||||
get_printoptions, set_printoptions functions. Palette box now
|
||||
a 2D numpy array instead of a list of 1D arrays. JP2 super box
|
||||
constructors now take optional box list argument. Fixed bug
|
||||
where JPX files with more than one codestream but advertising
|
||||
jp2 compatibility were not being read.
|
||||
|
||||
Jan 28, 2014 - v0.5.10 Fixed bad warning when reader requirements box mask
|
||||
length is unsupported.
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ ChangeLog
|
|||
* added write support for JP2 UUID, dataEntryURL, palette, and component mapping boxes
|
||||
* added read/write support for JPX free, number list, and data reference boxes
|
||||
* Added read support for JPX fragment list and fragment table boxes
|
||||
* incompatible change to channel definition box constructor, channel_type and association are no longer keyword arguments
|
||||
* incompatible change to palette box constructor, it now takes a 2D numpy array instead of a list of 1D arrays
|
||||
|
||||
0.5.0 (September 16, 2013)
|
||||
|
|
|
|||
|
|
@ -359,7 +359,7 @@ channel, but we aren't doing that). ::
|
|||
|
||||
>>> from glymur.core import RED, GREEN, BLUE, WHOLE_IMAGE
|
||||
>>> asoc = [RED, GREEN, BLUE, WHOLE_IMAGE]
|
||||
>>> cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=ctype, association=asoc)
|
||||
>>> cdef = glymur.jp2box.ChannelDefinitionBox(ctype, asoc)
|
||||
>>> print(cdef)
|
||||
Channel Definition Box (cdef) @ (0, 0)
|
||||
Channel 0 (color) ==> (1)
|
||||
|
|
|
|||
|
|
@ -544,23 +544,28 @@ class ChannelDefinitionBox(Jp2kBox):
|
|||
association : list
|
||||
index of the associated color
|
||||
"""
|
||||
def __init__(self, index=None, channel_type=None, association=None,
|
||||
**kwargs):
|
||||
def __init__(self, channel_type, association, index=None, **kwargs):
|
||||
Jp2kBox.__init__(self, box_id='cdef', longname='Channel Definition')
|
||||
|
||||
# channel type and association must be specified.
|
||||
if channel_type is None or association is None:
|
||||
raise IOError("channel_type and association must be specified.")
|
||||
|
||||
if index is None:
|
||||
index = list(range(len(channel_type)))
|
||||
self.index = tuple(range(len(channel_type)))
|
||||
else:
|
||||
self.index = tuple(index)
|
||||
|
||||
if len(index) != len(channel_type) or len(index) != len(association):
|
||||
self.channel_type = tuple(channel_type)
|
||||
self.association = tuple(association)
|
||||
self.__dict__.update(**kwargs)
|
||||
self._validate()
|
||||
|
||||
def _validate(self):
|
||||
"""Verify that the box obeys the specifications."""
|
||||
# channel type and association must be specified.
|
||||
if not (len(self.index) == len(self.channel_type) == len(self.association)):
|
||||
msg = "Length of channel definition box inputs must be the same."
|
||||
raise IOError(msg)
|
||||
|
||||
# channel types must be one of 0, 1, 2, 65535
|
||||
if any(x not in [0, 1, 2, 65535] for x in channel_type):
|
||||
if any(x not in [0, 1, 2, 65535] for x in self.channel_type):
|
||||
msg = "Channel types must be in the set of\n\n"
|
||||
msg += " 0 - colour image data for associated color\n"
|
||||
msg += " 1 - opacity\n"
|
||||
|
|
@ -568,10 +573,6 @@ class ChannelDefinitionBox(Jp2kBox):
|
|||
msg += " 65535 - unspecified"
|
||||
raise IOError(msg)
|
||||
|
||||
self.index = tuple(index)
|
||||
self.channel_type = tuple(channel_type)
|
||||
self.association = tuple(association)
|
||||
self.__dict__.update(**kwargs)
|
||||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
|
|
@ -597,6 +598,7 @@ class ChannelDefinitionBox(Jp2kBox):
|
|||
def write(self, fptr):
|
||||
"""Write a channel definition box to file.
|
||||
"""
|
||||
self._validate()
|
||||
num_components = len(self.association)
|
||||
fptr.write(struct.pack('>I', 8 + 2 + num_components * 6))
|
||||
fptr.write('cdef'.encode('utf-8'))
|
||||
|
|
@ -634,9 +636,10 @@ class ChannelDefinitionBox(Jp2kBox):
|
|||
channel_type = data[1:num_components * 6:3]
|
||||
association = data[2:num_components * 6:3]
|
||||
|
||||
box = ChannelDefinitionBox(index=index, channel_type=channel_type,
|
||||
association=association, length=length,
|
||||
offset=offset)
|
||||
box = ChannelDefinitionBox(index=tuple(index),
|
||||
channel_type=tuple(channel_type),
|
||||
association=tuple(association),
|
||||
length=length, offset=offset)
|
||||
return box
|
||||
|
||||
|
||||
|
|
@ -795,7 +798,6 @@ class ComponentMappingBox(Jp2kBox):
|
|||
if _printoptions['short'] == True:
|
||||
return msg
|
||||
|
||||
|
||||
for k in range(len(self.component_index)):
|
||||
if self.mapping_type[k] == 1:
|
||||
msg += '\n Component {0} ==> palette column {1}'
|
||||
|
|
@ -1050,7 +1052,6 @@ class FileTypeBox(Jp2kBox):
|
|||
self.brand = brand
|
||||
self.minor_version = minor_version
|
||||
if compatibility_list is None:
|
||||
# see W0102, pylint
|
||||
self.compatibility_list = ['jp2 ']
|
||||
else:
|
||||
self.compatibility_list = compatibility_list
|
||||
|
|
@ -1718,6 +1719,15 @@ class PaletteBox(Jp2kBox):
|
|||
self.signed = signed
|
||||
self.length = length
|
||||
self.offset = offset
|
||||
self._validate()
|
||||
|
||||
def _validate(self):
|
||||
"""Verify that the box obeys the specifications."""
|
||||
if ((len(self.bits_per_component) != len(self.signed)) or
|
||||
(len(self.signed) != self.palette.shape[1])):
|
||||
msg = "The length of the 'bits_per_component' and the 'signed' "
|
||||
msg += "members must equal the number of columns of the palette."
|
||||
raise IOError(msg)
|
||||
|
||||
def __repr__(self):
|
||||
msg = "glymur.jp2box.PaletteBox({0}, bits_per_component={1}, "
|
||||
|
|
@ -1737,6 +1747,7 @@ class PaletteBox(Jp2kBox):
|
|||
def write(self, fptr):
|
||||
"""Write a Palette box to file.
|
||||
"""
|
||||
self._validate()
|
||||
bytes_per_row = sum(self.bits_per_component) / 8
|
||||
bytes_per_palette = bytes_per_row * self.palette.shape[0]
|
||||
box_length = 8 + 3 + self.palette.shape[1] + bytes_per_palette
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
|
||||
def test_cdef_no_inputs(self):
|
||||
"""channel_type and association are required inputs."""
|
||||
with self.assertRaises(IOError):
|
||||
with self.assertRaises(TypeError):
|
||||
glymur.jp2box.ChannelDefinitionBox()
|
||||
|
||||
def test_rgb_with_index(self):
|
||||
|
|
@ -451,6 +451,36 @@ class TestColourSpecificationBox(unittest.TestCase):
|
|||
colr.write(tfile)
|
||||
|
||||
|
||||
@unittest.skipIf(os.name == "nt",
|
||||
"Problems using NamedTemporaryFile on windows.")
|
||||
class TestPaletteBox(unittest.TestCase):
|
||||
"""Test suite for pclr box instantiation."""
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_mismatched_bitdepth_signed(self):
|
||||
"""bitdepth and signed arguments must have equal length"""
|
||||
palette = np.array([[255, 0, 255], [0, 255, 0]], dtype=np.uint8)
|
||||
bps = (8, 8, 8)
|
||||
signed = (False, False)
|
||||
with self.assertRaises(IOError):
|
||||
pclr = glymur.jp2box.PaletteBox(palette, bits_per_component=bps,
|
||||
signed=signed)
|
||||
|
||||
def test_mismatched_signed_palette(self):
|
||||
"""bitdepth and signed arguments must have equal length"""
|
||||
palette = np.array([[255, 0, 255], [0, 255, 0]], dtype=np.uint8)
|
||||
bps = (8, 8, 8, 8)
|
||||
signed = (False, False, False, False)
|
||||
with self.assertRaises(IOError):
|
||||
pclr = glymur.jp2box.PaletteBox(palette, bits_per_component=bps,
|
||||
signed=signed)
|
||||
|
||||
|
||||
class TestAppend(unittest.TestCase):
|
||||
"""Tests for append method."""
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue