Merge branch 'devel' of github.com:quintusdias/glymur into devel

This commit is contained in:
John Evans 2013-09-15 10:32:20 -04:00
commit ddecb8a740
11 changed files with 141 additions and 82 deletions

View file

@ -2,6 +2,9 @@
""" """
import sys import sys
from glymur import version
__version__ = version.version
from .jp2k import Jp2k from .jp2k import Jp2k
from .jp2dump import jp2dump from .jp2dump import jp2dump

View file

@ -1,4 +1,8 @@
"""Access to JPEG2000 files. """This file is part of glymur, a Python interface for accessing JPEG 2000.
http://glymur.readthedocs.org
Copyright 2013 John Evans
License: MIT License: MIT
""" """
@ -31,15 +35,9 @@ from .jp2box import ColourSpecificationBox, ContiguousCodestreamBox
from .jp2box import ImageHeaderBox from .jp2box import ImageHeaderBox
from .lib import openjpeg as opj from .lib import openjpeg as opj
from .lib import openjp2 as opj2 from .lib import openjp2 as opj2
from . import version
from .lib import c as libc from .lib import c as libc
if opj.OPENJPEG is None and opj2.OPENJP2 is None:
OPENJPEG_VERSION = '0.0.0'
elif opj2.OPENJP2 is None:
OPENJPEG_VERSION = opj.version()
else:
OPENJPEG_VERSION = opj2.version()
class Jp2k(Jp2kBox): class Jp2k(Jp2kBox):
"""JPEG 2000 file. """JPEG 2000 file.
@ -192,7 +190,7 @@ class Jp2k(Jp2kBox):
cparams : CompressionParametersType(ctypes.Structure) cparams : CompressionParametersType(ctypes.Structure)
Corresponds to cparameters_t type in openjp2 headers. Corresponds to cparameters_t type in openjp2 headers.
""" """
if re.match(r"""1\.\d\.\d""", OPENJPEG_VERSION): if version.openjpeg_version_tuple[0] == 1:
cparams = opj.set_default_encoder_parameters() cparams = opj.set_default_encoder_parameters()
else: else:
cparams = opj2.set_default_encoder_parameters() cparams = opj2.set_default_encoder_parameters()
@ -428,8 +426,13 @@ class Jp2k(Jp2kBox):
# set encode format # set encode format
cinfo = opj.create_compress(cparams.codec_fmt) cinfo = opj.create_compress(cparams.codec_fmt)
event_mgr = opj.EventMgrType(None, None, None) event_mgr = opj.EventMgrType()
#opj.set_event_mgr(cparams, ctypes.byref(event_mgr), None) _info_handler = _INFO_CALLBACK if verbose else None
event_mgr.info_handler = _info_handler
event_mgr.warning_handler = ctypes.cast(_WARNING_CALLBACK,
ctypes.c_void_p)
event_mgr.error_handler = ctypes.cast(_ERROR_CALLBACK,
ctypes.c_void_p)
opj.setup_encoder(cinfo, ctypes.byref(cparams), image) opj.setup_encoder(cinfo, ctypes.byref(cparams), image)
@ -437,7 +440,9 @@ class Jp2k(Jp2kBox):
# allocate memory for all tiles # allocate memory for all tiles
cio = opj.cio_open(cinfo) cio = opj.cio_open(cinfo)
opj.encode(cinfo, cio, image) if not opj.encode(cinfo, cio, image):
raise IOError("Encode error.")
pos = opj.cio_tell(cio) pos = opj.cio_tell(cio)
ss = ctypes.string_at(cio.contents.buffer, pos) ss = ctypes.string_at(cio.contents.buffer, pos)
@ -773,41 +778,45 @@ class Jp2k(Jp2kBox):
raise IOError(msg) raise IOError(msg)
with ExitStack() as stack: with ExitStack() as stack:
# Set decoding parameters. try:
dparameters = opj.DecompressionParametersType() # Set decoding parameters.
opj.set_default_decoder_parameters(ctypes.byref(dparameters)) dparameters = opj.DecompressionParametersType()
dparameters.cp_reduce = rlevel opj.set_default_decoder_parameters(ctypes.byref(dparameters))
dparameters.decod_format = self._codec_format dparameters.cp_reduce = rlevel
dparameters.decod_format = self._codec_format
infile = self.filename.encode()
nelts = opj.PATH_LEN - len(infile)
infile += b'0' * nelts
dparameters.infile = infile
dinfo = opj.create_decompress(dparameters.decod_format)
event_mgr = opj.EventMgrType()
info_handler = ctypes.cast(_INFO_CALLBACK, ctypes.c_void_p)
event_mgr.info_handler = info_handler if verbose else None
event_mgr.warning_handler = ctypes.cast(_WARNING_CALLBACK,
ctypes.c_void_p)
event_mgr.error_handler = ctypes.cast(_ERROR_CALLBACK,
ctypes.c_void_p)
opj.set_event_mgr(dinfo, ctypes.byref(event_mgr))
opj.setup_decoder(dinfo, dparameters)
with open(self.filename, 'rb') as fptr:
src = fptr.read()
cio = opj.cio_open(dinfo, src)
image = opj.decode(dinfo, cio)
stack.callback(opj.image_destroy, image)
stack.callback(opj.destroy_decompress, dinfo)
stack.callback(opj.cio_close, cio)
data = extract_image_cube(image)
infile = self.filename.encode() except ValueError:
nelts = opj.PATH_LEN - len(infile) opj2.check_error(0)
infile += b'0' * nelts
dparameters.infile = infile
dinfo = opj.create_decompress(dparameters.decod_format)
event_mgr = opj.EventMgrType()
info_handler = ctypes.cast(_INFO_CALLBACK, ctypes.c_void_p)
event_mgr.info_handler = info_handler if verbose else None
event_mgr.warning_handler = ctypes.cast(_WARNING_CALLBACK,
ctypes.c_void_p)
event_mgr.error_handler = ctypes.cast(_ERROR_CALLBACK,
ctypes.c_void_p)
opj.set_event_mgr(dinfo, ctypes.byref(event_mgr))
opj.setup_decoder(dinfo, dparameters)
with open(self.filename, 'rb') as fptr:
src = fptr.read()
cio = opj.cio_open(dinfo, src)
image = opj.decode(dinfo, cio)
stack.callback(opj.image_destroy, image)
stack.callback(opj.destroy_decompress, dinfo)
stack.callback(opj.cio_close, cio)
data = extract_image_cube(image)
if data.shape[2] == 1: if data.shape[2] == 1:
# The third dimension has just a single layer. Make the image # The third dimension has just a single layer. Make the image
@ -987,8 +996,8 @@ class Jp2k(Jp2kBox):
glymur.LibraryNotFoundError glymur.LibraryNotFoundError
If glymur is unable to load the openjp2 library. If glymur is unable to load the openjp2 library.
""" """
if opj2.OPENJP2 is None: if version.openjpeg_version_tuple[0] < 2:
raise LibraryNotFoundError("You must have the development version " raise LibraryNotFoundError("You must have at least version 2.0.0"
"of OpenJP2 installed before using " "of OpenJP2 installed before using "
"this functionality.") "this functionality.")
@ -1330,7 +1339,7 @@ def _populate_comptparms(img_array, cparams):
comp_prec = 16 comp_prec = 16
numrows, numcols, num_comps = img_array.shape numrows, numcols, num_comps = img_array.shape
if re.match(r"""1\.\d\.\d""", OPENJPEG_VERSION): if version.openjpeg_version_tuple[0] == 1:
comptparms = (opj.ImageComptParmType * num_comps)() comptparms = (opj.ImageComptParmType * num_comps)()
else: else:
comptparms = (opj2.ImageComptParmType * num_comps)() comptparms = (opj2.ImageComptParmType * num_comps)()
@ -1465,18 +1474,18 @@ _CMPFUNC = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_char_p, ctypes.c_void_p)
def _default_error_handler(msg, _): def _default_error_handler(msg, _):
"""Default error handler callback for openjpeg library.""" """Default error handler callback for libopenjp2."""
msg = "OpenJPEG library error: {0}".format(msg.decode('utf-8').rstrip()) msg = "OpenJPEG library error: {0}".format(msg.decode('utf-8').rstrip())
opj2.set_error_message(msg) opj2.set_error_message(msg)
def _default_info_handler(msg, _): def _default_info_handler(msg, _):
"""Default info handler callback for openjpeg library.""" """Default info handler callback."""
print("[INFO] {0}".format(msg.decode('utf-8').rstrip())) print("[INFO] {0}".format(msg.decode('utf-8').rstrip()))
def _default_warning_handler(library_msg, _): def _default_warning_handler(library_msg, _):
"""Default warning handler callback for openjpeg library.""" """Default warning handler callback."""
library_msg = library_msg.decode('utf-8').rstrip() library_msg = library_msg.decode('utf-8').rstrip()
msg = "OpenJPEG library warning: {0}".format(library_msg) msg = "OpenJPEG library warning: {0}".format(library_msg)
warnings.warn(msg) warnings.warn(msg)

