Merge branch 'master' into devel

This commit is contained in:
John Evans 2013-05-28 11:27:43 -04:00
commit 555f84275f
8 changed files with 152 additions and 118 deletions

View file

@ -1 +1,7 @@
May 28, 2013 - Added jp2 boxes to rst docs, XMLBox.indent method made private.
May 27, 2013 - v0.1.1, Changed write example to not rely on matplotlib. Fixed
readthedocs.org setup to build documentation automatically. Can import
glymur without libopenjp2 actually being present.
May 27, 2013 - Changed write example to not rely on matplotlib. May 27, 2013 - Changed write example to not rely on matplotlib.

View file

@ -1,4 +1,3 @@
=========================================
glymur: a Python interface for JPEG 2000 glymur: a Python interface for JPEG 2000
========================================= =========================================
@ -6,8 +5,4 @@ glymur: a Python interface for JPEG 2000
which allows linux and mac users to read and write JPEG 2000 files. which allows linux and mac users to read and write JPEG 2000 files.
**glymur** works on Python 2.7 and 3.3. Python 3.3 is strongly recommended. **glymur** works on Python 2.7 and 3.3. Python 3.3 is strongly recommended.
Until I figure out how to get readthedocs.org to handle numpydoc, you'll have Please read the docs, https://glymur.readthedocs.org/en/latest/
to do as follows to build the documentation first::
$ make -C docs html
$ open docs/build/html/index.html

View file

@ -13,6 +13,29 @@
import sys, os import sys, os
class Mock(object):
def __init__(self, *args, **kwargs):
pass
def __call__(self, *args, **kwargs):
return Mock()
@classmethod
def __getattr__(cls, name):
if name in ('__file__', '__path__'):
return '/dev/null'
elif name[0] == name[0].upper():
mockType = type(name, (), {})
mockType.__module__ = __name__
return mockType
else:
return Mock()
MOCK_MODULES = ['numpy']
for mod_name in MOCK_MODULES:
sys.modules[mod_name] = Mock()
# If extensions (or modules to document with autodoc) are in another directory, # If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the # add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here. # documentation root, use os.path.abspath to make it absolute, like shown here.
@ -52,7 +75,7 @@ copyright = u'2013, John Evans'
# The short X.Y version. # The short X.Y version.
version = '0.1' version = '0.1'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.1.0.a1' release = '0.1.1'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View file

@ -4,10 +4,10 @@ glymur: a Python interface for JPEG 2000
**glymur** contains a Python interface to the OpenJPEG library **glymur** contains a Python interface to the OpenJPEG library
which allows linux and mac users to read and write JPEG 2000 files. For more which allows linux and mac users to read and write JPEG 2000 files. For more
information about OpenJPEG, please consult http://www.openjpeg.org. **glymur** information about OpenJPEG, please consult http://www.openjpeg.org. glymur
should be considered to be alpha-quality software. should be considered to be alpha-quality software.
**glymur** tries to support reading (including all metadata) and writing of glymur tries to support reading (including all metadata) and writing of
JP2 and J2C files. Writing J2C/JP2 files is currently limited to images that JP2 and J2C files. Writing J2C/JP2 files is currently limited to images that
can fit in memory, however. can fit in memory, however.
@ -18,7 +18,7 @@ metadata can be retrieved from such JPX files.
------------ ------------
Requirements Requirements
------------ ------------
**glymur** works on Python 2.7 and 3.3. Python 3.3 is strongly recommended. glymur works on Python 2.7 and 3.3. Python 3.3 is strongly recommended.
OpenJPEG OpenJPEG
======== ========
@ -26,7 +26,7 @@ OpenJPEG must be built as a shared library. In addition, you
currently must compile OpenJPEG from the developmental source that currently must compile OpenJPEG from the developmental source that
you can retrieve via subversion. As of this time of writing, svn you can retrieve via subversion. As of this time of writing, svn
revision 2345 works. In addition, you should also retrieve their test data, as revision 2345 works. In addition, you should also retrieve their test data, as
you will need it when running **glymur**'s test suite. you will need it when running glymur's test suite.
Earlier versions of OpenJPEG through the 2.0 official release are not supported. Earlier versions of OpenJPEG through the 2.0 official release are not supported.
@ -50,7 +50,7 @@ OS
Mac OS X Mac OS X
-------- --------
All the necessary packages are available to use **glymur** with Python 3.3 via All the necessary packages are available to use glymur with Python 3.3 via
MacPorts. A minimal set of ports includes MacPorts. A minimal set of ports includes
* python33 * python33
@ -83,12 +83,12 @@ combinations of RPMs / Python packages is installed.
* scikit-image and either Pillow or freeimage * scikit-image and either Pillow or freeimage
* matplotlib and Pillow * matplotlib and Pillow
The 2nd route is probably the easiest, so go ahead and install **Pillow** The 2nd route is probably the easiest, so go ahead and install Pillow
via **pip** since **Pillow** is not yet available in Fedora 18 default via pip since Pillow is not yet available in Fedora 18 default
repositories:: repositories::
$ yum install python3-devel # pip needs this in order to compile Pillow $ yum install python3-devel # pip needs this in order to compile Pillow
$ yum install python3-pip # First one must install pip of course! $ yum install python3-pip
$ pip-python3 install Pillow --user $ pip-python3 install Pillow --user
$ export PYTHONPATH=$HOME/.local/lib/python3.3/site-packages:$PYTHONPATH $ export PYTHONPATH=$HOME/.local/lib/python3.3/site-packages:$PYTHONPATH
@ -105,7 +105,7 @@ Required RPMs include::
* python-setuptools * python-setuptools
* numpy * numpy
In addition, you must install **contextlib2** via pip. In addition, you must install contextlib2 via pip.
A few tests still will not run, however, unless one of the following A few tests still will not run, however, unless one of the following
combinations of RPMs / Python packages is installed. combinations of RPMs / Python packages is installed.
@ -113,8 +113,8 @@ combinations of RPMs / Python packages is installed.
* scikit-image and either Pillow or freeimage * scikit-image and either Pillow or freeimage
* matplotlib and Pillow * matplotlib and Pillow
**scikit-image** is not available in the Fedora 17 default repositories, but scikit-image is not available in the Fedora 17 default repositories, but
it may be installed via **pip**:: it may be installed via pip::
$ yum install Cython # pip needs this in order to compile scikit-image $ yum install Cython # pip needs this in order to compile scikit-image
$ yum install python-devel # pip needs this in order to compile scikit-image $ yum install python-devel # pip needs this in order to compile scikit-image
@ -137,7 +137,7 @@ From this point forward, python3 will be referred to as just "python".
Installation Installation
============ ============
In addition to merely installing **glymur**, you should adjust your **$PATH** In addition to merely installing glymur, you should adjust your **$PATH**
environment variable in order to be able to use the **jp2dump** script from environment variable in order to be able to use the **jp2dump** script from
the unix command line. the unix command line.
@ -150,8 +150,8 @@ the unix command line.
Configuration Configuration
============= =============
glymur uses **ctypes** (for the moment) to access the openjp2 library, and glymur uses ctypes (for the moment) to access the openjp2 library, and
because **ctypes** access libraries in a platform-dependent manner, it is because ctypes access libraries in a platform-dependent manner, it is
recommended that you create a configuration file to help glymur properly find recommended that you create a configuration file to help glymur properly find
the openjp2 library. You may create the configuration file as follows:: the openjp2 library. You may create the configuration file as follows::

View file

@ -23,8 +23,12 @@ def _glymurrc_fname():
fname = os.path.join(path, 'glymurrc') fname = os.path.join(path, 'glymurrc')
if os.path.exists(fname): if os.path.exists(fname):
return fname return fname
else:
msg = "glymurrc file hinted at by GLYMURCONFIGDIR does not "
msg += "exist."
warnings.warn(msg, UserWarning)
# HOME/.glymur/jptoolrsc # HOME/.glymur/glymurrc
confdir = _get_configdir() confdir = _get_configdir()
if confdir is not None: if confdir is not None:
fname = os.path.join(_get_configdir(), 'glymurrc') fname = os.path.join(_get_configdir(), 'glymurrc')
@ -45,26 +49,22 @@ def _config():
# Read the configuration file for the library location. # Read the configuration file for the library location.
parser = ConfigParser() parser = ConfigParser()
parser.read(filename) parser.read(filename)
try: libopenjp2_path = parser.get('library', 'openjp2')
libopenjp2_path = parser.get('library', 'openjp2')
if not os.path.exists(libopenjp2_path):
msg = 'OpenJP2 library path specified by configuration file '
msg += 'does not exist.'
raise ImportError(msg)
except NoOptionError as e:
msg = "Error parsing configuration file '{0}': {1}"
msg = msg.format(fname, e.message)
warnings.warn(msg, UserWarning)
except:
raise
else: else:
# No help from the config file, try to find it ourselves. # No help from the config file, try to find it ourselves.
from ctypes.util import find_library from ctypes.util import find_library
libopenjp2_path = find_library('openjp2') libopenjp2_path = find_library('openjp2')
if libopenjp2_path is None:
raise ImportError('OpenJP2 library not found.')
_OPENJP2 = ctypes.CDLL(libopenjp2_path) if libopenjp2_path is None:
return None
try:
_OPENJP2 = ctypes.CDLL(libopenjp2_path)
except OSError:
msg = '"Library {0}" could not be loaded. Operating in degraded mode.'
msg = msg.format(libopenjp2_path)
warnings.warn(msg, UserWarning)
_OPENJP2 = None
return _OPENJP2 return _OPENJP2
@ -81,6 +81,7 @@ def _get_configdir():
if 'HOME' in os.environ: if 'HOME' in os.environ:
return os.path.join(os.environ['HOME'], '.glymur') return os.path.join(os.environ['HOME'], '.glymur')
import warnings
import sys import sys
if sys.hexversion <= 0x03000000: if sys.hexversion <= 0x03000000:
from ConfigParser import SafeConfigParser as ConfigParser from ConfigParser import SafeConfigParser as ConfigParser

View file

@ -528,105 +528,110 @@ class _codestream_info_v2_t(ctypes.Structure):
# Restrict the input and output argument types for each function used in the # Restrict the input and output argument types for each function used in the
# API. # API.
_OPENJP2.opj_create_compress.argtypes = [_codec_format_t] if _OPENJP2 is not None:
_OPENJP2.opj_create_compress.restype = _codec_t_p _OPENJP2.opj_create_compress.argtypes = [_codec_format_t]
_OPENJP2.opj_create_compress.restype = _codec_t_p
_OPENJP2.opj_create_decompress.argtypes = [_codec_format_t] _OPENJP2.opj_create_decompress.argtypes = [_codec_format_t]
_OPENJP2.opj_create_decompress.restype = _codec_t_p _OPENJP2.opj_create_decompress.restype = _codec_t_p
_argtypes = [_codec_t_p, _stream_t_p, ctypes.POINTER(_image_t)] _argtypes = [_codec_t_p, _stream_t_p, ctypes.POINTER(_image_t)]
_OPENJP2.opj_decode.argtypes = _argtypes _OPENJP2.opj_decode.argtypes = _argtypes
_argtypes = [_codec_t_p, ctypes.c_uint32, _argtypes = [_codec_t_p, ctypes.c_uint32,
ctypes.POINTER(ctypes.c_uint8), ctypes.POINTER(ctypes.c_uint8),
ctypes.c_uint32, ctypes.c_uint32,
_stream_t_p] _stream_t_p]
_OPENJP2.opj_decode_tile_data.argtypes = _argtypes _OPENJP2.opj_decode_tile_data.argtypes = _argtypes
_argtypes = [ctypes.POINTER(ctypes.POINTER(_codestream_info_v2_t))] _argtypes = [ctypes.POINTER(ctypes.POINTER(_codestream_info_v2_t))]
_OPENJP2.opj_destroy_cstr_info.argtypes = _argtypes _OPENJP2.opj_destroy_cstr_info.argtypes = _argtypes
_OPENJP2.opj_destroy_cstr_info.restype = ctypes.c_void_p _OPENJP2.opj_destroy_cstr_info.restype = ctypes.c_void_p
_argtypes = [_codec_t_p, _stream_t_p] _argtypes = [_codec_t_p, _stream_t_p]
_OPENJP2.opj_encode.argtypes = _argtypes _OPENJP2.opj_encode.argtypes = _argtypes
_OPENJP2.opj_get_cstr_info.argtypes = [_codec_t_p] _OPENJP2.opj_get_cstr_info.argtypes = [_codec_t_p]
_OPENJP2.opj_get_cstr_info.restype = ctypes.POINTER(_codestream_info_v2_t) _OPENJP2.opj_get_cstr_info.restype = ctypes.POINTER(_codestream_info_v2_t)
_argtypes = [_codec_t_p, _argtypes = [_codec_t_p,
_stream_t_p, _stream_t_p,
ctypes.POINTER(_image_t), ctypes.POINTER(_image_t),
ctypes.c_uint32] ctypes.c_uint32]
_OPENJP2.opj_get_decoded_tile.argtypes = _argtypes _OPENJP2.opj_get_decoded_tile.argtypes = _argtypes
_argtypes = [ctypes.c_uint32, _argtypes = [ctypes.c_uint32,
ctypes.POINTER(_image_comptparm_t), ctypes.POINTER(_image_comptparm_t),
color_space_t] color_space_t]
_OPENJP2.opj_image_create.argtypes = _argtypes _OPENJP2.opj_image_create.argtypes = _argtypes
_OPENJP2.opj_image_create.restype = ctypes.POINTER(_image_t) _OPENJP2.opj_image_create.restype = ctypes.POINTER(_image_t)
_argtypes = [ctypes.c_uint32, _argtypes = [ctypes.c_uint32,
ctypes.POINTER(_image_comptparm_t), ctypes.POINTER(_image_comptparm_t),
color_space_t] color_space_t]
_OPENJP2.opj_image_tile_create.argtypes = _argtypes _OPENJP2.opj_image_tile_create.argtypes = _argtypes
_OPENJP2.opj_image_tile_create.restype = ctypes.POINTER(_image_t) _OPENJP2.opj_image_tile_create.restype = ctypes.POINTER(_image_t)
_OPENJP2.opj_image_destroy.argtypes = [ctypes.POINTER(_image_t)] _OPENJP2.opj_image_destroy.argtypes = [ctypes.POINTER(_image_t)]
_argtypes = [_stream_t_p, _codec_t_p, ctypes.POINTER(ctypes.POINTER(_image_t))] _argtypes = [_stream_t_p, _codec_t_p,
_OPENJP2.opj_read_header.argtypes = _argtypes ctypes.POINTER(ctypes.POINTER(_image_t))]
_OPENJP2.opj_read_header.argtypes = _argtypes
_argtypes = [_codec_t_p, _argtypes = [_codec_t_p,
_stream_t_p, _stream_t_p,
ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32),
ctypes.POINTER(ctypes.c_int32), ctypes.POINTER(ctypes.c_int32), ctypes.POINTER(ctypes.c_uint32),
ctypes.POINTER(ctypes.c_int32), ctypes.POINTER(ctypes.c_int32), ctypes.POINTER(ctypes.c_int32),
ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_int32),
ctypes.POINTER(_bool_t)] ctypes.POINTER(ctypes.c_int32),
_OPENJP2.opj_read_tile_header.argtypes = _argtypes ctypes.POINTER(ctypes.c_int32),
ctypes.POINTER(ctypes.c_uint32),
ctypes.POINTER(_bool_t)]
_OPENJP2.opj_read_tile_header.argtypes = _argtypes
_argtypes = [_codec_t_p, ctypes.POINTER(_image_t), ctypes.c_int32, _argtypes = [_codec_t_p, ctypes.POINTER(_image_t), ctypes.c_int32,
ctypes.c_int32, ctypes.c_int32, ctypes.c_int32] ctypes.c_int32, ctypes.c_int32, ctypes.c_int32]
_OPENJP2.opj_set_decode_area.argtypes = _argtypes _OPENJP2.opj_set_decode_area.argtypes = _argtypes
_argtypes = [ctypes.POINTER(_cparameters_t)] _argtypes = [ctypes.POINTER(_cparameters_t)]
_OPENJP2.opj_set_default_encoder_parameters.argtypes = _argtypes _OPENJP2.opj_set_default_encoder_parameters.argtypes = _argtypes
_argtypes = [ctypes.POINTER(_dparameters_t)] _argtypes = [ctypes.POINTER(_dparameters_t)]
_OPENJP2.opj_set_default_decoder_parameters.argtypes = _argtypes _OPENJP2.opj_set_default_decoder_parameters.argtypes = _argtypes
_argtypes = [_codec_t_p, ctypes.c_void_p, ctypes.c_void_p] _argtypes = [_codec_t_p, ctypes.c_void_p, ctypes.c_void_p]
_OPENJP2.opj_set_error_handler.argtypes = _argtypes _OPENJP2.opj_set_error_handler.argtypes = _argtypes
_OPENJP2.opj_set_info_handler.argtypes = _argtypes _OPENJP2.opj_set_info_handler.argtypes = _argtypes
_OPENJP2.opj_set_warning_handler.argtypes = _argtypes _OPENJP2.opj_set_warning_handler.argtypes = _argtypes
_argtypes = [_codec_t_p, ctypes.POINTER(_dparameters_t)] _argtypes = [_codec_t_p, ctypes.POINTER(_dparameters_t)]
_OPENJP2.opj_setup_decoder.argtypes = _argtypes _OPENJP2.opj_setup_decoder.argtypes = _argtypes
_argtypes = [_codec_t_p, _argtypes = [_codec_t_p,
ctypes.POINTER(_cparameters_t), ctypes.POINTER(_cparameters_t),
ctypes.POINTER(_image_t)] ctypes.POINTER(_image_t)]
_OPENJP2.opj_setup_encoder.argtypes = _argtypes _OPENJP2.opj_setup_encoder.argtypes = _argtypes
_argtypes = [ctypes.c_char_p, ctypes.c_int32] _argtypes = [ctypes.c_char_p, ctypes.c_int32]
_OPENJP2.opj_stream_create_default_file_stream_v3.argtypes = _argtypes _OPENJP2.opj_stream_create_default_file_stream_v3.argtypes = _argtypes
_OPENJP2.opj_stream_create_default_file_stream_v3.restype = _stream_t_p _OPENJP2.opj_stream_create_default_file_stream_v3.restype = _stream_t_p
_argtypes = [_codec_t_p, ctypes.POINTER(_image_t), _stream_t_p] _argtypes = [_codec_t_p, ctypes.POINTER(_image_t), _stream_t_p]
_OPENJP2.opj_start_compress.argtypes = _argtypes _OPENJP2.opj_start_compress.argtypes = _argtypes
_OPENJP2.opj_end_compress.argtypes = [_codec_t_p, _stream_t_p] _OPENJP2.opj_end_compress.argtypes = [_codec_t_p, _stream_t_p]
_OPENJP2.opj_end_decompress.argtypes = [_codec_t_p, _stream_t_p] _OPENJP2.opj_end_decompress.argtypes = [_codec_t_p, _stream_t_p]
_OPENJP2.opj_stream_destroy_v3.argtypes = [_stream_t_p] _OPENJP2.opj_stream_destroy_v3.argtypes = [_stream_t_p]
_OPENJP2.opj_destroy_codec.argtypes = [_codec_t_p] _OPENJP2.opj_destroy_codec.argtypes = [_codec_t_p]
_argtypes = [_codec_t_p, _argtypes = [_codec_t_p,
ctypes.c_uint32, ctypes.c_uint32,
ctypes.POINTER(ctypes.c_uint8), ctypes.POINTER(ctypes.c_uint8),
ctypes.c_uint32, ctypes.c_uint32,
_stream_t_p] _stream_t_p]
_OPENJP2.opj_write_tile.argtypes = _argtypes _OPENJP2.opj_write_tile.argtypes = _argtypes
def _check_error(status): def _check_error(status):
@ -655,9 +660,10 @@ _fcns = ['opj_decode', 'opj_decode_tile_data', 'opj_end_compress',
'opj_set_warning_handler', 'opj_set_warning_handler',
'opj_setup_decoder', 'opj_setup_encoder', 'opj_start_compress', 'opj_setup_decoder', 'opj_setup_encoder', 'opj_start_compress',
'opj_write_tile'] 'opj_write_tile']
for _fcn in _fcns: if _OPENJP2 is not None:
_attr = getattr(_OPENJP2, _fcn) for _fcn in _fcns:
setattr(_attr, 'restype', _check_error) _attr = getattr(_OPENJP2, _fcn)
setattr(_attr, 'restype', _check_error)
def _create_compress(codec_format): def _create_compress(codec_format):

View file

@ -582,7 +582,7 @@ class TestJp2k(unittest.TestCase):
with patch.dict('os.environ', {'GLYMURCONFIGDIR': tdir}): with patch.dict('os.environ', {'GLYMURCONFIGDIR': tdir}):
# Misconfigured new configuration file should # Misconfigured new configuration file should
# be rejected. # be rejected.
with self.assertRaises(ImportError) as ce: with self.assertWarns(UserWarning) as cw:
imp.reload(glymur) imp.reload(glymur)
@unittest.skipIf(sys.hexversion < 0x03020000, @unittest.skipIf(sys.hexversion < 0x03020000,
@ -594,7 +594,7 @@ class TestJp2k(unittest.TestCase):
with patch.dict('os.environ', {'GLYMURCONFIGDIR': tdir}): with patch.dict('os.environ', {'GLYMURCONFIGDIR': tdir}):
# Misconfigured new configuration file should # Misconfigured new configuration file should
# be rejected. # be rejected.
with self.assertRaises(ImportError) as ce: with self.assertWarns(UserWarning) as cw:
imp.reload(glymur) imp.reload(glymur)

View file

@ -0,0 +1,3 @@
numpydoc==0.4
contextlib2==0.4.0
mock==1.0.1