Merge branch 'issue114' into devel

This commit is contained in:
John Evans 2013-09-15 11:16:29 -04:00
commit 14810b2add

View file

@ -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: