Merge branch 'release-0.5.5'

This commit is contained in:
John Evans 2013-10-03 11:10:26 -04:00
commit 6c90504270
14 changed files with 197 additions and 443 deletions

View file

@ -5,14 +5,17 @@ python:
before_install: before_install:
- sudo apt-get update -qq - sudo apt-get update -qq
- sudo apt-get install -qq libopenjpeg2
- sudo apt-get install -qq python-numpy - sudo apt-get install -qq python-numpy
- sudo apt-get install -qq python3-numpy - sudo apt-get install -qq python3-numpy
- wget http://openjpeg.googlecode.com/files/openjpeg-1.5.0-Linux-x86_64.tar.gz
- sudo tar -xvf openjpeg-1.5.0-Linux-x86_64.tar.gz --strip-components=1 -C /
# command to install dependencies # command to install dependencies
install: "pip install -r travis-requirements.txt --use-mirrors" install: "pip install -r travis-requirements.txt --use-mirrors"
# command to run tests # command to run tests
# 2.7 should skip no more than 342 tests
# 3.3 should skip no more than 339 tests
script: "python -m unittest discover" script: "python -m unittest discover"
notifications: notifications:

View file

@ -1,3 +1,13 @@
Oct 03, 2013 - v0.5.5 Fixed pip install error introduced in 0.5.0.
Sep 24, 2013 - v0.5.4 Fixed test error restricted to v2.0.
Sep 24, 2013 - v0.5.3 Removed a duplicated channel definition test in
test_jp2box that could cause a segfault in 1.3 if not properly skipped.
Sep 23, 2013 - v0.5.2 Fixed some tests that have been failing since 0.5.
under various edge cases.
Sep 19, 2013 - v0.5.1 Added more resiliency to XML box parsing. Fixed tests Sep 19, 2013 - v0.5.1 Added more resiliency to XML box parsing. Fixed tests
that failed if OPJ_DATA_ROOT not set. that failed if OPJ_DATA_ROOT not set.

View file

@ -78,7 +78,7 @@ copyright = u'2013, John Evans'
# The short X.Y version. # The short X.Y version.
version = '0.5' version = '0.5'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.5.1' release = '0.5.5'
# 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

@ -7,13 +7,13 @@ Most users won't need to read this! You've been warned...
Glymur Configuration Glymur Configuration
'''''''''''''''''''''' ''''''''''''''''''''''
The default glymur installation process relies upon OpenJPEG version The default glymur installation process relies upon OpenJPEG
1.X being properly installed on your system. If you have version 1.5 you can being properly installed on your system. If you have version 1.5 you can
both read and write JPEG 2000 files, but you may wish to install version 2.0 both read and write JPEG 2000 files, but you may wish to install version 2.0
or the 2.0+ version from OpenJPEG's development trunk for better performance. or the 2.0+ version from OpenJPEG's development trunk for better performance.
If you do that, you should compile it as a shared library (named *openjp2* If you do that, you should compile it as a shared library (named *openjp2*
instead of *openjpeg*) from the developmental source that you can retrieve instead of *openjpeg*) from the developmental source that you can retrieve
via subversion. As of this time of writing, svn revision 2345 works. via subversion. As of this time of writing, svn revision 2347 works.
You should also download the test data for the purpose of configuring You should also download the test data for the purpose of configuring
and running OpenJPEG's test suite, check their instructions for all this. and running OpenJPEG's test suite, check their instructions for all this.
You should set the **OPJ_DATA_ROOT** environment variable for the purpose You should set the **OPJ_DATA_ROOT** environment variable for the purpose
@ -25,16 +25,17 @@ of running Glymur's test suite. ::
Glymur uses ctypes to access the openjp2/openjpeg libraries, Glymur uses ctypes to access the openjp2/openjpeg libraries,
and because ctypes accesses libraries in a platform-dependent manner, it is and because ctypes accesses 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 openjpeg or openjp2 libraries (linux users don't need to bother if you are the openjpeg or openjp2 libraries (linux users don't need to bother with this
using OpenJPEG as provided by your package manager). The configuration if you are using OpenJPEG as provided by your package manager). The
format is the same as used by Python's configparser module, i.e. :: configuration format is the same as used by Python's configparser module,
i.e. ::
[library] [library]
openjp2: /opt/openjp2-svn/lib/libopenjp2.so openjp2: /opt/openjp2-svn/lib/libopenjp2.so
This assumes, of course, that you've installed OpenJPEG into This assumes, of course, that you've installed OpenJPEG into
/opt/openjp2-svn on a linux system. The location of the configuration file /opt/openjp2-svn on a linux system. The location of the configuration file
is platform-dependent (of course). If you use either linux or mac, the path can vary as well (of course). If you use either linux or mac, the path
to the configuration file would normally be :: to the configuration file would normally be ::
$HOME/.config/glymur/glymurrc $HOME/.config/glymur/glymurrc
@ -70,7 +71,8 @@ packages/RPMs/ports/whatever without going through pip.
Mac OS X Mac OS X
-------- --------
All the necessary packages are available to use glymur with Python 2.6, 2.7, All the necessary packages are available to use glymur with Python 2.6, 2.7,
and 3.3 via MacPorts. You should install the following set of ports: and 3.3 via MacPorts. For python 3.3, you should install the following set of
ports:
* python33 * python33
* py33-numpy * py33-numpy

View file

