Merge branch 'issue204' into devel
This commit is contained in:
commit
8a448600d2
3 changed files with 66 additions and 44 deletions
|
|
@ -316,9 +316,6 @@ class ColourSpecificationBox(Jp2kBox):
|
|||
|
||||
self.method = method
|
||||
self.precedence = precedence
|
||||
|
||||
if approximation not in (0, 1, 2, 3, 4):
|
||||
warnings.warn("Invalid approximation: {0}".format(approximation))
|
||||
self.approximation = approximation
|
||||
|
||||
self.colorspace = colorspace
|
||||
|
|
@ -326,14 +323,19 @@ class ColourSpecificationBox(Jp2kBox):
|
|||
self.length = length
|
||||
self.offset = offset
|
||||
|
||||
self._validate()
|
||||
self._validate(writing=False)
|
||||
|
||||
def _validate(self):
|
||||
def _validate(self, writing=False):
|
||||
"""Verify that the box obeys the specifications."""
|
||||
if self.colorspace is not None and self.icc_profile is not None:
|
||||
raise IOError("colorspace and icc_profile cannot both be set.")
|
||||
msg = "Colorspace and icc_profile cannot both be set."
|
||||
self._dispatch_validation_error(msg, writing=writing)
|
||||
if self.method not in (1, 2, 3, 4):
|
||||
raise IOError("Invalid method.")
|
||||
msg = "Invalid method.".format(self.method)
|
||||
self._dispatch_validation_error(msg, writing=writing)
|
||||
if self.approximation not in (0, 1, 2, 3, 4):
|
||||
msg = "Invalid approximation: {0}".format(self.approximation)
|
||||
self._dispatch_validation_error(msg, writing=writing)
|
||||
|
||||
def _write_validate(self):
|
||||
"""In addition to constructor validation steps, run validation steps
|
||||
|
|
@ -341,15 +343,15 @@ class ColourSpecificationBox(Jp2kBox):
|
|||
if self.colorspace is None:
|
||||
msg = "Writing Colour Specification boxes without enumerated "
|
||||
msg += "colorspaces is not supported at this time."
|
||||
raise IOError(msg)
|
||||
self._dispatch_validation_error(msg, writing=True)
|
||||
|
||||
if self.icc_profile is None:
|
||||
if self.colorspace not in [SRGB, GREYSCALE, YCC]:
|
||||
msg = "Colorspace should correspond to one of SRGB, GREYSCALE, "
|
||||
msg += "or YCC."
|
||||
raise IOError(msg)
|
||||
self._dispatch_validation_error(msg, writing=True)
|
||||
|
||||
self._validate()
|
||||
self._validate(writing=True)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
|
|
@ -607,15 +609,15 @@ class ChannelDefinitionBox(Jp2kBox):
|
|||
self.channel_type = tuple(channel_type)
|
||||
self.association = tuple(association)
|
||||
self.__dict__.update(**kwargs)
|
||||
self._validate()
|
||||
self._validate(writing=False)
|
||||
|
||||
def _validate(self):
|
||||
def _validate(self, writing=False):
|
||||
"""Verify that the box obeys the specifications."""
|
||||
# channel type and association must be specified.
|
||||
if not ((len(self.index) == len(self.channel_type)) and
|
||||
(len(self.channel_type) == len(self.association))):
|
||||
msg = "Length of channel definition box inputs must be the same."
|
||||
raise IOError(msg)
|
||||
self._dispatch_validation_error(msg, writing=writing)
|
||||
|
||||
# channel types must be one of 0, 1, 2, 65535
|
||||
if any(x not in [0, 1, 2, 65535] for x in self.channel_type):
|
||||
|
|
@ -624,7 +626,7 @@ class ChannelDefinitionBox(Jp2kBox):
|
|||
msg += " 1 - opacity\n"
|
||||
msg += " 2 - premultiplied opacity\n"
|
||||
msg += " 65535 - unspecified"
|
||||
raise IOError(msg)
|
||||
self._dispatch_validation_error(msg, writing=writing)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
|
|
@ -651,7 +653,7 @@ class ChannelDefinitionBox(Jp2kBox):
|
|||
def write(self, fptr):
|
||||
"""Write a channel definition box to file.
|
||||
"""
|
||||
self._validate()
|
||||
self._validate(writing=True)
|
||||
num_components = len(self.association)
|
||||
fptr.write(struct.pack('>I', 8 + 2 + num_components * 6))
|
||||
fptr.write('cdef'.encode('utf-8'))
|
||||
|
|
@ -993,23 +995,23 @@ class DataReferenceBox(Jp2kBox):
|
|||
self.DR = data_entry_url_boxes
|
||||
self.length = length
|
||||
self.offset = offset
|
||||
self._validate()
|
||||
self._validate(writing=False)
|
||||
|
||||
def _validate(self):
|
||||
def _validate(self, writing=False):
|
||||
"""Verify that the box obeys the specifications."""
|
||||
for box in self.DR:
|
||||
if box.box_id != 'url ':
|
||||
msg = 'All child boxes of a data reference box must be data '
|
||||
msg += 'entry URL boxes.'
|
||||
raise IOError(msg)
|
||||
self._dispatch_validation_error(msg, writing=writing)
|
||||
|
||||
def _write_validate(self):
|
||||
"""Verify that the box obeys the specifications for writing.
|
||||
"""
|
||||
if len(self.DR) == 0:
|
||||
msg = "A data reference box cannot be empty when written to a file."
|
||||
raise IOError(msg)
|
||||
self._validate()
|
||||
self._dispatch_validation_error(msg, writing=True)
|
||||
self._validate(writing=True)
|
||||
|
||||
def write(self, fptr):
|
||||
"""Write a Data Reference box to file.
|
||||
|
|
@ -1227,18 +1229,21 @@ class FragmentListBox(Jp2kBox):
|
|||
self.data_reference = data_reference
|
||||
self.length = length
|
||||
self.offset = offset
|
||||
self._validate(writing=False)
|
||||
|
||||
def _validate(self):
|
||||
def _validate(self, writing=False):
|
||||
"""Validate internal correctness."""
|
||||
if (((len(self.fragment_offset) != len(self.fragment_length)) or
|
||||
(len(self.fragment_length) != len(self.data_reference)))):
|
||||
msg = "The lengths of the fragment offsets, fragment lengths, and "
|
||||
msg += "data reference items must be the same."
|
||||
raise IOError(msg)
|
||||
self._dispatch_validation_error(msg, writing=writing)
|
||||
if any([x <= 0 for x in self.fragment_offset]):
|
||||
raise IOError("Fragment offsets must all be positive.")
|
||||
msg = "Fragment offsets must all be positive."
|
||||
self._dispatch_validation_error(msg, writing=writing)
|
||||
if any([x <= 0 for x in self.fragment_length]):
|
||||
raise IOError("Fragment lengths must all be positive.")
|
||||
msg = "Fragment lengths must all be positive."
|
||||
self._dispatch_validation_error(msg, writing=writing)
|
||||
|
||||
def __repr__(self):
|
||||
msg = "glymur.jp2box.FragmentListBox()"
|
||||
|
|
@ -1262,7 +1267,7 @@ class FragmentListBox(Jp2kBox):
|
|||
def write(self, fptr):
|
||||
"""Write a fragment list box to file.
|
||||
"""
|
||||
self._validate()
|
||||
self._validate(writing=True)
|
||||
num_items = len(self.fragment_offset)
|
||||
length = 8 + 2 + num_items * 14
|
||||
fptr.write(struct.pack('>I', length))
|
||||
|
|
@ -1357,18 +1362,18 @@ class FragmentTableBox(Jp2kBox):
|
|||
|
||||
return box
|
||||
|
||||
def _validate(self):
|
||||
def _validate(self, writing=False):
|
||||
"""Self-validate the box before writing."""
|
||||
box_ids = [box.box_id for box in self.box]
|
||||
if len(box_ids) != 1 or box_ids[0] != 'flst':
|
||||
msg = "Fragment table boxes must have a single fragment list "
|
||||
msg += "box as a child box."
|
||||
raise IOError(msg)
|
||||
self._dispatch_validation_error(msg, writing=writing)
|
||||
|
||||
def write(self, fptr):
|
||||
"""Write a fragment table box to file.
|
||||
"""
|
||||
self._validate()
|
||||
self._validate(writing=True)
|
||||
self._write_superbox(fptr)
|
||||
|
||||
|
||||
|
|
@ -1779,15 +1784,15 @@ class PaletteBox(Jp2kBox):
|
|||
self.signed = signed
|
||||
self.length = length
|
||||
self.offset = offset
|
||||
self._validate()
|
||||
self._validate(writing=False)
|
||||
|
||||
def _validate(self):
|
||||
def _validate(self, writing=False):
|
||||
"""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)
|
||||
self._dispatch_validation_error(msg, writing=writing)
|
||||
|
||||
def __repr__(self):
|
||||
msg = "glymur.jp2box.PaletteBox({0}, bits_per_component={1}, "
|
||||
|
|
@ -1807,7 +1812,7 @@ class PaletteBox(Jp2kBox):
|
|||
def write(self, fptr):
|
||||
"""Write a Palette box to file.
|
||||
"""
|
||||
self._validate()
|
||||
self._validate(writing=True)
|
||||
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
|
||||
|
|
|
|||
|
|
@ -340,6 +340,7 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
with self.assertRaises((IOError, OSError)):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03000000, "Needs unittest in 3.x.")
|
||||
def test_bad_type(self):
|
||||
"""Channel types are limited to 0, 1, 2, 65535
|
||||
Should reject if not all of index, channel_type, association the
|
||||
|
|
@ -347,17 +348,18 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
"""
|
||||
channel_type = (COLOR, COLOR, 3)
|
||||
association = (RED, GREEN, BLUE)
|
||||
with self.assertRaises(IOError):
|
||||
with self.assertWarns(UserWarning):
|
||||
glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
|
||||
association=association)
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03000000, "Needs unittest in 3.x.")
|
||||
def test_wrong_lengths(self):
|
||||
"""Should reject if not all of index, channel_type, association the
|
||||
same length.
|
||||
"""
|
||||
channel_type = (COLOR, COLOR)
|
||||
association = (RED, GREEN, BLUE)
|
||||
with self.assertRaises(IOError):
|
||||
with self.assertWarns(UserWarning):
|
||||
glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
|
||||
association=association)
|
||||
|
||||
|
|
@ -443,19 +445,21 @@ class TestColourSpecificationBox(unittest.TestCase):
|
|||
self.assertEqual(colr.colorspace, glymur.core.SRGB)
|
||||
self.assertIsNone(colr.icc_profile)
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03030000, "Requires 3.3+")
|
||||
def test_colr_with_cspace_and_icc(self):
|
||||
"""Colour specification boxes can't have both."""
|
||||
with self.assertRaises((OSError, IOError)):
|
||||
with self.assertWarns(UserWarning):
|
||||
colorspace = glymur.core.SRGB
|
||||
rawb = b'\x01\x02\x03\x04'
|
||||
glymur.jp2box.ColourSpecificationBox(colorspace=colorspace,
|
||||
icc_profile=rawb)
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03030000, "Requires 3.3+")
|
||||
def test_colr_with_bad_method(self):
|
||||
"""colr must have a valid method field"""
|
||||
colorspace = glymur.core.SRGB
|
||||
method = -1
|
||||
with self.assertRaises(IOError):
|
||||
with self.assertWarns(UserWarning):
|
||||
glymur.jp2box.ColourSpecificationBox(colorspace=colorspace,
|
||||
method=method)
|
||||
|
||||
|
|
@ -490,21 +494,23 @@ class TestPaletteBox(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
pass
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03000000, "Needs unittest in 3.x.")
|
||||
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):
|
||||
with self.assertWarns(UserWarning):
|
||||
pclr = glymur.jp2box.PaletteBox(palette, bits_per_component=bps,
|
||||
signed=signed)
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03000000, "Needs unittest in 3.x.")
|
||||
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):
|
||||
with self.assertWarns(UserWarning):
|
||||
pclr = glymur.jp2box.PaletteBox(palette, bits_per_component=bps,
|
||||
signed=signed)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import struct
|
|||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
import warnings
|
||||
|
||||
import lxml.etree as ET
|
||||
|
||||
import glymur
|
||||
|
|
@ -207,13 +209,14 @@ class TestJPXWrap(unittest.TestCase):
|
|||
with self.assertRaises(IOError):
|
||||
jp2.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03000000, "Needs unittest in 3.x.")
|
||||
def test_deurl_child_of_dtbl(self):
|
||||
"""Data reference boxes can only contain data entry url boxes."""
|
||||
jp2 = Jp2k(self.jp2file)
|
||||
boxes = [jp2.box[idx] for idx in [0, 1, 2, 4]]
|
||||
|
||||
ftyp = glymur.jp2box.FileTypeBox()
|
||||
with self.assertRaises(IOError):
|
||||
with self.assertWarns(UserWarning):
|
||||
dref = glymur.jp2box.DataReferenceBox([ftyp])
|
||||
|
||||
# Try to get around it by appending the ftyp box after creation.
|
||||
|
|
@ -337,7 +340,9 @@ class TestJPX(unittest.TestCase):
|
|||
offset = [89]
|
||||
length = [1132288]
|
||||
reference = [0, 0]
|
||||
flst = glymur.jp2box.FragmentListBox(offset, length, reference)
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
flst = glymur.jp2box.FragmentListBox(offset, length, reference)
|
||||
with self.assertRaises(IOError):
|
||||
with tempfile.TemporaryFile() as tfile:
|
||||
flst.write(tfile)
|
||||
|
|
@ -347,8 +352,10 @@ class TestJPX(unittest.TestCase):
|
|||
offset = [0]
|
||||
length = [1132288]
|
||||
reference = [0]
|
||||
flst = glymur.jp2box.FragmentListBox(offset, length, reference)
|
||||
with self.assertRaises(IOError):
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
flst = glymur.jp2box.FragmentListBox(offset, length, reference)
|
||||
with self.assertRaises((IOError, OSError)):
|
||||
with tempfile.TemporaryFile() as tfile:
|
||||
flst.write(tfile)
|
||||
|
||||
|
|
@ -357,14 +364,18 @@ class TestJPX(unittest.TestCase):
|
|||
offset = [89]
|
||||
length = [0]
|
||||
reference = [0]
|
||||
flst = glymur.jp2box.FragmentListBox(offset, length, reference)
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
flst = glymur.jp2box.FragmentListBox(offset, length, reference)
|
||||
with self.assertRaises(IOError):
|
||||
with tempfile.TemporaryFile() as tfile:
|
||||
flst.write(tfile)
|
||||
|
||||
def test_ftbl_boxes_empty(self):
|
||||
"""A fragment table box must have at least one child box."""
|
||||
ftbl = glymur.jp2box.FragmentTableBox()
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
ftbl = glymur.jp2box.FragmentTableBox()
|
||||
with self.assertRaises(IOError):
|
||||
with tempfile.TemporaryFile() as tfile:
|
||||
ftbl.write(tfile)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue