diff --git a/glymur/_uuid_io/Exif.py b/glymur/_uuid_io/Exif.py index 967468d..b07cd42 100644 --- a/glymur/_uuid_io/Exif.py +++ b/glymur/_uuid_io/Exif.py @@ -3,6 +3,7 @@ Handlers for Exif UUIDs. Be nice if we would find a standard for this. """ import pprint +import re import struct import sys import warnings diff --git a/glymur/codestream.py b/glymur/codestream.py index d01795f..67b2d56 100644 --- a/glymur/codestream.py +++ b/glymur/codestream.py @@ -663,7 +663,7 @@ class Codestream(object): bitdepth = tuple(((x & 0x7f) + 1) for x in data[0::3]) signed = tuple(((x & 0xb0) > 0) for x in data[0::3]) - + xrsiz = data[1::3] yrsiz = data[2::3] @@ -1529,7 +1529,7 @@ class SIZsegment(Segment): signed=self.signed, xyrsiz=(self.xrsiz, self.yrsiz)) return msg - + def __str__(self): msg = Segment.__str__(self) msg += '\n ' diff --git a/glymur/jp2box.py b/glymur/jp2box.py index da8e1c9..b3fcf89 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -19,7 +19,6 @@ import os import pprint import struct import sys -import traceback import uuid import warnings import xml.etree.cElementTree as ET @@ -563,11 +562,11 @@ class CodestreamHeaderBox(Jp2kBox): box : list List of boxes contained in this superbox. """ - def __init__(self, box=[], length=0, offset=-1): + def __init__(self, box=None, length=0, offset=-1): Jp2kBox.__init__(self, box_id='jpch', longname='Codestream Header') self.length = length self.offset = offset - self.box = box + self.box = box if box is not None else [] def __repr__(self): msg = "glymur.jp2box.CodestreamHeaderBox(box={0})".format(self.box) @@ -625,12 +624,12 @@ class CompositingLayerHeaderBox(Jp2kBox): box : list List of boxes contained in this superbox. """ - def __init__(self, box=[], length=0, offset=-1): + def __init__(self, box=None, length=0, offset=-1): Jp2kBox.__init__(self, box_id='jplh', longname='Compositing Layer Header') self.length = length self.offset = offset - self.box = [] + self.box = box if box is not None else [] def __repr__(self): msg = "glymur.jp2box.CompositingLayerHeaderBox(box={0})" @@ -1073,11 +1072,11 @@ class AssociationBox(Jp2kBox): box : list List of boxes contained in this superbox. """ - def __init__(self, box=[], length=0, offset=-1): + def __init__(self, box=None, length=0, offset=-1): Jp2kBox.__init__(self, box_id='asoc', longname='Association') self.length = length self.offset = offset - self.box = box + self.box = box if box is not None else [] def __repr__(self): msg = "glymur.jp2box.AssociationBox(box={0})".format(self.box) @@ -1135,11 +1134,11 @@ class JP2HeaderBox(Jp2kBox): box : list List of boxes contained in this superbox. """ - def __init__(self, box=[], length=0, offset=-1): + def __init__(self, box=None, length=0, offset=-1): Jp2kBox.__init__(self, box_id='jp2h', longname='JP2 Header') self.length = length self.offset = offset - self.box = box + self.box = box if box is not None else [] def __repr__(self): msg = "glymur.jp2box.JP2HeaderBox(box={0})".format(self.box) @@ -1621,11 +1620,11 @@ class ResolutionBox(Jp2kBox): box : list List of boxes contained in this superbox. """ - def __init__(self, box=[], length=0, offset=-1): + def __init__(self, box=None, length=0, offset=-1): Jp2kBox.__init__(self, box_id='res ', longname='Resolution') self.length = length self.offset = offset - self.box = box + self.box = box if box is not None else [] def __repr__(self): msg = "glymur.jp2box.ResolutionBox(box={0})" @@ -2040,11 +2039,11 @@ class UUIDInfoBox(Jp2kBox): box : list List of boxes contained in this superbox. """ - def __init__(self, box=[], length=0, offset=-1): + def __init__(self, box=None, length=0, offset=-1): Jp2kBox.__init__(self, box_id='uinf', longname='UUIDInfo') self.length = length self.offset = offset - self.box = box + self.box = box if box is not None else [] def __repr__(self): msg = "glymur.jp2box.UUIDInfoBox(box={0})".format(self.box) diff --git a/glymur/jp2k.py b/glymur/jp2k.py index a337ae7..4eb8b2a 100644 --- a/glymur/jp2k.py +++ b/glymur/jp2k.py @@ -484,17 +484,17 @@ class Jp2k(Jp2kBox): stack.callback(opj2.image_destroy, image) _populate_image_struct(cparams, image, img_array) - + codec = opj2.create_compress(cparams.codec_fmt) stack.callback(opj2.destroy_codec, codec) - + info_handler = _INFO_CALLBACK if verbose else None opj2.set_info_handler(codec, info_handler) opj2.set_warning_handler(codec, _WARNING_CALLBACK) opj2.set_error_handler(codec, _ERROR_CALLBACK) - + opj2.setup_encoder(codec, cparams, image) - + if _OPENJP2_IS_OFFICIAL_V2: fptr = libc.fopen(self.filename, 'wb') strm = opj2.stream_create_default_file_stream(fptr, False) @@ -505,11 +505,11 @@ class Jp2k(Jp2kBox): strm = opj2.stream_create_default_file_stream_v3(self.filename, False) stack.callback(opj2.stream_destroy_v3, strm) - + opj2.start_compress(codec, image, strm) opj2.encode(codec, strm) opj2.end_compress(codec, strm) - + # Refresh the metadata. self.parse() diff --git a/glymur/lib/openjpeg.py b/glymur/lib/openjpeg.py index 5b1183f..418e9df 100644 --- a/glymur/lib/openjpeg.py +++ b/glymur/lib/openjpeg.py @@ -11,8 +11,8 @@ import numpy as np from .config import glymur_config _, OPENJPEG = glymur_config() -# Maximum number of tile parts expected by JPWL: increase at your will -JPWL_MAX_NO_TILESPECS = 16 +# Maximum number of tile parts expected by JPWL: increase at your will +JPWL_MAX_NO_TILESPECS = 16 J2K_MAXRLVLS = 33 # Number of maximum resolution level authorized PATH_LEN = 4096 # maximum allowed size for filenames @@ -58,7 +58,7 @@ class CommonStructType(ctypes.Structure): ("mj2_handle", ctypes.c_void_p)] -STREAM_READ = 0x0001 # The stream was opened for reading. +STREAM_READ = 0x0001 # The stream was opened for reading. STREAM_WRITE = 0x0002 # The stream was opened for writing. class CioType(ctypes.Structure): """Byte input-output stream (CIO) @@ -81,7 +81,7 @@ class CioType(ctypes.Structure): class CompressionInfoType(CommonStructType): - """Common fields between JPEG-2000 compression and decompression contexts. + """Common fields between JPEG-2000 compression and decompression contexts. This is for compression contexts. Corresponds to common_struct_t. """ pass @@ -91,68 +91,68 @@ class PocType(ctypes.Structure): """Progression order changes.""" _fields_ = [("resno", ctypes.c_int), # Resolution num start, Component num start, given by POC - ("compno0", ctypes.c_int), + ("compno0", ctypes.c_int), # Layer num end,Resolution num end, Component num end, given by POC - ("layno1", ctypes.c_int), - ("resno1", ctypes.c_int), - ("compno1", ctypes.c_int), + ("layno1", ctypes.c_int), + ("resno1", ctypes.c_int), + ("compno1", ctypes.c_int), - # Layer num start,Precinct num start, Precinct num end - ("layno0", ctypes.c_int), - ("precno0", ctypes.c_int), - ("precno1", ctypes.c_int), + # Layer num start,Precinct num start, Precinct num end + ("layno0", ctypes.c_int), + ("precno0", ctypes.c_int), + ("precno1", ctypes.c_int), # Progression order enum # OPJ_PROG_ORDER prg1,prg; - ("prg1", ctypes.c_int), - ("prg", ctypes.c_int), + ("prg1", ctypes.c_int), + ("prg", ctypes.c_int), - # Progression order string + # Progression order string # char progorder[5]; ("progorder", ctypes.c_char * 5), - # Tile number + # Tile number # int tile; - ("tile", ctypes.c_int), + ("tile", ctypes.c_int), # /** Start and end values for Tile width and height*/ # int tx0,tx1,ty0,ty1; - ("tx0", ctypes.c_int), - ("tx1", ctypes.c_int), - ("ty0", ctypes.c_int), - ("ty1", ctypes.c_int), + ("tx0", ctypes.c_int), + ("tx1", ctypes.c_int), + ("ty0", ctypes.c_int), + ("ty1", ctypes.c_int), # /** Start value, initialised in pi_initialise_encode*/ # int layS, resS, compS, prcS; - ("layS", ctypes.c_int), - ("resS", ctypes.c_int), - ("compS", ctypes.c_int), + ("layS", ctypes.c_int), + ("resS", ctypes.c_int), + ("compS", ctypes.c_int), ("prcS", ctypes.c_int), # /** End value, initialised in pi_initialise_encode */ # int layE, resE, compE, prcE; - ("layE", ctypes.c_int), - ("resE", ctypes.c_int), - ("compE", ctypes.c_int), - ("prcE", ctypes.c_int), + ("layE", ctypes.c_int), + ("resE", ctypes.c_int), + ("compE", ctypes.c_int), + ("prcE", ctypes.c_int), # Start and end values of Tile width and height, initialised in # pi_initialise_encode int txS,txE,tyS,tyE,dx,dy; - ("txS", ctypes.c_int), - ("txE", ctypes.c_int), - ("tyS", ctypes.c_int), - ("tyE", ctypes.c_int), - ("dx", ctypes.c_int), - ("dy", ctypes.c_int), + ("txS", ctypes.c_int), + ("txE", ctypes.c_int), + ("tyS", ctypes.c_int), + ("tyE", ctypes.c_int), + ("dx", ctypes.c_int), + ("dy", ctypes.c_int), - # Temporary values for Tile parts, initialised in pi_create_encode + # Temporary values for Tile parts, initialised in pi_create_encode # int lay_t, res_t, comp_t, prc_t,tx0_t,ty0_t; - ("lay_t", ctypes.c_int), - ("res_t", ctypes.c_int), - ("comp_t", ctypes.c_int), - ("prc_t", ctypes.c_int), - ("tx0_t", ctypes.c_int), + ("lay_t", ctypes.c_int), + ("res_t", ctypes.c_int), + ("comp_t", ctypes.c_int), + ("prc_t", ctypes.c_int), + ("tx0_t", ctypes.c_int), ("ty0_t", ctypes.c_int)] @@ -374,23 +374,23 @@ class DecompressionParametersType(ctypes.Structure): class ImageComptParmType(ctypes.Structure): """Component parameters structure used by the opj_image_create function. """ - _fields_ = [ - # XRsiz: horizontal separation of a sample of ith component with - # respect to the reference grid - ("dx", ctypes.c_int), + _fields_ = [ + # XRsiz: horizontal separation of a sample of ith component with + # respect to the reference grid + ("dx", ctypes.c_int), - # YRsiz: vertical separation of a sample of ith component with + # YRsiz: vertical separation of a sample of ith component with # respect to the reference grid */ - ("dy", ctypes.c_int), - - # data width, height - ("w", ctypes.c_int), - ("h", ctypes.c_int), + ("dy", ctypes.c_int), - # x component offset compared to the whole image - # y component offset compared to the whole image - ("x0", ctypes.c_int), - ("y0", ctypes.c_int), + # data width, height + ("w", ctypes.c_int), + ("h", ctypes.c_int), + + # x component offset compared to the whole image + # y component offset compared to the whole image + ("x0", ctypes.c_int), + ("y0", ctypes.c_int), # precision ('prec', ctypes.c_int), @@ -398,7 +398,7 @@ class ImageComptParmType(ctypes.Structure): # image depth in bits ('bpp', ctypes.c_int), - # signed (1) / unsigned (0) + # signed (1) / unsigned (0) ('sgnd', ctypes.c_int)] @@ -511,7 +511,7 @@ def destroy_compress(cinfo): def encode(cinfo, cio, image): """Wrapper for openjpeg library function opj_encode. - Encodes an image into a JPEG-2000 codestream. + Encodes an image into a JPEG-2000 codestream. Parameters ---------- @@ -540,7 +540,7 @@ def destroy_decompress(dinfo): def image_cmptparm_t_from_np(np_image): """Return appropriate image_cmptparm_t based on given numpy array. """ - try: + try: num_comps = np_image.shape[2] except IndexError: num_comps = 1 @@ -557,17 +557,17 @@ def image_cmptparm_t_from_np(np_image): bpp = 8 sgnd = 1 elif np_image.dtype == np.uint16: - prec = 16 - bpp = 16 + prec = 16 + bpp = 16 sgnd = 0 elif np_image.dtype == np.int16: - prec = 16 - bpp = 16 + prec = 16 + bpp = 16 sgnd = 1 else: raise(TypeError("unhandled")) - for j in range(0, num_comps): + for j in range(0, num_comps): tarr[j].dx = 1 tarr[j].dy = 1 tarr[j].w = np_image.shape[1] diff --git a/glymur/lib/test/test_openjp2.py b/glymur/lib/test/test_openjp2.py index 54d8254..8694507 100644 --- a/glymur/lib/test/test_openjp2.py +++ b/glymur/lib/test/test_openjp2.py @@ -1,5 +1,5 @@ """ -Tests for libopenjp2 wrapping functions. +Tests for libopenjp2 wrapping functions. """ # R0904: Seems like pylint is fooled in this situation # W0142: using kwargs is ok in this context @@ -212,7 +212,7 @@ class TestOpenJP2(unittest.TestCase): """Runs test designated tte3 in OpenJPEG test suite.""" with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile: xtx3_setup(tfile.name) - self.assertTrue(True) + self.assertTrue(True) def test_rta3(self): """Runs test designated rta3 in OpenJPEG test suite.""" @@ -221,13 +221,13 @@ class TestOpenJP2(unittest.TestCase): codec_format = openjp2.CODEC_J2K self.j2k_random_tile_access(tfile.name, codec_format) - self.assertTrue(True) + self.assertTrue(True) def test_tte4(self): """Runs test designated tte4 in OpenJPEG test suite.""" with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile: xtx4_setup(tfile.name) - self.assertTrue(True) + self.assertTrue(True) def test_rta4(self): """Runs test designated rta4 in OpenJPEG test suite.""" @@ -241,7 +241,7 @@ class TestOpenJP2(unittest.TestCase): """Runs test designated tte5 in OpenJPEG test suite.""" with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile: xtx5_setup(tfile.name) - self.assertTrue(True) + self.assertTrue(True) def test_rta5(self): """Runs test designated rta5 in OpenJPEG test suite.""" @@ -332,8 +332,8 @@ def tile_encoder(**kwargs): def tile_decoder(**kwargs): """Fixture called with various configurations by many tests. - - Reads a tile. That's all it does. + + Reads a tile. That's all it does. """ stream = openjp2.stream_create_default_file_stream_v3(kwargs['filename'], True) @@ -355,7 +355,7 @@ def tile_decoder(**kwargs): openjp2.setup_decoder(codec, dparam) image = openjp2.read_header(stream, codec) - openjp2.set_decode_area(codec, image, + openjp2.set_decode_area(codec, image, kwargs['x0'], kwargs['y0'], kwargs['x1'], kwargs['y1']) diff --git a/glymur/test/fixtures.py b/glymur/test/fixtures.py index 9c543bf..6626075 100644 --- a/glymur/test/fixtures.py +++ b/glymur/test/fixtures.py @@ -11,6 +11,19 @@ import numpy as np import glymur +# The Python XMP Toolkit may be used for XMP UUIDs, but only if available and +# if the version is at least 2.0.0. +try: + import libxmp + if hasattr(libxmp, 'version') and re.match(r'''[2-9].\d*.\d*''', + libxmp.version.VERSION): + from libxmp import XMPMeta + HAS_PYTHON_XMP_TOOLKIT = True + else: + HAS_PYTHON_XMP_TOOLKIT = False +except ImportError: + HAS_PYTHON_XMP_TOOLKIT = False + # Need to know of the libopenjp2 version is the official 2.0.0 release and NOT # the 2.0+ development version. OPENJP2_IS_V2_OFFICIAL = False @@ -170,90 +183,96 @@ def read_pgx_header(pgx_file): nemo_xmp_box = """UUID Box (uuid) @ (77, 3146) UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP) - UUID Data: - - - - Google - 2013-02-09T14:47:53 - - - 1 - 72/1 - 72/1 - 2 - HTC - HTC Glacier - 2592 - 1456 - - - 8 - 8 - 8 - - - 2 - 3 - - - 1343036288/4294967295 - 1413044224/4294967295 - - - - - 2748779008/4294967295 - 1417339264/4294967295 - 1288490240/4294967295 - 2576980480/4294967295 - 644245120/4294967295 - 257698032/4294967295 - - - - - 1 - 2528 - 1424 - 353/100 - 0 - 0/1 - WGS-84 - 2013-02-09T14:47:53 - - - 76 - - - 0220 - 0100 - - - 1 - 2 - 3 - 0 - - - 42,20.56N - 71,5.29W - 2013-02-09T19:47:53Z - NETWORK - - - 2013-02-09T14:47:53 - - - - - Glymur - Python XMP Toolkit - - - - - """ + UUID Data: + + + + Google + 2013-02-09T14:47:53 + + + 1 + 72/1 + 72/1 + 2 + HTC + HTC Glacier + 2592 + 1456 + + + 8 + 8 + 8 + + + 2 + 3 + + + 1343036288/4294967295 + 1413044224/4294967295 + + + + + 2748779008/4294967295 + 1417339264/4294967295 + 1288490240/4294967295 + 2576980480/4294967295 + 644245120/4294967295 + 257698032/4294967295 + + + + + 1 + 2528 + 1424 + 353/100 + 0 + 0/1 + WGS-84 + 2013-02-09T14:47:53 + + + 76 + + + 0220 + 0100 + + + 1 + 2 + 3 + 0 + + + 42,20.56N + 71,5.29W + 2013-02-09T19:47:53Z + NETWORK + + + 2013-02-09T14:47:53 + + + + + Glymur + Python XMP Toolkit + + + + + +""" SimpleRDF = """ \)""" if sys.hexversion < 0x03000000: self.assertRegexpMatches(repr(box), regexp) @@ -927,9 +927,9 @@ class TestRepr(unittest.TestCase): # Since the raw_data parameter is a sequence of bytes which could be # quite long, don't bother trying to make it conform to eval(repr()). - regexp = "glymur.jp2box.UUIDBox\(" - regexp += "the_uuid=UUID\('00000000-0000-0000-0000-000000000000'\),\s" - regexp += "raw_data=\)" + regexp = r"""glymur.jp2box.UUIDBox\(""" + regexp += """the_uuid=UUID\('00000000-0000-0000-0000-000000000000'\),\s""" + regexp += """raw_data=\)""" if sys.hexversion < 0x03000000: self.assertRegexpMatches(repr(box), regexp) diff --git a/glymur/test/test_jp2box_uuid.py b/glymur/test/test_jp2box_uuid.py index 0d3684a..82dc253 100644 --- a/glymur/test/test_jp2box_uuid.py +++ b/glymur/test/test_jp2box_uuid.py @@ -35,7 +35,9 @@ if sys.hexversion <= 0x03030000: else: from unittest.mock import patch -from libxmp import XMPMeta +from .fixtures import HAS_PYTHON_XMP_TOOLKIT, OPJ_DATA_ROOT +if HAS_PYTHON_XMP_TOOLKIT: + from libxmp import XMPMeta import glymur from glymur import Jp2k diff --git a/glymur/test/test_jp2k.py b/glymur/test/test_jp2k.py index aeb0e41..852312f 100644 --- a/glymur/test/test_jp2k.py +++ b/glymur/test/test_jp2k.py @@ -30,13 +30,14 @@ import warnings import numpy as np import pkg_resources -import libxmp -from libxmp import XMPMeta - import glymur from glymur import Jp2k -from .fixtures import OPENJP2_IS_V2_OFFICIAL +from .fixtures import HAS_PYTHON_XMP_TOOLKIT, OPENJP2_IS_V2_OFFICIAL +if HAS_PYTHON_XMP_TOOLKIT: + import libxmp + from libxmp import XMPMeta + from .fixtures import OPJ_DATA_ROOT, opj_data_file @@ -362,6 +363,8 @@ class TestJp2k(unittest.TestCase): self.assertEqual(ET.tostring(jp2k.box[3].xml.getroot()), b'this is a test') + @unittest.skipIf(not HAS_PYTHON_XMP_TOOLKIT, + "Requires Python XMP Toolkit >= 2.0") def test_xmp_attribute(self): """Verify the XMP packet in the shipping example file can be read.""" j = Jp2k(self.jp2file) diff --git a/glymur/version.py b/glymur/version.py index af7523e..260f880 100644 --- a/glymur/version.py +++ b/glymur/version.py @@ -1,10 +1,12 @@ -# This file is part of glymur, a Python interface for accessing JPEG 2000. -# -# http://glymur.readthedocs.org -# -# Copyright 2013 John Evans -# -# License: MIT +""" +This file is part of glymur, a Python interface for accessing JPEG 2000. + +http://glymur.readthedocs.org + +Copyright 2013 John Evans + +License: MIT +""" import sys import numpy as np