Merge branch 'issue114' into devel
This commit is contained in:
commit
14810b2add
1 changed files with 58 additions and 106 deletions
164
glymur/jp2k.py
164
glymur/jp2k.py
|
|
@ -19,7 +19,6 @@ else:
|
||||||
import ctypes
|
import ctypes
|
||||||
import math
|
import math
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import struct
|
import struct
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
|
@ -386,132 +385,85 @@ class Jp2k(Jp2kBox):
|
||||||
If glymur is unable to load the openjp2 library.
|
If glymur is unable to load the openjp2 library.
|
||||||
"""
|
"""
|
||||||
if opj2.OPENJP2 is not None:
|
if opj2.OPENJP2 is not None:
|
||||||
img = self._write_openjp2(img_array, verbose=verbose, **kwargs)
|
self._write_openjp2(img_array, verbose=verbose, **kwargs)
|
||||||
elif opj.OPENJPEG is not None:
|
elif opj.OPENJPEG is not None:
|
||||||
img = self._write_openjpeg(img_array, verbose=verbose, **kwargs)
|
self._write_openjpeg(img_array, verbose=verbose, **kwargs)
|
||||||
else:
|
else:
|
||||||
raise LibraryNotFoundError("You must have version 1.5 of OpenJPEG "
|
raise LibraryNotFoundError("You must have at least version 1.5 of "
|
||||||
"or more recent before using this "
|
"OpenJPEG before using this "
|
||||||
"functionality.")
|
"functionality.")
|
||||||
|
|
||||||
def _write_openjpeg(self, img_array, verbose=False, **kwargs):
|
def _write_openjpeg(self, img_array, verbose=False, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
Write JPEG 2000 file using OpenJPEG 1.5 interface.
|
||||||
"""
|
"""
|
||||||
cparams, colorspace = self._process_write_inputs(img_array, **kwargs)
|
cparams, colorspace = self._process_write_inputs(img_array, **kwargs)
|
||||||
|
|
||||||
if img_array.ndim == 2:
|
if img_array.ndim == 2:
|
||||||
# Force the image to be 3D. Just makes things easier later on.
|
# Force the image to be 3D. Just makes things easier later on.
|
||||||
numrows, numcols = img_array.shape
|
img_array = img_array.reshape(img_array.shape[0],
|
||||||
img_array = img_array.reshape(numrows, numcols, 1)
|
img_array.shape[1],
|
||||||
|
1)
|
||||||
|
|
||||||
comptparms = _populate_comptparms(img_array, cparams)
|
comptparms = _populate_comptparms(img_array, cparams)
|
||||||
|
|
||||||
image = opj.image_create(comptparms, colorspace)
|
with ExitStack() as stack:
|
||||||
|
image = opj.image_create(comptparms, colorspace)
|
||||||
|
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 = cparams.image_offset_x0
|
||||||
image.contents.y0 = cparams.image_offset_y0
|
image.contents.y0 = cparams.image_offset_y0
|
||||||
image.contents.x1 = image.contents.x0 + (numcols - 1) * cparams.subsampling_dx + 1
|
image.contents.x1 = image.contents.x0 \
|
||||||
image.contents.y1 = image.contents.y0 + (numrows - 1) * cparams.subsampling_dy + 1
|
+ (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.
|
# Stage the image data to the openjpeg data structure.
|
||||||
for k in range(0,numlayers):
|
for k in range(0, numlayers):
|
||||||
layer = np.ascontiguousarray(img_array[:,:,k], dtype=np.int32)
|
layer = np.ascontiguousarray(img_array[:, :, k],
|
||||||
dest = image.contents.comps[k].data
|
dtype=np.int32)
|
||||||
src = layer.ctypes.data
|
dest = image.contents.comps[k].data
|
||||||
ctypes.memmove(dest, src, layer.nbytes)
|
src = layer.ctypes.data
|
||||||
|
ctypes.memmove(dest, src, layer.nbytes)
|
||||||
|
|
||||||
# set encode format
|
cinfo = opj.create_compress(cparams.codec_fmt)
|
||||||
cinfo = opj.create_compress(cparams.codec_fmt)
|
stack.callback(opj.destroy_compress, cinfo)
|
||||||
|
|
||||||
event_mgr = opj.EventMgrType()
|
# Setup the info, warning, and error handlers.
|
||||||
_info_handler = _INFO_CALLBACK if verbose else None
|
# Always use the warning and error handler. Use of an info
|
||||||
event_mgr.info_handler = _info_handler
|
# handler is optional.
|
||||||
event_mgr.warning_handler = ctypes.cast(_WARNING_CALLBACK,
|
event_mgr = opj.EventMgrType()
|
||||||
ctypes.c_void_p)
|
_info_handler = _INFO_CALLBACK if verbose else None
|
||||||
event_mgr.error_handler = ctypes.cast(_ERROR_CALLBACK,
|
event_mgr.info_handler = _info_handler
|
||||||
ctypes.c_void_p)
|
event_mgr.warning_handler = ctypes.cast(_WARNING_CALLBACK,
|
||||||
|
ctypes.c_void_p)
|
||||||
|
event_mgr.error_handler = ctypes.cast(_ERROR_CALLBACK,
|
||||||
|
ctypes.c_void_p)
|
||||||
|
|
||||||
opj.setup_encoder(cinfo, ctypes.byref(cparams), image)
|
opj.setup_encoder(cinfo, ctypes.byref(cparams), image)
|
||||||
|
|
||||||
# open a byte stream for writing
|
cio = opj.cio_open(cinfo)
|
||||||
# allocate memory for all tiles
|
stack.callback(opj.cio_close, cio)
|
||||||
cio = opj.cio_open(cinfo)
|
|
||||||
|
|
||||||
if not opj.encode(cinfo, cio, image):
|
|
||||||
raise IOError("Encode error.")
|
|
||||||
|
|
||||||
pos = opj.cio_tell(cio)
|
if not opj.encode(cinfo, cio, image):
|
||||||
|
raise IOError("Encode error.")
|
||||||
|
|
||||||
ss = ctypes.string_at(cio.contents.buffer, pos)
|
pos = opj.cio_tell(cio)
|
||||||
f = open(self.filename,'wb')
|
|
||||||
f.write(ss)
|
|
||||||
f.close()
|
|
||||||
opj.cio_close(cio);
|
|
||||||
|
|
||||||
opj.destroy_compress(cinfo);
|
blob = ctypes.string_at(cio.contents.buffer, pos)
|
||||||
opj.image_destroy(image);
|
fptr = open(self.filename, 'wb')
|
||||||
|
stack.callback(fptr.close)
|
||||||
|
fptr.write(blob)
|
||||||
|
|
||||||
self.parse()
|
self.parse()
|
||||||
|
|
||||||
|
|
||||||
def _write_openjp2(self, img_array, verbose=False, **kwargs):
|
def _write_openjp2(self, img_array, verbose=False, **kwargs):
|
||||||
"""Write image data to a JP2/JPX/J2k file. Intended usage of the
|
"""
|
||||||
various parameters follows that of OpenJPEG's opj_compress utility.
|
Write JPEG 2000 file using OpenJPEG 1.5 interface.
|
||||||
|
|
||||||
This method can only be used to create JPEG 2000 images that can fit
|
|
||||||
in memory.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
img_array : ndarray
|
|
||||||
Image data to be written to file.
|
|
||||||
cbsize : tuple, optional
|
|
||||||
Code block size (DY, DX).
|
|
||||||
colorspace : str, optional
|
|
||||||
Either 'rgb' or 'gray'.
|
|
||||||
cratios : iterable
|
|
||||||
Compression ratios for successive layers.
|
|
||||||
eph : bool, optional
|
|
||||||
If true, write SOP marker after each header packet.
|
|
||||||
grid_offset : tuple, optional
|
|
||||||
Offset (DY, DX) of the origin of the image in the reference grid.
|
|
||||||
mct : bool, optional
|
|
||||||
Specifies usage of the multi component transform. If not
|
|
||||||
specified, defaults to True if the colorspace is RGB.
|
|
||||||
modesw : int, optional
|
|
||||||
Mode switch.
|
|
||||||
1 = BYPASS(LAZY)
|
|
||||||
2 = RESET
|
|
||||||
4 = RESTART(TERMALL)
|
|
||||||
8 = VSC
|
|
||||||
16 = ERTERM(SEGTERM)
|
|
||||||
32 = SEGMARK(SEGSYM)
|
|
||||||
numres : int, optional
|
|
||||||
Number of resolutions.
|
|
||||||
prog : str, optional
|
|
||||||
Progression order, one of "LRCP" "RLCP", "RPCL", "PCRL", "CPRL".
|
|
||||||
psnr : iterable, optional
|
|
||||||
Different PSNR for successive layers.
|
|
||||||
psizes : list, optional
|
|
||||||
List of precinct sizes. Each precinct size tuple is defined in
|
|
||||||
(height x width).
|
|
||||||
sop : bool, optional
|
|
||||||
If true, write SOP marker before each packet.
|
|
||||||
subsam : tuple, optional
|
|
||||||
Subsampling factors (dy, dx).
|
|
||||||
tilesize : tuple, optional
|
|
||||||
Numeric tuple specifying tile size in terms of (numrows, numcols),
|
|
||||||
not (X, Y).
|
|
||||||
verbose : bool, optional
|
|
||||||
Print informational messages produced by the OpenJPEG library.
|
|
||||||
|
|
||||||
Raises
|
|
||||||
------
|
|
||||||
glymur.LibraryNotFoundError
|
|
||||||
If glymur is unable to load the openjp2 library.
|
|
||||||
"""
|
"""
|
||||||
cparams, colorspace = self._process_write_inputs(img_array, **kwargs)
|
cparams, colorspace = self._process_write_inputs(img_array, **kwargs)
|
||||||
|
|
||||||
|
|
@ -784,14 +736,14 @@ class Jp2k(Jp2kBox):
|
||||||
opj.set_default_decoder_parameters(ctypes.byref(dparameters))
|
opj.set_default_decoder_parameters(ctypes.byref(dparameters))
|
||||||
dparameters.cp_reduce = rlevel
|
dparameters.cp_reduce = rlevel
|
||||||
dparameters.decod_format = self._codec_format
|
dparameters.decod_format = self._codec_format
|
||||||
|
|
||||||
infile = self.filename.encode()
|
infile = self.filename.encode()
|
||||||
nelts = opj.PATH_LEN - len(infile)
|
nelts = opj.PATH_LEN - len(infile)
|
||||||
infile += b'0' * nelts
|
infile += b'0' * nelts
|
||||||
dparameters.infile = infile
|
dparameters.infile = infile
|
||||||
|
|
||||||
dinfo = opj.create_decompress(dparameters.decod_format)
|
dinfo = opj.create_decompress(dparameters.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)
|
||||||
event_mgr.info_handler = info_handler if verbose else None
|
event_mgr.info_handler = info_handler if verbose else None
|
||||||
|
|
@ -800,19 +752,19 @@ 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.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, dparameters)
|
||||||
|
|
||||||
with open(self.filename, 'rb') as fptr:
|
with open(self.filename, 'rb') as fptr:
|
||||||
src = fptr.read()
|
src = fptr.read()
|
||||||
cio = opj.cio_open(dinfo, src)
|
cio = opj.cio_open(dinfo, src)
|
||||||
|
|
||||||
image = opj.decode(dinfo, cio)
|
image = opj.decode(dinfo, cio)
|
||||||
|
|
||||||
stack.callback(opj.image_destroy, image)
|
stack.callback(opj.image_destroy, image)
|
||||||
stack.callback(opj.destroy_decompress, dinfo)
|
stack.callback(opj.destroy_decompress, dinfo)
|
||||||
stack.callback(opj.cio_close, cio)
|
stack.callback(opj.cio_close, cio)
|
||||||
|
|
||||||
data = extract_image_cube(image)
|
data = extract_image_cube(image)
|
||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue