Writing works with 1.5, two failures with 3.3. #111

This commit is contained in:
jevans 2013-09-11 20:30:54 -04:00
commit 5b401e1e2d
2 changed files with 64 additions and 127 deletions

View file

@ -15,14 +15,14 @@ else:
import ctypes
import math
import os
import re
import struct
import warnings
import numpy as np
from .codestream import Codestream
from .core import SRGB
from .core import GREYSCALE
from .core import SRGB, GREYSCALE
from .core import PROGRESSION_ORDER
from .core import ENUMERATED_COLORSPACE, RESTRICTED_ICC_PROFILE
from .jp2box import Jp2kBox
@ -33,6 +33,13 @@ from .lib import openjpeg as opj
from .lib import openjp2 as opj2
from .lib import c as libc
if opj.OPENJPEG is None and opj2.OPENJP2 is None:
OPENJPEG_VERSION = '0.0.0'
elif opj2.OPENJP2 is None:
OPENJPEG_VERSION = opj.version()
else:
OPENJPEG_VERSION = opj2.version()
class Jp2k(Jp2kBox):
"""JPEG 2000 file.
@ -185,7 +192,10 @@ class Jp2k(Jp2kBox):
cparams : CompressionParametersType(ctypes.Structure)
Corresponds to cparameters_t type in openjp2 headers.
"""
cparams = opj2.set_default_encoder_parameters()
if re.match(r"""1\.\d\.\d""", OPENJPEG_VERSION):
cparams = opj.set_default_encoder_parameters()
else:
cparams = opj2.set_default_encoder_parameters()
outfile = self.filename.encode()
num_pad_bytes = opj2.PATH_LEN - len(outfile)
@ -389,99 +399,18 @@ class Jp2k(Jp2kBox):
def _write_openjpeg(self, img_array, verbose=False, **kwargs):
"""
"""
if codeblock is not None:
if (np.prod(codeblock) > 4096) or (np.any(np.array(codeblock) < 4)) or (np.any(np.array(codeblock) > 1024)):
msg = 'Size of code block error. '
msg += 'Restriction: width*height <= 4096, '
msg += '4 <= width, height <= 1024'
raise(RuntimeError(msg))
cparams, colorspace = self._process_write_inputs(img_array, **kwargs)
if cratio is not None and len(cratio) >= opj.MAX_NUM_LAYERS:
msg = 'Maximum number of layers is %d.' % opj.MAX_NUM_LAYERS
raise(RuntimeError(msg))
if img_array.ndim == 2:
# Force the image to be 3D. Just makes things easier later on.
numrows, numcols = img_array.shape
img_array = img_array.reshape(numrows, numcols, 1)
if psnr is not None and len(psnr) >= opj.MAX_NUM_LAYERS:
msg = 'Maximum number of layers is %d.' % opj.MAX_NUM_LAYERS
raise(RuntimeError(msg))
comptparms = _populate_comptparms(img_array, cparams)
if cratio is not None and psnr is not None:
msg = 'Psnr and cratio parameters cannot be specified together.'
raise(RuntimeError(msg))
image = opj.image_create(comptparms, colorspace)
cparams = opj.CompressionParametersType()
opj.set_default_encoder_parameters(ctypes.byref(cparams))
# Set default to lossless until we know otherwise.
cparams.tcp_rates[0] = 0
cparams.tcp_numlayers = 1
cparams.cp_disto_alloc = 1
outfile = self.jp2k_file
nelts = opj.OPJ_PATH_LEN - len(outfile)
outfile += b'0'*nelts
cparams.outfile = outfile
numrows = data.shape[0]
numcols = data.shape[1]
numlayers = data.shape[2]
if codeblock is not None:
cparams.cblockw_init = codeblock[0]
cparams.cblockh_init = codeblock[1]
if comment is None:
comment = 'Created by OpenJPEG version %s' % opj.version()
cparams.cp_comment = ctypes.c_char_p(comment)
if cratio is not None:
cparams.tcp_numlayers = len(cratio)
for j in range(0,len(cratio)):
cparams.tcp_rates[j] = cratio[j]
cparams.cp_disto_alloc = 1
if eph:
cparams.csty = cparams.csty | 0x04
if modeswitch is not None:
cparams.mode = modeswitch
if numres is not None:
cparams.numresolution = numres
if origin is not None:
cparams.image_offset_x0 = origin[0]
cparams.image_offset_y0 = origin[1]
if progorder is not None:
cparams.prog_order = opj.progression_order[progorder]
if precinct is not None:
cparams.csty = cparams.csty | 0x01
cparams.res_spec = len(precinct)
for j in range(0,len(precinct)):
cparams.prcw_init[j] = precinct[j][0]
cparams.prch_init[j] = precinct[j][1]
if psnr is not None:
cparams.tcp_numlayers = len(psnr)
for j in range(0,len(psnr)):
cparams.tcp_distoratio[j] = psnr[j]
cparams.cp_fixed_quality = 1
if sop:
cparams.csty = cparams.csty | 0x02
if tile is not None:
cparams.tile_size_on = 1
cparams.cp_tdx = tile[0]
cparams.cp_tdy = tile[1]
# comment = what?
cmptparms = opj.image_cmptparm_t_from_np(data)
image = opj.image_create(cmptparms)
numrows, numcols, numlayers = img_array.shape
# set image offset and reference grid
image.contents.x0 = cparams.image_offset_x0
@ -491,23 +420,16 @@ class Jp2k(Jp2kBox):
# Stage the image data to the openjpeg data structure.
for k in range(0,numlayers):
layer = np.ascontiguousarray(data[:,:,k], dtype=np.int32)
layer = np.ascontiguousarray(img_array[:,:,k], dtype=np.int32)
dest = image.contents.comps[k].data
src = layer.ctypes.data
ctypes.memmove(dest, src, layer.nbytes)
# set multi-component transform?
if image.contents.numcomps == 3:
cparams.tcp_mct = chr(1)
else:
cparams.tcp_mct = chr(0)
# set encode format
#cinfo = opj.create_compress(opj.codec_format[self.file_format])
cinfo = opj.create_compress(self.file_format)
cinfo = opj.create_compress(cparams.codec_fmt)
event_mgr = opj.EventMgrType(None, None, None)
opj.set_event_mgr(cparams, ctypes.byref(event_mgr), None)
#opj.set_event_mgr(cparams, ctypes.byref(event_mgr), None)
opj.setup_encoder(cinfo, ctypes.byref(cparams), image)
@ -519,7 +441,7 @@ class Jp2k(Jp2kBox):
pos = opj.cio_tell(cio)
ss = ctypes.string_at(cio.contents.buffer, pos)
f = open(self.jp2k_file,'wb')
f = open(self.filename,'wb')
f.write(ss)
f.close()
opj.cio_close(cio);
@ -1408,7 +1330,10 @@ def _populate_comptparms(img_array, cparams):
comp_prec = 16
numrows, numcols, num_comps = img_array.shape
comptparms = (opj2.ImageComptParmType * num_comps)()
if re.match(r"""1\.\d\.\d""", OPENJPEG_VERSION):
comptparms = (opj.ImageComptParmType * num_comps)()
else:
comptparms = (opj2.ImageComptParmType * num_comps)()
for j in range(num_comps):
comptparms[j].dx = cparams.subsampling_dx
comptparms[j].dy = cparams.subsampling_dy

View file

@ -371,7 +371,7 @@ class DecompressionParametersType(ctypes.Structure):
_fields_.append(("flags", ctypes.c_uint))
class ImageCmptparmType(ctypes.Structure):
class ImageComptParmType(ctypes.Structure):
"""Component parameters structure used by the opj_image_create function.
"""
_fields_ = [
@ -395,7 +395,7 @@ class ImageCmptparmType(ctypes.Structure):
# precision
('prec', ctypes.c_int),
# imgae depth in bits
# image depth in bits
('bpp', ctypes.c_int),
# signed (1) / unsigned (0)
@ -403,22 +403,19 @@ class ImageCmptparmType(ctypes.Structure):
class ImageCompType(ctypes.Structure):
"""Defines a single image component.
Corresponds to image_comp_t type in openjpeg.
"""
_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))]
"""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 ImageType(ctypes.Structure):
@ -437,16 +434,22 @@ class ImageType(ctypes.Structure):
("icc_profile_len", ctypes.c_int)]
def cio_open(cinfo, src):
def cio_open(cinfo, src=None):
"""Wrapper for openjpeg library function opj_cio_open."""
argtypes = [ctypes.POINTER(CommonStructType), ctypes.c_char_p,
ctypes.c_int]
OPENJPEG.opj_cio_open.argtypes = argtypes
OPENJPEG.opj_cio_open.restype = ctypes.POINTER(CioType)
if src is None:
length = 0
else:
length = len(src)
cio = OPENJPEG.opj_cio_open(ctypes.cast(cinfo,
ctypes.POINTER(CommonStructType)),
src, len(src))
src,
length)
return cio
@ -457,6 +460,13 @@ def cio_close(cio):
OPENJPEG.opj_cio_close(cio)
def cio_tell(cio):
"""Get position in byte stream."""
OPENJPEG.cio_tell.argtypes = [ctypes.POINTER(CioType)]
OPENJPEG.cio_tell.restype = ctypes.c_int
pos = OPENJPEG.cio_tell(cio)
return pos
def create_compress(fmt):
"""Wrapper for openjpeg library function opj_create_compress.
@ -576,7 +586,7 @@ def image_create(cmptparms, cspace):
"""Wrapper for openjpeg library function opj_image_create.
"""
OPENJPEG.opj_image_create.argtypes = [ctypes.c_int,
ctypes.POINTER(ImageCmptparmType),
ctypes.POINTER(ImageComptParmType),
ctypes.c_int]
OPENJPEG.opj_image_create.restype = ctypes.POINTER(ImageType)
@ -590,12 +600,14 @@ def image_destroy(image):
OPENJPEG.opj_image_destroy(image)
def set_default_encoder_parameters(cparams_p):
def set_default_encoder_parameters():
"""Wrapper for openjpeg library function opj_set_default_encoder_parameters.
"""
cparams = CompressionParametersType()
argtypes = [ctypes.POINTER(CompressionParametersType)]
OPENJPEG.opj_set_default_encoder_parameters.argtypes = argtypes
OPENJPEG.opj_set_default_encoder_parameters(cparams_p)
OPENJPEG.opj_set_default_encoder_parameters(ctypes.byref(cparams))
return cparams
def set_default_decoder_parameters(dparams_p):