Compare commits

...
Sign in to create a new pull request.

7 commits

7 changed files with 412 additions and 168 deletions

View file

@ -157,7 +157,7 @@ class Jp2k(Jp2kBox):
msg += "profile if the file type box brand is 'jp2 '." msg += "profile if the file type box brand is 'jp2 '."
warnings.warn(msg) warnings.warn(msg)
def _set_cinema_params(self, cparams, cinema_mode, fps): def _set_cinema_params(self, cinema_mode, fps):
"""Populate compression parameters structure for cinema2K. """Populate compression parameters structure for cinema2K.
Parameters Parameters
@ -176,7 +176,7 @@ class Jp2k(Jp2kBox):
raise IOError(msg) raise IOError(msg)
# Cinema modes imply MCT. # Cinema modes imply MCT.
cparams.tcp_mct = 1 self._cparams.tcp_mct = 1
if cinema_mode == 'cinema2k': if cinema_mode == 'cinema2k':
if fps not in [24, 48]: if fps not in [24, 48]:
@ -185,30 +185,28 @@ class Jp2k(Jp2kBox):
if re.match("2.0", version.openjpeg_version) is not None: if re.match("2.0", version.openjpeg_version) is not None:
# 2.0 API # 2.0 API
if fps == 24: if fps == 24:
cparams.cp_cinema = core.OPJ_CINEMA2K_24 self._cparams.cp_cinema = core.OPJ_CINEMA2K_24
else: else:
cparams.cp_cinema = core.OPJ_CINEMA2K_48 self._cparams.cp_cinema = core.OPJ_CINEMA2K_48
else: else:
# 2.1 API # 2.1 API
if fps == 24: if fps == 24:
cparams.rsiz = core.OPJ_PROFILE_CINEMA_2K self._cparams.rsiz = core.OPJ_PROFILE_CINEMA_2K
cparams.max_comp_size = core.OPJ_CINEMA_24_COMP self._cparams.max_comp_size = core.OPJ_CINEMA_24_COMP
cparams.max_cs_size = core.OPJ_CINEMA_24_CS self._cparams.max_cs_size = core.OPJ_CINEMA_24_CS
else: else:
cparams.rsiz = core.OPJ_PROFILE_CINEMA_2K self._cparams.rsiz = core.OPJ_PROFILE_CINEMA_2K
cparams.max_comp_size = core.OPJ_CINEMA_48_COMP self._cparams.max_comp_size = core.OPJ_CINEMA_48_COMP
cparams.max_cs_size = core.OPJ_CINEMA_48_CS self._cparams.max_cs_size = core.OPJ_CINEMA_48_CS
else: else:
# cinema4k # cinema4k
if re.match("2.0", version.openjpeg_version) is not None: if re.match("2.0", version.openjpeg_version) is not None:
# 2.0 API # 2.0 API
cparams.cp_cinema = core.OPJ_CINEMA4K_24 self._cparams.cp_cinema = core.OPJ_CINEMA4K_24
else: else:
# 2.1 API # 2.1 API
cparams.rsiz = core.OPJ_PROFILE_CINEMA_4K self._cparams.rsiz = core.OPJ_PROFILE_CINEMA_4K
return
def _populate_cparams(self, img_array, **kwargs): def _populate_cparams(self, img_array, **kwargs):
"""Directs processing of write method arguments. """Directs processing of write method arguments.
@ -219,11 +217,6 @@ class Jp2k(Jp2kBox):
image data to be written to file image data to be written to file
kwargs : dictionary kwargs : dictionary
non-image keyword inputs provided to write method non-image keyword inputs provided to write method
Returns
-------
cparams : CompressionParametersType(ctypes.Structure)
corresponds to cparameters_t openjpeg datatype
""" """
if (('cinema2k' in kwargs or 'cinema4k' in kwargs) and if (('cinema2k' in kwargs or 'cinema4k' in kwargs) and
(len(set(kwargs)) > 1)): (len(set(kwargs)) > 1)):
@ -258,12 +251,14 @@ class Jp2k(Jp2kBox):
cparams.irreversible = 1 cparams.irreversible = 1
if 'cinema2k' in kwargs: if 'cinema2k' in kwargs:
self._set_cinema_params(cparams, 'cinema2k', kwargs['cinema2k']) self._cparams = cparams
return cparams self._set_cinema_params('cinema2k', kwargs['cinema2k'])
return
if 'cinema4k' in kwargs: if 'cinema4k' in kwargs:
self._set_cinema_params(cparams, 'cinema4k', kwargs['cinema4k']) self._cparams = cparams
return cparams self._set_cinema_params('cinema4k', kwargs['cinema4k'])
return
if 'cbsize' in kwargs: if 'cbsize' in kwargs:
cparams.cblockw_init = kwargs['cbsize'][1] cparams.cblockw_init = kwargs['cbsize'][1]
@ -337,7 +332,7 @@ class Jp2k(Jp2kBox):
self._validate_compression_params(img_array, cparams, **kwargs) self._validate_compression_params(img_array, cparams, **kwargs)
return cparams self._cparams = cparams
def write(self, img_array, verbose=False, **kwargs): def write(self, img_array, verbose=False, **kwargs):
"""Write image data to a JP2/JPX/J2k file. Intended usage of the """Write image data to a JP2/JPX/J2k file. Intended usage of the
@ -412,14 +407,14 @@ class Jp2k(Jp2kBox):
"in order to write images.") "in order to write images.")
self._determine_colorspace(img_array, **kwargs) self._determine_colorspace(img_array, **kwargs)
cparams = self._populate_cparams(img_array, **kwargs) self._populate_cparams(img_array, **kwargs)
if opj2.OPENJP2 is not None: if opj2.OPENJP2 is not None:
self._write_openjp2(img_array, cparams, verbose=verbose) self._write_openjp2(img_array, verbose=verbose)
else: else:
self._write_openjpeg(img_array, cparams, verbose=verbose) self._write_openjpeg(img_array, verbose=verbose)
def _write_openjpeg(self, img_array, cparams, verbose=False): def _write_openjpeg(self, img_array, verbose=False):
""" """
Write JPEG 2000 file using OpenJPEG 1.5 interface. Write JPEG 2000 file using OpenJPEG 1.5 interface.
""" """
@ -429,21 +424,21 @@ class Jp2k(Jp2kBox):
img_array.shape[1], img_array.shape[1],
1) 1)
comptparms = _populate_comptparms(img_array, cparams) self._populate_comptparms(img_array)
with ExitStack() as stack: with ExitStack() as stack:
image = opj.image_create(comptparms, self._colorspace) image = opj.image_create(self._comptparms, self._colorspace)
stack.callback(opj.image_destroy, image) stack.callback(opj.image_destroy, image)
numrows, numcols, numlayers = img_array.shape numrows, numcols, numlayers = img_array.shape
# set image offset and reference grid # set image offset and reference grid
image.contents.x0 = cparams.image_offset_x0 image.contents.x0 = self._cparams.image_offset_x0
image.contents.y0 = cparams.image_offset_y0 image.contents.y0 = self._cparams.image_offset_y0
image.contents.x1 = image.contents.x0 \ image.contents.x1 = image.contents.x0 \
+ (numcols - 1) * cparams.subsampling_dx + 1 + (numcols - 1) * self._cparams.subsampling_dx + 1
image.contents.y1 = image.contents.y0 \ image.contents.y1 = image.contents.y0 \
+ (numrows - 1) * cparams.subsampling_dy + 1 + (numrows - 1) * self._cparams.subsampling_dy + 1
# Stage the image data to the openjpeg data structure. # Stage the image data to the openjpeg data structure.
for k in range(0, numlayers): for k in range(0, numlayers):
@ -453,7 +448,7 @@ class Jp2k(Jp2kBox):
src = layer.ctypes.data src = layer.ctypes.data
ctypes.memmove(dest, src, layer.nbytes) ctypes.memmove(dest, src, layer.nbytes)
cinfo = opj.create_compress(cparams.codec_fmt) cinfo = opj.create_compress(self._cparams.codec_fmt)
stack.callback(opj.destroy_compress, cinfo) stack.callback(opj.destroy_compress, cinfo)
# Setup the info, warning, and error handlers. # Setup the info, warning, and error handlers.
@ -467,7 +462,7 @@ class Jp2k(Jp2kBox):
event_mgr.error_handler = ctypes.cast(_ERROR_CALLBACK, event_mgr.error_handler = ctypes.cast(_ERROR_CALLBACK,
ctypes.c_void_p) ctypes.c_void_p)
opj.setup_encoder(cinfo, ctypes.byref(cparams), image) opj.setup_encoder(cinfo, ctypes.byref(self._cparams), image)
cio = opj.cio_open(cinfo) cio = opj.cio_open(cinfo)
stack.callback(opj.cio_close, cio) stack.callback(opj.cio_close, cio)
@ -588,7 +583,7 @@ class Jp2k(Jp2kBox):
self._colorspace = _COLORSPACE_MAP[colorspace.lower()] self._colorspace = _COLORSPACE_MAP[colorspace.lower()]
def _write_openjp2(self, img_array, cparams, verbose=False): def _write_openjp2(self, img_array, verbose=False):
""" """
Write JPEG 2000 file using OpenJPEG 2.x interface. Write JPEG 2000 file using OpenJPEG 2.x interface.
""" """
@ -597,15 +592,15 @@ class Jp2k(Jp2kBox):
numrows, numcols = img_array.shape numrows, numcols = img_array.shape
img_array = img_array.reshape(numrows, numcols, 1) img_array = img_array.reshape(numrows, numcols, 1)
comptparms = _populate_comptparms(img_array, cparams) self._populate_comptparms(img_array)
with ExitStack() as stack: with ExitStack() as stack:
image = opj2.image_create(comptparms, self._colorspace) image = opj2.image_create(self._comptparms, self._colorspace)
stack.callback(opj2.image_destroy, image) stack.callback(opj2.image_destroy, image)
_populate_image_struct(cparams, image, img_array) self._populate_image_struct(image, img_array)
codec = opj2.create_compress(cparams.codec_fmt) codec = opj2.create_compress(self._cparams.codec_fmt)
stack.callback(opj2.destroy_codec, codec) stack.callback(opj2.destroy_codec, codec)
info_handler = _INFO_CALLBACK if verbose else None info_handler = _INFO_CALLBACK if verbose else None
@ -613,7 +608,7 @@ class Jp2k(Jp2kBox):
opj2.set_warning_handler(codec, _WARNING_CALLBACK) opj2.set_warning_handler(codec, _WARNING_CALLBACK)
opj2.set_error_handler(codec, _ERROR_CALLBACK) opj2.set_error_handler(codec, _ERROR_CALLBACK)
opj2.setup_encoder(codec, cparams, image) opj2.setup_encoder(codec, self._cparams, image)
if re.match("2.0", version.openjpeg_version) is not None: if re.match("2.0", version.openjpeg_version) is not None:
fptr = libc.fopen(self.filename, 'wb') fptr = libc.fopen(self.filename, 'wb')
@ -1020,13 +1015,13 @@ class Jp2k(Jp2kBox):
""" """
self._subsampling_sanity_check() self._subsampling_sanity_check()
dparameters = self._populate_dparam(rlevel, ignore_pclr_cmap_cdef) self._populate_dparams(rlevel, ignore_pclr_cmap_cdef)
with ExitStack() as stack: with ExitStack() as stack:
try: try:
dparameters.decod_format = self._codec_format self._dparams.decod_format = self._codec_format
dinfo = opj.create_decompress(dparameters.decod_format) dinfo = opj.create_decompress(self._dparams.decod_format)
event_mgr = opj.EventMgrType() event_mgr = opj.EventMgrType()
info_handler = ctypes.cast(_INFO_CALLBACK, ctypes.c_void_p) info_handler = ctypes.cast(_INFO_CALLBACK, ctypes.c_void_p)
@ -1037,7 +1032,7 @@ class Jp2k(Jp2kBox):
ctypes.c_void_p) ctypes.c_void_p)
opj.set_event_mgr(dinfo, ctypes.byref(event_mgr)) opj.set_event_mgr(dinfo, ctypes.byref(event_mgr))
opj.setup_decoder(dinfo, dparameters) opj.setup_decoder(dinfo, self._dparams)
with open(self.filename, 'rb') as fptr: with open(self.filename, 'rb') as fptr:
src = fptr.read() src = fptr.read()
@ -1104,8 +1099,8 @@ class Jp2k(Jp2kBox):
""" """
self._subsampling_sanity_check() self._subsampling_sanity_check()
dparam = self._populate_dparam(rlevel, ignore_pclr_cmap_cdef, self._populate_dparams(rlevel, ignore_pclr_cmap_cdef,
layer=layer, tile=tile, area=area) layer=layer, tile=tile, area=area)
with ExitStack() as stack: with ExitStack() as stack:
if re.match("2.1", version.openjpeg_version): if re.match("2.1", version.openjpeg_version):
@ -1127,16 +1122,17 @@ class Jp2k(Jp2kBox):
else: else:
opj2.set_info_handler(codec, None) opj2.set_info_handler(codec, None)
opj2.setup_decoder(codec, dparam) opj2.setup_decoder(codec, self._dparams)
image = opj2.read_header(stream, codec) image = opj2.read_header(stream, codec)
stack.callback(opj2.image_destroy, image) stack.callback(opj2.image_destroy, image)
if dparam.nb_tile_to_decode: if self._dparams.nb_tile_to_decode:
opj2.get_decoded_tile(codec, stream, image, dparam.tile_index) opj2.get_decoded_tile(codec, stream, image,
self._dparams.tile_index)
else: else:
opj2.set_decode_area(codec, image, opj2.set_decode_area(codec, image,
dparam.DA_x0, dparam.DA_y0, self._dparams.DA_x0, self._dparams.DA_y0,
dparam.DA_x1, dparam.DA_y1) self._dparams.DA_x1, self._dparams.DA_y1)
opj2.decode(codec, stream, image) opj2.decode(codec, stream, image)
opj2.end_decompress(codec, stream) opj2.end_decompress(codec, stream)
@ -1147,8 +1143,8 @@ class Jp2k(Jp2kBox):
return img_array return img_array
def _populate_dparam(self, rlevel, ignore_pclr_cmap_cdef, tile=None, def _populate_dparams(self, rlevel, ignore_pclr_cmap_cdef, tile=None,
layer=None, area=None): layer=None, area=None):
"""Populate decompression structure with appropriate input parameters. """Populate decompression structure with appropriate input parameters.
Parameters Parameters
@ -1165,11 +1161,6 @@ class Jp2k(Jp2kBox):
ignore_pclr_cmap_cdef : bool ignore_pclr_cmap_cdef : bool
Whether or not to ignore the pclr, cmap, or cdef boxes during any Whether or not to ignore the pclr, cmap, or cdef boxes during any
color transformation. Defaults to False. color transformation. Defaults to False.
Returns
-------
dparam : DecompressionParametersType (ctypes)
Corresponds to openjp2 decompression parameters structure.
""" """
if opj2.OPENJP2 is not None: if opj2.OPENJP2 is not None:
dparam = opj2.set_default_decoder_parameters() dparam = opj2.set_default_decoder_parameters()
@ -1220,7 +1211,7 @@ class Jp2k(Jp2kBox):
# Return raw codestream components. # Return raw codestream components.
dparam.flags |= 1 dparam.flags |= 1
return dparam self._dparams = dparam
def read_bands(self, rlevel=0, layer=0, area=None, tile=None, def read_bands(self, rlevel=0, layer=0, area=None, tile=None,
verbose=False, ignore_pclr_cmap_cdef=False): verbose=False, ignore_pclr_cmap_cdef=False):
@ -1268,8 +1259,8 @@ class Jp2k(Jp2kBox):
"OpenJPEG installed before using this " "OpenJPEG installed before using this "
"functionality.") "functionality.")
dparam = self._populate_dparam(rlevel, ignore_pclr_cmap_cdef, self._populate_dparams(rlevel, ignore_pclr_cmap_cdef,
layer=layer, tile=tile, area=area) layer=layer, tile=tile, area=area)
with ExitStack() as stack: with ExitStack() as stack:
if re.match("2.1", version.openjpeg_version): if re.match("2.1", version.openjpeg_version):
@ -1292,16 +1283,17 @@ class Jp2k(Jp2kBox):
else: else:
opj2.set_info_handler(codec, None) opj2.set_info_handler(codec, None)
opj2.setup_decoder(codec, dparam) opj2.setup_decoder(codec, self._dparams)
image = opj2.read_header(stream, codec) image = opj2.read_header(stream, codec)
stack.callback(opj2.image_destroy, image) stack.callback(opj2.image_destroy, image)
if dparam.nb_tile_to_decode: if self._dparams.nb_tile_to_decode:
opj2.get_decoded_tile(codec, stream, image, dparam.tile_index) opj2.get_decoded_tile(codec, stream, image,
self._dparams.tile_index)
else: else:
opj2.set_decode_area(codec, image, opj2.set_decode_area(codec, image,
dparam.DA_x0, dparam.DA_y0, self._dparams.DA_x0, self._dparams.DA_y0,
dparam.DA_x1, dparam.DA_y1) self._dparams.DA_x1, self._dparams.DA_y1)
opj2.decode(codec, stream, image) opj2.decode(codec, stream, image)
opj2.end_decompress(codec, stream) opj2.end_decompress(codec, stream)
@ -1362,7 +1354,83 @@ class Jp2k(Jp2kBox):
return codestream return codestream
def _populate_image_struct(self, image, imgdata):
"""Populates image struct needed for compression.
Parameters
----------
image : ImageType(ctypes.Structure)
Corresponds to image_t type in openjp2 headers.
img_array : ndarray
Image data to be written to file.
"""
numrows, numcols, num_comps = imgdata.shape
# set image offset and reference grid
image.contents.x0 = self._cparams.image_offset_x0
image.contents.y0 = self._cparams.image_offset_y0
image.contents.x1 = (image.contents.x0 +
(numcols - 1) * self._cparams.subsampling_dx + 1)
image.contents.y1 = (image.contents.y0 +
(numrows - 1) * self._cparams.subsampling_dy + 1)
# Stage the image data to the openjpeg data structure.
for k in range(0, num_comps):
if re.match("2.0", version.openjpeg_version) is not None:
# 2.0 API
if self._cparams.cp_cinema:
image.contents.comps[k].prec = 12
image.contents.comps[k].bpp = 12
else:
# 2.1 API
if self._cparams.rsiz in (core.OPJ_PROFILE_CINEMA_2K,
core.OPJ_PROFILE_CINEMA_4K):
image.contents.comps[k].prec = 12
image.contents.comps[k].bpp = 12
layer = np.ascontiguousarray(imgdata[:, :, k], dtype=np.int32)
dest = image.contents.comps[k].data
src = layer.ctypes.data
ctypes.memmove(dest, src, layer.nbytes)
return image
def _populate_comptparms(self, img_array):
"""Instantiate and populate comptparms structure.
This structure defines the image components.
Parameters
----------
img_array : ndarray
Image data to be written to file.
"""
# Only two precisions are possible.
if img_array.dtype == np.uint8:
comp_prec = 8
else:
comp_prec = 16
numrows, numcols, num_comps = img_array.shape
if version.openjpeg_version_tuple[0] == 1:
comptparms = (opj.ImageComptParmType * num_comps)()
else:
comptparms = (opj2.ImageComptParmType * num_comps)()
for j in range(num_comps):
comptparms[j].dx = self._cparams.subsampling_dx
comptparms[j].dy = self._cparams.subsampling_dy
comptparms[j].w = numcols
comptparms[j].h = numrows
comptparms[j].x0 = self._cparams.image_offset_x0
comptparms[j].y0 = self._cparams.image_offset_y0
comptparms[j].prec = comp_prec
comptparms[j].bpp = comp_prec
comptparms[j].sgnd = 0
self._comptparms = comptparms
def _component2dtype(component): def _component2dtype(component):
"""Take an OpenJPEG component structure and determine the numpy datatype. """Take an OpenJPEG component structure and determine the numpy datatype.
@ -1704,92 +1772,6 @@ def extract_image_bands(image):
return data return data
def _populate_comptparms(img_array, cparams):
"""Instantiate and populate comptparms structure.
This structure defines the image components.
Parameters
----------
img_array : ndarray
Image data to be written to file.
cparams : CompressionParametersType(ctypes.Structure)
Corresponds to cparameters_t type in openjp2 headers.
Returns
-------
comptparms : ImageCompType(ctypes.Structure)
Corresponds to image_comp_t type in openjp2 headers.
"""
# Only two precisions are possible.
if img_array.dtype == np.uint8:
comp_prec = 8
else:
comp_prec = 16
numrows, numcols, num_comps = img_array.shape
if version.openjpeg_version_tuple[0] == 1:
comptparms = (opj.ImageComptParmType * num_comps)()
else:
comptparms = (opj2.ImageComptParmType * num_comps)()
for j in range(num_comps):
comptparms[j].dx = cparams.subsampling_dx
comptparms[j].dy = cparams.subsampling_dy
comptparms[j].w = numcols
comptparms[j].h = numrows
comptparms[j].x0 = cparams.image_offset_x0
comptparms[j].y0 = cparams.image_offset_y0
comptparms[j].prec = comp_prec
comptparms[j].bpp = comp_prec
comptparms[j].sgnd = 0
return comptparms
def _populate_image_struct(cparams, image, imgdata):
"""Populates image struct needed for compression.
Parameters
----------
cparams : CompressionParametersType(ctypes.Structure)
Corresponds to cparameters_t type in openjp2 headers.
image : ImageType(ctypes.Structure)
Corresponds to image_t type in openjp2 headers.
imgarray : ndarray
Image data to be written to file.
"""
numrows, numcols, num_comps = imgdata.shape
# set image offset and reference grid
image.contents.x0 = cparams.image_offset_x0
image.contents.y0 = cparams.image_offset_y0
image.contents.x1 = (image.contents.x0 +
(numcols - 1) * cparams.subsampling_dx + 1)
image.contents.y1 = (image.contents.y0 +
(numrows - 1) * cparams.subsampling_dy + 1)
# Stage the image data to the openjpeg data structure.
for k in range(0, num_comps):
if re.match("2.0", version.openjpeg_version) is not None:
# 2.0 API
if cparams.cp_cinema:
image.contents.comps[k].prec = 12
image.contents.comps[k].bpp = 12
else:
# 2.1 API
if cparams.rsiz in (core.OPJ_PROFILE_CINEMA_2K,
core.OPJ_PROFILE_CINEMA_4K):
image.contents.comps[k].prec = 12
image.contents.comps[k].bpp = 12
layer = np.ascontiguousarray(imgdata[:, :, k], dtype=np.int32)
dest = image.contents.comps[k].data
src = layer.ctypes.data
ctypes.memmove(dest, src, layer.nbytes)
return image
# Setup the default callback handlers. See the callback functions subsection # Setup the default callback handlers. See the callback functions subsection
# in the ctypes section of the Python documentation for a solid explanation of # in the ctypes section of the Python documentation for a solid explanation of

View file

@ -117,15 +117,17 @@ def read_config_file(libname):
None if no location is specified, otherwise a path to the library None if no location is specified, otherwise a path to the library
""" """
filename = glymurrc_fname() filename = glymurrc_fname()
if filename is not None: if filename is None:
# Read the configuration file for the library location. # There's no library file path to return in this case.
parser = ConfigParser() return None
parser.read(filename)
try:
path = parser.get('library', libname)
except NoOptionError:
path = None
# Read the configuration file for the library location.
parser = ConfigParser()
parser.read(filename)
try:
path = parser.get('library', libname)
except NoOptionError:
path = None
return path return path
def glymur_config(): def glymur_config():

View file

@ -7,6 +7,7 @@ Wraps individual functions in openjp2 library.
import ctypes import ctypes
import re import re
import sys import sys
import textwrap
from .config import glymur_config from .config import glymur_config
@ -138,6 +139,13 @@ class PocType(ctypes.Structure):
("tx0_t", ctypes.c_uint32), ("tx0_t", ctypes.c_uint32),
("ty0_t", ctypes.c_uint32)] ("ty0_t", ctypes.c_uint32)]
def __str__(self):
msg = "{0}:\n".format(self.__class__)
for field_name, _ in self._fields_:
msg += " {0}: {1}\n".format(
field_name, getattr(self, field_name))
return msg
class DecompressionParametersType(ctypes.Structure): class DecompressionParametersType(ctypes.Structure):
"""Decompression parameters. """Decompression parameters.
@ -201,6 +209,13 @@ class DecompressionParametersType(ctypes.Structure):
# maximum number of tiles # maximum number of tiles
("flags", ctypes.c_uint32)] ("flags", ctypes.c_uint32)]
def __str__(self):
msg = "{0}:\n".format(self.__class__)
for field_name, _ in self._fields_:
msg += " {0}: {1}\n".format(
field_name, getattr(self, field_name))
return msg
class CompressionParametersType(ctypes.Structure): class CompressionParametersType(ctypes.Structure):
"""Compression parameters. """Compression parameters.
@ -392,6 +407,47 @@ class CompressionParametersType(ctypes.Structure):
# values. # values.
_fields_.append(("rsiz", ctypes.c_uint16)) _fields_.append(("rsiz", ctypes.c_uint16))
def __str__(self):
msg = "{0}:\n".format(self.__class__)
for field_name, _ in self._fields_:
if field_name == 'poc':
msg += " numpocs: {0}\n".format(self.numpocs)
for j in range(self.numpocs):
msg += " [#{0}]:".format(j)
msg += " {0}".format(str(self.poc[j]))
msg += textwrap.indent(textstr, ' ' * 12)
elif field_name in ['tcp_rates', 'tcp_distoratio']:
lst = []
arr = getattr(self, field_name)
lst = [arr[j] for j in range(self.tcp_numlayers)]
msg += " {0}: {1}\n".format(field_name, lst)
elif field_name in ['prcw_init', 'prch_init']:
pass
elif field_name == 'res_spec':
prcw_init = [self.prcw_init[j] for j in range(self.res_spec)]
prch_init = [self.prch_init[j] for j in range(self.res_spec)]
msg += " res_spec: {0}\n".format(self.res_spec)
msg += " prch_init: {0}\n".format(prch_init)
msg += " prcw_init: {0}\n".format(prcw_init)
elif field_name in [
'jpwl_hprot_tph_tileno', 'jpwl_hprot_tph',
'jpwl_pprot_tileno', 'jpwl_pprot_packno', 'jpwl_pprot',
'jpwl_sens_tph_tileno', 'jpwl_sens_tph']:
arr = getattr(self, field_name)
lst = [arr[j] for j in range(JPWL_MAX_NO_TILESPECS)]
msg += " {0}: {1}\n".format(field_name, lst)
else:
msg += " {0}: {1}\n".format(
field_name, getattr(self, field_name))
return msg
class ImageCompType(ctypes.Structure): class ImageCompType(ctypes.Structure):
"""Defines a single image component. """Defines a single image component.
@ -492,6 +548,13 @@ class ImageComptParmType(ctypes.Structure):
# signed (1) / unsigned (0) # signed (1) / unsigned (0)
("sgnd", ctypes.c_uint32)] ("sgnd", ctypes.c_uint32)]
def __str__(self):
msg = "{0}:\n".format(self.__class__)
for field_name, _ in self._fields_:
msg += " {0}: {1}\n".format(
field_name, getattr(self, field_name))
return msg
class TccpInfo(ctypes.Structure): class TccpInfo(ctypes.Structure):
"""Tile-component coding parameters information. """Tile-component coding parameters information.

129
glymur/lib/test/fixtures.py Normal file
View file

@ -0,0 +1,129 @@
decompression_parameters_type = """<class 'glymur.lib.openjp2.DecompressionParametersType'>:
cp_reduce: 0
cp_layer: 0
infile: b''
outfile: b''
decod_format: -1
cod_format: -1
DA_x0: 0
DA_x1: 0
DA_y0: 0
DA_y1: 0
m_verbose: 0
tile_index: 0
nb_tile_to_decode: 0
jpwl_correct: 0
jpwl_exp_comps: 0
jpwl_max_tiles: 0
flags: 0"""
default_progression_order_changes_type = """<class 'glymur.lib.openjp2.PocType'>:
resno0: 0
compno0: 0
layno1: 0
resno1: 0
compno1: 0
layno0: 0
precno0: 0
precno1: 0
prg1: 0
prg: 0
progorder: b''
tile: 0
tx0: 0
tx1: 0
ty0: 0
ty1: 0
layS: 0
resS: 0
compS: 0
prcS: 0
layE: 0
resE: 0
compE: 0
prcE: 0
txS: 0
txE: 0
tyS: 0
tyE: 0
dx: 0
dy: 0
lay_t: 0
res_t: 0
comp_t: 0
prec_t: 0
tx0_t: 0
ty0_t: 0"""
default_compression_parameters_type = """<class 'glymur.lib.openjp2.CompressionParametersType'>:
tile_size_on: 0
cp_tx0: 0
cp_ty0: 0
cp_tdx: 0
cp_tdy: 0
cp_disto_alloc: 0
cp_fixed_alloc: 0
cp_fixed_quality: 0
cp_matrice: None
cp_comment: None
csty: 0
prog_order: 0
numpocs: 0
numpocs: 0
tcp_numlayers: 0
tcp_rates: []
tcp_distoratio: []
numresolution: 6
cblockw_init: 64
cblockh_init: 64
mode: 0
irreversible: 0
roi_compno: -1
roi_shift: 0
res_spec: 0
prch_init: []
prcw_init: []
infile: b''
outfile: b''
index_on: 0
index: b''
image_offset_x0: 0
image_offset_y0: 0
subsampling_dx: 1
subsampling_dy: 1
decod_format: -1
cod_format: -1
jpwl_epc_on: 0
jpwl_hprot_mh: 0
jpwl_hprot_tph_tileno: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
jpwl_hprot_tph: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
jpwl_pprot_tileno: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
jpwl_pprot_packno: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
jpwl_pprot: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
jpwl_sens_size: 0
jpwl_sens_addr: 0
jpwl_sens_range: 0
jpwl_sens_mh: 0
jpwl_sens_tph_tileno: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
jpwl_sens_tph: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
cp_cinema: 0
max_comp_size: 0
cp_rsiz: 0
tp_on: 0
tp_flag: 0
tcp_mct: 0
jpip_on: 0
mct_data: None
max_cs_size: 0
rsiz: 0"""
default_image_component_parameters = """<class 'glymur.lib.openjp2.ImageComptParmType'>:
dx: 0
dy: 0
w: 0
h: 0
x0: 0
y0: 0
prec: 0
bpp: 0
sgnd: 0"""

View file

@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
"""Test suite for printing.
"""
import re
import sys
import unittest
if sys.hexversion < 0x03000000:
from mock import patch
from StringIO import StringIO
else:
from unittest.mock import patch
from io import StringIO
import glymur
from . import fixtures
@unittest.skipIf(sys.hexversion < 0x03000000, "do not care about 2.7 here")
@unittest.skipIf(re.match('1|2.0', glymur.version.openjpeg_version),
"Requires openjpeg 2.1.0 or higher")
class TestPrintingOpenjp2(unittest.TestCase):
"""Tests for verifying how printing works on openjp2 library structures."""
def setUp(self):
self.jp2file = glymur.data.nemo()
def tearDown(self):
pass
def test_decompression_parameters(self):
"""printing DecompressionParametersType"""
dparams = glymur.lib.openjp2.set_default_decoder_parameters()
with patch('sys.stdout', new=StringIO()) as fake_out:
print(dparams)
actual = fake_out.getvalue().strip()
expected = fixtures.decompression_parameters_type
self.assertEqual(actual, expected)
def test_progression_order_changes(self):
"""printing PocType"""
ptype = glymur.lib.openjp2.PocType()
with patch('sys.stdout', new=StringIO()) as fake_out:
print(ptype)
actual = fake_out.getvalue().strip()
expected = fixtures.default_progression_order_changes_type
self.assertEqual(actual, expected)
def test_default_compression_parameters(self):
"""printing default compression parameters"""
cparams = glymur.lib.openjp2.set_default_encoder_parameters()
with patch('sys.stdout', new=StringIO()) as fake_out:
print(cparams)
actual = fake_out.getvalue().strip()
expected = fixtures.default_compression_parameters_type
self.assertEqual(actual, expected)
def test_default_component_parameters(self):
"""printing default image component parameters"""
icpt = glymur.lib.openjp2.ImageComptParmType()
with patch('sys.stdout', new=StringIO()) as fake_out:
print(icpt)
actual = fake_out.getvalue().strip()
expected = fixtures.default_image_component_parameters
self.assertEqual(actual, expected)

View file

@ -900,3 +900,4 @@ goodstuff_with_full_header = r"""Codestream:
Step size: [(0, 8), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10)] Step size: [(0, 8), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), (0, 10)]
SOD marker segment @ (164, 0) SOD marker segment @ (164, 0)
EOC marker segment @ (115218, 0)""" EOC marker segment @ (115218, 0)"""

View file

@ -32,12 +32,13 @@ import lxml.etree as ET
import glymur import glymur
from glymur import Jp2k, command_line from glymur import Jp2k, command_line
from . import fixtures from . import fixtures
from .fixtures import OPJ_DATA_ROOT, opj_data_file from .fixtures import (
from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG OPJ_DATA_ROOT, opj_data_file,
from .fixtures import text_gbr_27, text_gbr_33, text_gbr_34 WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG,
WINDOWS_TMP_FILE_MSG, text_gbr_27, text_gbr_33, text_gbr_34
)
@unittest.skipIf(os.name == "nt", WINDOWS_TMP_FILE_MSG)
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
class TestPrinting(unittest.TestCase): class TestPrinting(unittest.TestCase):
"""Tests for verifying how printing works.""" """Tests for verifying how printing works."""
def setUp(self): def setUp(self):
@ -617,7 +618,6 @@ class TestPrinting(unittest.TestCase):
self.assertEqual(actual, expected) self.assertEqual(actual, expected)
@unittest.skipIf(OPJ_DATA_ROOT is None, @unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set") "OPJ_DATA_ROOT environment variable not set")
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.") @unittest.skipIf(os.name == "nt", "Temporary file issue on window.")