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
|
||||
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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue