pylint work, #99
This commit is contained in:
parent
fbc9bbcf14
commit
63168e6b3a
2 changed files with 151 additions and 138 deletions
287
glymur/jp2k.py
287
glymur/jp2k.py
|
|
@ -3,7 +3,9 @@
|
|||
License: MIT
|
||||
"""
|
||||
|
||||
# pylint: disable=C0302
|
||||
# W0201: Since we are using ctypes Structures, we often have to access
|
||||
# attributes that are not defined in __init__ but in _fields_ instead.
|
||||
# pylint: disable=W0201
|
||||
|
||||
import sys
|
||||
if sys.hexversion >= 0x03030000:
|
||||
|
|
@ -32,7 +34,7 @@ from .jp2box import ImageHeaderBox
|
|||
from .jp2box import ColourSpecificationBox
|
||||
from .lib import openjpeg as opj
|
||||
from .lib import openjp2 as opj2
|
||||
from .lib import c as _libc
|
||||
from .lib import c as libc
|
||||
|
||||
# Need to known if openjp2 library is the officially release v2.0.0 or not.
|
||||
_OPENJP2_IS_OFFICIAL_V2 = False
|
||||
|
|
@ -233,7 +235,6 @@ class Jp2k(Jp2kBox):
|
|||
cparams : CompressionParametersType(ctypes.Structure)
|
||||
Corresponds to cparameters_t type in openjp2 headers.
|
||||
"""
|
||||
|
||||
cparams = opj2.set_default_encoder_parameters()
|
||||
|
||||
outfile = self.filename.encode()
|
||||
|
|
@ -308,70 +309,6 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
return cparams
|
||||
|
||||
def _validate_compression_params(self, img_array, cparams):
|
||||
"""Check that the compression parameters are valid.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
img_array : ndarray
|
||||
Image data to be written to file.
|
||||
cparams : CompressionParametersType(ctypes.Structure)
|
||||
Corresponds to cparameters_t type in openjp2 headers.
|
||||
"""
|
||||
|
||||
# Code block size
|
||||
code_block_specified = False
|
||||
if cparams.cblockw_init != 0 and cparams.cblockh_init != 0:
|
||||
# These fields ARE zero if uninitialized.
|
||||
width = cparams.cblockw_init
|
||||
height = cparams.cblockh_init
|
||||
code_block_specified = True
|
||||
if height * width > 4096 or height < 4 or width < 4:
|
||||
msg = "Code block area cannot exceed 4096. "
|
||||
msg += "Code block height and width must be larger than 4."
|
||||
raise IOError(msg)
|
||||
if ((math.log(height, 2) != math.floor(math.log(height, 2)) or
|
||||
math.log(width, 2) != math.floor(math.log(width, 2)))):
|
||||
msg = "Bad code block size ({0}, {1}), "
|
||||
msg += "must be powers of 2."
|
||||
raise IOError(msg.format(height, width))
|
||||
|
||||
# Precinct size
|
||||
if cparams.res_spec != 0:
|
||||
# precinct size was not specified if this field is zero.
|
||||
for j in range(cparams.res_spec):
|
||||
prch = cparams.prch_init[j]
|
||||
prcw = cparams.prcw_init[j]
|
||||
if j == 0 and code_block_specified:
|
||||
height, width = cparams.cblockh_init, cparams.cblockw_init
|
||||
if height * 2 > prch or width * 2 > prcw:
|
||||
msg = "Highest Resolution precinct size must be at "
|
||||
msg += "least twice that of the code block dimensions."
|
||||
raise IOError(msg)
|
||||
if ((math.log(prch, 2) != math.floor(math.log(prch, 2)) or
|
||||
math.log(prcw, 2) != math.floor(math.log(prcw, 2)))):
|
||||
msg = "Bad precinct sizes ({0}, {1}), "
|
||||
msg += "must be powers of 2."
|
||||
raise IOError(msg.format(prch, prcw))
|
||||
|
||||
# What would the point of 1D images be?
|
||||
if img_array.ndim == 1 or img_array.ndim > 3:
|
||||
msg = "{0}D imagery is not allowed.".format(img_array.ndim)
|
||||
raise IOError(msg)
|
||||
|
||||
if _OPENJP2_IS_OFFICIAL_V2:
|
||||
if (((img_array.ndim != 2) and
|
||||
(img_array.shape[2] != 1 and img_array.shape[2] != 3))):
|
||||
msg = "Writing images is restricted to single-channel "
|
||||
msg += "greyscale images or three-channel RGB images when "
|
||||
msg += "the OpenJPEG library version is the official 2.0.0 "
|
||||
msg += "release."
|
||||
raise IOError(msg)
|
||||
|
||||
if img_array.dtype != np.uint8 and img_array.dtype != np.uint16:
|
||||
msg = "Only uint8 and uint16 images are currently supported."
|
||||
raise RuntimeError(msg)
|
||||
|
||||
def _process_write_inputs(self, img_array, colorspace=None, **kwargs):
|
||||
"""Directs processing of write method arguments.
|
||||
|
||||
|
|
@ -403,7 +340,7 @@ class Jp2k(Jp2kBox):
|
|||
raise IOError(msg)
|
||||
|
||||
cparams = self._populate_cparams(**kwargs)
|
||||
self._validate_compression_params(img_array, cparams)
|
||||
_validate_compression_params(img_array, cparams)
|
||||
|
||||
colorspace = _unpack_colorspace(colorspace, img_array, cparams)
|
||||
|
||||
|
|
@ -426,38 +363,6 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
return cparams, colorspace
|
||||
|
||||
def _populate_image_struct(self, cparams, image, imgdata):
|
||||
"""Populates image struct needed for compression.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
cparams : CompressionParametersType(ctypes.Structure)
|
||||
Corresponds to cparameters_t type in openjp2 headers.
|
||||
image : ImageType(ctypes.Structure)
|
||||
Corresponds to image_t type in openjp2 headers.
|
||||
imgarray : ndarray
|
||||
Image data to be written to file.
|
||||
"""
|
||||
|
||||
numrows, numcols, num_comps = imgdata.shape
|
||||
|
||||
# set image offset and reference grid
|
||||
image.contents.x0 = cparams.image_offset_x0
|
||||
image.contents.y0 = cparams.image_offset_y0
|
||||
image.contents.x1 = (image.contents.x0 +
|
||||
(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.
|
||||
for k in range(0, num_comps):
|
||||
layer = np.ascontiguousarray(imgdata[:, :, k], dtype=np.int32)
|
||||
dest = image.contents.comps[k].data
|
||||
src = layer.ctypes.data
|
||||
ctypes.memmove(dest, src, layer.nbytes)
|
||||
|
||||
return image
|
||||
|
||||
def write(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.
|
||||
|
|
@ -537,24 +442,10 @@ class Jp2k(Jp2kBox):
|
|||
numrows, numcols = img_array.shape
|
||||
img_array = img_array.reshape(numrows, numcols, 1)
|
||||
|
||||
# Only two precisions are possible.
|
||||
comp_prec = 8 if img_array.dtype == np.uint8 else 16
|
||||
|
||||
numrows, numcols, num_comps = img_array.shape
|
||||
comptparms = (opj2.ImageComptParmType * num_comps)()
|
||||
for j in range(num_comps):
|
||||
comptparms[j].dx = cparams.subsampling_dx
|
||||
comptparms[j].dy = cparams.subsampling_dy
|
||||
comptparms[j].w = numcols
|
||||
comptparms[j].h = numrows
|
||||
comptparms[j].x0 = cparams.image_offset_x0
|
||||
comptparms[j].y0 = cparams.image_offset_y0
|
||||
comptparms[j].prec = comp_prec
|
||||
comptparms[j].bpp = comp_prec
|
||||
comptparms[j].sgnd = 0
|
||||
comptparms = _populate_comptparms(img_array, cparams)
|
||||
|
||||
image = opj2.image_create(comptparms, colorspace)
|
||||
self._populate_image_struct(cparams, image, img_array)
|
||||
_populate_image_struct(cparams, image, img_array)
|
||||
|
||||
codec = opj2.create_compress(cparams.codec_fmt)
|
||||
|
||||
|
|
@ -566,7 +457,7 @@ class Jp2k(Jp2kBox):
|
|||
opj2.setup_encoder(codec, cparams, image)
|
||||
|
||||
if _OPENJP2_IS_OFFICIAL_V2:
|
||||
fptr = _libc.fopen(self.filename, 'wb')
|
||||
fptr = libc.fopen(self.filename, 'wb')
|
||||
strm = opj2.stream_create_default_file_stream(fptr, False)
|
||||
else:
|
||||
# This routine introduced in 2.0 devel series.
|
||||
|
|
@ -580,7 +471,7 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
if _OPENJP2_IS_OFFICIAL_V2:
|
||||
opj2.stream_destroy(strm)
|
||||
_libc.fclose(fptr)
|
||||
libc.fclose(fptr)
|
||||
else:
|
||||
# This routine introduced in 2.0 devel series.
|
||||
opj2.stream_destroy_v3(strm)
|
||||
|
|
@ -804,8 +695,7 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
return data
|
||||
|
||||
def _read_openjp2(self, rlevel=0, layer=0, area=None, tile=None,
|
||||
verbose=False):
|
||||
def _read_openjp2(self, **kwargs):
|
||||
"""Read a JPEG 2000 image using libopenjp2.
|
||||
|
||||
Parameters
|
||||
|
|
@ -835,12 +725,7 @@ class Jp2k(Jp2kBox):
|
|||
"""
|
||||
self._subsampling_sanity_check()
|
||||
|
||||
img_array = self._read_common(rlevel=rlevel,
|
||||
layer=layer,
|
||||
area=area,
|
||||
tile=tile,
|
||||
verbose=verbose,
|
||||
as_bands=False)
|
||||
img_array = self._read_common(as_bands=False, **kwargs)
|
||||
|
||||
if img_array.shape[2] == 1:
|
||||
img_array = img_array.view()
|
||||
|
|
@ -936,8 +821,8 @@ class Jp2k(Jp2kBox):
|
|||
True)
|
||||
stack.callback(opj2.stream_destroy_v3, stream)
|
||||
else:
|
||||
fptr = _libc.fopen(self.filename, 'rb')
|
||||
stack.callback(_libc.fclose, fptr)
|
||||
fptr = libc.fopen(self.filename, 'rb')
|
||||
stack.callback(libc.fclose, fptr)
|
||||
stream = opj2.stream_create_default_file_stream(fptr, True)
|
||||
stack.callback(opj2.stream_destroy, stream)
|
||||
codec = opj2.create_decompress(self._codec_format)
|
||||
|
|
@ -970,8 +855,7 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
return data
|
||||
|
||||
def read_bands(self, rlevel=0, layer=0, area=None, tile=None,
|
||||
verbose=False):
|
||||
def read_bands(self, **kwargs):
|
||||
"""Read a JPEG 2000 image.
|
||||
|
||||
The only time you should use this method is when the image has
|
||||
|
|
@ -1018,13 +902,7 @@ class Jp2k(Jp2kBox):
|
|||
"of OpenJP2 installed before using "
|
||||
"this functionality.")
|
||||
|
||||
lst = self._read_common(rlevel=rlevel,
|
||||
layer=layer,
|
||||
area=area,
|
||||
tile=tile,
|
||||
verbose=verbose,
|
||||
as_bands=True)
|
||||
|
||||
lst = self._read_common(as_bands=True, **kwargs)
|
||||
return lst
|
||||
|
||||
def get_codestream(self, header_only=True):
|
||||
|
|
@ -1298,3 +1176,138 @@ def _unpack_colorspace(colorspace, img_array, cparams):
|
|||
colorspace = _COLORSPACE_MAP[colorspace.lower()]
|
||||
|
||||
return colorspace
|
||||
|
||||
def _populate_comptparms(img_array, cparams):
|
||||
"""Instantiate and populate comptparms structure.
|
||||
|
||||
This structure defines the image components.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
img_array : ndarray
|
||||
Image data to be written to file.
|
||||
cparams : CompressionParametersType(ctypes.Structure)
|
||||
Corresponds to cparameters_t type in openjp2 headers.
|
||||
|
||||
Returns
|
||||
-------
|
||||
comptparms : ImageCompType(ctypes.Structure)
|
||||
Corresponds to image_comp_t type in openjp2 headers.
|
||||
"""
|
||||
# Only two precisions are possible.
|
||||
if img_array.dtype == np.uint8:
|
||||
comp_prec = 8
|
||||
else:
|
||||
comp_prec = 16
|
||||
|
||||
numrows, numcols, num_comps = img_array.shape
|
||||
comptparms = (opj2.ImageComptParmType * num_comps)()
|
||||
for j in range(num_comps):
|
||||
comptparms[j].dx = cparams.subsampling_dx
|
||||
comptparms[j].dy = cparams.subsampling_dy
|
||||
comptparms[j].w = numcols
|
||||
comptparms[j].h = numrows
|
||||
comptparms[j].x0 = cparams.image_offset_x0
|
||||
comptparms[j].y0 = cparams.image_offset_y0
|
||||
comptparms[j].prec = comp_prec
|
||||
comptparms[j].bpp = comp_prec
|
||||
comptparms[j].sgnd = 0
|
||||
|
||||
return comptparms
|
||||
|
||||
def _populate_image_struct(cparams, image, imgdata):
|
||||
"""Populates image struct needed for compression.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
cparams : CompressionParametersType(ctypes.Structure)
|
||||
Corresponds to cparameters_t type in openjp2 headers.
|
||||
image : ImageType(ctypes.Structure)
|
||||
Corresponds to image_t type in openjp2 headers.
|
||||
imgarray : ndarray
|
||||
Image data to be written to file.
|
||||
"""
|
||||
|
||||
numrows, numcols, num_comps = imgdata.shape
|
||||
|
||||
# set image offset and reference grid
|
||||
image.contents.x0 = cparams.image_offset_x0
|
||||
image.contents.y0 = cparams.image_offset_y0
|
||||
image.contents.x1 = (image.contents.x0 +
|
||||
(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.
|
||||
for k in range(0, num_comps):
|
||||
layer = np.ascontiguousarray(imgdata[:, :, k], dtype=np.int32)
|
||||
dest = image.contents.comps[k].data
|
||||
src = layer.ctypes.data
|
||||
ctypes.memmove(dest, src, layer.nbytes)
|
||||
|
||||
return image
|
||||
|
||||
def _validate_compression_params(img_array, cparams):
|
||||
"""Check that the compression parameters are valid.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
img_array : ndarray
|
||||
Image data to be written to file.
|
||||
cparams : CompressionParametersType(ctypes.Structure)
|
||||
Corresponds to cparameters_t type in openjp2 headers.
|
||||
"""
|
||||
|
||||
# Code block size
|
||||
code_block_specified = False
|
||||
if cparams.cblockw_init != 0 and cparams.cblockh_init != 0:
|
||||
# These fields ARE zero if uninitialized.
|
||||
width = cparams.cblockw_init
|
||||
height = cparams.cblockh_init
|
||||
code_block_specified = True
|
||||
if height * width > 4096 or height < 4 or width < 4:
|
||||
msg = "Code block area cannot exceed 4096. "
|
||||
msg += "Code block height and width must be larger than 4."
|
||||
raise IOError(msg)
|
||||
if ((math.log(height, 2) != math.floor(math.log(height, 2)) or
|
||||
math.log(width, 2) != math.floor(math.log(width, 2)))):
|
||||
msg = "Bad code block size ({0}, {1}), "
|
||||
msg += "must be powers of 2."
|
||||
raise IOError(msg.format(height, width))
|
||||
|
||||
# Precinct size
|
||||
if cparams.res_spec != 0:
|
||||
# precinct size was not specified if this field is zero.
|
||||
for j in range(cparams.res_spec):
|
||||
prch = cparams.prch_init[j]
|
||||
prcw = cparams.prcw_init[j]
|
||||
if j == 0 and code_block_specified:
|
||||
height, width = cparams.cblockh_init, cparams.cblockw_init
|
||||
if height * 2 > prch or width * 2 > prcw:
|
||||
msg = "Highest Resolution precinct size must be at "
|
||||
msg += "least twice that of the code block dimensions."
|
||||
raise IOError(msg)
|
||||
if ((math.log(prch, 2) != math.floor(math.log(prch, 2)) or
|
||||
math.log(prcw, 2) != math.floor(math.log(prcw, 2)))):
|
||||
msg = "Bad precinct sizes ({0}, {1}), "
|
||||
msg += "must be powers of 2."
|
||||
raise IOError(msg.format(prch, prcw))
|
||||
|
||||
# What would the point of 1D images be?
|
||||
if img_array.ndim == 1 or img_array.ndim > 3:
|
||||
msg = "{0}D imagery is not allowed.".format(img_array.ndim)
|
||||
raise IOError(msg)
|
||||
|
||||
if _OPENJP2_IS_OFFICIAL_V2:
|
||||
if (((img_array.ndim != 2) and
|
||||
(img_array.shape[2] != 1 and img_array.shape[2] != 3))):
|
||||
msg = "Writing images is restricted to single-channel "
|
||||
msg += "greyscale images or three-channel RGB images when "
|
||||
msg += "the OpenJPEG library version is the official 2.0.0 "
|
||||
msg += "release."
|
||||
raise IOError(msg)
|
||||
|
||||
if img_array.dtype != np.uint8 and img_array.dtype != np.uint16:
|
||||
msg = "Only uint8 and uint16 images are currently supported."
|
||||
raise RuntimeError(msg)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Wraps individual functions in openjp2 library.
|
||||
"""
|
||||
|
||||
# pylint: disable=C0302,R0903
|
||||
# pylint: disable=C0302,R0903,W0201
|
||||
|
||||
import ctypes
|
||||
import sys
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue