Writing works with 1.5, two failures with 3.3. #111
This commit is contained in:
parent
5626f3f460
commit
5b401e1e2d
2 changed files with 64 additions and 127 deletions
133
glymur/jp2k.py
133
glymur/jp2k.py
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue