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 ctypes
import math import math
import os import os
import re
import struct import struct
import warnings import warnings
import numpy as np import numpy as np
from .codestream import Codestream from .codestream import Codestream
from .core import SRGB from .core import SRGB, GREYSCALE
from .core import GREYSCALE
from .core import PROGRESSION_ORDER from .core import PROGRESSION_ORDER
from .core import ENUMERATED_COLORSPACE, RESTRICTED_ICC_PROFILE from .core import ENUMERATED_COLORSPACE, RESTRICTED_ICC_PROFILE
from .jp2box import Jp2kBox from .jp2box import Jp2kBox
@ -33,6 +33,13 @@ from .lib import openjpeg as opj
from .lib import openjp2 as opj2 from .lib import openjp2 as opj2
from .lib import c as libc 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): class Jp2k(Jp2kBox):
"""JPEG 2000 file. """JPEG 2000 file.
@ -185,7 +192,10 @@ class Jp2k(Jp2kBox):
cparams : CompressionParametersType(ctypes.Structure) cparams : CompressionParametersType(ctypes.Structure)
Corresponds to cparameters_t type in openjp2 headers. 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() outfile = self.filename.encode()
num_pad_bytes = opj2.PATH_LEN - len(outfile) num_pad_bytes = opj2.PATH_LEN - len(outfile)
@ -389,99 +399,18 @@ class Jp2k(Jp2kBox):
def _write_openjpeg(self, img_array, verbose=False, **kwargs): def _write_openjpeg(self, img_array, verbose=False, **kwargs):
""" """
""" """
if codeblock is not None: cparams, colorspace = self._process_write_inputs(img_array, **kwargs)
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))
if cratio is not None and len(cratio) >= opj.MAX_NUM_LAYERS: if img_array.ndim == 2:
msg = 'Maximum number of layers is %d.' % opj.MAX_NUM_LAYERS # Force the image to be 3D. Just makes things easier later on.
raise(RuntimeError(msg)) 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: comptparms = _populate_comptparms(img_array, cparams)
msg = 'Maximum number of layers is %d.' % opj.MAX_NUM_LAYERS
raise(RuntimeError(msg))
if cratio is not None and psnr is not None: image = opj.image_create(comptparms, colorspace)
msg = 'Psnr and cratio parameters cannot be specified together.'
raise(RuntimeError(msg))
numrows, numcols, numlayers = img_array.shape
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)
# 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
@ -491,23 +420,16 @@ class Jp2k(Jp2kBox):
# 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(data[:,:,k], dtype=np.int32) layer = np.ascontiguousarray(img_array[:,:,k], dtype=np.int32)
dest = image.contents.comps[k].data dest = image.contents.comps[k].data
src = layer.ctypes.data src = layer.ctypes.data
ctypes.memmove(dest, src, layer.nbytes) 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 # set encode format
#cinfo = opj.create_compress(opj.codec_format[self.file_format]) cinfo = opj.create_compress(cparams.codec_fmt)
cinfo = opj.create_compress(self.file_format)
event_mgr = opj.EventMgrType(None, None, None) 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) opj.setup_encoder(cinfo, ctypes.byref(cparams), image)
@ -519,7 +441,7 @@ class Jp2k(Jp2kBox):
pos = opj.cio_tell(cio) pos = opj.cio_tell(cio)
ss = ctypes.string_at(cio.contents.buffer, pos) ss = ctypes.string_at(cio.contents.buffer, pos)
f = open(self.jp2k_file,'wb') f = open(self.filename,'wb')
f.write(ss) f.write(ss)
f.close() f.close()
opj.cio_close(cio); opj.cio_close(cio);
@ -1408,7 +1330,10 @@ def _populate_comptparms(img_array, cparams):
comp_prec = 16 comp_prec = 16
numrows, numcols, num_comps = img_array.shape 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): for j in range(num_comps):
comptparms[j].dx = cparams.subsampling_dx comptparms[j].dx = cparams.subsampling_dx
comptparms[j].dy = cparams.subsampling_dy comptparms[j].dy = cparams.subsampling_dy

View file

@ -371,7 +371,7 @@ class DecompressionParametersType(ctypes.Structure):
_fields_.append(("flags", ctypes.c_uint)) _fields_.append(("flags", ctypes.c_uint))
class ImageCmptparmType(ctypes.Structure): class ImageComptParmType(ctypes.Structure):
"""Component parameters structure used by the opj_image_create function. """Component parameters structure used by the opj_image_create function.
""" """
_fields_ = [ _fields_ = [
@ -395,7 +395,7 @@ class ImageCmptparmType(ctypes.Structure):
# precision # precision
('prec', ctypes.c_int), ('prec', ctypes.c_int),
# imgae depth in bits # image depth in bits
('bpp', ctypes.c_int), ('bpp', ctypes.c_int),
# signed (1) / unsigned (0) # signed (1) / unsigned (0)
@ -403,22 +403,19 @@ class ImageCmptparmType(ctypes.Structure):
class ImageCompType(ctypes.Structure): class ImageCompType(ctypes.Structure):
"""Defines a single image component. """Defines a single image component. """
_fields_ = [("dx", ctypes.c_int),
Corresponds to image_comp_t type in openjpeg. ("dy", ctypes.c_int),
""" ("w", ctypes.c_int),
_fields_ = [("dx", ctypes.c_int), ("h", ctypes.c_int),
("dy", ctypes.c_int), ("x0", ctypes.c_int),
("w", ctypes.c_int), ("y0", ctypes.c_int),
("h", ctypes.c_int), ("prec", ctypes.c_int),
("x0", ctypes.c_int), ("bpp", ctypes.c_int),
("y0", ctypes.c_int), ("sgnd", ctypes.c_int),
("prec", ctypes.c_int), ("resno_decoded", ctypes.c_int),
("bpp", ctypes.c_int), ("factor", ctypes.c_int),
("sgnd", ctypes.c_int), ("data", ctypes.POINTER(ctypes.c_int))]
("resno_decoded", ctypes.c_int),
("factor", ctypes.c_int),
("data", ctypes.POINTER(ctypes.c_int))]
class ImageType(ctypes.Structure): class ImageType(ctypes.Structure):
@ -437,16 +434,22 @@ class ImageType(ctypes.Structure):
("icc_profile_len", ctypes.c_int)] ("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.""" """Wrapper for openjpeg library function opj_cio_open."""
argtypes = [ctypes.POINTER(CommonStructType), ctypes.c_char_p, argtypes = [ctypes.POINTER(CommonStructType), ctypes.c_char_p,
ctypes.c_int] ctypes.c_int]
OPENJPEG.opj_cio_open.argtypes = argtypes OPENJPEG.opj_cio_open.argtypes = argtypes
OPENJPEG.opj_cio_open.restype = ctypes.POINTER(CioType) 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, cio = OPENJPEG.opj_cio_open(ctypes.cast(cinfo,
ctypes.POINTER(CommonStructType)), ctypes.POINTER(CommonStructType)),
src, len(src)) src,
length)
return cio return cio
@ -457,6 +460,13 @@ def cio_close(cio):
OPENJPEG.opj_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): def create_compress(fmt):
"""Wrapper for openjpeg library function opj_create_compress. """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. """Wrapper for openjpeg library function opj_image_create.
""" """
OPENJPEG.opj_image_create.argtypes = [ctypes.c_int, OPENJPEG.opj_image_create.argtypes = [ctypes.c_int,
ctypes.POINTER(ImageCmptparmType), ctypes.POINTER(ImageComptParmType),
ctypes.c_int] ctypes.c_int]
OPENJPEG.opj_image_create.restype = ctypes.POINTER(ImageType) OPENJPEG.opj_image_create.restype = ctypes.POINTER(ImageType)
@ -590,12 +600,14 @@ def image_destroy(image):
OPENJPEG.opj_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. """Wrapper for openjpeg library function opj_set_default_encoder_parameters.
""" """
cparams = CompressionParametersType()
argtypes = [ctypes.POINTER(CompressionParametersType)] argtypes = [ctypes.POINTER(CompressionParametersType)]
OPENJPEG.opj_set_default_encoder_parameters.argtypes = argtypes 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): def set_default_decoder_parameters(dparams_p):