@ -3,7 +3,7 @@ How do I...?
------------ ------------
read the lowest resolution thumbnail? ... read the lowest resolution thumbnail?
===================================== =====================================
Printing the Jp2k object should reveal the number of resolutions (look in the Printing the Jp2k object should reveal the number of resolutions (look in the
COD segment section), but you can take a shortcut by supplying -1 as the COD segment section), but you can take a shortcut by supplying -1 as the
@ -14,7 +14,7 @@ resolution level. ::
>>> j = glymur.Jp2k(file) >>> j = glymur.Jp2k(file)
>>> thumbnail = j.read(rlevel=-1) >>> thumbnail = j.read(rlevel=-1)
display metadata? ... display metadata?
================= =================
There are two ways. From the unix command line, the script *jp2dump* is There are two ways. From the unix command line, the script *jp2dump* is
available. :: available. ::
@ -34,7 +34,7 @@ codestream box, only the main header is printed. It is possible to print
>>> print(j.get_codestream()) >>> print(j.get_codestream())
add XML metadata? ... add XML metadata?
================= =================
You can append any number of XML boxes to a JP2 file (not to a raw codestream). You can append any number of XML boxes to a JP2 file (not to a raw codestream).
Consider the following XML file `data.xml` : :: Consider the following XML file `data.xml` : ::
@ -66,7 +66,7 @@ The **append** method can add an XML box as shown below::
>>> jp2.append(xmlbox) >>> jp2.append(xmlbox)
>>> print(jp2) >>> print(jp2)
add metadata in a more general fashion? ... add metadata in a more general fashion?
======================================= =======================================
An existing raw codestream (or JP2 file) can be wrapped (re-wrapped) in a An existing raw codestream (or JP2 file) can be wrapped (re-wrapped) in a
user-defined set of JP2 boxes. To get just a minimal JP2 jacket on the user-defined set of JP2 boxes. To get just a minimal JP2 jacket on the
@ -157,18 +157,18 @@ to add metadata, you should keep in mind that **wrap** produces a new JP2 file,
while **append** modifies an existing file and is currently limited to XML while **append** modifies an existing file and is currently limited to XML
boxes. boxes.
create an image with an alpha layer? ... create an image with an alpha layer?
==================================== ====================================
OpenJPEG can create JP2 files with more than 3 components (requires OpenJPEG can create JP2 files with more than 3 components (requires
the development version), but by default, any extra components are the development version of OpenJPEG), but by default, any extra components are
not described as such. In order to do so, we need to rewrap such not described as such. In order to do so, we need to rewrap such
an image in a set of boxes that includes a channel definition box. an image in a set of boxes that includes a channel definition box.
This example is based on SciPy example code found at This example is based on SciPy example code found at
http://scipy-lectures.github.io/advanced/image_processing/#basic-manipulations . http://scipy-lectures.github.io/advanced/image_processing/#basic-manipulations .
Instead of a circular mask, however, we'll make it an ellipse since the source Instead of a circular mask we'll make it an ellipse since the source
image isn't square. image isn't square. ::
>>> import numpy as np >>> import numpy as np
>>> import glymur >>> import glymur

View file

@ -4,9 +4,8 @@ Glymur: a Python interface for JPEG 2000
**Glymur** is an interface to the OpenJPEG library **Glymur** is an interface to the OpenJPEG library
which allows one to read and write JPEG 2000 files from within Python. which allows one to read and write JPEG 2000 files from within Python.
Glymur supports both reading and writing of JPEG 2000 images. Writing Glymur supports both reading and writing of JPEG 2000 images, but writing
JPEG 2000 images is currently limited to images that can fit in memory, JPEG 2000 images is currently limited to images that can fit in memory
however.
Of particular focus is retrieval of metadata. Reading Exif UUIDs is supported, Of particular focus is retrieval of metadata. Reading Exif UUIDs is supported,
as is reading XMP UUIDs as the XMP data packet is just XML. There is as is reading XMP UUIDs as the XMP data packet is just XML. There is
@ -24,11 +23,10 @@ only supported with the 1.5 or better, however, and the trunk/development
version is strongly recommended. For more information about OpenJPEG, version is strongly recommended. For more information about OpenJPEG,
please consult http://www.openjpeg.org. please consult http://www.openjpeg.org.
If you use MacPorts on the mac or if you have a sufficiently recent If you use MacPorts or if you have a sufficiently recent version of
version of Linux, your package manager should already provide you Linux, your package manager should already provide you with a version of
with a version of OpenJPEG 1.X with which glymur can already use OpenJPEG 1.X which glymur can already use. If your platform is windows,
for read-only purposes. If your platform is windows, I suggest I suggest using the windows installers provided to you by the OpenJPEG
using the windows installers provided to you by the OpenJPEG
folks at https://code.google.com/p/openjpeg/downloads/list . folks at https://code.google.com/p/openjpeg/downloads/list .
Glymur Installation Glymur Installation
@ -47,13 +45,5 @@ line, so you should adjust your **$PATH**
to take advantage of it. For example, if you install with pip's to take advantage of it. For example, if you install with pip's
`--user` option on linux :: `--user` option on linux ::
$ export PYTHONPATH=$HOME/.local/lib/python3.3/site-packages
$ export PATH=$HOME/.local/bin:$PATH $ export PATH=$HOME/.local/bin:$PATH
You can run the tests from within python as follows::
>>> import glymur
>>> glymur.runtests()
Many tests are currently skipped, but the The important thing is whether or
not any tests fail.

View file

@ -553,119 +553,6 @@ class CodestreamInfoV2(ctypes.Structure):
# information regarding tiles inside of image # information regarding tiles inside of image
("tile_info", ctypes.POINTER(TileInfoV2))] ("tile_info", ctypes.POINTER(TileInfoV2))]
# Restrict the input and output argument types for each function used in the
# API.
if OPENJP2 is not None:
OPENJP2.opj_create_compress.restype = CODEC_TYPE
OPENJP2.opj_create_compress.argtypes = [CODEC_FORMAT_TYPE]
OPENJP2.opj_create_decompress.argtypes = [CODEC_FORMAT_TYPE]
OPENJP2.opj_create_decompress.restype = CODEC_TYPE
ARGTYPES = [CODEC_TYPE, STREAM_TYPE_P, ctypes.POINTER(ImageType)]
OPENJP2.opj_decode.argtypes = ARGTYPES
ARGTYPES = [CODEC_TYPE, ctypes.c_uint32,
ctypes.POINTER(ctypes.c_uint8),
ctypes.c_uint32,
STREAM_TYPE_P]
OPENJP2.opj_decode_tile_data.argtypes = ARGTYPES
ARGTYPES = [ctypes.POINTER(ctypes.POINTER(CodestreamInfoV2))]
OPENJP2.opj_destroy_cstr_info.argtypes = ARGTYPES
OPENJP2.opj_destroy_cstr_info.restype = ctypes.c_void_p
ARGTYPES = [CODEC_TYPE, STREAM_TYPE_P]
OPENJP2.opj_encode.argtypes = ARGTYPES
OPENJP2.opj_get_cstr_info.argtypes = [CODEC_TYPE]
OPENJP2.opj_get_cstr_info.restype = ctypes.POINTER(CodestreamInfoV2)
ARGTYPES = [CODEC_TYPE,
STREAM_TYPE_P,
ctypes.POINTER(ImageType),
ctypes.c_uint32]
OPENJP2.opj_get_decoded_tile.argtypes = ARGTYPES
ARGTYPES = [ctypes.c_uint32,
ctypes.POINTER(ImageComptParmType),
COLOR_SPACE_TYPE]
OPENJP2.opj_image_create.argtypes = ARGTYPES
OPENJP2.opj_image_create.restype = ctypes.POINTER(ImageType)
ARGTYPES = [ctypes.c_uint32,
ctypes.POINTER(ImageComptParmType),
COLOR_SPACE_TYPE]
OPENJP2.opj_image_tile_create.argtypes = ARGTYPES
OPENJP2.opj_image_tile_create.restype = ctypes.POINTER(ImageType)
OPENJP2.opj_image_destroy.argtypes = [ctypes.POINTER(ImageType)]
ARGTYPES = [STREAM_TYPE_P, CODEC_TYPE,
ctypes.POINTER(ctypes.POINTER(ImageType))]
OPENJP2.opj_read_header.argtypes = ARGTYPES
ARGTYPES = [CODEC_TYPE,
STREAM_TYPE_P,
ctypes.POINTER(ctypes.c_uint32),
ctypes.POINTER(ctypes.c_uint32),
ctypes.POINTER(ctypes.c_int32),
ctypes.POINTER(ctypes.c_int32),
ctypes.POINTER(ctypes.c_int32),
ctypes.POINTER(ctypes.c_int32),
ctypes.POINTER(ctypes.c_uint32),
ctypes.POINTER(BOOL_TYPE)]
OPENJP2.opj_read_tile_header.argtypes = ARGTYPES
ARGTYPES = [CODEC_TYPE, ctypes.POINTER(ImageType), ctypes.c_int32,
ctypes.c_int32, ctypes.c_int32, ctypes.c_int32]
OPENJP2.opj_set_decode_area.argtypes = ARGTYPES
ARGTYPES = [ctypes.POINTER(CompressionParametersType)]
OPENJP2.opj_set_default_encoder_parameters.argtypes = ARGTYPES
ARGTYPES = [ctypes.POINTER(DecompressionParametersType)]
OPENJP2.opj_set_default_decoder_parameters.argtypes = ARGTYPES
ARGTYPES = [CODEC_TYPE, ctypes.c_void_p, ctypes.c_void_p]
OPENJP2.opj_set_error_handler.argtypes = ARGTYPES
OPENJP2.opj_set_info_handler.argtypes = ARGTYPES
OPENJP2.opj_set_warning_handler.argtypes = ARGTYPES
ARGTYPES = [CODEC_TYPE, ctypes.POINTER(DecompressionParametersType)]
OPENJP2.opj_setup_decoder.argtypes = ARGTYPES
ARGTYPES = [CODEC_TYPE,
ctypes.POINTER(CompressionParametersType),
ctypes.POINTER(ImageType)]
OPENJP2.opj_setup_encoder.argtypes = ARGTYPES
if hasattr(OPENJP2, 'opj_stream_create_default_file_stream_v3'):
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.restype = STREAM_TYPE_P
OPENJP2.opj_stream_destroy_v3.argtypes = [STREAM_TYPE_P]
else:
ARGTYPES = [ctypes.c_void_p, ctypes.c_int32]
OPENJP2.opj_stream_create_default_file_stream.argtypes = ARGTYPES
OPENJP2.opj_stream_create_default_file_stream.restype = STREAM_TYPE_P
OPENJP2.opj_stream_destroy.argtypes = [STREAM_TYPE_P]
ARGTYPES = [CODEC_TYPE, ctypes.POINTER(ImageType), STREAM_TYPE_P]
OPENJP2.opj_start_compress.argtypes = ARGTYPES
OPENJP2.opj_end_compress.argtypes = [CODEC_TYPE, STREAM_TYPE_P]
OPENJP2.opj_end_decompress.argtypes = [CODEC_TYPE, STREAM_TYPE_P]
OPENJP2.opj_destroy_codec.argtypes = [CODEC_TYPE]
ARGTYPES = [CODEC_TYPE,
ctypes.c_uint32,
ctypes.POINTER(ctypes.c_uint8),
ctypes.c_uint32,
STREAM_TYPE_P]
OPENJP2.opj_write_tile.argtypes = ARGTYPES
def check_error(status): def check_error(status):
"""Set a generic function as the restype attribute of all OpenJPEG """Set a generic function as the restype attribute of all OpenJPEG
@ -684,19 +571,6 @@ def check_error(status):
else: else:
raise IOError("OpenJPEG function failure.") raise IOError("OpenJPEG function failure.")
# These library functions all return an error status. Circumvent that and
# force them to raise an exception.
FCNS = ['opj_decode', 'opj_decode_tile_data', 'opj_end_compress',
'opj_encode', 'opj_end_decompress', 'opj_get_decoded_tile',
'opj_read_header', 'opj_read_tile_header', 'opj_set_decode_area',
'opj_set_error_handler', 'opj_set_info_handler',
'opj_set_warning_handler',
'opj_setup_decoder', 'opj_setup_encoder', 'opj_start_compress',
'opj_write_tile']
if OPENJP2 is not None:
for fcn in FCNS:
setattr(getattr(OPENJP2, fcn), 'restype', check_error)
def create_compress(codec_format): def create_compress(codec_format):
"""Creates a J2K/JP2 compress structure. """Creates a J2K/JP2 compress structure.
@ -712,6 +586,9 @@ def create_compress(codec_format):
------- -------
codec : Reference to CODEC_TYPE instance. codec : Reference to CODEC_TYPE instance.
""" """
OPENJP2.opj_create_compress.restype = CODEC_TYPE
OPENJP2.opj_create_compress.argtypes = [CODEC_FORMAT_TYPE]
codec = OPENJP2.opj_create_compress(codec_format) codec = OPENJP2.opj_create_compress(codec_format)
return codec return codec
@ -735,6 +612,10 @@ def decode(codec, stream, image):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_decode fails. If the OpenJPEG library routine opj_decode fails.
""" """
OPENJP2.opj_decode.argtypes = [CODEC_TYPE, STREAM_TYPE_P,
ctypes.POINTER(ImageType)]
OPENJP2.opj_decode.restype = check_error
OPENJP2.opj_decode(codec, stream, image) OPENJP2.opj_decode(codec, stream, image)
@ -761,13 +642,19 @@ def decode_tile_data(codec, tidx, data, data_size, stream):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_decode fails. If the OpenJPEG library routine opj_decode fails.
""" """
OPENJP2.opj_decode_tile_data.argtypes = [CODEC_TYPE,
ctypes.c_uint32,
ctypes.POINTER(ctypes.c_uint8),
ctypes.c_uint32,
STREAM_TYPE_P]
OPENJP2.opj_decode_tile_data.restype = check_error
datap = data.ctypes.data_as(ctypes.POINTER(ctypes.c_uint8)) datap = data.ctypes.data_as(ctypes.POINTER(ctypes.c_uint8))
OPENJP2.opj_decode_tile_data(codec, OPENJP2.opj_decode_tile_data(codec,
ctypes.c_uint32(tidx), ctypes.c_uint32(tidx),
datap, datap,
ctypes.c_uint32(data_size), ctypes.c_uint32(data_size),
stream) stream)
return codec
def create_decompress(codec_format): def create_decompress(codec_format):
@ -784,6 +671,9 @@ def create_decompress(codec_format):
------- -------
codec : Reference to CODEC_TYPE instance. codec : Reference to CODEC_TYPE instance.
""" """
OPENJP2.opj_create_decompress.argtypes = [CODEC_FORMAT_TYPE]
OPENJP2.opj_create_decompress.restype = CODEC_TYPE
codec = OPENJP2.opj_create_decompress(codec_format) codec = OPENJP2.opj_create_decompress(codec_format)
return codec return codec
@ -798,6 +688,8 @@ def destroy_codec(codec):
codec : CODEC_TYPE codec : CODEC_TYPE
Decompressor handle to destroy. Decompressor handle to destroy.
""" """
OPENJP2.opj_destroy_codec.argtypes = [CODEC_TYPE]
OPENJP2.opj_destroy_codec.restype = ctypes.c_void_p
OPENJP2.opj_destroy_codec(codec) OPENJP2.opj_destroy_codec(codec)
@ -818,6 +710,9 @@ def encode(codec, stream):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_encode fails. If the OpenJPEG library routine opj_encode fails.
""" """
OPENJP2.opj_encode.argtypes = [CODEC_TYPE, STREAM_TYPE_P]
OPENJP2.opj_encode.restype = check_error
OPENJP2.opj_encode(codec, stream) OPENJP2.opj_encode(codec, stream)
@ -836,6 +731,9 @@ def get_cstr_info(codec):
cstr_info_p : CodestreamInfoV2 cstr_info_p : CodestreamInfoV2
Reference to codestream information. Reference to codestream information.
""" """
OPENJP2.opj_get_cstr_info.argtypes = [CODEC_TYPE]
OPENJP2.opj_get_cstr_info.restype = ctypes.POINTER(CodestreamInfoV2)
cstr_info_p = OPENJP2.opj_get_cstr_info(codec) cstr_info_p = OPENJP2.opj_get_cstr_info(codec)
return cstr_info_p return cstr_info_p
@ -861,6 +759,12 @@ def get_decoded_tile(codec, stream, imagep, tile_index):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_get_decoded_tile fails. If the OpenJPEG library routine opj_get_decoded_tile fails.
""" """
OPENJP2.opj_get_decoded_tile.argtypes = [CODEC_TYPE,
STREAM_TYPE_P,
ctypes.POINTER(ImageType),
ctypes.c_uint32]
OPENJP2.opj_get_decoded_tile.restype = check_error
OPENJP2.opj_get_decoded_tile(codec, stream, imagep, tile_index) OPENJP2.opj_get_decoded_tile(codec, stream, imagep, tile_index)
@ -874,6 +778,10 @@ def destroy_cstr_info(cstr_info_p):
cstr_info_p : CodestreamInfoV2 pointer cstr_info_p : CodestreamInfoV2 pointer
Pointer to codestream info structure. Pointer to codestream info structure.
""" """
ARGTYPES = [ctypes.POINTER(ctypes.POINTER(CodestreamInfoV2))]
OPENJP2.opj_destroy_cstr_info.argtypes = ARGTYPES
OPENJP2.opj_destroy_cstr_info.restype = ctypes.c_void_p
OPENJP2.opj_destroy_cstr_info(ctypes.byref(cstr_info_p)) OPENJP2.opj_destroy_cstr_info(ctypes.byref(cstr_info_p))
@ -894,6 +802,8 @@ def end_compress(codec, stream):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_end_compress fails. If the OpenJPEG library routine opj_end_compress fails.
""" """
OPENJP2.opj_end_compress.argtypes = [CODEC_TYPE, STREAM_TYPE_P]
OPENJP2.opj_end_compress.restype = check_error
OPENJP2.opj_end_compress(codec, stream) OPENJP2.opj_end_compress(codec, stream)
@ -914,6 +824,8 @@ def end_decompress(codec, stream):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_end_decompress fails. If the OpenJPEG library routine opj_end_decompress fails.
""" """
OPENJP2.opj_end_decompress.argtypes = [CODEC_TYPE, STREAM_TYPE_P]
OPENJP2.opj_end_decompress.restype = check_error
OPENJP2.opj_end_decompress(codec, stream) OPENJP2.opj_end_decompress(codec, stream)
@ -927,6 +839,9 @@ def image_destroy(image):
image : ImageType pointer image : ImageType pointer
Image resource to be disposed. Image resource to be disposed.
""" """
OPENJP2.opj_image_destroy.argtypes = [ctypes.POINTER(ImageType)]
OPENJP2.opj_image_destroy.restype = ctypes.c_void_p
OPENJP2.opj_image_destroy(image) OPENJP2.opj_image_destroy(image)
@ -947,6 +862,11 @@ def image_create(comptparms, clrspc):
image : ImageType image : ImageType
Reference to ImageType instance. Reference to ImageType instance.
""" """
OPENJP2.opj_image_create.argtypes = [ctypes.c_uint32,
ctypes.POINTER(ImageComptParmType),
COLOR_SPACE_TYPE]
OPENJP2.opj_image_create.restype = ctypes.POINTER(ImageType)
image = OPENJP2.opj_image_create(len(comptparms), image = OPENJP2.opj_image_create(len(comptparms),
comptparms, comptparms,
clrspc) clrspc)
@ -970,6 +890,12 @@ def image_tile_create(comptparms, clrspc):
image : ImageType image : ImageType
Reference to ImageType instance. Reference to ImageType instance.
""" """
ARGTYPES = [ctypes.c_uint32,
ctypes.POINTER(ImageComptParmType),
COLOR_SPACE_TYPE]
OPENJP2.opj_image_tile_create.argtypes = ARGTYPES
OPENJP2.opj_image_tile_create.restype = ctypes.POINTER(ImageType)
image = OPENJP2.opj_image_tile_create(len(comptparms), image = OPENJP2.opj_image_tile_create(len(comptparms),
comptparms, comptparms,
clrspc) clrspc)
@ -998,6 +924,11 @@ def read_header(stream, codec):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_read_header fails. If the OpenJPEG library routine opj_read_header fails.
""" """
ARGTYPES = [STREAM_TYPE_P, CODEC_TYPE,
ctypes.POINTER(ctypes.POINTER(ImageType))]
OPENJP2.opj_read_header.argtypes = ARGTYPES
OPENJP2.opj_read_header.restype = check_error
imagep = ctypes.POINTER(ImageType)() imagep = ctypes.POINTER(ImageType)()
OPENJP2.opj_read_header(stream, codec, ctypes.byref(imagep)) OPENJP2.opj_read_header(stream, codec, ctypes.byref(imagep))
return imagep return imagep
@ -1035,6 +966,19 @@ def read_tile_header(codec, stream):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_read_tile_header fails. If the OpenJPEG library routine opj_read_tile_header fails.
""" """
ARGTYPES = [CODEC_TYPE,
STREAM_TYPE_P,
ctypes.POINTER(ctypes.c_uint32),
ctypes.POINTER(ctypes.c_uint32),
ctypes.POINTER(ctypes.c_int32),
ctypes.POINTER(ctypes.c_int32),
ctypes.POINTER(ctypes.c_int32),
ctypes.POINTER(ctypes.c_int32),
ctypes.POINTER(ctypes.c_uint32),
ctypes.POINTER(BOOL_TYPE)]
OPENJP2.opj_read_tile_header.argtypes = ARGTYPES
OPENJP2.opj_read_tile_header.restype = check_error
tile_index = ctypes.c_uint32() tile_index = ctypes.c_uint32()
data_size = ctypes.c_uint32() data_size = ctypes.c_uint32()
col0 = ctypes.c_int32() col0 = ctypes.c_int32()
@ -1086,6 +1030,14 @@ def set_decode_area(codec, image, start_x=0, start_y=0, end_x=0, end_y=0):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_set_decode_area fails. If the OpenJPEG library routine opj_set_decode_area fails.
""" """
OPENJP2.opj_set_decode_area.argtypes = [CODEC_TYPE,
ctypes.POINTER(ImageType),
ctypes.c_int32,
ctypes.c_int32,
ctypes.c_int32,
ctypes.c_int32]
OPENJP2.opj_set_decode_area.restype = check_error
OPENJP2.opj_set_decode_area(codec, image, OPENJP2.opj_set_decode_area(codec, image,
ctypes.c_int32(start_x), ctypes.c_int32(start_x),
ctypes.c_int32(start_y), ctypes.c_int32(start_y),
@ -1103,6 +1055,10 @@ def set_default_decoder_parameters():
dparam : DecompressionParametersType dparam : DecompressionParametersType
Decompression parameters. Decompression parameters.
""" """
ARGTYPES = [ctypes.POINTER(DecompressionParametersType)]
OPENJP2.opj_set_default_decoder_parameters.argtypes = ARGTYPES
OPENJP2.opj_set_default_decoder_parameters.restype = ctypes.c_void_p
dparams = DecompressionParametersType() dparams = DecompressionParametersType()
OPENJP2.opj_set_default_decoder_parameters(ctypes.byref(dparams)) OPENJP2.opj_set_default_decoder_parameters(ctypes.byref(dparams))
return dparams return dparams
@ -1138,6 +1094,10 @@ def set_default_encoder_parameters():
cparameters : CompressionParametersType cparameters : CompressionParametersType
Compression parameters. Compression parameters.
""" """
ARGTYPES = [ctypes.POINTER(CompressionParametersType)]
OPENJP2.opj_set_default_encoder_parameters.argtypes = ARGTYPES
OPENJP2.opj_set_default_encoder_parameters.restype = ctypes.c_void_p
cparams = CompressionParametersType() cparams = CompressionParametersType()
OPENJP2.opj_set_default_encoder_parameters(ctypes.byref(cparams)) OPENJP2.opj_set_default_encoder_parameters(ctypes.byref(cparams))
return cparams return cparams
@ -1162,6 +1122,10 @@ def set_error_handler(codec, handler, data=None):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_set_error_handler fails. If the OpenJPEG library routine opj_set_error_handler fails.
""" """
OPENJP2.opj_set_error_handler.argtypes = [CODEC_TYPE,
ctypes.c_void_p,
ctypes.c_void_p]
OPENJP2.opj_set_error_handler.restype = check_error
OPENJP2.opj_set_error_handler(codec, handler, data) OPENJP2.opj_set_error_handler(codec, handler, data)
@ -1184,6 +1148,10 @@ def set_info_handler(codec, handler, data=None):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_set_info_handler fails. If the OpenJPEG library routine opj_set_info_handler fails.
""" """
OPENJP2.opj_set_info_handler.argtypes = [CODEC_TYPE,
ctypes.c_void_p,
ctypes.c_void_p]
OPENJP2.opj_set_info_handler.restype = check_error
OPENJP2.opj_set_info_handler(codec, handler, data) OPENJP2.opj_set_info_handler(codec, handler, data)
@ -1206,6 +1174,11 @@ def set_warning_handler(codec, handler, data=None):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_set_warning_handler fails. If the OpenJPEG library routine opj_set_warning_handler fails.
""" """
OPENJP2.opj_set_warning_handler.argtypes = [CODEC_TYPE,
ctypes.c_void_p,
ctypes.c_void_p]
OPENJP2.opj_set_warning_handler.restype = check_error
OPENJP2.opj_set_warning_handler(codec, handler, data) OPENJP2.opj_set_warning_handler(codec, handler, data)
@ -1226,6 +1199,10 @@ def setup_decoder(codec, dparams):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_setup_decoder fails. If the OpenJPEG library routine opj_setup_decoder fails.
""" """
ARGTYPES = [CODEC_TYPE, ctypes.POINTER(DecompressionParametersType)]
OPENJP2.opj_setup_decoder.argtypes = ARGTYPES
OPENJP2.opj_setup_decoder.restype = check_error
OPENJP2.opj_setup_decoder(codec, ctypes.byref(dparams)) OPENJP2.opj_setup_decoder(codec, ctypes.byref(dparams))
@ -1249,6 +1226,11 @@ def setup_encoder(codec, cparams, image):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_setup_encoder fails. If the OpenJPEG library routine opj_setup_encoder fails.
""" """
ARGTYPES = [CODEC_TYPE,
ctypes.POINTER(CompressionParametersType),
ctypes.POINTER(ImageType)]
OPENJP2.opj_setup_encoder.argtypes = ARGTYPES
OPENJP2.opj_setup_encoder.restype = check_error
OPENJP2.opj_setup_encoder(codec, ctypes.byref(cparams), image) OPENJP2.opj_setup_encoder(codec, ctypes.byref(cparams), image)
@ -1271,6 +1253,11 @@ def start_compress(codec, image, stream):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_start_compress fails. If the OpenJPEG library routine opj_start_compress fails.
""" """
OPENJP2.opj_start_compress.argtypes = [CODEC_TYPE,
ctypes.POINTER(ImageType),
STREAM_TYPE_P]
OPENJP2.opj_start_compress.restype = check_error
OPENJP2.opj_start_compress(codec, image, stream) OPENJP2.opj_start_compress(codec, image, stream)
@ -1292,6 +1279,9 @@ def stream_create_default_file_stream(fptr, isa_read_stream):
stream : stream_t stream : stream_t
An OpenJPEG file stream. An OpenJPEG file stream.
""" """
ARGTYPES = [ctypes.c_void_p, ctypes.c_int32]
OPENJP2.opj_stream_create_default_file_stream.argtypes = ARGTYPES
OPENJP2.opj_stream_create_default_file_stream.restype = STREAM_TYPE_P
read_stream = 1 if isa_read_stream else 0 read_stream = 1 if isa_read_stream else 0
stream = OPENJP2.opj_stream_create_default_file_stream(fptr, read_stream) stream = OPENJP2.opj_stream_create_default_file_stream(fptr, read_stream)
return stream return stream
@ -1315,6 +1305,9 @@ def stream_create_default_file_stream_v3(fname, isa_read_stream):
stream : stream_t stream : stream_t
An OpenJPEG file stream. An OpenJPEG file stream.
""" """
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.restype = STREAM_TYPE_P
read_stream = 1 if isa_read_stream else 0 read_stream = 1 if isa_read_stream else 0
file_argument = ctypes.c_char_p(fname.encode()) file_argument = ctypes.c_char_p(fname.encode())
stream = OPENJP2.opj_stream_create_default_file_stream_v3(file_argument, stream = OPENJP2.opj_stream_create_default_file_stream_v3(file_argument,
@ -1332,6 +1325,8 @@ def stream_destroy(stream):
stream : STREAM_TYPE_P stream : STREAM_TYPE_P
The file stream. The file stream.
""" """
OPENJP2.opj_stream_destroy.argtypes = [STREAM_TYPE_P]
OPENJP2.opj_stream_destroy.restype = ctypes.c_void_p
OPENJP2.opj_stream_destroy(stream) OPENJP2.opj_stream_destroy(stream)
@ -1345,6 +1340,8 @@ def stream_destroy_v3(stream):
stream : STREAM_TYPE_P stream : STREAM_TYPE_P
The file stream. The file stream.
""" """
OPENJP2.opj_stream_destroy_v3.argtypes = [STREAM_TYPE_P]
OPENJP2.opj_stream_destroy_v3.restype = ctypes.c_void_p
OPENJP2.opj_stream_destroy_v3(stream) OPENJP2.opj_stream_destroy_v3(stream)
@ -1371,6 +1368,13 @@ def write_tile(codec, tile_index, data, data_size, stream):
RuntimeError RuntimeError
If the OpenJPEG library routine opj_write_tile fails. If the OpenJPEG library routine opj_write_tile fails.
""" """
OPENJP2.opj_write_tile.argtypes = [CODEC_TYPE,
ctypes.c_uint32,
ctypes.POINTER(ctypes.c_uint8),
ctypes.c_uint32,
STREAM_TYPE_P]
OPENJP2.opj_write_tile.restype = check_error
datap = data.ctypes.data_as(ctypes.POINTER(ctypes.c_uint8)) datap = data.ctypes.data_as(ctypes.POINTER(ctypes.c_uint8))
OPENJP2.opj_write_tile(codec, OPENJP2.opj_write_tile(codec,
ctypes.c_uint32(int(tile_index)), ctypes.c_uint32(int(tile_index)),

View file

@ -124,7 +124,7 @@ class TestConfig(unittest.TestCase):
@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):
"""Don't have openjp2 library? Must error out. """Don't have openjpeg libraries? Must error out.
""" """
data = glymur.Jp2k(self.j2kfile).read() data = glymur.Jp2k(self.j2kfile).read()
with patch('glymur.lib.openjp2.OPENJP2', new=None): with patch('glymur.lib.openjp2.OPENJP2', new=None):

View file

@ -56,12 +56,10 @@ def load_tests(loader, tests, ignore):
tests.addTests(doctest.DocTestSuite('glymur.jp2box')) tests.addTests(doctest.DocTestSuite('glymur.jp2box'))
return tests return tests
@unittest.skipIf(glymur.version.openjpeg_version_tuple[0] < 2 or
@unittest.skipIf(OPENJP2_IS_V2_OFFICIAL, OPENJP2_IS_V2_OFFICIAL,
"Requires v2.0.0+ in order to run.") "Not supported until 2.0+.")
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.") @unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
"Missing openjp2 library.")
class TestChannelDefinition(unittest.TestCase): class TestChannelDefinition(unittest.TestCase):
"""Test suite for channel definition boxes.""" """Test suite for channel definition boxes."""
@ -398,8 +396,6 @@ class TestColourSpecificationBox(unittest.TestCase):
approximation=approx) approximation=approx)
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
"Missing openjp2 library.")
class TestAppend(unittest.TestCase): class TestAppend(unittest.TestCase):
"""Tests for append method.""" """Tests for append method."""
@ -492,8 +488,6 @@ class TestAppend(unittest.TestCase):
jp2.append(uuidbox) jp2.append(uuidbox)
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
"Missing openjp2 library.")
class TestWrap(unittest.TestCase): class TestWrap(unittest.TestCase):
"""Tests for wrap method.""" """Tests for wrap method."""
@ -749,264 +743,5 @@ class TestJpxBoxes(unittest.TestCase):
self.assertEqual(len(jpx.box[5].box), 0) self.assertEqual(len(jpx.box[5].box), 0)
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
class TestChannelDefinition(unittest.TestCase):
"""Test suite for channel definition boxes."""
@classmethod
def setUpClass(cls):
"""Need a one_plane plane image for greyscale testing."""
j2k = Jp2k(glymur.data.goodstuff())
data = j2k.read()
# Write the first component back out to file.
with tempfile.NamedTemporaryFile(suffix=".j2k", delete=False) as tfile:
grey_j2k = Jp2k(tfile.name, 'wb')
grey_j2k.write(data[:, :, 0])
cls.one_plane = tfile.name
# Write the first two components back out to file.
with tempfile.NamedTemporaryFile(suffix=".j2k", delete=False) as tfile:
grey_j2k = Jp2k(tfile.name, 'wb')
grey_j2k.write(data[:, :, 0:1])
cls.two_planes = tfile.name
# Write four components back out to file.
with tempfile.NamedTemporaryFile(suffix=".j2k", delete=False) as tfile:
rgba_jp2 = Jp2k(tfile.name, 'wb')
shape = (data.shape[0], data.shape[1], 1)
alpha = np.zeros((shape), dtype=data.dtype)
data4 = np.concatenate((data, alpha), axis=2)
rgba_jp2.write(data4)
cls.four_planes = tfile.name
@classmethod
def tearDownClass(cls):
os.unlink(cls.one_plane)
os.unlink(cls.two_planes)
os.unlink(cls.four_planes)
def setUp(self):
self.jp2file = glymur.data.nemo()
self.j2kfile = glymur.data.goodstuff()
j2k = Jp2k(self.j2kfile)
codestream = j2k.get_codestream()
height = codestream.segment[1].ysiz
width = codestream.segment[1].xsiz
num_components = len(codestream.segment[1].xrsiz)
self.jp2b = JPEG2000SignatureBox()
self.ftyp = FileTypeBox()
self.jp2h = JP2HeaderBox()
self.jp2c = ContiguousCodestreamBox()
self.ihdr = ImageHeaderBox(height=height, width=width,
num_components=num_components)
self.colr_rgb = ColourSpecificationBox(colorspace=glymur.core.SRGB)
self.colr_gr = ColourSpecificationBox(colorspace=glymur.core.GREYSCALE)
def tearDown(self):
pass
def test_cdef_no_inputs(self):
"""channel_type and association are required inputs."""
with self.assertRaises(IOError):
glymur.jp2box.ChannelDefinitionBox()
def test_rgb_with_index(self):
"""Just regular RGB."""
j2k = Jp2k(self.j2kfile)
channel_type = [COLOR, COLOR, COLOR]
association = [RED, GREEN, BLUE]
cdef = glymur.jp2box.ChannelDefinitionBox(index=[0, 1, 2],
channel_type=channel_type,
association=association)
boxes = [self.ihdr, self.colr_rgb, cdef]
self.jp2h.box = boxes
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
j2k.wrap(tfile.name, boxes=boxes)
jp2 = Jp2k(tfile.name)
jp2h = jp2.box[2]
boxes = [box.box_id for box in jp2h.box]
self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
self.assertEqual(jp2h.box[2].index, (0, 1, 2))
self.assertEqual(jp2h.box[2].channel_type,
(COLOR, COLOR, COLOR))
self.assertEqual(jp2h.box[2].association,
(RED, GREEN, BLUE))
def test_rgb(self):
"""Just regular RGB, but don't supply the optional index."""
j2k = Jp2k(self.j2kfile)
channel_type = [COLOR, COLOR, COLOR]
association = [RED, GREEN, BLUE]
cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
boxes = [self.ihdr, self.colr_rgb, cdef]
self.jp2h.box = boxes
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
j2k.wrap(tfile.name, boxes=boxes)
jp2 = Jp2k(tfile.name)
jp2h = jp2.box[2]
boxes = [box.box_id for box in jp2h.box]
self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
self.assertEqual(jp2h.box[2].index, (0, 1, 2))
self.assertEqual(jp2h.box[2].channel_type,
(COLOR, COLOR, COLOR))
self.assertEqual(jp2h.box[2].association,
(RED, GREEN, BLUE))
def test_rgba(self):
"""Just regular RGBA."""
j2k = Jp2k(self.four_planes)
channel_type = (COLOR, COLOR, COLOR, OPACITY)
association = (RED, GREEN, BLUE, WHOLE_IMAGE)
cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
boxes = [self.ihdr, self.colr_rgb, cdef]
self.jp2h.box = boxes
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
j2k.wrap(tfile.name, boxes=boxes)
jp2 = Jp2k(tfile.name)
jp2h = jp2.box[2]
boxes = [box.box_id for box in jp2h.box]
self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
self.assertEqual(jp2h.box[2].index, (0, 1, 2, 3))
self.assertEqual(jp2h.box[2].channel_type, channel_type)
self.assertEqual(jp2h.box[2].association, association)
def test_bad_rgba(self):
"""R, G, and B must be specified."""
j2k = Jp2k(self.four_planes)
channel_type = (COLOR, COLOR, OPACITY, OPACITY)
association = (RED, GREEN, BLUE, WHOLE_IMAGE)
cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
boxes = [self.ihdr, self.colr_rgb, cdef]
self.jp2h.box = boxes
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
with self.assertRaises(IOError):
j2k.wrap(tfile.name, boxes=boxes)
def test_grey(self):
"""Just regular greyscale."""
j2k = Jp2k(self.one_plane)
channel_type = (COLOR,)
association = (GREY,)
cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
boxes = [self.ihdr, self.colr_gr, cdef]
self.jp2h.box = boxes
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
j2k.wrap(tfile.name, boxes=boxes)
jp2 = Jp2k(tfile.name)
jp2h = jp2.box[2]
boxes = [box.box_id for box in jp2h.box]
self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
self.assertEqual(jp2h.box[2].index, (0,))
self.assertEqual(jp2h.box[2].channel_type, channel_type)
self.assertEqual(jp2h.box[2].association, association)
def test_grey_alpha(self):
"""Just regular greyscale plus alpha."""
j2k = Jp2k(self.two_planes)
channel_type = (COLOR, OPACITY)
association = (GREY, WHOLE_IMAGE)
cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
boxes = [self.ihdr, self.colr_gr, cdef]
self.jp2h.box = boxes
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
j2k.wrap(tfile.name, boxes=boxes)
jp2 = Jp2k(tfile.name)
jp2h = jp2.box[2]
boxes = [box.box_id for box in jp2h.box]
self.assertEqual(boxes, ['ihdr', 'colr', 'cdef'])
self.assertEqual(jp2h.box[2].index, (0, 1))
self.assertEqual(jp2h.box[2].channel_type, channel_type)
self.assertEqual(jp2h.box[2].association, association)
def test_bad_grey_alpha(self):
"""A greyscale image with alpha layer must specify a color channel"""
j2k = Jp2k(self.two_planes)
channel_type = (OPACITY, OPACITY)
association = (GREY, WHOLE_IMAGE)
# This cdef box
cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
boxes = [self.ihdr, self.colr_gr, cdef]
self.jp2h.box = boxes
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
with self.assertRaises((OSError, IOError)):
j2k.wrap(tfile.name, boxes=boxes)
def test_only_one_cdef_in_jp2h(self):
"""There can only be one channel definition box in the jp2 header."""
j2k = Jp2k(self.j2kfile)
channel_type = (COLOR, COLOR, COLOR)
association = (RED, GREEN, BLUE)
cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
boxes = [self.ihdr, cdef, self.colr_rgb, cdef]
self.jp2h.box = boxes
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
with self.assertRaises(IOError):
j2k.wrap(tfile.name, boxes=boxes)
def test_not_in_jp2h(self):
"""need cdef in jp2h"""
j2k = Jp2k(self.j2kfile)
boxes = [self.ihdr, self.colr_rgb]
self.jp2h.box = boxes
channel_type = (COLOR, COLOR, COLOR)
association = (RED, GREEN, BLUE)
cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
boxes = [self.jp2b, self.ftyp, self.jp2h, cdef, self.jp2c]
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
with self.assertRaises(IOError):
j2k.wrap(tfile.name, boxes=boxes)
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
same length.
"""
channel_type = (COLOR, COLOR, 3)
association = (RED, GREEN, BLUE)
with self.assertRaises(IOError):
glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
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):
glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
association=association)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -55,8 +55,8 @@ def load_tests(loader, tests, ignore):
return tests return tests
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None and @unittest.skipIf(glymur.version.openjpeg_version_tuple[0] < 2 or
not OPENJP2_IS_V2_OFFICIAL, OPENJP2_IS_V2_OFFICIAL,
"Missing openjp2 library version 2.0+.") "Missing openjp2 library version 2.0+.")
class TestJp2k_2_1(unittest.TestCase): class TestJp2k_2_1(unittest.TestCase):
"""Test suite for version 2.0+ of openjpeg software""" """Test suite for version 2.0+ of openjpeg software"""
@ -146,7 +146,7 @@ class TestJp2k_2_0(unittest.TestCase):
def test_extra_components_on_v2(self): def test_extra_components_on_v2(self):
"""must error out in 1.x with extra components.""" """must error out in 1.x with extra components."""
# Extra components seems to require 2.0+. Verify that we error out. # Extra components seems to require 2.0+. Verify that we error out.
with self.assertRaises(OSError): with self.assertRaises((IOError, OSError)):
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
j = Jp2k(tfile.name, 'wb') j = Jp2k(tfile.name, 'wb')
data = np.zeros((128, 128, 4), dtype=np.uint8) data = np.zeros((128, 128, 4), dtype=np.uint8)

View file

@ -12,6 +12,7 @@ seem like logical negative tests to add.
# pylint: disable=F0401 # pylint: disable=F0401
import os import os
import re
import sys import sys
import tempfile import tempfile
@ -22,16 +23,15 @@ else:
import numpy as np import numpy as np
from .fixtures import read_image, NO_READ_BACKEND, NO_READ_BACKEND_MSG from .fixtures import OPJ_DATA_ROOT, opj_data_file, read_image
from .fixtures import OPJ_DATA_ROOT, opj_data_file from .fixtures import NO_READ_BACKEND, NO_READ_BACKEND_MSG
from glymur import Jp2k from glymur import Jp2k
import glymur import glymur
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None, @unittest.skipIf(re.match(r"""1\.[01234]""", glymur.version.openjpeg_version),
"Missing openjp2 library.") "Functionality not implemented for 1.3, 1.4")
@unittest.skipIf(NO_READ_BACKEND, NO_READ_BACKEND_MSG)
@unittest.skipIf(OPJ_DATA_ROOT is None, @unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_OPJ_DATA_ROOT environment variable not set") "OPJ_OPJ_DATA_ROOT environment variable not set")
class TestSuiteNegative(unittest.TestCase): class TestSuiteNegative(unittest.TestCase):
@ -44,6 +44,7 @@ class TestSuiteNegative(unittest.TestCase):
def tearDown(self): def tearDown(self):
pass pass
@unittest.skipIf(NO_READ_BACKEND, NO_READ_BACKEND_MSG)
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.") @unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_psnr_with_cratios(self): def test_psnr_with_cratios(self):
"""Using psnr with cratios options is not allowed.""" """Using psnr with cratios options is not allowed."""

View file

@ -10,6 +10,7 @@
# pylint: disable=R0904 # pylint: disable=R0904
import os import os
import re
import struct import struct
import sys import sys
import tempfile import tempfile
@ -36,8 +37,8 @@ from .fixtures import OPJ_DATA_ROOT, opj_data_file
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.") @unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None, @unittest.skipIf(re.match(r"""1\.[01234]""", glymur.version.openjpeg_version),
"Missing openjp2 library.") "Need at least 1.5 in order to write jp2 files.")
class TestPrintingNeedsLib(unittest.TestCase): class TestPrintingNeedsLib(unittest.TestCase):
"""These tests require the library, mostly in order to just setup the test. """These tests require the library, mostly in order to just setup the test.
""" """

View file

@ -13,7 +13,9 @@ from distutils.version import LooseVersion
from .lib import openjpeg as opj from .lib import openjpeg as opj
from .lib import openjp2 as opj2 from .lib import openjp2 as opj2
version = "0.5.1" # Do not change the format of this next line! Doing so risks breaking
# setup.py
version = "0.5.5"
_sv = LooseVersion(version) _sv = LooseVersion(version)
version_tuple = _sv.version version_tuple = _sv.version

View file

@ -1,4 +1,6 @@
from setuptools import setup, find_packages from setuptools import setup, find_packages
import os
import re
import sys import sys
kwargs = {'name': 'Glymur', kwargs = {'name': 'Glymur',
@ -38,7 +40,11 @@ clssfrs = ["Programming Language :: Python",
"Topic :: Software Development :: Libraries :: Python Modules"] "Topic :: Software Development :: Libraries :: Python Modules"]
kwargs['classifiers'] = clssfrs kwargs['classifiers'] = clssfrs
import glymur # Get the version string. Cannot do this by importing glymur!
kwargs['version'] = glymur.version.version version_file = os.path.join('glymur', 'version.py')
with open('glymur/version.py', 'rt') as fptr:
contents = fptr.read()
match = re.search('version\s*=\s*"(?P<version>\d*.\d*.\d*.*)"\n', contents)
kwargs['version'] = match.group('version')
setup(**kwargs) setup(**kwargs)