View file

@ -685,7 +685,7 @@ def check_error(status):
raise IOError("OpenJPEG function failure.") raise IOError("OpenJPEG function failure.")
# These library functions all return an error status. Circumvent that and # These library functions all return an error status. Circumvent that and
# force # them to raise an exception. # force them to raise an exception.
FCNS = ['opj_decode', 'opj_decode_tile_data', 'opj_end_compress', FCNS = ['opj_decode', 'opj_decode_tile_data', 'opj_end_compress',
'opj_encode', 'opj_end_decompress', 'opj_get_decoded_tile', 'opj_encode', 'opj_end_decompress', 'opj_get_decoded_tile',
'opj_read_header', 'opj_read_tile_header', 'opj_set_decode_area', 'opj_read_header', 'opj_read_tile_header', 'opj_set_decode_area',

View file

@ -527,8 +527,7 @@ def encode(cinfo, cio, image):
OPENJPEG.opj_encode.argtypes = argtypes OPENJPEG.opj_encode.argtypes = argtypes
OPENJPEG.opj_encode.restype = ctypes.c_int OPENJPEG.opj_encode.restype = ctypes.c_int
status = OPENJPEG.opj_encode(cinfo, cio, image) status = OPENJPEG.opj_encode(cinfo, cio, image)
if not status: return status
raise RuntimeError("opj_encode failed")
def destroy_decompress(dinfo): def destroy_decompress(dinfo):

View file

@ -10,13 +10,6 @@ import numpy as np
import glymur import glymur
# Need to know the version of the openjpeg software. If openjpeg is not
# installed, we use # '0.0.0'
OPENJPEG_VERSION = '0.0.0'
if glymur.lib.openjp2.OPENJP2 is not None:
OPENJPEG_VERSION = glymur.lib.openjp2.version()
elif glymur.lib.openjpeg.OPENJPEG is not None:
OPENJPEG_VERSION = glymur.lib.openjpeg.version()
# Need to know of the libopenjp2 version is the official 2.0.0 release and NOT # Need to know of the libopenjp2 version is the official 2.0.0 release and NOT
# the 2.0+ development version. # the 2.0+ development version.

View file

@ -117,8 +117,10 @@ class TestConfig(unittest.TestCase):
""" """
with patch('glymur.lib.openjp2.OPENJP2', new=None): with patch('glymur.lib.openjp2.OPENJP2', new=None):
with patch('glymur.lib.openjpeg.OPENJPEG', new=None): with patch('glymur.lib.openjpeg.OPENJPEG', new=None):
with self.assertRaises(glymur.jp2k.LibraryNotFoundError): with patch('glymur.version.openjpeg_version_tuple',
glymur.Jp2k(self.jp2file).read_bands() new=(0, 0, 0)):
with self.assertRaises(glymur.jp2k.LibraryNotFoundError):
glymur.Jp2k(self.jp2file).read_bands()
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows") @unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
def test_write_without_library(self): def test_write_without_library(self):

View file

@ -34,7 +34,6 @@ import glymur
from glymur import Jp2k from glymur import Jp2k
from .fixtures import OPENJP2_IS_V2_OFFICIAL from .fixtures import OPENJP2_IS_V2_OFFICIAL
from .fixtures import OPENJPEG_VERSION
from .fixtures import OPJ_DATA_ROOT, opj_data_file from .fixtures import OPJ_DATA_ROOT, opj_data_file
@ -192,7 +191,7 @@ class TestJp2k_2_1(unittest.TestCase):
j.read(rlevel=1) j.read(rlevel=1)
@unittest.skipIf(re.match(r"""1\.\d.\d""", OPENJPEG_VERSION), @unittest.skipIf(glymur.version.openjpeg_version_tuple[0] < 2,
"Not tested for 1.x") "Not tested for 1.x")
class TestJp2k_2_0(unittest.TestCase): class TestJp2k_2_0(unittest.TestCase):
"""Test suite requiring at least version 2.0""" """Test suite requiring at least version 2.0"""
@ -679,8 +678,7 @@ class TestJp2k15(unittest.TestCase):
j2k.read(layer=1) j2k.read(layer=1)
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows") @unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
@unittest.skipIf(re.match(r"""1\.[01234]\.\d""", @unittest.skipIf(glymur.version.openjpeg_version_tuple[1] < 5,
OPENJPEG_VERSION) is not None,
"Writing only supported with openjpeg version 1.5+.") "Writing only supported with openjpeg version 1.5+.")
def test_2d_rgb(self): def test_2d_rgb(self):
"""RGB must have at least 3 components.""" """RGB must have at least 3 components."""
@ -723,8 +721,7 @@ class TestJp2k15(unittest.TestCase):
b'<test>this is a test</test>') b'<test>this is a test</test>')
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows") @unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
@unittest.skipIf(re.match(r"""1\.[345]\.\d""", @unittest.skipIf(glymur.version.openjpeg_version_tuple[0] < 2,
OPENJPEG_VERSION) is not None,
"Segfault on official v1.x series.") "Segfault on official v1.x series.")
def test_openjpeg_library_message(self): def test_openjpeg_library_message(self):
"""Verify the error message produced by the openjpeg library""" """Verify the error message produced by the openjpeg library"""
@ -760,8 +757,6 @@ class TestJp2k15(unittest.TestCase):
j.read(rlevel=1) j.read(rlevel=1)
@unittest.skipIf(re.match(r"""1\.[012]\.\d""", OPENJPEG_VERSION),
"Unsupported version of openjpeg.")
class TestJp2k(unittest.TestCase): class TestJp2k(unittest.TestCase):
"""Test suite for openjpeg software starting at 1.3""" """Test suite for openjpeg software starting at 1.3"""

View file

@ -45,7 +45,7 @@ import numpy as np
from glymur import Jp2k from glymur import Jp2k
import glymur import glymur
from .fixtures import OPENJPEG_VERSION, OPENJP2_IS_V2_OFFICIAL, OPJ_DATA_ROOT from .fixtures import OPENJP2_IS_V2_OFFICIAL, OPJ_DATA_ROOT
from .fixtures import mse, peak_tolerance, read_pgx, opj_data_file from .fixtures import mse, peak_tolerance, read_pgx, opj_data_file
@ -601,7 +601,7 @@ class TestSuite(unittest.TestCase):
jpdata = jp2k.read() jpdata = jp2k.read()
self.assertEqual(jpdata.shape, (640, 480, 3)) self.assertEqual(jpdata.shape, (640, 480, 3))
@unittest.skipIf(re.match(r"""1\.[0125]\.\d""", OPENJPEG_VERSION), @unittest.skipIf(glymur.version.openjpeg_version_tuple[0] < 2,
"Functionality not implemented for 1.x") "Functionality not implemented for 1.x")
def test_ETS_JP2_file3(self): def test_ETS_JP2_file3(self):
jfile = opj_data_file('input/conformance/file3.jp2') jfile = opj_data_file('input/conformance/file3.jp2')
@ -6720,7 +6720,7 @@ class TestSuiteDump(unittest.TestCase):
[8, 9, 9, 10, 9, 9, 10, 9, 9, 10, 9, 9, 10, 9, 9, 10]) [8, 9, 9, 10, 9, 9, 10, 9, 9, 10, 9, 9, 10, 9, 9, 10])
@unittest.skipIf(re.match(r"""1\.\d.\d""", OPENJPEG_VERSION), @unittest.skipIf(glymur.version.openjpeg_version_tuple[0] == 1,
"Feature not supported in glymur until openjpeg 2.0") "Feature not supported in glymur until openjpeg 2.0")
class TestSuite_bands(unittest.TestCase): class TestSuite_bands(unittest.TestCase):
"""Runs tests introduced in version 1.x but only pass in glymur with 2.0 """Runs tests introduced in version 1.x but only pass in glymur with 2.0
@ -6849,7 +6849,7 @@ class TestSuite_bands(unittest.TestCase):
self.assertTrue(True) self.assertTrue(True)
@unittest.skipIf(re.match(r"""1\.\d.\d""", OPENJPEG_VERSION), @unittest.skipIf(glymur.version.openjpeg_version_tuple[0] == 1,
"Tests not passing until 2.0") "Tests not passing until 2.0")
class TestSuite2point0(unittest.TestCase): class TestSuite2point0(unittest.TestCase):
"""Runs tests introduced in version 2.0 or that pass only in 2.0""" """Runs tests introduced in version 2.0 or that pass only in 2.0"""
@ -6901,13 +6901,19 @@ class TestSuite2point0(unittest.TestCase):
# messages that cannot be turned off? # messages that cannot be turned off?
relpath = 'input/nonregression/kakadu_v4-4_openjpegv2_broken.j2k' relpath = 'input/nonregression/kakadu_v4-4_openjpegv2_broken.j2k'
jfile = opj_data_file(relpath) jfile = opj_data_file(relpath)
Jp2k(jfile).read() if glymur.version.openjpeg_version_tuple[0] < 2:
with warnings.catch_warnings():
# Incorrect warning issued about tile parts.
warnings.simplefilter("ignore")
Jp2k(jfile).read()
else:
Jp2k(jfile).read()
self.assertTrue(True) self.assertTrue(True)
@unittest.skipIf(OPENJP2_IS_V2_OFFICIAL, @unittest.skipIf(OPENJP2_IS_V2_OFFICIAL,
"Test not in done in v2.0.0 official") "Test not in done in v2.0.0 official")
@unittest.skipIf(re.match(r"""1\.\d.\d""", OPENJPEG_VERSION), @unittest.skipIf(glymur.version.openjpeg_version_tuple[0] == 1,
"Tests not introduced until 2.1") "Tests not introduced until 2.1")
class TestSuite2point1(unittest.TestCase): class TestSuite2point1(unittest.TestCase):
"""Runs tests introduced in version 2.0+ or that pass only in 2.0+""" """Runs tests introduced in version 2.0+ or that pass only in 2.0+"""

View file

@ -20,7 +20,7 @@ else:
import unittest import unittest
from .fixtures import read_image, NO_READ_BACKEND, NO_READ_BACKEND_MSG from .fixtures import read_image, NO_READ_BACKEND, NO_READ_BACKEND_MSG
from .fixtures import OPJ_DATA_ROOT, OPENJPEG_VERSION, opj_data_file from .fixtures import OPJ_DATA_ROOT, opj_data_file
from glymur import Jp2k from glymur import Jp2k
import glymur import glymur
@ -28,7 +28,7 @@ import glymur
@unittest.skipIf(os.name == "nt", "no write support on windows, period") @unittest.skipIf(os.name == "nt", "no write support on windows, period")
@unittest.skipIf(re.match(r"""1\.[01234]\.\d""", @unittest.skipIf(re.match(r"""1\.[01234]\.\d""",
OPENJPEG_VERSION) is not None, glymur.version.openjpeg_version) is not None,
"Writing only supported with openjpeg version 1.5+.") "Writing only supported with openjpeg version 1.5+.")
@unittest.skipIf(NO_READ_BACKEND, NO_READ_BACKEND_MSG) @unittest.skipIf(NO_READ_BACKEND, NO_READ_BACKEND_MSG)
@unittest.skipIf(OPJ_DATA_ROOT is None, @unittest.skipIf(OPJ_DATA_ROOT is None,

53
glymur/version.py Normal file
View file

@ -0,0 +1,53 @@
# This file is part of glymur, a Python interface for accessing JPEG 2000.
#
# http://glymur.readthedocs.org
#
# Copyright 2013 John Evans
#
# License: MIT
import sys
import numpy as np
from distutils.version import StrictVersion
from .lib import openjpeg as opj
from .lib import openjp2 as opj2
version = "0.4.1"
_sv = StrictVersion(version)
version_tuple = _sv.version
if opj.OPENJPEG is None and opj2.OPENJP2 is None:
openjpeg_version = '0.0.0'
elif opj2.OPENJP2 is None:
openjpeg_version = opj.version()
else:
openjpeg_version = opj2.version()
_sv = StrictVersion(openjpeg_version)
openjpeg_version_tuple = _sv.version
__doc__ = """\
This is glymur **{glymur_version}**
* OPENJPEG version: **{openjpeg}**
""".format(glymur_version=version,
openjpeg=openjpeg_version)
info = """\
Summary of glymur configuration
-------------------------------
glymur {glymur}
OPENJPEG {openjpeg}
Python {python}
sys.platform {platform}
sys.maxsize {maxsize}
numpy {numpy}
""".format(glymur=version,
openjpeg=openjpeg_version,
python=sys.version,
platform=sys.platform,
maxsize=sys.maxsize,
numpy=np.__version__)

View file

@ -13,8 +13,7 @@ kwargs = {'name': 'Glymur',
'package_data': {'glymur': ['data/*.jp2', 'data/*.j2k']}, 'package_data': {'glymur': ['data/*.jp2', 'data/*.j2k']},
'scripts': ['bin/jp2dump'], 'scripts': ['bin/jp2dump'],
'license': 'MIT', 'license': 'MIT',
'test_suite': 'glymur.test', 'test_suite': 'glymur.test'}
'platforms': ['darwin']}
instllrqrs = ['numpy>=1.4.1'] instllrqrs = ['numpy>=1.4.1']
if sys.hexversion < 0x03030000: if sys.hexversion < 0x03030000: