Reading goodstuff on 64-bit linux works, but nemo is oddly truncated.
This commit is contained in:
parent
4bb034e966
commit
e071a96f68
3 changed files with 193 additions and 4 deletions
|
|
@ -614,7 +614,72 @@ class Jp2k(Jp2kBox):
|
||||||
IOError
|
IOError
|
||||||
If the image has differing subsample factors.
|
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,
|
def _read_openjp2(self, reduce=0, layer=0, area=None, tile=None,
|
||||||
verbose=False):
|
verbose=False):
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,50 @@ else:
|
||||||
elif platform.system() == 'Linux':
|
elif platform.system() == 'Linux':
|
||||||
_OPENJPEG = ctypes.CDLL(find_library('openjpeg'))
|
_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):
|
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: the maximum number of quality layers to decode
|
||||||
("cp_layer", ctypes.c_int),
|
("cp_layer", ctypes.c_int),
|
||||||
# infile: input file name
|
# infile: input file name
|
||||||
("infile", ctypes.c_char * OPJ_PATH_LEN),
|
("infile", ctypes.c_char * _PATH_LEN),
|
||||||
# outfile: output file name
|
# 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: input file format 0: J2K, 1: JP2, 2: JPT
|
||||||
("decod_format", ctypes.c_int),
|
("decod_format", ctypes.c_int),
|
||||||
# cod_format: output file format 0: PGX, 1: PxM, 2: BMP
|
# cod_format: output file format 0: PGX, 1: PxM, 2: BMP
|
||||||
|
|
@ -42,6 +85,77 @@ class dparameters_t(ctypes.Structure):
|
||||||
("flags", ctypes.c_uint)]
|
("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):
|
def _set_default_decoder_parameters(dparams_p):
|
||||||
"""Wrapper for opj_set_default_decoder_parameters.
|
"""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)
|
_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():
|
def _version():
|
||||||
"""Wrapper for opj_version library routine."""
|
"""Wrapper for opj_version library routine."""
|
||||||
_OPENJPEG.opj_version.restype = ctypes.c_char_p
|
_OPENJPEG.opj_version.restype = ctypes.c_char_p
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,10 @@ class TestJp2k15(unittest.TestCase):
|
||||||
# Verbose option not allowed for 1.5.1.
|
# Verbose option not allowed for 1.5.1.
|
||||||
self.assertTrue(False)
|
self.assertTrue(False)
|
||||||
|
|
||||||
|
def test_differing_subsampling(self):
|
||||||
|
# Only images with same subsampling is allowed.
|
||||||
|
self.assertTrue(False)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue