merge branch 'devel' of github.com:quintusdias/glymur into devel
This commit is contained in:
commit
39cc8a845a
15 changed files with 302 additions and 278 deletions
|
|
@ -11,6 +11,7 @@ import warnings
|
|||
|
||||
import lxml.etree as ET
|
||||
|
||||
|
||||
def xml(raw_data):
|
||||
"""
|
||||
XMP data to be parsed as XML.
|
||||
|
|
@ -23,6 +24,7 @@ def xml(raw_data):
|
|||
|
||||
return ET.ElementTree(elt)
|
||||
|
||||
|
||||
def tiff_header(read_buffer):
|
||||
"""
|
||||
Interpret the uuid raw data as a tiff header.
|
||||
|
|
@ -37,8 +39,8 @@ def tiff_header(read_buffer):
|
|||
# big endian
|
||||
endian = '>'
|
||||
else:
|
||||
msg = "The byte order indication in the TIFF header ({0}) is invalid. "
|
||||
msg += "It should be either {1} or {2}."
|
||||
msg = "The byte order indication in the TIFF header ({0}) is "
|
||||
msg += "invalid. It should be either {1} or {2}."
|
||||
msg = msg.format(read_buffer[6:8], bytes([73, 73]), bytes([77, 77]))
|
||||
raise IOError(msg)
|
||||
|
||||
|
|
@ -503,6 +505,3 @@ class _ExifInteroperabilityIfd(_Ifd):
|
|||
def __init__(self, endian, read_buffer, offset):
|
||||
_Ifd.__init__(self, endian, read_buffer, offset)
|
||||
self.post_process(self.tagnum2name)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -24,11 +24,10 @@ import warnings
|
|||
|
||||
import numpy as np
|
||||
|
||||
from .core import (
|
||||
LRCP, RLCP, RPCL, PCRL, CPRL,
|
||||
WAVELET_XFORM_9X7_IRREVERSIBLE, WAVELET_XFORM_5X3_REVERSIBLE,
|
||||
_Keydefaultdict
|
||||
)
|
||||
from .core import (LRCP, RLCP, RPCL, PCRL, CPRL,
|
||||
WAVELET_XFORM_9X7_IRREVERSIBLE,
|
||||
WAVELET_XFORM_5X3_REVERSIBLE,
|
||||
_Keydefaultdict)
|
||||
from .lib import openjp2 as opj2
|
||||
|
||||
_factory = lambda x: '{0} (invalid)'.format(x)
|
||||
|
|
@ -57,7 +56,7 @@ _CAPABILITIES_DISPLAY = _Keydefaultdict(_factory,
|
|||
_PROFILE_0: '0',
|
||||
_PROFILE_1: '1',
|
||||
_PROFILE_3: 'Cinema 2K',
|
||||
_PROFILE_4: 'Cinema 4K'} )
|
||||
_PROFILE_4: 'Cinema 4K'})
|
||||
|
||||
# Need a catch-all list of valid markers.
|
||||
# See table A-1 in ISO/IEC FCD15444-1.
|
||||
|
|
@ -703,7 +702,6 @@ class Codestream(object):
|
|||
msg = "Invalid number of tiles ({0}).".format(numtiles)
|
||||
warnings.warn(msg)
|
||||
|
||||
|
||||
kwargs = {'rsiz': rsiz,
|
||||
'xysiz': xysiz,
|
||||
'xyosiz': xyosiz,
|
||||
|
|
@ -1614,6 +1612,7 @@ class SOCsegment(Segment):
|
|||
msg = "glymur.codestream.SOCsegment()"
|
||||
return msg
|
||||
|
||||
|
||||
class SODsegment(Segment):
|
||||
"""Container for Start of Data (SOD) segment information.
|
||||
|
||||
|
|
|
|||
|
|
@ -8,28 +8,29 @@ import warnings
|
|||
|
||||
from . import Jp2k, set_printoptions, lib
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Entry point for console script jp2dump.
|
||||
"""
|
||||
|
||||
description='Print JPEG2000 metadata.'
|
||||
description = 'Print JPEG2000 metadata.'
|
||||
parser = argparse.ArgumentParser(description=description)
|
||||
|
||||
parser.add_argument('-x', '--noxml',
|
||||
help='Suppress XML.',
|
||||
action='store_true')
|
||||
help='Suppress XML.',
|
||||
action='store_true')
|
||||
parser.add_argument('-s', '--short',
|
||||
help='Only print box id, offset, and length.',
|
||||
action='store_true')
|
||||
help='Only print box id, offset, and length.',
|
||||
action='store_true')
|
||||
|
||||
chelp = 'Level of codestream information. 0 suppressed all details, '
|
||||
chelp += '1 prints headers, 2 prints the full codestream'
|
||||
parser.add_argument('-c', '--codestream',
|
||||
help=chelp,
|
||||
nargs=1,
|
||||
type=int,
|
||||
default=[0])
|
||||
help=chelp,
|
||||
nargs=1,
|
||||
type=int,
|
||||
default=[0])
|
||||
|
||||
parser.add_argument('filename')
|
||||
|
||||
|
|
@ -38,7 +39,7 @@ def main():
|
|||
set_printoptions(xml=False)
|
||||
if args.short:
|
||||
set_printoptions(short=True)
|
||||
|
||||
|
||||
codestream_level = args.codestream[0]
|
||||
if codestream_level not in [0, 1, 2]:
|
||||
raise ValueError("Invalid level of codestream information specified.")
|
||||
|
|
@ -50,15 +51,16 @@ def main():
|
|||
print_full_codestream = False
|
||||
else:
|
||||
print_full_codestream = True
|
||||
|
||||
|
||||
filename = args.filename
|
||||
|
||||
|
||||
with warnings.catch_warnings(record=True) as wctx:
|
||||
|
||||
# JP2 metadata can be extensive, so don't print any warnings until we
|
||||
# are done with the metadata.
|
||||
jp2 = Jp2k(filename)
|
||||
if jp2._codec_format == lib.openjp2.CODEC_J2K and codestream_level == 0:
|
||||
if (((jp2._codec_format == lib.openjp2.CODEC_J2K) and
|
||||
(codestream_level == 0))):
|
||||
print('File: {0}'.format(os.path.basename(filename)))
|
||||
elif print_full_codestream:
|
||||
print(jp2.get_codestream(header_only=False))
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import collections
|
|||
import copy
|
||||
import lxml.etree as ET
|
||||
|
||||
|
||||
class _Keydefaultdict(collections.defaultdict):
|
||||
"""Unlisted keys help form their own error message.
|
||||
|
||||
|
|
@ -121,12 +122,12 @@ ROMM_RGB = 21
|
|||
|
||||
_factory = lambda x: '{0} (unrecognized)'.format(x)
|
||||
_COLORSPACE_MAP_DISPLAY = _Keydefaultdict(_factory,
|
||||
{ CMYK: 'CMYK',
|
||||
SRGB: 'sRGB',
|
||||
GREYSCALE: 'greyscale',
|
||||
YCC: 'YCC',
|
||||
E_SRGB: 'e-sRGB',
|
||||
ROMM_RGB: 'ROMM-RGB'} )
|
||||
{CMYK: 'CMYK',
|
||||
SRGB: 'sRGB',
|
||||
GREYSCALE: 'greyscale',
|
||||
YCC: 'YCC',
|
||||
E_SRGB: 'e-sRGB',
|
||||
ROMM_RGB: 'ROMM-RGB'})
|
||||
|
||||
# enumerated color channel types
|
||||
COLOR = 0
|
||||
|
|
@ -134,11 +135,11 @@ OPACITY = 1
|
|||
PRE_MULTIPLIED_OPACITY = 2
|
||||
_UNSPECIFIED = 65535
|
||||
_factory = lambda x: '{0} (invalid)'.format(x)
|
||||
_COLOR_TYPE_MAP_DISPLAY = _Keydefaultdict(_factory,
|
||||
{ COLOR: 'color',
|
||||
OPACITY: 'opacity',
|
||||
PRE_MULTIPLIED_OPACITY: 'pre-multiplied opacity',
|
||||
_UNSPECIFIED: 'unspecified'})
|
||||
_dict = {COLOR: 'color',
|
||||
OPACITY: 'opacity',
|
||||
PRE_MULTIPLIED_OPACITY: 'pre-multiplied opacity',
|
||||
_UNSPECIFIED: 'unspecified'}
|
||||
_COLOR_TYPE_MAP_DISPLAY = _Keydefaultdict(_factory, _dict)
|
||||
|
||||
# color channel definitions.
|
||||
RED = 1
|
||||
|
|
@ -153,4 +154,3 @@ _COLORSPACE = {SRGB: {"R": 1, "G": 2, "B": 3},
|
|||
YCC: {"Y": 1, "Cb": 2, "Cr": 3},
|
||||
E_SRGB: {"R": 1, "G": 2, "B": 3},
|
||||
ROMM_RGB: {"R": 1, "G": 2, "B": 3}}
|
||||
|
||||
|
|
|
|||
119
glymur/jp2box.py
119
glymur/jp2box.py
|
|
@ -29,13 +29,11 @@ import lxml.etree as ET
|
|||
import numpy as np
|
||||
|
||||
from .codestream import Codestream
|
||||
from .core import (
|
||||
_COLORSPACE_MAP_DISPLAY, _COLOR_TYPE_MAP_DISPLAY,
|
||||
SRGB, GREYSCALE, YCC,
|
||||
ENUMERATED_COLORSPACE, RESTRICTED_ICC_PROFILE,
|
||||
ANY_ICC_PROFILE, VENDOR_COLOR_METHOD,
|
||||
_Keydefaultdict
|
||||
)
|
||||
from .core import (_COLORSPACE_MAP_DISPLAY, _COLOR_TYPE_MAP_DISPLAY,
|
||||
SRGB, GREYSCALE, YCC,
|
||||
ENUMERATED_COLORSPACE, RESTRICTED_ICC_PROFILE,
|
||||
ANY_ICC_PROFILE, VENDOR_COLOR_METHOD,
|
||||
_Keydefaultdict)
|
||||
|
||||
from . import _uuid_io
|
||||
|
||||
|
|
@ -52,6 +50,7 @@ _APPROX_DISPLAY = _Keydefaultdict(_factory,
|
|||
3: 'approximates correct colorspace definition, reasonable quality',
|
||||
4: 'approximates correct colorspace definition, poor quality'})
|
||||
|
||||
|
||||
class Jp2kBox(object):
|
||||
"""Superclass for JPEG 2000 boxes.
|
||||
|
||||
|
|
@ -109,7 +108,6 @@ class Jp2kBox(object):
|
|||
msg += '\n' + self._indent(boxstr)
|
||||
return msg
|
||||
|
||||
|
||||
def _indent(self, textstr, indent_level=4):
|
||||
"""
|
||||
Indent a string.
|
||||
|
|
@ -135,7 +133,6 @@ class Jp2kBox(object):
|
|||
lst = [(' ' * indent_level + x) for x in textstr.split('\n')]
|
||||
return '\n'.join(lst)
|
||||
|
||||
|
||||
def _write_superbox(self, fptr, box_id):
|
||||
"""Write a superbox.
|
||||
|
||||
|
|
@ -191,13 +188,14 @@ class Jp2kBox(object):
|
|||
try:
|
||||
box = parser(fptr, start, num_bytes)
|
||||
except ValueError as err:
|
||||
msg = "Encountered an unrecoverable ValueError while parsing a {0} "
|
||||
msg += "box at byte offset {1}. The original error message was "
|
||||
msg += "\"{2}\""
|
||||
msg = "Encountered an unrecoverable ValueError while parsing a "
|
||||
msg += "{0} box at byte offset {1}. The original error message "
|
||||
msg += "was \"{2}\""
|
||||
msg = msg.format(_BOX_WITH_ID[box_id].longname, start, str(err))
|
||||
warnings.warn(msg, UserWarning)
|
||||
box = UnknownBox(box_id.decode('utf-8'),
|
||||
length=num_bytes, offset=start, longname='Unknown')
|
||||
length=num_bytes,
|
||||
offset=start, longname='Unknown')
|
||||
|
||||
return box
|
||||
|
||||
|
|
@ -299,6 +297,7 @@ class ColourSpecificationBox(Jp2kBox):
|
|||
"""
|
||||
longname = 'Colour Specification'
|
||||
box_id = 'colr'
|
||||
|
||||
def __init__(self, method=ENUMERATED_COLORSPACE, precedence=0,
|
||||
approximation=0, colorspace=None, icc_profile=None,
|
||||
length=0, offset=-1):
|
||||
|
|
@ -337,16 +336,16 @@ class ColourSpecificationBox(Jp2kBox):
|
|||
|
||||
if self.icc_profile is None:
|
||||
if self.colorspace not in [SRGB, GREYSCALE, YCC]:
|
||||
msg = "Colorspace should correspond to one of SRGB, GREYSCALE, "
|
||||
msg += "or YCC."
|
||||
msg = "Colorspace should correspond to one of SRGB, "
|
||||
msg += "GREYSCALE, or YCC."
|
||||
self._dispatch_validation_error(msg, writing=True)
|
||||
|
||||
self._validate(writing=True)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
msg = "glymur.jp2box.ColourSpecificationBox("
|
||||
msg += "method={0}, precedence={1}, approximation={2}, colorspace={3}, "
|
||||
msg += "method={0}, precedence={1}, approximation={2}, "
|
||||
msg += "colorspace={3}, "
|
||||
msg += "icc_profile={4})"
|
||||
msg = msg.format(self.method,
|
||||
self.precedence,
|
||||
|
|
@ -357,7 +356,7 @@ class ColourSpecificationBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
msg += '\n Method: {0}'.format(_METHOD_DISPLAY[self.method])
|
||||
|
|
@ -619,10 +618,9 @@ class ChannelDefinitionBox(Jp2kBox):
|
|||
msg += " 65535 - unspecified"
|
||||
self._dispatch_validation_error(msg, writing=writing)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
for j in range(len(self.association)):
|
||||
|
|
@ -842,7 +840,7 @@ class CompositingLayerHeaderBox(Jp2kBox):
|
|||
List of boxes contained in this superbox.
|
||||
"""
|
||||
box_id = 'jplh'
|
||||
longname='Compositing Layer Header'
|
||||
longname = 'Compositing Layer Header'
|
||||
|
||||
def __init__(self, box=None, length=0, offset=-1):
|
||||
Jp2kBox.__init__(self)
|
||||
|
|
@ -931,7 +929,7 @@ class ComponentMappingBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
for k in range(len(self.component_index)):
|
||||
|
|
@ -1027,7 +1025,9 @@ class ContiguousCodestreamBox(Jp2kBox):
|
|||
if self._filename is not None:
|
||||
with open(self._filename, 'rb') as fptr:
|
||||
fptr.seek(self.main_header_offset)
|
||||
main_header = Codestream(fptr, self._length, header_only=True)
|
||||
main_header = Codestream(fptr,
|
||||
self._length,
|
||||
header_only=True)
|
||||
self._main_header = main_header
|
||||
return self._main_header
|
||||
|
||||
|
|
@ -1037,9 +1037,9 @@ class ContiguousCodestreamBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
if _printoptions['codestream'] == False:
|
||||
if _printoptions['codestream'] is False:
|
||||
return msg
|
||||
|
||||
msg += '\n Main header:'
|
||||
|
|
@ -1118,7 +1118,8 @@ class DataReferenceBox(Jp2kBox):
|
|||
"""Verify that the box obeys the specifications for writing.
|
||||
"""
|
||||
if len(self.DR) == 0:
|
||||
msg = "A data reference box cannot be empty when written to a file."
|
||||
msg = "A data reference box cannot be empty when written to a "
|
||||
msg += "file."
|
||||
self._dispatch_validation_error(msg, writing=True)
|
||||
self._validate(writing=True)
|
||||
|
||||
|
|
@ -1145,7 +1146,7 @@ class DataReferenceBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
for box in self.DR:
|
||||
|
|
@ -1248,7 +1249,7 @@ class FileTypeBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
lst = [msg,
|
||||
|
|
@ -1311,7 +1312,7 @@ class FileTypeBox(Jp2kBox):
|
|||
brand = brand.decode('utf-8')
|
||||
|
||||
# Extract the compatibility list. Each entry has 4 bytes.
|
||||
num_entries = int((length - 16)/ 4)
|
||||
num_entries = int((length - 16) / 4)
|
||||
compatibility_list = []
|
||||
for j in range(int(num_entries)):
|
||||
entry, = struct.unpack_from('>4s', read_buffer, 8 + j * 4)
|
||||
|
|
@ -1374,7 +1375,7 @@ class FragmentListBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
for j in range(len(self.fragment_offset)):
|
||||
|
|
@ -1458,7 +1459,10 @@ class FragmentTableBox(Jp2kBox):
|
|||
|
||||
def __repr__(self):
|
||||
msg = "glymur.jp2box.FragmentTableBox(box={0})"
|
||||
msg = msg.format(None) if (len(self.box) == 0) else msg.format(self.box)
|
||||
if len(self.box) == 0:
|
||||
msg = msg.format(None)
|
||||
else:
|
||||
msg = msg.format(self.box)
|
||||
return msg
|
||||
|
||||
def __str__(self):
|
||||
|
|
@ -1505,7 +1509,6 @@ class FragmentTableBox(Jp2kBox):
|
|||
self._write_superbox(fptr, b'ftbl')
|
||||
|
||||
|
||||
|
||||
class FreeBox(Jp2kBox):
|
||||
"""Container for JPX free box information.
|
||||
|
||||
|
|
@ -1534,7 +1537,7 @@ class FreeBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
return msg
|
||||
|
|
@ -1630,7 +1633,7 @@ class ImageHeaderBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
msg = "{0}"
|
||||
|
|
@ -1861,7 +1864,7 @@ class JPEG2000SignatureBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
msg += '\n Signature: {0:02x}{1:02x}{2:02x}{3:02x}'
|
||||
|
|
@ -1950,7 +1953,7 @@ class PaletteBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
msg += '\n Size: ({0} x {1})'.format(*self.palette.shape)
|
||||
|
|
@ -2203,7 +2206,7 @@ class ReaderRequirementsBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
msg += '\n Fully Understands Aspect Mask: 0x{0:x}'.format(self.fuam)
|
||||
|
|
@ -2262,7 +2265,8 @@ class ReaderRequirementsBox(Jp2kBox):
|
|||
standard_flag, standard_mask = data
|
||||
|
||||
nflags = len(standard_flag)
|
||||
vendor_offset = 1 + 2 * mask_length + 2 + (2 + mask_length) * nflags
|
||||
vendor_offset = 1 + 2 * mask_length + 2 \
|
||||
+ (2 + mask_length) * nflags
|
||||
data = _parse_vendor_features(read_buffer[vendor_offset:],
|
||||
mask_length)
|
||||
vendor_feature, vendor_mask = data
|
||||
|
|
@ -2348,14 +2352,11 @@ def _parse_standard_flag(read_buffer, mask_length):
|
|||
# from the buffer read from file.
|
||||
mask_format = {1: 'B', 2: 'H', 4: 'I'}[mask_length]
|
||||
|
||||
#read_buffer = fptr.read(2)
|
||||
num_standard_flags, = struct.unpack_from('>H', read_buffer, offset=0)
|
||||
|
||||
# Read in standard flags and standard masks. Each standard flag should
|
||||
# be two bytes, but the standard mask flag is as long as specified by
|
||||
# the mask length.
|
||||
#read_buffer = fptr.read(num_standard_flags * (2 + mask_length))
|
||||
|
||||
fmt = '>' + ('H' + mask_format) * num_standard_flags
|
||||
data = struct.unpack_from(fmt, read_buffer, offset=2)
|
||||
|
||||
|
|
@ -2386,7 +2387,6 @@ def _parse_vendor_features(read_buffer, mask_length):
|
|||
# Each vendor feature consists of a 16-byte UUID plus a mask whose
|
||||
# length is specified by, you guessed it, "mask_length".
|
||||
entry_length = 16 + mask_length
|
||||
#read_buffer = fptr.read(num_vendor_features * entry_length)
|
||||
vendor_feature = []
|
||||
vendor_mask = []
|
||||
for j in range(num_vendor_features):
|
||||
|
|
@ -2494,7 +2494,7 @@ class CaptureResolutionBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
msg += '\n VCR: {0}'.format(self.vertical_resolution)
|
||||
|
|
@ -2560,7 +2560,7 @@ class DisplayResolutionBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
msg += '\n VDR: {0}'.format(self.vertical_resolution)
|
||||
|
|
@ -2620,7 +2620,7 @@ class LabelBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
msg += '\n Label: {0}'.format(self.label)
|
||||
|
|
@ -2688,7 +2688,7 @@ class NumberListBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
for j, association in enumerate(self.associations):
|
||||
|
|
@ -2738,7 +2738,8 @@ class NumberListBox(Jp2kBox):
|
|||
def write(self, fptr):
|
||||
"""Write a NumberList box to file.
|
||||
"""
|
||||
fptr.write(struct.pack('>I4s', len(self.associations) * 4 + 8, b'nlst'))
|
||||
fptr.write(struct.pack('>I4s',
|
||||
len(self.associations) * 4 + 8, b'nlst'))
|
||||
|
||||
fmt = '>' + 'I' * len(self.associations)
|
||||
write_buffer = struct.pack(fmt, *self.associations)
|
||||
|
|
@ -2790,9 +2791,9 @@ class XMLBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
if _printoptions['xml'] == False:
|
||||
if _printoptions['xml'] is False:
|
||||
return msg
|
||||
|
||||
msg += '\n'
|
||||
|
|
@ -2911,7 +2912,7 @@ class UUIDListBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
for j, uuid_item in enumerate(self.ulst):
|
||||
|
|
@ -2942,7 +2943,7 @@ class UUIDListBox(Jp2kBox):
|
|||
|
||||
ulst = []
|
||||
for j in range(num_uuids):
|
||||
uuid_buffer = read_buffer[2 + j * 16 : 2 + (j + 1) * 16]
|
||||
uuid_buffer = read_buffer[2 + j * 16:2 + (j + 1) * 16]
|
||||
ulst.append(uuid.UUID(bytes=uuid_buffer))
|
||||
|
||||
return cls(ulst, length=length, offset=offset)
|
||||
|
|
@ -3056,7 +3057,6 @@ class DataEntryURLBox(Jp2kBox):
|
|||
fptr.write(write_buffer)
|
||||
fptr.write(url)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
msg = "glymur.jp2box.DataEntryURLBox({0}, {1}, '{2}')"
|
||||
msg = msg.format(self.version, self.flag, self.url)
|
||||
|
|
@ -3064,7 +3064,7 @@ class DataEntryURLBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
msg += '\n '
|
||||
|
|
@ -3216,7 +3216,7 @@ class UUIDBox(Jp2kBox):
|
|||
|
||||
def __str__(self):
|
||||
msg = Jp2kBox.__str__(self)
|
||||
if _printoptions['short'] == True:
|
||||
if _printoptions['short'] is True:
|
||||
return msg
|
||||
|
||||
msg = '{0}\n UUID: {1}'.format(msg, self.uuid)
|
||||
|
|
@ -3227,7 +3227,7 @@ class UUIDBox(Jp2kBox):
|
|||
else:
|
||||
msg += ' (unknown)'
|
||||
|
||||
if (((_printoptions['xml'] == False) and
|
||||
if (((_printoptions['xml'] is False) and
|
||||
(self.uuid == uuid.UUID('be7acfcb-97a9-42e8-9c71-999491e3afac')))):
|
||||
# If it's an XMP UUID, don't print the XML contents.
|
||||
return msg
|
||||
|
|
@ -3312,6 +3312,7 @@ _BOX_WITH_ID = {
|
|||
|
||||
_parseoptions = {'codestream': True}
|
||||
|
||||
|
||||
def set_parseoptions(codestream=True):
|
||||
"""Set parsing options.
|
||||
|
||||
|
|
@ -3336,6 +3337,7 @@ def set_parseoptions(codestream=True):
|
|||
"""
|
||||
_parseoptions['codestream'] = codestream
|
||||
|
||||
|
||||
def get_parseoptions():
|
||||
"""Return the current parsing options.
|
||||
|
||||
|
|
@ -3356,6 +3358,7 @@ def get_parseoptions():
|
|||
|
||||
_printoptions = {'short': False, 'xml': True, 'codestream': True}
|
||||
|
||||
|
||||
def set_printoptions(**kwargs):
|
||||
"""Set printing options.
|
||||
|
||||
|
|
@ -3365,7 +3368,8 @@ def set_printoptions(**kwargs):
|
|||
----------
|
||||
short : bool, optional
|
||||
When True, only the box ID, offset, and length are displayed. Useful
|
||||
for displaying only the basic structure or skeleton of a JPEG 2000 file.
|
||||
for displaying only the basic structure or skeleton of a JPEG 2000
|
||||
file.
|
||||
xml : bool, optional
|
||||
When False, printing of the XML contents of any XML boxes or UUID XMP
|
||||
boxes is suppressed.
|
||||
|
|
@ -3388,6 +3392,7 @@ def set_printoptions(**kwargs):
|
|||
raise TypeError('"{0}" not a valid keyword parameter.'.format(key))
|
||||
_printoptions[key] = value
|
||||
|
||||
|
||||
def get_printoptions():
|
||||
"""Return the current print options.
|
||||
|
||||
|
|
@ -3407,5 +3412,3 @@ def get_printoptions():
|
|||
set_printoptions
|
||||
"""
|
||||
return _printoptions
|
||||
|
||||
|
||||
|
|
|
|||
154
glymur/jp2k.py
154
glymur/jp2k.py
|
|
@ -31,12 +31,12 @@ import numpy as np
|
|||
|
||||
from .codestream import Codestream
|
||||
from . import core, version
|
||||
from .jp2box import (
|
||||
Jp2kBox, JPEG2000SignatureBox, FileTypeBox, JP2HeaderBox,
|
||||
ColourSpecificationBox, ContiguousCodestreamBox, ImageHeaderBox
|
||||
)
|
||||
from .jp2box import (Jp2kBox, JPEG2000SignatureBox, FileTypeBox,
|
||||
JP2HeaderBox, ColourSpecificationBox,
|
||||
ContiguousCodestreamBox, ImageHeaderBox)
|
||||
from .lib import openjpeg as opj, openjp2 as opj2, c as libc
|
||||
|
||||
|
||||
class Jp2k(Jp2kBox):
|
||||
"""JPEG 2000 file.
|
||||
|
||||
|
|
@ -138,7 +138,6 @@ class Jp2k(Jp2kBox):
|
|||
not (X, Y)
|
||||
verbose : bool, optional
|
||||
print informational messages produced by the OpenJPEG library
|
||||
|
||||
"""
|
||||
Jp2kBox.__init__(self)
|
||||
self.filename = filename
|
||||
|
|
@ -176,8 +175,8 @@ class Jp2k(Jp2kBox):
|
|||
@layer.setter
|
||||
def layer(self, layer):
|
||||
if version.openjpeg_version_tuple[0] < 2:
|
||||
msg = "Layer property not supported unless the version of OpenJPEG "
|
||||
msg += "is 2.0 or higher."
|
||||
msg = "Layer property not supported unless the version of "
|
||||
msg += "OpenJPEG is 2.0 or higher."
|
||||
raise RuntimeError(msg)
|
||||
self._layer = layer
|
||||
|
||||
|
|
@ -361,8 +360,8 @@ class Jp2k(Jp2kBox):
|
|||
kwargs : dictionary
|
||||
non-image keyword inputs provided to write method
|
||||
"""
|
||||
if (('cinema2k' in kwargs or 'cinema4k' in kwargs) and
|
||||
(len(set(kwargs)) > 1)):
|
||||
if ((('cinema2k' in kwargs or 'cinema4k' in kwargs) and
|
||||
(len(set(kwargs)) > 1))):
|
||||
msg = "Cannot specify cinema2k/cinema4k along with other options."
|
||||
raise IOError(msg)
|
||||
|
||||
|
|
@ -484,9 +483,10 @@ class Jp2k(Jp2kBox):
|
|||
This method can only be used to create JPEG 2000 images that can fit
|
||||
in memory.
|
||||
"""
|
||||
if re.match("1.[0-4]", version.openjpeg_version) is not None:
|
||||
raise RuntimeError("You must have at least version 1.5 of OpenJPEG "
|
||||
"in order to write images.")
|
||||
if re.match("0|1.[0-4]", version.openjpeg_version) is not None:
|
||||
msg = "You must have at least version 1.5 of OpenJPEG "
|
||||
msg += "in order to write images."
|
||||
raise RuntimeError(msg)
|
||||
|
||||
self._determine_colorspace(**kwargs)
|
||||
self._populate_cparams(img_array, **kwargs)
|
||||
|
|
@ -518,9 +518,11 @@ class Jp2k(Jp2kBox):
|
|||
image.contents.x0 = self._cparams.image_offset_x0
|
||||
image.contents.y0 = self._cparams.image_offset_y0
|
||||
image.contents.x1 = image.contents.x0 \
|
||||
+ (numcols - 1) * self._cparams.subsampling_dx + 1
|
||||
+ (numcols - 1) * self._cparams.subsampling_dx \
|
||||
+ 1
|
||||
image.contents.y1 = image.contents.y0 \
|
||||
+ (numrows - 1) * self._cparams.subsampling_dy + 1
|
||||
+ (numrows - 1) * self._cparams.subsampling_dy \
|
||||
+ 1
|
||||
|
||||
# Stage the image data to the openjpeg data structure.
|
||||
for k in range(0, numlayers):
|
||||
|
|
@ -633,7 +635,7 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
def _determine_colorspace(self, colorspace=None, **kwargs):
|
||||
"""Determine the colorspace from the supplied inputs.
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
colorspace : str, optional
|
||||
|
|
@ -658,7 +660,7 @@ class Jp2k(Jp2kBox):
|
|||
elif colorspace.lower() == 'rgb' and self.shape[2] < 3:
|
||||
msg = 'RGB colorspace requires at least 3 components.'
|
||||
raise IOError(msg)
|
||||
|
||||
|
||||
# Turn the colorspace from a string to the enumerated value that
|
||||
# the library expects.
|
||||
COLORSPACE_MAP = {'rgb': opj2.CLRSPC_SRGB,
|
||||
|
|
@ -667,8 +669,7 @@ class Jp2k(Jp2kBox):
|
|||
'ycc': opj2.CLRSPC_YCC}
|
||||
|
||||
self._colorspace = COLORSPACE_MAP[colorspace.lower()]
|
||||
|
||||
|
||||
|
||||
def _write_openjp2(self, img_array, verbose=False):
|
||||
"""
|
||||
Write JPEG 2000 file using OpenJPEG 2.x interface.
|
||||
|
|
@ -734,7 +735,8 @@ class Jp2k(Jp2kBox):
|
|||
if not ((box.box_id == 'xml ') or
|
||||
(box.box_id == 'uuid' and
|
||||
box.uuid == UUID('be7acfcb-97a9-42e8-9c71-999491e3afac'))):
|
||||
msg = "Only XML boxes and XMP UUID boxes can currently be appended."
|
||||
msg = "Only XML boxes and XMP UUID boxes can currently be "
|
||||
msg += "appended."
|
||||
raise IOError(msg)
|
||||
|
||||
# Check the last box. If the length field is zero, then rewrite
|
||||
|
|
@ -891,9 +893,9 @@ class Jp2k(Jp2kBox):
|
|||
Slicing protocol.
|
||||
"""
|
||||
if ((isinstance(index, slice) and
|
||||
(index.start == None and
|
||||
index.stop == None and
|
||||
index.step == None)) or (index is Ellipsis)):
|
||||
(index.start is None and
|
||||
index.stop is None and
|
||||
index.step is None)) or (index is Ellipsis)):
|
||||
# Case of jp2[:] = data, i.e. write the entire image.
|
||||
#
|
||||
# Should have a slice object where start = stop = step = None
|
||||
|
|
@ -923,12 +925,14 @@ class Jp2k(Jp2kBox):
|
|||
return self._read()
|
||||
|
||||
if isinstance(pargs, slice):
|
||||
if pargs.start is None and pargs.stop is None and pargs.step is None:
|
||||
if (((pargs.start is None) and
|
||||
(pargs.stop is None) and
|
||||
(pargs.step is None))):
|
||||
# Case of jp2[:]
|
||||
return self._read()
|
||||
|
||||
# Corner case of jp2[x] where x is a slice object with non-null
|
||||
# members. Just augment it with an ellipsis and let the code
|
||||
# members. Just augment it with an ellipsis and let the code
|
||||
# below handle it.
|
||||
pargs = (pargs, Ellipsis)
|
||||
|
||||
|
|
@ -971,8 +975,7 @@ class Jp2k(Jp2kBox):
|
|||
# Reduce dimensionality in the scalar dimension.
|
||||
return np.squeeze(data, axis=idx)
|
||||
|
||||
|
||||
# Assuming pargs is a tuple of slices from now on.
|
||||
# Assuming pargs is a tuple of slices from now on.
|
||||
rows = pargs[0]
|
||||
cols = pargs[1]
|
||||
if len(pargs) == 2:
|
||||
|
|
@ -989,15 +992,14 @@ class Jp2k(Jp2kBox):
|
|||
# Ok, reduce layer step is the same in both xy directions, so just take
|
||||
# one of them.
|
||||
step = rows_step
|
||||
|
||||
|
||||
# Check if the step size is a power of 2.
|
||||
if np.abs(np.log2(step) - np.round(np.log2(step))) > 1e-6:
|
||||
msg = "Row and column strides must be powers of 2."
|
||||
raise IndexError(msg)
|
||||
rlevel = np.int(np.round(np.log2(step)))
|
||||
|
||||
area = (
|
||||
0 if rows.start is None else rows.start,
|
||||
area = (0 if rows.start is None else rows.start,
|
||||
0 if cols.start is None else cols.start,
|
||||
numrows if rows.stop is None else rows.stop,
|
||||
numcols if cols.stop is None else cols.stop
|
||||
|
|
@ -1009,7 +1011,6 @@ class Jp2k(Jp2kBox):
|
|||
# Ok, 3 arguments in pargs.
|
||||
return data[:, :, bands]
|
||||
|
||||
|
||||
def _read(self, **kwargs):
|
||||
"""Read a JPEG 2000 image.
|
||||
|
||||
|
|
@ -1032,34 +1033,34 @@ class Jp2k(Jp2kBox):
|
|||
def read(self, **kwargs):
|
||||
"""
|
||||
"""
|
||||
#Read a JPEG 2000 image.
|
||||
# Read a JPEG 2000 image.
|
||||
#
|
||||
#Parameters
|
||||
#----------
|
||||
#rlevel : int, optional
|
||||
# Factor by which to rlevel output resolution. Use -1 to get the
|
||||
# lowest resolution thumbnail. This is the only keyword option
|
||||
# available to use when the OpenJPEG version is 1.5 or earlier.
|
||||
#layer : int, optional
|
||||
# Number of quality layer to decode.
|
||||
#area : tuple, optional
|
||||
# Specifies decoding image area,
|
||||
# (first_row, first_col, last_row, last_col)
|
||||
#tile : int, optional
|
||||
# Number of tile to decode.
|
||||
#verbose : bool, optional
|
||||
# Print informational messages produced by the OpenJPEG library.
|
||||
# Parameters
|
||||
# ----------
|
||||
# rlevel : int, optional
|
||||
# Factor by which to rlevel output resolution. Use -1 to get the
|
||||
# lowest resolution thumbnail. This is the only keyword option
|
||||
# available to use when the OpenJPEG version is 1.5 or earlier.
|
||||
# layer : int, optional
|
||||
# Number of quality layer to decode.
|
||||
# area : tuple, optional
|
||||
# Specifies decoding image area,
|
||||
# (first_row, first_col, last_row, last_col)
|
||||
# tile : int, optional
|
||||
# Number of tile to decode.
|
||||
# verbose : bool, optional
|
||||
# Print informational messages produced by the OpenJPEG library.
|
||||
#
|
||||
#Returns
|
||||
#-------
|
||||
#img_array : ndarray
|
||||
# The image data.
|
||||
# Returns
|
||||
# -------
|
||||
# img_array : ndarray
|
||||
# The image data.
|
||||
#
|
||||
#Raises
|
||||
#------
|
||||
#IOError
|
||||
# If the image has differing subsample factors.
|
||||
|
||||
# Raises
|
||||
# ------
|
||||
# IOError
|
||||
# If the image has differing subsample factors.
|
||||
|
||||
if 'ignore_pclr_cmap_cdef' in kwargs:
|
||||
self.ignore_pclr_cmap_cdef = kwargs['ignore_pclr_cmap_cdef']
|
||||
warnings.warn("Use array-style slicing instead.", DeprecationWarning)
|
||||
|
|
@ -1163,7 +1164,8 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
return data
|
||||
|
||||
def _read_openjp2(self, rlevel=0, layer=None, area=None, tile=None, verbose=False):
|
||||
def _read_openjp2(self, rlevel=0, layer=None, area=None, tile=None,
|
||||
verbose=False):
|
||||
"""Read a JPEG 2000 image using libopenjp2.
|
||||
|
||||
Parameters
|
||||
|
|
@ -1453,7 +1455,7 @@ class Jp2k(Jp2kBox):
|
|||
|
||||
def _populate_image_struct(self, image, imgdata):
|
||||
"""Populates image struct needed for compression.
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : ImageType(ctypes.Structure)
|
||||
|
|
@ -1461,9 +1463,9 @@ class Jp2k(Jp2kBox):
|
|||
img_array : ndarray
|
||||
Image data to be written to file.
|
||||
"""
|
||||
|
||||
|
||||
numrows, numcols, num_comps = imgdata.shape
|
||||
|
||||
|
||||
# set image offset and reference grid
|
||||
image.contents.x0 = self._cparams.image_offset_x0
|
||||
image.contents.y0 = self._cparams.image_offset_y0
|
||||
|
|
@ -1471,7 +1473,7 @@ class Jp2k(Jp2kBox):
|
|||
(numcols - 1) * self._cparams.subsampling_dx + 1)
|
||||
image.contents.y1 = (image.contents.y0 +
|
||||
(numrows - 1) * self._cparams.subsampling_dy + 1)
|
||||
|
||||
|
||||
# Stage the image data to the openjpeg data structure.
|
||||
for k in range(0, num_comps):
|
||||
if re.match("2.0", version.openjpeg_version) is not None:
|
||||
|
|
@ -1485,19 +1487,19 @@ class Jp2k(Jp2kBox):
|
|||
core.OPJ_PROFILE_CINEMA_4K):
|
||||
image.contents.comps[k].prec = 12
|
||||
image.contents.comps[k].bpp = 12
|
||||
|
||||
|
||||
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 _populate_comptparms(self, img_array):
|
||||
"""Instantiate and populate comptparms structure.
|
||||
|
||||
|
||||
This structure defines the image components.
|
||||
|
||||
|
||||
Parameters
|
||||
----------
|
||||
img_array : ndarray
|
||||
|
|
@ -1526,8 +1528,8 @@ class Jp2k(Jp2kBox):
|
|||
comptparms[j].sgnd = 0
|
||||
|
||||
self._comptparms = comptparms
|
||||
|
||||
|
||||
|
||||
|
||||
def _component2dtype(component):
|
||||
"""Take an OpenJPEG component structure and determine the numpy datatype.
|
||||
|
||||
|
|
@ -1573,6 +1575,7 @@ JP2_IDS = ['colr', 'cdef', 'cmap', 'jp2c', 'ftyp', 'ihdr', 'jp2h', 'jP ',
|
|||
'pclr', 'res ', 'resc', 'resd', 'xml ', 'ulst', 'uinf', 'url ',
|
||||
'uuid']
|
||||
|
||||
|
||||
def _validate_jp2_box_sequence(boxes):
|
||||
"""Run through series of tests for JP2 box legality.
|
||||
|
||||
|
|
@ -1588,12 +1591,13 @@ def _validate_jp2_box_sequence(boxes):
|
|||
count = _collect_box_count(boxes)
|
||||
for box_id in count.keys():
|
||||
if box_id not in JP2_IDS:
|
||||
msg = "The presence of a '{0}' box requires that the file type "
|
||||
msg += "brand be set to 'jpx '."
|
||||
msg = "The presence of a '{0}' box requires that the file "
|
||||
msg += "type brand be set to 'jpx '."
|
||||
raise IOError(msg.format(box_id))
|
||||
|
||||
_validate_jp2_colr(boxes)
|
||||
|
||||
|
||||
def _validate_jp2_colr(boxes):
|
||||
"""
|
||||
Validate JP2 requirements on colour specification boxes.
|
||||
|
|
@ -1605,6 +1609,7 @@ def _validate_jp2_colr(boxes):
|
|||
msg = "A JP2 colr box cannot have a non-zero approximation field."
|
||||
raise IOError(msg)
|
||||
|
||||
|
||||
def _validate_jpx_box_sequence(boxes):
|
||||
"""Run through series of tests for JPX box legality."""
|
||||
_validate_label(boxes)
|
||||
|
|
@ -1613,6 +1618,7 @@ def _validate_jpx_box_sequence(boxes):
|
|||
_validate_singletons(boxes)
|
||||
_validate_top_level(boxes)
|
||||
|
||||
|
||||
def _validate_signature_compatibility(boxes):
|
||||
"""Validate the file signature and compatibility status."""
|
||||
# Check for a bad sequence of boxes.
|
||||
|
|
@ -1700,6 +1706,8 @@ def _validate_channel_definition(jp2h, colr):
|
|||
|
||||
|
||||
JP2H_CHILDREN = set(['bpcc', 'cdef', 'cmap', 'ihdr', 'pclr'])
|
||||
|
||||
|
||||
def _check_jp2h_child_boxes(boxes, parent_box_name):
|
||||
"""Certain boxes can only reside in the JP2 header."""
|
||||
box_ids = set([box.box_id for box in boxes])
|
||||
|
|
@ -1727,6 +1735,7 @@ def _collect_box_count(boxes):
|
|||
|
||||
TOP_LEVEL_ONLY_BOXES = set(['dtbl'])
|
||||
|
||||
|
||||
def _check_superbox_for_top_levels(boxes):
|
||||
"""Several boxes can only occur at the top level."""
|
||||
# We are only looking at the boxes contained in a superbox, so if any of
|
||||
|
|
@ -1742,6 +1751,7 @@ def _check_superbox_for_top_levels(boxes):
|
|||
if hasattr(box, 'box'):
|
||||
_check_superbox_for_top_levels(box.box)
|
||||
|
||||
|
||||
def _validate_top_level(boxes):
|
||||
"""Several boxes can only occur at the top level."""
|
||||
# Add the counts in the superboxes.
|
||||
|
|
@ -1761,6 +1771,7 @@ def _validate_top_level(boxes):
|
|||
msg += 'a fragment table box as well.'
|
||||
raise IOError(msg)
|
||||
|
||||
|
||||
def _validate_singletons(boxes):
|
||||
"""Several boxes can only occur once."""
|
||||
count = _collect_box_count(boxes)
|
||||
|
|
@ -1771,6 +1782,7 @@ def _validate_singletons(boxes):
|
|||
|
||||
JPX_IDS = ['asoc', 'nlst']
|
||||
|
||||
|
||||
def _validate_jpx_brand(boxes, brand):
|
||||
"""
|
||||
If there is a JPX box then the brand must be 'jpx '.
|
||||
|
|
@ -1785,6 +1797,7 @@ def _validate_jpx_brand(boxes, brand):
|
|||
# Same set of checks on any child boxes.
|
||||
_validate_jpx_brand(box.box, brand)
|
||||
|
||||
|
||||
def _validate_jpx_compatibility(boxes, compatibility_list):
|
||||
"""
|
||||
If there is a JPX box then the compatibility list must also contain 'jpx '.
|
||||
|
|
@ -1800,6 +1813,7 @@ def _validate_jpx_compatibility(boxes, compatibility_list):
|
|||
# Same set of checks on any child boxes.
|
||||
_validate_jpx_compatibility(box.box, compatibility_list)
|
||||
|
||||
|
||||
def _validate_label(boxes):
|
||||
"""
|
||||
Label boxes can only be inside association, codestream headers, or
|
||||
|
|
@ -1816,6 +1830,7 @@ def _validate_label(boxes):
|
|||
# Same set of checks on any child boxes.
|
||||
_validate_label(box.box)
|
||||
|
||||
|
||||
def extract_image_cube(image):
|
||||
"""Extract 3D image from openjpeg data structure.
|
||||
"""
|
||||
|
|
@ -1871,7 +1886,6 @@ def extract_image_bands(image):
|
|||
return data
|
||||
|
||||
|
||||
|
||||
# Setup the default callback handlers. See the callback functions subsection
|
||||
# in the ctypes section of the Python documentation for a solid explanation of
|
||||
# what's going on here.
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ def glymur_config():
|
|||
lst.append(load_openjpeg_library(libname))
|
||||
if all(handle is None for handle in lst):
|
||||
msg = "Neither the openjp2 nor the openjpeg library could be loaded. "
|
||||
raise IOError(msg)
|
||||
warnings.warn(msg)
|
||||
return tuple(lst)
|
||||
|
||||
def get_configdir():
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ from .config import glymur_config
|
|||
|
||||
OPENJP2, OPENJPEG = glymur_config()
|
||||
|
||||
|
||||
def version():
|
||||
"""Wrapper for opj_version library routine."""
|
||||
try:
|
||||
|
|
@ -50,13 +51,6 @@ JPWL_MAX_NO_TILESPECS = 16
|
|||
TRUE = 1
|
||||
FALSE = 0
|
||||
|
||||
#PROFILE = {'none': 0, # No profile
|
||||
# 0: 1, # Profile 0
|
||||
# 1: 2, # Profile 1
|
||||
# 'part2': 0x8000, # At least one extension
|
||||
# 'Cinema2K': 0x0003, # 2K cinema profile
|
||||
# 'Cinema4K': 0x0004, # 4K cinema profile
|
||||
|
||||
# supported color spaces
|
||||
CLRSPC_UNKNOWN = -1
|
||||
CLRSPC_UNSPECIFIED = 0
|
||||
|
|
@ -548,7 +542,6 @@ class ImageType(ctypes.Structure):
|
|||
return msg
|
||||
|
||||
|
||||
|
||||
class ImageComptParmType(ctypes.Structure):
|
||||
"""Component parameters structure used by image_create function.
|
||||
|
||||
|
|
@ -958,7 +951,7 @@ def read_header(stream, codec):
|
|||
ARGTYPES = [STREAM_TYPE_P, CODEC_TYPE,
|
||||
ctypes.POINTER(ctypes.POINTER(ImageType))]
|
||||
OPENJP2.opj_read_header.argtypes = ARGTYPES
|
||||
OPENJP2.opj_read_header.restype = check_error
|
||||
OPENJP2.opj_read_header.restype = check_error
|
||||
|
||||
imagep = ctypes.POINTER(ImageType)()
|
||||
OPENJP2.opj_read_header(stream, codec, ctypes.byref(imagep))
|
||||
|
|
@ -1317,6 +1310,7 @@ def _stream_create_default_file_stream_2p0(fptr, isa_read_stream):
|
|||
stream = OPENJP2.opj_stream_create_default_file_stream(fptr, read_stream)
|
||||
return stream
|
||||
|
||||
|
||||
def _stream_create_default_file_stream_2p1(fname, isa_read_stream):
|
||||
"""Wraps openjp2 library function opj_stream_create_default_vile_stream.
|
||||
|
||||
|
|
@ -1343,7 +1337,7 @@ def _stream_create_default_file_stream_2p1(fname, isa_read_stream):
|
|||
stream = OPENJP2.opj_stream_create_default_file_stream(file_argument,
|
||||
read_stream)
|
||||
return stream
|
||||
|
||||
|
||||
if re.match(r'''2.0''', version()):
|
||||
stream_create_default_file_stream = _stream_create_default_file_stream_2p0
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -59,8 +59,10 @@ class CommonStructType(ctypes.Structure):
|
|||
("mj2_handle", ctypes.c_void_p)]
|
||||
|
||||
|
||||
STREAM_READ = 0x0001 # The stream was opened for reading.
|
||||
STREAM_WRITE = 0x0002 # The stream was opened for writing.
|
||||
STREAM_READ = 0x0001 # The stream was opened for reading.
|
||||
STREAM_WRITE = 0x0002 # The stream was opened for writing.
|
||||
|
||||
|
||||
class CioType(ctypes.Structure):
|
||||
"""Byte input-output stream (CIO)
|
||||
|
||||
|
|
@ -91,70 +93,57 @@ class CompressionInfoType(CommonStructType):
|
|||
class PocType(ctypes.Structure):
|
||||
"""Progression order changes."""
|
||||
_fields_ = [("resno", ctypes.c_int),
|
||||
# Resolution num start, Component num start, given by POC
|
||||
("compno0", ctypes.c_int),
|
||||
# Resolution num start, Component num start, given by POC
|
||||
("compno0", ctypes.c_int),
|
||||
|
||||
# Layer num end,Resolution num end, Component num end, given by POC
|
||||
("layno1", ctypes.c_int),
|
||||
("resno1", ctypes.c_int),
|
||||
("compno1", ctypes.c_int),
|
||||
# Layer num end,Resolution num end, Component num end, given
|
||||
# by POC
|
||||
("layno1", ctypes.c_int),
|
||||
("resno1", ctypes.c_int),
|
||||
("compno1", ctypes.c_int),
|
||||
|
||||
# Layer num start,Precinct num start, Precinct num end
|
||||
("layno0", ctypes.c_int),
|
||||
("precno0", ctypes.c_int),
|
||||
("precno1", ctypes.c_int),
|
||||
# Layer num start,Precinct num start, Precinct num end
|
||||
("layno0", ctypes.c_int),
|
||||
("precno0", ctypes.c_int),
|
||||
("precno1", ctypes.c_int),
|
||||
|
||||
# Progression order enum
|
||||
# OPJ_PROG_ORDER prg1,prg;
|
||||
("prg1", ctypes.c_int),
|
||||
("prg", ctypes.c_int),
|
||||
# Progression order enum
|
||||
# OPJ_PROG_ORDER prg1,prg;
|
||||
("prg1", ctypes.c_int),
|
||||
("prg", ctypes.c_int),
|
||||
|
||||
# Progression order string
|
||||
# char progorder[5];
|
||||
("progorder", ctypes.c_char * 5),
|
||||
# Progression order string
|
||||
# char progorder[5];
|
||||
("progorder", ctypes.c_char * 5),
|
||||
|
||||
# Tile number
|
||||
# int tile;
|
||||
("tile", ctypes.c_int),
|
||||
# Tile number
|
||||
# int tile;
|
||||
("tile", ctypes.c_int),
|
||||
|
||||
# /** Start and end values for Tile width and height*/
|
||||
# int tx0,tx1,ty0,ty1;
|
||||
("tx0", ctypes.c_int),
|
||||
("tx1", ctypes.c_int),
|
||||
("ty0", ctypes.c_int),
|
||||
("ty1", ctypes.c_int),
|
||||
|
||||
# /** Start value, initialised in pi_initialise_encode*/
|
||||
# int layS, resS, compS, prcS;
|
||||
("layS", ctypes.c_int),
|
||||
("resS", ctypes.c_int),
|
||||
("compS", ctypes.c_int),
|
||||
("prcS", ctypes.c_int),
|
||||
|
||||
# /** End value, initialised in pi_initialise_encode */
|
||||
# int layE, resE, compE, prcE;
|
||||
("layE", ctypes.c_int),
|
||||
("resE", ctypes.c_int),
|
||||
("compE", ctypes.c_int),
|
||||
("prcE", ctypes.c_int),
|
||||
|
||||
# Start and end values of Tile width and height, initialised in
|
||||
# pi_initialise_encode int txS,txE,tyS,tyE,dx,dy;
|
||||
("txS", ctypes.c_int),
|
||||
("txE", ctypes.c_int),
|
||||
("tyS", ctypes.c_int),
|
||||
("tyE", ctypes.c_int),
|
||||
("dx", ctypes.c_int),
|
||||
("dy", ctypes.c_int),
|
||||
|
||||
# Temporary values for Tile parts, initialised in pi_create_encode
|
||||
# int lay_t, res_t, comp_t, prc_t,tx0_t,ty0_t;
|
||||
("lay_t", ctypes.c_int),
|
||||
("res_t", ctypes.c_int),
|
||||
("comp_t", ctypes.c_int),
|
||||
("prc_t", ctypes.c_int),
|
||||
("tx0_t", ctypes.c_int),
|
||||
("ty0_t", ctypes.c_int)]
|
||||
("tx0", ctypes.c_int),
|
||||
("tx1", ctypes.c_int),
|
||||
("ty0", ctypes.c_int),
|
||||
("ty1", ctypes.c_int),
|
||||
("layS", ctypes.c_int),
|
||||
("resS", ctypes.c_int),
|
||||
("compS", ctypes.c_int),
|
||||
("prcS", ctypes.c_int),
|
||||
("layE", ctypes.c_int),
|
||||
("resE", ctypes.c_int),
|
||||
("compE", ctypes.c_int),
|
||||
("prcE", ctypes.c_int),
|
||||
("txS", ctypes.c_int),
|
||||
("txE", ctypes.c_int),
|
||||
("tyS", ctypes.c_int),
|
||||
("tyE", ctypes.c_int),
|
||||
("dx", ctypes.c_int),
|
||||
("dy", ctypes.c_int),
|
||||
("lay_t", ctypes.c_int),
|
||||
("res_t", ctypes.c_int),
|
||||
("comp_t", ctypes.c_int),
|
||||
("prc_t", ctypes.c_int),
|
||||
("tx0_t", ctypes.c_int),
|
||||
("ty0_t", ctypes.c_int)]
|
||||
|
||||
|
||||
class CompressionParametersType(ctypes.Structure):
|
||||
|
|
@ -375,48 +364,47 @@ class DecompressionParametersType(ctypes.Structure):
|
|||
class ImageComptParmType(ctypes.Structure):
|
||||
"""Component parameters structure used by the opj_image_create function.
|
||||
"""
|
||||
_fields_ = [
|
||||
# XRsiz: horizontal separation of a sample of ith component with
|
||||
# respect to the reference grid
|
||||
("dx", ctypes.c_int),
|
||||
_fields_ = [# XRsiz: horizontal separation of a sample of ith component
|
||||
# with respect to the reference grid
|
||||
("dx", ctypes.c_int),
|
||||
|
||||
# YRsiz: vertical separation of a sample of ith component with
|
||||
# respect to the reference grid */
|
||||
("dy", ctypes.c_int),
|
||||
# YRsiz: vertical separation of a sample of ith component with
|
||||
# respect to the reference grid */
|
||||
("dy", ctypes.c_int),
|
||||
|
||||
# data width, height
|
||||
("w", ctypes.c_int),
|
||||
("h", ctypes.c_int),
|
||||
# data width, height
|
||||
("w", ctypes.c_int),
|
||||
("h", ctypes.c_int),
|
||||
|
||||
# x component offset compared to the whole image
|
||||
# y component offset compared to the whole image
|
||||
("x0", ctypes.c_int),
|
||||
("y0", ctypes.c_int),
|
||||
# x component offset compared to the whole image
|
||||
# y component offset compared to the whole image
|
||||
("x0", ctypes.c_int),
|
||||
("y0", ctypes.c_int),
|
||||
|
||||
# precision
|
||||
('prec', ctypes.c_int),
|
||||
# precision
|
||||
('prec', ctypes.c_int),
|
||||
|
||||
# image depth in bits
|
||||
('bpp', ctypes.c_int),
|
||||
# image depth in bits
|
||||
('bpp', ctypes.c_int),
|
||||
|
||||
# signed (1) / unsigned (0)
|
||||
('sgnd', ctypes.c_int)]
|
||||
# signed (1) / unsigned (0)
|
||||
('sgnd', ctypes.c_int)]
|
||||
|
||||
|
||||
class ImageCompType(ctypes.Structure):
|
||||
"""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))]
|
||||
("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):
|
||||
|
|
@ -468,6 +456,7 @@ def cio_tell(cio):
|
|||
pos = OPENJPEG.cio_tell(cio)
|
||||
return pos
|
||||
|
||||
|
||||
def create_compress(fmt):
|
||||
"""Wrapper for openjpeg library function opj_create_compress.
|
||||
|
||||
|
|
@ -585,9 +574,8 @@ def image_cmptparm_t_from_np(np_image):
|
|||
def image_create(cmptparms, cspace):
|
||||
"""Wrapper for openjpeg library function opj_image_create.
|
||||
"""
|
||||
OPENJPEG.opj_image_create.argtypes = [ctypes.c_int,
|
||||
ctypes.POINTER(ImageComptParmType),
|
||||
ctypes.c_int]
|
||||
lst = [ctypes.c_int, ctypes.POINTER(ImageComptParmType), ctypes.c_int]
|
||||
OPENJPEG.opj_image_create.argtypes = lst
|
||||
OPENJPEG.opj_image_create.restype = ctypes.POINTER(ImageType)
|
||||
|
||||
image = OPENJPEG.opj_image_create(len(cmptparms), cmptparms, cspace)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import glymur
|
|||
from . import fixtures
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03000000, "do not care about 2.7 here")
|
||||
@unittest.skipIf(re.match('1|2.0', glymur.version.openjpeg_version),
|
||||
@unittest.skipIf(re.match('0|1|2.0', glymur.version.openjpeg_version),
|
||||
"Requires openjpeg 2.1.0 or higher")
|
||||
class TestPrintingOpenjp2(unittest.TestCase):
|
||||
"""Tests for verifying how printing works on openjp2 library structures."""
|
||||
|
|
|
|||
|
|
@ -13,6 +13,14 @@ import six
|
|||
|
||||
import glymur
|
||||
|
||||
# If openjpeg is not installed, many tests cannot be run.
|
||||
if glymur.version.openjpeg_version == '0.0.0':
|
||||
OPENJPEG_NOT_AVAILABLE = True
|
||||
OPENJPEG_NOT_AVAILABLE_MSG = 'OpenJPEG library not installed'
|
||||
else:
|
||||
OPENJPEG_NOT_AVAILABLE = False
|
||||
OPENJPEG_NOT_AVAILABLE_MSG = None
|
||||
|
||||
# Some versions of "six" on python3 cause problems when verifying warnings.
|
||||
# Only use when the version is 1.7 or higher.
|
||||
# And moreover, we only test using the 3.x infrastructure, never on 2.x.
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ class TestCallbacks(unittest.TestCase):
|
|||
expected = '[INFO] tile number 1 / 1'
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(glymur.version.openjpeg_version[0] == '0',
|
||||
"Missing openjpeg/openjp2 library.")
|
||||
def test_info_callbacks_on_read(self):
|
||||
"""stdio output when info callback handler is enabled"""
|
||||
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ class TestDataEntryURL(unittest.TestCase):
|
|||
self.assertEqual(url + chr(0), read_url)
|
||||
|
||||
|
||||
@unittest.skipIf(re.match(r'''(1|2.0.0)''',
|
||||
@unittest.skipIf(re.match(r'''0|1|2.0.0''',
|
||||
glymur.version.openjpeg_version) is not None,
|
||||
"Not supported until 2.1")
|
||||
@unittest.skipIf(os.name == "nt", WINDOWS_TMP_FILE_MSG)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ from glymur.version import openjpeg_version
|
|||
|
||||
from .fixtures import HAS_PYTHON_XMP_TOOLKIT
|
||||
from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG
|
||||
from .fixtures import OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG
|
||||
|
||||
if HAS_PYTHON_XMP_TOOLKIT:
|
||||
import libxmp
|
||||
|
|
@ -76,6 +77,7 @@ class SliceProtocolBase(unittest.TestCase):
|
|||
self.j2k_data_r1 = self.j2k[::2, ::2]
|
||||
self.j2k_data_r5 = self.j2k[::32, ::32]
|
||||
|
||||
@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG)
|
||||
@unittest.skipIf(re.match("1.5|2", glymur.version.openjpeg_version) is None,
|
||||
"Must have openjpeg 1.5 or higher to run")
|
||||
@unittest.skipIf(os.name == "nt", fixtures.WINDOWS_TMP_FILE_MSG)
|
||||
|
|
@ -143,6 +145,7 @@ class TestSliceProtocolBaseWrite(SliceProtocolBase):
|
|||
j[:25, :45, :] = self.j2k_data[:25, :25, :]
|
||||
|
||||
|
||||
@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG)
|
||||
class TestSliceProtocolRead(SliceProtocolBase):
|
||||
|
||||
def test_resolution_strides_cannot_differ(self):
|
||||
|
|
@ -251,6 +254,7 @@ class TestJp2k(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
pass
|
||||
|
||||
@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG)
|
||||
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
|
||||
def test_warn_if_using_read_method(self):
|
||||
"""Should warn if deprecated read method is called"""
|
||||
|
|
@ -313,6 +317,7 @@ class TestJp2k(unittest.TestCase):
|
|||
actdata = j2[:]
|
||||
self.assertTrue(fixtures.mse(actdata[0], expdata[0]) < 0.38)
|
||||
|
||||
@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG)
|
||||
@unittest.skipIf(re.match('1.[0-4]', openjpeg_version) is not None,
|
||||
"Not supported with OpenJPEG {0}".format(openjpeg_version))
|
||||
@unittest.skipIf(re.match('1.5.(1|2)', openjpeg_version) is not None,
|
||||
|
|
@ -345,6 +350,7 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(newjp2.filename, self.j2kfile)
|
||||
self.assertEqual(len(newjp2.box), 0)
|
||||
|
||||
@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG)
|
||||
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
|
||||
def test_rlevel_max_backwards_compatibility(self):
|
||||
"""
|
||||
|
|
@ -367,6 +373,7 @@ class TestJp2k(unittest.TestCase):
|
|||
np.testing.assert_array_equal(thumbnail1, thumbnail2)
|
||||
self.assertEqual(thumbnail1.shape, (25, 15, 3))
|
||||
|
||||
@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG)
|
||||
def test_rlevel_too_high(self):
|
||||
"""Should error out appropriately if reduce level too high"""
|
||||
j = Jp2k(self.jp2file)
|
||||
|
|
@ -518,12 +525,14 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(new_jp2.box[j].length,
|
||||
baseline_jp2.box[j].length)
|
||||
|
||||
@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG)
|
||||
def test_basic_jp2(self):
|
||||
"""Just a very basic test that reading a JP2 file does not error out.
|
||||
"""
|
||||
j2k = Jp2k(self.jp2file)
|
||||
j2k[::2, ::2]
|
||||
|
||||
@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG)
|
||||
def test_basic_j2k(self):
|
||||
"""This test is only useful when openjp2 is not available
|
||||
and OPJ_DATA_ROOT is not set. We need at least one
|
||||
|
|
@ -648,6 +657,7 @@ class TestJp2k(unittest.TestCase):
|
|||
creator_tool = xmp.get_property(libxmp.consts.XMP_NS_XMP, 'CreatorTool')
|
||||
self.assertEqual(creator_tool, 'Google')
|
||||
|
||||
@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG)
|
||||
@unittest.skipIf(re.match(r'''(1|2.0.0)''',
|
||||
glymur.version.openjpeg_version) is not None,
|
||||
"Not supported until 2.0.1")
|
||||
|
|
@ -664,6 +674,7 @@ class TestJp2k(unittest.TestCase):
|
|||
with self.assertRaises(RuntimeError):
|
||||
glymur.Jp2k(self.jp2file).read_bands()
|
||||
|
||||
@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG)
|
||||
@unittest.skipIf(re.match('1.[0-4]', openjpeg_version) is not None,
|
||||
"Not supported with OpenJPEG {0}".format(openjpeg_version))
|
||||
@unittest.skipIf(os.name == "nt", fixtures.WINDOWS_TMP_FILE_MSG)
|
||||
|
|
@ -869,6 +880,7 @@ class TestJp2k_1_x(unittest.TestCase):
|
|||
|
||||
|
||||
@unittest.skipIf(os.name == "nt", fixtures.WINDOWS_TMP_FILE_MSG)
|
||||
@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG)
|
||||
class Test_2p0_official(unittest.TestCase):
|
||||
"""Tests specific to v2.0.0"""
|
||||
|
||||
|
|
@ -962,6 +974,7 @@ class TestJp2k_2_0(unittest.TestCase):
|
|||
self.assertEqual(jasoc.box[3].box[1].box_id, 'xml ')
|
||||
|
||||
|
||||
@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG)
|
||||
@unittest.skipIf(re.match(r'''(1|2.0.0)''',
|
||||
glymur.version.openjpeg_version) is not None,
|
||||
"Not to be run until unless 2.0.1 or higher is present")
|
||||
|
|
@ -1135,7 +1148,7 @@ class TestJp2kOpjDataRoot(unittest.TestCase):
|
|||
|
||||
actdata = j[:]
|
||||
self.assertTrue(fixtures.mse(actdata, expdata) < 250)
|
||||
|
||||
|
||||
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
|
||||
def test_no_cxform_pclr_jp2(self):
|
||||
"""Indices for pclr jpxfile if no color transform"""
|
||||
|
|
|
|||
|
|
@ -41,10 +41,12 @@ from glymur.jp2box import FileTypeBox, ImageHeaderBox, ColourSpecificationBox
|
|||
from .fixtures import (
|
||||
OPJ_DATA_ROOT, MetadataBase,
|
||||
WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG,
|
||||
mse, peak_tolerance, read_pgx, opj_data_file
|
||||
mse, peak_tolerance, read_pgx, opj_data_file,
|
||||
OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG
|
||||
)
|
||||
|
||||
|
||||
@unittest.skipIf(OPENJPEG_NOT_AVAILABLE, OPENJPEG_NOT_AVAILABLE_MSG)
|
||||
@unittest.skipIf(OPJ_DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
class TestSuite(unittest.TestCase):
|
||||
|
|
@ -482,7 +484,7 @@ class TestSuiteWarns(MetadataBase):
|
|||
|
||||
@unittest.skipIf(OPJ_DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
@unittest.skipIf(glymur.version.openjpeg_version_tuple[0] == 1,
|
||||
@unittest.skipIf(glymur.version.openjpeg_version_tuple[0] != 2,
|
||||
"Feature not supported in glymur until openjpeg 2.0")
|
||||
class TestSuiteBands(unittest.TestCase):
|
||||
"""
|
||||
|
|
@ -577,7 +579,7 @@ class TestSuiteBands(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(OPJ_DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
@unittest.skipIf(glymur.version.openjpeg_version_tuple[0] == 1,
|
||||
@unittest.skipIf(glymur.version.openjpeg_version_tuple[0] < 2,
|
||||
"Tests not passing until 2.0")
|
||||
class TestSuite2point0(unittest.TestCase):
|
||||
"""Runs tests introduced in version 2.0 or that pass only in 2.0"""
|
||||
|
|
@ -641,7 +643,7 @@ class TestSuite2point0(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(OPJ_DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
@unittest.skipIf(re.match(r'''(1|2.0.0)''',
|
||||
@unittest.skipIf(re.match(r'''0|1|2.0.0''',
|
||||
glymur.version.openjpeg_version) is not None,
|
||||
"Only supported in 2.0.1 or higher")
|
||||
class TestSuite2point1(unittest.TestCase):
|
||||
|
|
@ -798,7 +800,7 @@ class TestSuite2point1(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(OPJ_DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
@unittest.skipIf(re.match(r'''(1|2.0.0)''',
|
||||
@unittest.skipIf(re.match(r'''0|1|2.0.0''',
|
||||
glymur.version.openjpeg_version) is not None,
|
||||
"Only supported in 2.0.1 or higher")
|
||||
class TestReadArea(unittest.TestCase):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue