diff --git a/.travis.yml b/.travis.yml index 4898e65..cd80fa2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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: diff --git a/CHANGES.txt b/CHANGES.txt index d0e2bce..30387a6 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,9 +1,11 @@ +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 teests that have been failing since 0.5. +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 diff --git a/docs/source/conf.py b/docs/source/conf.py index e01cc91..f847e68 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -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.4' +release = '0.5.5' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/detailed_installation.rst b/docs/source/detailed_installation.rst index 3f42275..3e4d9dc 100644 --- a/docs/source/detailed_installation.rst +++ b/docs/source/detailed_installation.rst @@ -7,8 +7,8 @@ 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* @@ -35,7 +35,7 @@ i.e. :: 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 @@ -71,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 diff --git a/docs/source/how_do_i.rst b/docs/source/how_do_i.rst index cc0b227..212862d 100644 --- a/docs/source/how_do_i.rst +++ b/docs/source/how_do_i.rst @@ -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 diff --git a/docs/source/introduction.rst b/docs/source/introduction.rst index 37dcb5a..e1a3b3b 100644 --- a/docs/source/introduction.rst +++ b/docs/source/introduction.rst @@ -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. diff --git a/glymur/lib/openjp2.py b/glymur/lib/openjp2.py index 8c0ae32..f056db0 100644 --- a/glymur/lib/openjp2.py +++ b/glymur/lib/openjp2.py @@ -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)), diff --git a/glymur/test/test_config.py b/glymur/test/test_config.py index 16af663..32f067a 100644 --- a/glymur/test/test_config.py +++ b/glymur/test/test_config.py @@ -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): diff --git a/glymur/version.py b/glymur/version.py index 5e4122b..192859f 100644 --- a/glymur/version.py +++ b/glymur/version.py @@ -13,7 +13,9 @@ from distutils.version import LooseVersion from .lib import openjpeg as opj from .lib import openjp2 as opj2 -version = "0.5.4" +# 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 diff --git a/setup.py b/setup.py index 8d62705..89e69f7 100644 --- a/setup.py +++ b/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\d*.\d*.\d*.*)"\n', contents) + kwargs['version'] = match.group('version') setup(**kwargs)