Merge branch 'issue199' into devel

This commit is contained in:
jevans 2014-03-18 18:48:47 -04:00
commit 869f8e9e3e
5 changed files with 52 additions and 29 deletions

View file

@ -17,7 +17,6 @@ codestreams.
# the base Segment class. # the base Segment class.
# pylint: disable=R0903 # pylint: disable=R0903
import collections
import math import math
import struct import struct
import sys import sys
@ -28,30 +27,18 @@ import numpy as np
from .core import LRCP, RLCP, RPCL, PCRL, CPRL from .core import LRCP, RLCP, RPCL, PCRL, CPRL
from .core import WAVELET_XFORM_9X7_IRREVERSIBLE from .core import WAVELET_XFORM_9X7_IRREVERSIBLE
from .core import WAVELET_XFORM_5X3_REVERSIBLE from .core import WAVELET_XFORM_5X3_REVERSIBLE
from .core import _Keydefaultdict
from .lib import openjp2 as opj2 from .lib import openjp2 as opj2
class _keydefaultdict(collections.defaultdict):
"""Unlisted keys help form their own error message.
Normally defaultdict uses a factory function with no input arguments, but
that's not quite the behavior we want.
"""
def __missing__(self, key):
if self.default_factory is None:
raise KeyError(key)
else:
ret = self[key] = self.default_factory(key)
return ret
_factory = lambda x: '{0} (invalid)'.format(x) _factory = lambda x: '{0} (invalid)'.format(x)
_PROGRESSION_ORDER_DISPLAY = _keydefaultdict(_factory, _PROGRESSION_ORDER_DISPLAY = _Keydefaultdict(_factory,
{ LRCP: 'LRCP', { LRCP: 'LRCP',
RLCP: 'RLCP', RLCP: 'RLCP',
RPCL: 'RPCL', RPCL: 'RPCL',
PCRL: 'PCRL', PCRL: 'PCRL',
CPRL: 'CPRL'}) CPRL: 'CPRL'})
_WAVELET_TRANSFORM_DISPLAY = _keydefaultdict(_factory, _WAVELET_TRANSFORM_DISPLAY = _Keydefaultdict(_factory,
{ WAVELET_XFORM_9X7_IRREVERSIBLE: '9-7 irreversible', { WAVELET_XFORM_9X7_IRREVERSIBLE: '9-7 irreversible',
WAVELET_XFORM_5X3_REVERSIBLE: '5-3 reversible'}) WAVELET_XFORM_5X3_REVERSIBLE: '5-3 reversible'})
@ -64,7 +51,7 @@ _PROFILE_4 = 4
_KNOWN_PROFILES = [_NO_PROFILE, _PROFILE_0, _PROFILE_1, _PROFILE_3, _PROFILE_4] _KNOWN_PROFILES = [_NO_PROFILE, _PROFILE_0, _PROFILE_1, _PROFILE_3, _PROFILE_4]
# How to display the codestream profile. # How to display the codestream profile.
_CAPABILITIES_DISPLAY = _keydefaultdict(_factory, _CAPABILITIES_DISPLAY = _Keydefaultdict(_factory,
{ _NO_PROFILE: 'no profile', { _NO_PROFILE: 'no profile',
_PROFILE_0: '0', _PROFILE_0: '0',
_PROFILE_1: '1', _PROFILE_1: '1',

View file

@ -1,8 +1,22 @@
"""Core definitions to be shared amongst the modules. """Core definitions to be shared amongst the modules.
""" """
import collections
import copy import copy
import lxml.etree as ET import lxml.etree as ET
class _Keydefaultdict(collections.defaultdict):
"""Unlisted keys help form their own error message.
Normally defaultdict uses a factory function with no input arguments, but
that's not quite the behavior we want.
"""
def __missing__(self, key):
if self.default_factory is None:
raise KeyError(key)
else:
ret = self[key] = self.default_factory(key)
return ret
# Progression order # Progression order
LRCP = 0 LRCP = 0
RLCP = 1 RLCP = 1
@ -57,24 +71,26 @@ YCC = 18
E_SRGB = 20 E_SRGB = 20
ROMM_RGB = 21 ROMM_RGB = 21
_COLORSPACE_MAP_DISPLAY = { _factory = lambda x: '{0} (unrecognized)'.format(x)
CMYK: 'CMYK', _COLORSPACE_MAP_DISPLAY = _Keydefaultdict(_factory,
SRGB: 'sRGB', { CMYK: 'CMYK',
GREYSCALE: 'greyscale', SRGB: 'sRGB',
YCC: 'YCC', GREYSCALE: 'greyscale',
E_SRGB: 'e-sRGB', YCC: 'YCC',
ROMM_RGB: 'ROMM-RGB'} E_SRGB: 'e-sRGB',
ROMM_RGB: 'ROMM-RGB'} )
# enumerated color channel types # enumerated color channel types
COLOR = 0 COLOR = 0
OPACITY = 1 OPACITY = 1
PRE_MULTIPLIED_OPACITY = 2 PRE_MULTIPLIED_OPACITY = 2
_UNSPECIFIED = 65535 _UNSPECIFIED = 65535
_COLOR_TYPE_MAP_DISPLAY = { _factory = lambda x: '{0} (invalid)'.format(x)
COLOR: 'color', _COLOR_TYPE_MAP_DISPLAY = _Keydefaultdict(_factory,
OPACITY: 'opacity', { COLOR: 'color',
PRE_MULTIPLIED_OPACITY: 'pre-multiplied opacity', OPACITY: 'opacity',
_UNSPECIFIED: 'unspecified'} PRE_MULTIPLIED_OPACITY: 'pre-multiplied opacity',
_UNSPECIFIED: 'unspecified'})
# color channel definitions. # color channel definitions.
RED = 1 RED = 1

View file

@ -419,6 +419,9 @@ class ColourSpecificationBox(Jp2kBox):
# enumerated colour space # enumerated colour space
read_buffer = fptr.read(4) read_buffer = fptr.read(4)
colorspace, = struct.unpack('>I', read_buffer) colorspace, = struct.unpack('>I', read_buffer)
if colorspace not in _COLORSPACE_MAP_DISPLAY.keys():
msg = "Unrecognized colorspace: {0}".format(colorspace)
warnings.warn(msg)
icc_profile = None icc_profile = None
else: else:

View file

@ -758,6 +758,13 @@ class TestJp2k_2_1(unittest.TestCase):
class TestJp2kOpjDataRoot(unittest.TestCase): class TestJp2kOpjDataRoot(unittest.TestCase):
"""These tests should be run by just about all configuration.""" """These tests should be run by just about all configuration."""
@unittest.skipIf(sys.hexversion < 0x03000000, "Test requires Python 3.3+")
def test_invalid_colorspace(self):
"""Should warn in case of invalid colorspace."""
filename = opj_data_file('input/nonregression/edf_c2_1103421.jp2')
with self.assertWarns(UserWarning):
jp2 = Jp2k(filename)
def test_no_cxform_pclr_jp2(self): def test_no_cxform_pclr_jp2(self):
"""Indices for pclr jpxfile if no color transform""" """Indices for pclr jpxfile if no color transform"""
filename = opj_data_file('input/conformance/file9.jp2') filename = opj_data_file('input/conformance/file9.jp2')

View file

@ -653,6 +653,16 @@ class TestPrintingOpjDataRoot(unittest.TestCase):
def tearDown(self): def tearDown(self):
pass pass
def test_invalid_colorspace(self):
"""An invalid colorspace shouldn't cause an error."""
filename = opj_data_file('input/nonregression/edf_c2_1103421.jp2')
with warnings.catch_warnings():
warnings.simplefilter("ignore")
jp2 = Jp2k(filename)
with patch('sys.stdout', new=StringIO()) as fake_out:
print(jp2)
def test_bad_rsiz(self): def test_bad_rsiz(self):
"""Should still be able to print if rsiz is bad, issue196""" """Should still be able to print if rsiz is bad, issue196"""
filename = opj_data_file('input/nonregression/edf_c2_1002767.jp2') filename = opj_data_file('input/nonregression/edf_c2_1002767.jp2')