Merge branch 'release-0.5.5'
This commit is contained in:
commit
6c90504270
14 changed files with 197 additions and 443 deletions
|
|
@ -5,14 +5,17 @@ python:
|
|||
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq libopenjpeg2
|
||||
- sudo apt-get install -qq python-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
|
||||
install: "pip install -r travis-requirements.txt --use-mirrors"
|
||||
|
||||
# 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"
|
||||
|
||||
notifications:
|
||||
|
|
|
|||
10
CHANGES.txt
10
CHANGES.txt
|
|
@ -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
|
||||
that failed if OPJ_DATA_ROOT not set.
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ copyright = u'2013, John Evans'
|
|||
# The short X.Y version.
|
||||
version = '0.5'
|
||||
# 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
|
||||
# for a list of supported languages.
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ Most users won't need to read this! You've been warned...
|
|||
Glymur Configuration
|
||||
''''''''''''''''''''''
|
||||
|
||||
The default glymur installation process relies upon OpenJPEG version
|
||||
1.X being properly installed on your system. If you have version 1.5 you can
|
||||
The default glymur installation process relies upon OpenJPEG
|
||||
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
|
||||
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*
|
||||
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
|
||||
and running OpenJPEG's test suite, check their instructions for all this.
|
||||
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,
|
||||
and because ctypes accesses libraries in a platform-dependent manner, it is
|
||||
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
|
||||
using OpenJPEG as provided by your package manager). The configuration
|
||||
format is the same as used by Python's configparser module, i.e. ::
|
||||
the openjpeg or openjp2 libraries (linux users don't need to bother with this
|
||||
if you are using OpenJPEG as provided by your package manager). The
|
||||
configuration format is the same as used by Python's configparser module,
|
||||
i.e. ::
|
||||
|
||||
[library]
|
||||
openjp2: /opt/openjp2-svn/lib/libopenjp2.so
|
||||
|
||||
This assumes, of course, that you've installed OpenJPEG into
|
||||
/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 ::
|
||||
|
||||
$HOME/.config/glymur/glymurrc
|
||||
|
|
@ -70,7 +71,8 @@ packages/RPMs/ports/whatever without going through pip.
|
|||
Mac OS X
|
||||
--------
|
||||
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
|
||||
* py33-numpy
|
||||
|
|
|
|||
|
|
@ -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
|
||||
COD segment section), but you can take a shortcut by supplying -1 as the
|
||||
|
|
@ -14,7 +14,7 @@ resolution level. ::
|
|||
>>> j = glymur.Jp2k(file)
|
||||
>>> thumbnail = j.read(rlevel=-1)
|
||||
|
||||
display metadata?
|
||||
... display metadata?
|
||||
=================
|
||||
There are two ways. From the unix command line, the script *jp2dump* is
|
||||
available. ::
|
||||
|
|
@ -34,7 +34,7 @@ codestream box, only the main header is printed. It is possible to print
|
|||
|
||||
>>> 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).
|
||||
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)
|
||||
>>> 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
|
||||
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
|
||||
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
|
||||
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
|
||||
an image in a set of boxes that includes a channel definition box.
|
||||
|
||||
This example is based on SciPy example code found at
|
||||
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
|
||||
image isn't square.
|
||||
Instead of a circular mask we'll make it an ellipse since the source
|
||||
image isn't square. ::
|
||||
|
||||
>>> import numpy as np
|
||||
>>> import glymur
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@ Glymur: a Python interface for JPEG 2000
|
|||
|
||||
**Glymur** is an interface to the OpenJPEG library
|
||||
which allows one to read and write JPEG 2000 files from within Python.
|
||||
Glymur supports both reading and writing of JPEG 2000 images. Writing
|
||||
JPEG 2000 images is currently limited to images that can fit in memory,
|
||||
however.
|
||||
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
|
||||
|
||||
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
|
||||
|
|
@ -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,
|
||||
please consult http://www.openjpeg.org.
|
||||
|
||||
If you use MacPorts on the mac or if you have a sufficiently recent
|
||||
version of Linux, your package manager should already provide you
|
||||
with a version of OpenJPEG 1.X with which glymur can already use
|
||||
for read-only purposes. If your platform is windows, I suggest
|
||||
using the windows installers provided to you by the OpenJPEG
|
||||
If you use MacPorts or if you have a sufficiently recent version of
|
||||
Linux, your package manager should already provide you with a version of
|
||||
OpenJPEG 1.X which glymur can already use. If your platform is windows,
|
||||
I suggest using the windows installers provided to you by the OpenJPEG
|
||||
folks at https://code.google.com/p/openjpeg/downloads/list .
|
||||
|
||||
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
|
||||
`--user` option on linux ::
|
||||
|
||||
$ export PYTHONPATH=$HOME/.local/lib/python3.3/site-packages
|
||||
$ 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.
|
||||
|
|
|
|||
|
|
@ -553,119 +553,6 @@ class CodestreamInfoV2(ctypes.Structure):
|
|||
# information regarding tiles inside of image
|
||||
("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):
|
||||
"""Set a generic function as the restype attribute of all OpenJPEG
|
||||
|
|
@ -684,19 +571,6 @@ def check_error(status):
|
|||
else:
|
||||
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):
|
||||
"""Creates a J2K/JP2 compress structure.
|
||||
|
|
@ -712,6 +586,9 @@ def create_compress(codec_format):
|
|||
-------
|
||||
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)
|
||||
return codec
|
||||
|
||||
|
|
@ -735,6 +612,10 @@ def decode(codec, stream, image):
|
|||
RuntimeError
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -761,13 +642,19 @@ def decode_tile_data(codec, tidx, data, data_size, stream):
|
|||
RuntimeError
|
||||
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))
|
||||
OPENJP2.opj_decode_tile_data(codec,
|
||||
ctypes.c_uint32(tidx),
|
||||
datap,
|
||||
ctypes.c_uint32(data_size),
|
||||
stream)
|
||||
return codec
|
||||
|
||||
|
||||
def create_decompress(codec_format):
|
||||
|
|
@ -784,6 +671,9 @@ def create_decompress(codec_format):
|
|||
-------
|
||||
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)
|
||||
return codec
|
||||
|
||||
|
|
@ -798,6 +688,8 @@ def destroy_codec(codec):
|
|||
codec : CODEC_TYPE
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -818,6 +710,9 @@ def encode(codec, stream):
|
|||
RuntimeError
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -836,6 +731,9 @@ def get_cstr_info(codec):
|
|||
cstr_info_p : CodestreamInfoV2
|
||||
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)
|
||||
return cstr_info_p
|
||||
|
||||
|
|
@ -861,6 +759,12 @@ def get_decoded_tile(codec, stream, imagep, tile_index):
|
|||
RuntimeError
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -874,6 +778,10 @@ def destroy_cstr_info(cstr_info_p):
|
|||
cstr_info_p : CodestreamInfoV2 pointer
|
||||
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))
|
||||
|
||||
|
||||
|
|
@ -894,6 +802,8 @@ def end_compress(codec, stream):
|
|||
RuntimeError
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -914,6 +824,8 @@ def end_decompress(codec, stream):
|
|||
RuntimeError
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -927,6 +839,9 @@ def image_destroy(image):
|
|||
image : ImageType pointer
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -947,6 +862,11 @@ def image_create(comptparms, clrspc):
|
|||
image : ImageType
|
||||
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),
|
||||
comptparms,
|
||||
clrspc)
|
||||
|
|
@ -970,6 +890,12 @@ def image_tile_create(comptparms, clrspc):
|
|||
image : ImageType
|
||||
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),
|
||||
comptparms,
|
||||
clrspc)
|
||||
|
|
@ -998,6 +924,11 @@ def read_header(stream, codec):
|
|||
RuntimeError
|
||||
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)()
|
||||
OPENJP2.opj_read_header(stream, codec, ctypes.byref(imagep))
|
||||
return imagep
|
||||
|
|
@ -1035,6 +966,19 @@ def read_tile_header(codec, stream):
|
|||
RuntimeError
|
||||
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()
|
||||
data_size = ctypes.c_uint32()
|
||||
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
|
||||
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,
|
||||
ctypes.c_int32(start_x),
|
||||
ctypes.c_int32(start_y),
|
||||
|
|
@ -1103,6 +1055,10 @@ def set_default_decoder_parameters():
|
|||
dparam : DecompressionParametersType
|
||||
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()
|
||||
OPENJP2.opj_set_default_decoder_parameters(ctypes.byref(dparams))
|
||||
return dparams
|
||||
|
|
@ -1138,6 +1094,10 @@ def set_default_encoder_parameters():
|
|||
cparameters : CompressionParametersType
|
||||
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()
|
||||
OPENJP2.opj_set_default_encoder_parameters(ctypes.byref(cparams))
|
||||
return cparams
|
||||
|
|
@ -1162,6 +1122,10 @@ def set_error_handler(codec, handler, data=None):
|
|||
RuntimeError
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -1184,6 +1148,10 @@ def set_info_handler(codec, handler, data=None):
|
|||
RuntimeError
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -1206,6 +1174,11 @@ def set_warning_handler(codec, handler, data=None):
|
|||
RuntimeError
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -1226,6 +1199,10 @@ def setup_decoder(codec, dparams):
|
|||
RuntimeError
|
||||
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))
|
||||
|
||||
|
||||
|
|
@ -1249,6 +1226,11 @@ def setup_encoder(codec, cparams, image):
|
|||
RuntimeError
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -1271,6 +1253,11 @@ def start_compress(codec, image, stream):
|
|||
RuntimeError
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -1292,6 +1279,9 @@ def stream_create_default_file_stream(fptr, isa_read_stream):
|
|||
stream : stream_t
|
||||
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
|
||||
stream = OPENJP2.opj_stream_create_default_file_stream(fptr, read_stream)
|
||||
return stream
|
||||
|
|
@ -1315,6 +1305,9 @@ def stream_create_default_file_stream_v3(fname, isa_read_stream):
|
|||
stream : stream_t
|
||||
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
|
||||
file_argument = ctypes.c_char_p(fname.encode())
|
||||
stream = OPENJP2.opj_stream_create_default_file_stream_v3(file_argument,
|
||||
|
|
@ -1332,6 +1325,8 @@ def stream_destroy(stream):
|
|||
stream : STREAM_TYPE_P
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -1345,6 +1340,8 @@ def stream_destroy_v3(stream):
|
|||
stream : STREAM_TYPE_P
|
||||
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)
|
||||
|
||||
|
||||
|
|
@ -1371,6 +1368,13 @@ def write_tile(codec, tile_index, data, data_size, stream):
|
|||
RuntimeError
|
||||
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))
|
||||
OPENJP2.opj_write_tile(codec,
|
||||
ctypes.c_uint32(int(tile_index)),
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ class TestConfig(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
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()
|
||||
with patch('glymur.lib.openjp2.OPENJP2', new=None):
|
||||
|
|
|
|||
|
|
@ -56,12 +56,10 @@ def load_tests(loader, tests, ignore):
|
|||
tests.addTests(doctest.DocTestSuite('glymur.jp2box'))
|
||||
return tests
|
||||
|
||||
|
||||
@unittest.skipIf(OPENJP2_IS_V2_OFFICIAL,
|
||||
"Requires v2.0.0+ in order to run.")
|
||||
@unittest.skipIf(glymur.version.openjpeg_version_tuple[0] < 2 or
|
||||
OPENJP2_IS_V2_OFFICIAL,
|
||||
"Not supported until 2.0+.")
|
||||
@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):
|
||||
"""Test suite for channel definition boxes."""
|
||||
|
||||
|
|
@ -398,8 +396,6 @@ class TestColourSpecificationBox(unittest.TestCase):
|
|||
approximation=approx)
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestAppend(unittest.TestCase):
|
||||
"""Tests for append method."""
|
||||
|
||||
|
|
@ -492,8 +488,6 @@ class TestAppend(unittest.TestCase):
|
|||
jp2.append(uuidbox)
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestWrap(unittest.TestCase):
|
||||
"""Tests for wrap method."""
|
||||
|
||||
|
|
@ -749,264 +743,5 @@ class TestJpxBoxes(unittest.TestCase):
|
|||
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__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ def load_tests(loader, tests, ignore):
|
|||
return tests
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None and
|
||||
not OPENJP2_IS_V2_OFFICIAL,
|
||||
@unittest.skipIf(glymur.version.openjpeg_version_tuple[0] < 2 or
|
||||
OPENJP2_IS_V2_OFFICIAL,
|
||||
"Missing openjp2 library version 2.0+.")
|
||||
class TestJp2k_2_1(unittest.TestCase):
|
||||
"""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):
|
||||
"""must error out in 1.x with extra components."""
|
||||
# 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:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
data = np.zeros((128, 128, 4), dtype=np.uint8)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ seem like logical negative tests to add.
|
|||
# pylint: disable=F0401
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
|
|
@ -22,16 +23,15 @@ else:
|
|||
|
||||
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
|
||||
from .fixtures import OPJ_DATA_ROOT, opj_data_file, read_image
|
||||
from .fixtures import NO_READ_BACKEND, NO_READ_BACKEND_MSG
|
||||
|
||||
from glymur import Jp2k
|
||||
import glymur
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
@unittest.skipIf(NO_READ_BACKEND, NO_READ_BACKEND_MSG)
|
||||
@unittest.skipIf(re.match(r"""1\.[01234]""", glymur.version.openjpeg_version),
|
||||
"Functionality not implemented for 1.3, 1.4")
|
||||
@unittest.skipIf(OPJ_DATA_ROOT is None,
|
||||
"OPJ_OPJ_DATA_ROOT environment variable not set")
|
||||
class TestSuiteNegative(unittest.TestCase):
|
||||
|
|
@ -44,6 +44,7 @@ class TestSuiteNegative(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
pass
|
||||
|
||||
@unittest.skipIf(NO_READ_BACKEND, NO_READ_BACKEND_MSG)
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_psnr_with_cratios(self):
|
||||
"""Using psnr with cratios options is not allowed."""
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
# pylint: disable=R0904
|
||||
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
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(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
@unittest.skipIf(re.match(r"""1\.[01234]""", glymur.version.openjpeg_version),
|
||||
"Need at least 1.5 in order to write jp2 files.")
|
||||
class TestPrintingNeedsLib(unittest.TestCase):
|
||||
"""These tests require the library, mostly in order to just setup the test.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ from distutils.version import LooseVersion
|
|||
from .lib import openjpeg as opj
|
||||
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)
|
||||
version_tuple = _sv.version
|
||||
|
||||
|
|
|
|||
10
setup.py
10
setup.py
|
|
@ -1,4 +1,6 @@
|
|||
from setuptools import setup, find_packages
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
kwargs = {'name': 'Glymur',
|
||||
|
|
@ -38,7 +40,11 @@ clssfrs = ["Programming Language :: Python",
|
|||
"Topic :: Software Development :: Libraries :: Python Modules"]
|
||||
kwargs['classifiers'] = clssfrs
|
||||
|
||||
import glymur
|
||||
kwargs['version'] = glymur.version.version
|
||||
# Get the version string. Cannot do this by importing glymur!
|
||||
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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue