Reading goodstuff on 64-bit linux works, but nemo is oddly truncated.

This commit is contained in:
John Evans 2013-07-03 11:04:47 -04:00
commit e071a96f68
3 changed files with 193 additions and 4 deletions

View file

@ -614,7 +614,72 @@ class Jp2k(Jp2kBox):
IOError
If the image has differing subsample factors.
"""
raise NotImplementedError("not there yet")
# Set decoding parameters.
dparameters = opj.dparameters_t()
opj._set_default_decoder_parameters(ctypes.byref(dparameters))
dparameters.cp_reduce = reduce
dparameters.decod_format = self._codec_format
infile = self.filename.encode()
nelts = opj._PATH_LEN - len(infile)
infile += b'0' * nelts
dparameters.infile = infile
dinfo = opj._create_decompress(dparameters.decod_format)
opj._setup_decoder(dinfo, dparameters)
with open(self.filename, 'rb') as fp:
src = fp.read()
cio = opj._cio_open(dinfo, src)
image = opj._decode(dinfo, cio)
ncomps = image.contents.numcomps
component = image.contents.comps[0]
if component.sgnd:
if component.prec <= 8:
dtype = np.int8
elif component.prec <= 16:
dtype = np.int16
else:
raise RuntimeError("Unhandled precision, datatype")
else:
if component.prec <= 8:
dtype = np.uint8
elif component.prec <= 16:
dtype = np.uint16
else:
raise RuntimeError("Unhandled precision, datatype")
nrows = image.contents.comps[0].h
ncols = image.contents.comps[0].w
ncomps = image.contents.numcomps
data = np.zeros((nrows, ncols, ncomps), dtype)
for k in range(image.contents.numcomps):
component = image.contents.comps[k]
nrows = component.h
ncols = component.w
if nrows == 0 or ncols == 0:
# Letting this situation continue would segfault
# Python.
msg = "Component {0} has dimensions {1} x {2}"
msg = msg.format(k, nrows, ncols)
raise IOError(msg)
addr = ctypes.addressof(component.data.contents)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
x = np.ctypeslib.as_array( (ctypes.c_int32 * nrows * ncols).from_address(addr))
data[:, :, k] = np.reshape(x.astype(dtype), (nrows, ncols))
opj._cio_close(cio)
opj._destroy_decompress(dinfo)
opj._image_destroy(image)
return data
def _read_openjp2(self, reduce=0, layer=0, area=None, tile=None,
verbose=False):

View file

@ -14,7 +14,50 @@ else:
elif platform.system() == 'Linux':
_OPENJPEG = ctypes.CDLL(find_library('openjpeg'))
OPJ_PATH_LEN = 4096 # maximum allowed size for filenames
_PATH_LEN = 4096 # maximum allowed size for filenames
class event_mgr_t(ctypes.Structure):
"""Message handler object.
"""
_fields_ = [("error_handler", ctypes.c_void_p),
("warning_handler", ctypes.c_void_p),
("info_handler", ctypes.c_void_p)]
class common_struct_t(ctypes.Structure):
"""Common fields between JPEG 2000 compression and decompression contextx.
"""
_fields_ = [("event_mgr", ctypes.POINTER(event_mgr_t)),
("client_data", ctypes.c_void_p),
("is_decompressor", ctypes.c_bool),
("codec_format", ctypes.c_int),
("j2k_handle", ctypes.c_void_p),
("jp2_handle", ctypes.c_void_p),
("mj2_handle", ctypes.c_void_p)]
class dinfo_t(ctypes.Structure):
"""Common fields between JPEG 2000 compression and decompression contextx.
This is for decompression contexts.
"""
pass
class cio_t(ctypes.Structure):
_fields_ = [# codec context
("cinfo", ctypes.POINTER(common_struct_t)),
# STREAM_READ or STREAM_WRITE
("openmode", ctypes.c_int),
# pointer to start of buffer
("buffer", ctypes.POINTER(ctypes.c_char)),
# buffer size in bytes
("length", ctypes.c_int),
# pointer to start of stream
("start", ctypes.c_char_p),
# pointer to end of stream
("end", ctypes.c_char_p),
# pointer to current position
("bp", ctypes.c_char_p)]
class dparameters_t(ctypes.Structure):
@ -23,9 +66,9 @@ class dparameters_t(ctypes.Structure):
# cp_layer: the maximum number of quality layers to decode
("cp_layer", ctypes.c_int),
# infile: input file name
("infile", ctypes.c_char * OPJ_PATH_LEN),
("infile", ctypes.c_char * _PATH_LEN),
# outfile: output file name
("outfile", ctypes.c_char * OPJ_PATH_LEN),
("outfile", ctypes.c_char * _PATH_LEN),
# decod_format: input file format 0: J2K, 1: JP2, 2: JPT
("decod_format", ctypes.c_int),
# cod_format: output file format 0: PGX, 1: PxM, 2: BMP
@ -42,6 +85,77 @@ class dparameters_t(ctypes.Structure):
("flags", ctypes.c_uint)]
class image_comp_t(ctypes.Structure):
"""Defines a single image component. """
_fields_ = [("dx", ctypes.c_int),
("dy", ctypes.c_int),
("w", ctypes.c_int),
("h", ctypes.c_int),
("x0", ctypes.c_int),
("y0", ctypes.c_int),
("prec", ctypes.c_int),
("bpp", ctypes.c_int),
("sgnd", ctypes.c_int),
("resno_decoded", ctypes.c_int),
("factor", ctypes.c_int),
("data", ctypes.POINTER(ctypes.c_int))]
class image_t(ctypes.Structure):
"""Defines image data and characteristics."""
_fields_ = [("x0", ctypes.c_int),
("y0", ctypes.c_int),
("x1", ctypes.c_int),
("y1", ctypes.c_int),
("numcomps", ctypes.c_int),
("color_space", ctypes.c_int),
("comps", ctypes.POINTER(image_comp_t)),
("icc_profile_buf", ctypes.c_char_p),
("icc_profile_len", ctypes.c_int)]
def _cio_open(cinfo, src):
"""Wrapper for openjpeg library function opj_cio_open."""
argtypes = [ctypes.POINTER(common_struct_t), ctypes.c_char_p, ctypes.c_int]
_OPENJPEG.opj_cio_open.argtypes = argtypes
_OPENJPEG.opj_cio_open.restype = ctypes.POINTER(cio_t)
cio = _OPENJPEG.opj_cio_open(ctypes.cast(cinfo, ctypes.POINTER(common_struct_t)),
src, len(src))
return cio
def _cio_close(cio):
"""Wraps openjpeg library function cio_close.
"""
_OPENJPEG.opj_cio_close.argtypes = [ctypes.POINTER(cio_t)]
_OPENJPEG.opj_cio_close(cio)
def _create_decompress(fmt):
"""Wraps openjpeg library function opj_create_decompress.
"""
_OPENJPEG.opj_create_decompress.argtypes = [ctypes.c_int]
_OPENJPEG.opj_create_decompress.restype = ctypes.POINTER(dinfo_t)
dinfo = _OPENJPEG.opj_create_decompress(fmt)
return dinfo
def _decode(dinfo, cio):
"""Wrapper for opj_decode.
"""
argtypes = [ctypes.POINTER(dinfo_t), ctypes.POINTER(cio_t)]
_OPENJPEG.opj_decode.argtypes = argtypes
_OPENJPEG.opj_decode.restype = ctypes.POINTER(image_t)
image = _OPENJPEG.opj_decode(dinfo, cio)
return image
def _destroy_decompress(dinfo):
"""Wraps openjpeg library function opj_destroy_decompress."""
_OPENJPEG.opj_destroy_decompress.argtypes = [ctypes.POINTER(dinfo_t)]
_OPENJPEG.opj_destroy_decompress(dinfo)
def _image_destroy(image):
"""Wraps openjpeg library function opj_image_destroy."""
_OPENJPEG.opj_image_destroy.argtypes = [ctypes.POINTER(image_t)]
_OPENJPEG.opj_image_destroy(image)
def _set_default_decoder_parameters(dparams_p):
"""Wrapper for opj_set_default_decoder_parameters.
"""
@ -50,6 +164,12 @@ def _set_default_decoder_parameters(dparams_p):
_OPENJPEG.opj_set_default_decoder_parameters(dparams_p)
def _setup_decoder(dinfo, dparams):
"""Wrapper for openjpeg library function opj_setup_decoder."""
argtypes = [ctypes.POINTER(dinfo_t), ctypes.POINTER(dparameters_t)]
_OPENJPEG.opj_setup_decoder.argtypes = argtypes
_OPENJPEG.opj_setup_decoder(dinfo, dparams)
def _version():
"""Wrapper for opj_version library routine."""
_OPENJPEG.opj_version.restype = ctypes.c_char_p

View file

@ -42,6 +42,10 @@ class TestJp2k15(unittest.TestCase):
# Verbose option not allowed for 1.5.1.
self.assertTrue(False)
def test_differing_subsampling(self):
# Only images with same subsampling is allowed.
self.assertTrue(False)
if __name__ == "__main__":
unittest.main()