Merge branch 'issue99' into devel
This commit is contained in:
commit
24de4a442a
23 changed files with 3034 additions and 2471 deletions
|
|
@ -1,3 +1,7 @@
|
|||
Aug 13, 2013 - v0.3.1 Exposed mantissa, exponent, and guard_bits fields in QCC
|
||||
and QCD segments. Exposed layers and code_block_size in COD segment.
|
||||
Exposed precinct_size in COC segment.
|
||||
|
||||
Jul 31, 2013 - v0.3.0 Added support for official 2.0.0.
|
||||
|
||||
Jul 27, 2013 - v0.2.8 Fixed inconsistency regarding configuration
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ from .jp2dump import jp2dump
|
|||
from . import data
|
||||
|
||||
|
||||
# unittest2 only in python-2.6 (pylint/python2.7 issue)
|
||||
# pylint: disable=F0401
|
||||
def runtests():
|
||||
"""Discover and run all tests for the glymur package.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -3,7 +3,19 @@
|
|||
The module contains classes used to store information parsed from JPEG 2000
|
||||
codestreams.
|
||||
"""
|
||||
# pylint: disable=C0302,R0902,R0903,R0913
|
||||
|
||||
# The number of lines in the module is long and that's ok. It would not help
|
||||
# matters to move anything out to another file.
|
||||
# pylint: disable=C0302
|
||||
|
||||
# "Too many instance attributes", "Too many arguments"
|
||||
# Some segments just have a lot of information.
|
||||
# It doesn't make sense to subclass just for that.
|
||||
# pylint: disable=R0902,R0913
|
||||
|
||||
# "Too few public methods" Some segments don't define any new methods from
|
||||
# the base Segment class.
|
||||
# pylint: disable=R0903
|
||||
|
||||
import math
|
||||
import struct
|
||||
|
|
@ -775,12 +787,15 @@ class Segment(object):
|
|||
length : int
|
||||
Length of marker segment in bytes. This number does not include the
|
||||
two bytes constituting the marker.
|
||||
data : bytes iterable or None
|
||||
Uninterpreted buffer of raw bytes, only used where a segment is not
|
||||
well understood.
|
||||
"""
|
||||
def __init__(self, marker_id='', offset=-1, length=-1, data=None):
|
||||
self.marker_id = marker_id
|
||||
self.offset = offset
|
||||
self.length = length
|
||||
self._data = data
|
||||
self.data = data
|
||||
|
||||
def __str__(self):
|
||||
msg = '{0} marker segment @ ({1}, {2})'.format(self.marker_id,
|
||||
|
|
@ -807,6 +822,8 @@ class COCsegment(Segment):
|
|||
Coding style for this component.
|
||||
spcoc : byte array
|
||||
Coding style parameters for this component.
|
||||
precinct_size : list of tuples
|
||||
Dimensions of precinct.
|
||||
|
||||
References
|
||||
----------
|
||||
|
|
@ -820,13 +837,13 @@ class COCsegment(Segment):
|
|||
self.scoc = scoc
|
||||
self.spcoc = spcoc
|
||||
|
||||
self._code_block_size = (4 * math.pow(2, self.spcoc[2]),
|
||||
4 * math.pow(2, self.spcoc[1]))
|
||||
self.code_block_size = (4 * math.pow(2, self.spcoc[2]),
|
||||
4 * math.pow(2, self.spcoc[1]))
|
||||
|
||||
if len(self.spcoc) > 5:
|
||||
self._precinct_size = _parse_precinct_size(self.spcoc[5:])
|
||||
self.precinct_size = _parse_precinct_size(self.spcoc[5:])
|
||||
else:
|
||||
self._precinct_size = None
|
||||
self.precinct_size = None
|
||||
|
||||
self.length = length
|
||||
self.offset = offset
|
||||
|
|
@ -847,16 +864,16 @@ class COCsegment(Segment):
|
|||
msg += '\n Code block height, width: ({1} x {2})'
|
||||
msg += '\n Wavelet transform: {3}'
|
||||
msg = msg.format(self.spcoc[0] + 1,
|
||||
int(self._code_block_size[0]),
|
||||
int(self._code_block_size[1]),
|
||||
int(self.code_block_size[0]),
|
||||
int(self.code_block_size[1]),
|
||||
_WAVELET_TRANSFORM_DISPLAY[self.spcoc[4]])
|
||||
|
||||
msg += '\n '
|
||||
msg += _context_string(self.spcoc[3])
|
||||
|
||||
if self._precinct_size is not None:
|
||||
if self.precinct_size is not None:
|
||||
msg += '\n Precinct size: '
|
||||
for pps in self._precinct_size:
|
||||
for pps in self.precinct_size:
|
||||
msg += '(%d, %d)'.format(pps)
|
||||
|
||||
return msg
|
||||
|
|
@ -876,10 +893,16 @@ class CODsegment(Segment):
|
|||
two bytes constituting the marker.
|
||||
scod : int
|
||||
Default coding style.
|
||||
layers : int
|
||||
Quality layers.
|
||||
code_block_size : tuple
|
||||
Size of code block.
|
||||
spcod : bytes
|
||||
Coding style parameters, including quality layers, multicomponent
|
||||
transform usage, decomposition levels, code block size, style of code-
|
||||
block passes, and which wavelet transform is used.
|
||||
Encoded coding style parameters, including quality layers,
|
||||
multi component transform usage, decomposition levels, code block size,
|
||||
style of code-block passes, and which wavelet transform is used.
|
||||
precinct_size : list of tuples
|
||||
Dimensions of precinct.
|
||||
|
||||
References
|
||||
----------
|
||||
|
|
@ -895,7 +918,7 @@ class CODsegment(Segment):
|
|||
self.offset = offset
|
||||
|
||||
params = struct.unpack('>BHBBBBBB', self.spcod[0:9])
|
||||
self._layers = params[1]
|
||||
self.layers = params[1]
|
||||
self._numresolutions = params[3]
|
||||
|
||||
if params[3] > opj2.J2K_MAXRLVLS:
|
||||
|
|
@ -906,12 +929,12 @@ class CODsegment(Segment):
|
|||
cblk_width = 4 * math.pow(2, params[4])
|
||||
cblk_height = 4 * math.pow(2, params[5])
|
||||
code_block_size = (cblk_height, cblk_width)
|
||||
self._code_block_size = code_block_size
|
||||
self.code_block_size = code_block_size
|
||||
|
||||
if len(self.spcod) > 9:
|
||||
self._precinct_size = _parse_precinct_size(self.spcod[9:])
|
||||
self.precinct_size = _parse_precinct_size(self.spcod[9:])
|
||||
else:
|
||||
self._precinct_size = None
|
||||
self.precinct_size = None
|
||||
|
||||
def __str__(self):
|
||||
msg = Segment.__str__(self)
|
||||
|
|
@ -944,18 +967,18 @@ class CODsegment(Segment):
|
|||
msg += '\n '.join(lines)
|
||||
|
||||
msg = msg.format(_PROGRESSION_ORDER_DISPLAY[self.spcod[0]],
|
||||
self._layers,
|
||||
self.layers,
|
||||
mct,
|
||||
self.spcod[4] + 1,
|
||||
int(self._code_block_size[0]),
|
||||
int(self._code_block_size[1]),
|
||||
int(self.code_block_size[0]),
|
||||
int(self.code_block_size[1]),
|
||||
_WAVELET_TRANSFORM_DISPLAY[self.spcod[8]])
|
||||
|
||||
msg += '\n Precinct size: '
|
||||
if self._precinct_size is None:
|
||||
if self.precinct_size is None:
|
||||
msg += 'default, 2^15 x 2^15'
|
||||
else:
|
||||
for pps in self._precinct_size:
|
||||
for pps in self.precinct_size:
|
||||
msg += '({0}, {1})'.format(pps[0], pps[1])
|
||||
|
||||
msg += '\n '
|
||||
|
|
@ -1195,8 +1218,8 @@ class PPMsegment(Segment):
|
|||
Segment.__init__(self, marker_id='PPM')
|
||||
self.zppm = zppm
|
||||
|
||||
# both Nppm and Ippms information stored in _data
|
||||
self._data = data
|
||||
# both Nppm and Ippms information stored in data
|
||||
self.data = data
|
||||
|
||||
self.length = length
|
||||
self.offset = offset
|
||||
|
|
@ -1205,7 +1228,7 @@ class PPMsegment(Segment):
|
|||
msg = Segment.__str__(self)
|
||||
msg += '\n Index: {0}'
|
||||
msg += '\n Data: {1} uninterpreted bytes'
|
||||
msg = msg.format(self.zppm, len(self._data))
|
||||
msg = msg.format(self.zppm, len(self.data))
|
||||
return msg
|
||||
|
||||
|
||||
|
|
@ -1265,6 +1288,10 @@ class QCCsegment(Segment):
|
|||
Quantization style for this component.
|
||||
spqcc : iterable bytes
|
||||
Quantization value for each sub-band.
|
||||
mantissa, exponent : iterable
|
||||
Defines quantization factors.
|
||||
guard_bits : int
|
||||
Number of guard bits.
|
||||
|
||||
References
|
||||
----------
|
||||
|
|
@ -1280,18 +1307,18 @@ class QCCsegment(Segment):
|
|||
self.length = length
|
||||
self.offset = offset
|
||||
|
||||
self._mantissa, self._exponent = parse_quantization(self.spqcc,
|
||||
self.mantissa, self.exponent = parse_quantization(self.spqcc,
|
||||
self.sqcc)
|
||||
self._guard_bits = (self.sqcc & 0xe0) >> 5
|
||||
self.guard_bits = (self.sqcc & 0xe0) >> 5
|
||||
|
||||
def __str__(self):
|
||||
msg = Segment.__str__(self)
|
||||
|
||||
msg += '\n Associated Component: {0}'.format(self.cqcc)
|
||||
msg += _print_quantization_style(self.sqcc)
|
||||
msg += '{0} guard bits'.format(self._guard_bits)
|
||||
msg += '{0} guard bits'.format(self.guard_bits)
|
||||
|
||||
step_size = zip(self._mantissa, self._exponent)
|
||||
step_size = zip(self.mantissa, self.exponent)
|
||||
msg += '\n Step size: ' + str(list(step_size))
|
||||
return msg
|
||||
|
||||
|
|
@ -1312,6 +1339,10 @@ class QCDsegment(Segment):
|
|||
Quantization style for all components.
|
||||
spqcd : iterable bytes
|
||||
Quantization step size values (uninterpreted).
|
||||
mantissa, exponent : iterable
|
||||
Defines quantization factors.
|
||||
guard_bits : int
|
||||
Number of guard bits.
|
||||
|
||||
References
|
||||
----------
|
||||
|
|
@ -1328,18 +1359,18 @@ class QCDsegment(Segment):
|
|||
self.offset = offset
|
||||
|
||||
mantissa, exponent = parse_quantization(self.spqcd, self.sqcd)
|
||||
self._mantissa = mantissa
|
||||
self._exponent = exponent
|
||||
self._guard_bits = (self.sqcd & 0xe0) >> 5
|
||||
self.mantissa = mantissa
|
||||
self.exponent = exponent
|
||||
self.guard_bits = (self.sqcd & 0xe0) >> 5
|
||||
|
||||
def __str__(self):
|
||||
msg = Segment.__str__(self)
|
||||
|
||||
msg += _print_quantization_style(self.sqcd)
|
||||
|
||||
msg += '{0} guard bits'.format(self._guard_bits)
|
||||
msg += '{0} guard bits'.format(self.guard_bits)
|
||||
|
||||
step_size = zip(self._mantissa, self._exponent)
|
||||
step_size = zip(self.mantissa, self.exponent)
|
||||
msg += '\n Step size: ' + str(list(step_size))
|
||||
return msg
|
||||
|
||||
|
|
@ -1411,7 +1442,11 @@ class SIZsegment(Segment):
|
|||
xtosiz, ytosiz : int
|
||||
Horizontal and vertical offsets of tile from origin of reference grid.
|
||||
ssiz : iterable bytes
|
||||
Precision (depth) in bits and sign of each component.
|
||||
Encoded precision (depth) in bits and sign of each component.
|
||||
bitdepth : iterable bytes
|
||||
Precision (depth) in bits of each component.
|
||||
signed : iterable bool
|
||||
Signedness of each component.
|
||||
xrsiz, yrsiz : int
|
||||
Horizontal and vertical sample separations with respect to reference
|
||||
grid.
|
||||
|
|
@ -1459,8 +1494,8 @@ class SIZsegment(Segment):
|
|||
self.xrsiz = data[1::3]
|
||||
self.yrsiz = data[2::3]
|
||||
|
||||
self._bitdepth = tuple(((x & 0x7f) + 1) for x in self.ssiz)
|
||||
self._signed = tuple(((x & 0xb0) > 0) for x in self.ssiz)
|
||||
self.bitdepth = tuple(((x & 0x7f) + 1) for x in self.ssiz)
|
||||
self.signed = tuple(((x & 0xb0) > 0) for x in self.ssiz)
|
||||
|
||||
self.length = length
|
||||
self.offset = offset
|
||||
|
|
@ -1483,8 +1518,8 @@ class SIZsegment(Segment):
|
|||
self.yosiz, self.xosiz,
|
||||
self.ytsiz, self.xtsiz,
|
||||
self.ytosiz, self.xtosiz,
|
||||
self._bitdepth,
|
||||
self._signed,
|
||||
self.bitdepth,
|
||||
self.signed,
|
||||
tuple(zip(self.yrsiz, self.xrsiz)))
|
||||
|
||||
return msg
|
||||
|
|
|
|||
214
glymur/jp2box.py
214
glymur/jp2box.py
|
|
@ -24,6 +24,7 @@ import uuid
|
|||
import warnings
|
||||
import xml.etree.cElementTree as ET
|
||||
if sys.hexversion < 0x02070000:
|
||||
# pylint: disable=F0401,E0611
|
||||
from ordereddict import OrderedDict
|
||||
from xml.etree.cElementTree import XMLParserError as ParseError
|
||||
else:
|
||||
|
|
@ -361,7 +362,8 @@ class _ICCProfile(object):
|
|||
header['Connection Space'] = data
|
||||
|
||||
data = struct.unpack('>HHHHHH', self._raw_buffer[24:36])
|
||||
header['Datetime'] = datetime.datetime(*data)
|
||||
header['Datetime'] = datetime.datetime(data[0], data[1], data[2],
|
||||
data[3], data[4], data[5])
|
||||
header['File Signature'] = read_buffer[36:40].decode('utf-8')
|
||||
if read_buffer[40:44] == b'\x00\x00\x00\x00':
|
||||
header['Platform'] = 'unrecognized'
|
||||
|
|
@ -369,10 +371,9 @@ class _ICCProfile(object):
|
|||
header['Platform'] = read_buffer[40:44].decode('utf-8')
|
||||
|
||||
fval, = struct.unpack('>I', read_buffer[44:48])
|
||||
flags = 'embedded, ' if fval & 0x01 else 'not embedded, '
|
||||
flags += 'cannot ' if fval & 0x02 else 'can '
|
||||
flags += 'be used independently'
|
||||
header['Flags'] = flags
|
||||
flags = "{0}embedded, {1} be used independently"
|
||||
header['Flags'] = flags.format('' if fval & 0x01 else 'not ',
|
||||
'cannot' if fval & 0x02 else 'can')
|
||||
|
||||
header['Device Manufacturer'] = read_buffer[48:52].decode('utf-8')
|
||||
if read_buffer[52:56] == b'\x00\x00\x00\x00':
|
||||
|
|
@ -382,11 +383,11 @@ class _ICCProfile(object):
|
|||
header['Device Model'] = device_model
|
||||
|
||||
val, = struct.unpack('>Q', read_buffer[56:64])
|
||||
attr = 'transparency, ' if val & 0x01 else 'reflective, '
|
||||
attr += 'matte, ' if val & 0x02 else 'glossy, '
|
||||
attr += 'negative ' if val & 0x04 else 'positive '
|
||||
attr += 'media polarity, '
|
||||
attr += 'black and white media' if val & 0x08 else 'color media'
|
||||
attr = "{0}, {1}, {2} media polarity, {3} media"
|
||||
attr = attr.format('transparency' if val & 0x01 else 'reflective',
|
||||
'matte' if val & 0x02 else 'glossy',
|
||||
'negative' if val & 0x04 else 'positive',
|
||||
'black and white' if val & 0x08 else 'color')
|
||||
header['Device Attributes'] = attr
|
||||
|
||||
rval, = struct.unpack('>I', read_buffer[64:68])
|
||||
|
|
@ -1237,43 +1238,68 @@ class PaletteBox(Jp2kBox):
|
|||
bps = [((x & 0x07f) + 1) for x in data]
|
||||
signed = [((x & 0x80) > 1) for x in data]
|
||||
|
||||
# Each palette component is padded out to the next largest byte.
|
||||
# That means a list comprehension does this in one shot.
|
||||
row_nbytes = sum([int(math.ceil(x/8.0)) for x in bps])
|
||||
|
||||
# Form the format string so that we can intelligently unpack the
|
||||
# colormap. We have to do this because it is possible that the
|
||||
# colormap columns could have different datatypes.
|
||||
#
|
||||
# This means that we store the palette as a list of 1D arrays,
|
||||
# which reverses the usual indexing scheme.
|
||||
palette = []
|
||||
fmt = '>'
|
||||
row_nbytes = 0
|
||||
for j in range(num_columns):
|
||||
if bps[j] <= 8:
|
||||
fmt += 'B'
|
||||
row_nbytes += 1
|
||||
palette.append(np.zeros(num_entries, dtype=np.uint8))
|
||||
elif bps[j] <= 16:
|
||||
fmt += 'H'
|
||||
row_nbytes += 2
|
||||
palette.append(np.zeros(num_entries, dtype=np.uint16))
|
||||
elif bps[j] <= 32:
|
||||
fmt += 'I'
|
||||
row_nbytes += 4
|
||||
palette.append(np.zeros(num_entries, dtype=np.uint32))
|
||||
else:
|
||||
msg = 'Unsupported palette bitdepth (%d).'.format(bps[j])
|
||||
raise IOError(msg)
|
||||
read_buffer = fptr.read(num_entries * row_nbytes)
|
||||
palette = _buffer2palette(read_buffer, num_entries, num_columns, bps)
|
||||
|
||||
for j in range(num_entries):
|
||||
row_buffer = read_buffer[(row_nbytes * j):(row_nbytes * (j + 1))]
|
||||
row = struct.unpack(fmt, row_buffer)
|
||||
for k in range(num_columns):
|
||||
palette[k][j] = row[k]
|
||||
|
||||
box = PaletteBox(palette, bps, signed, length=length,
|
||||
offset=offset)
|
||||
box = PaletteBox(palette, bps, signed, length=length, offset=offset)
|
||||
return box
|
||||
|
||||
|
||||
def _buffer2palette(read_buffer, num_rows, num_cols, bps):
|
||||
"""Construct the palette from the buffer read from file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
read_buffer : iterable
|
||||
Byte array of palette information read from file.
|
||||
num_rows, num_cols : int
|
||||
Size of palette.
|
||||
bps : iterable
|
||||
Bits per sample for each channel.
|
||||
|
||||
Returns
|
||||
-------
|
||||
palette : list of 1D arrays
|
||||
Each 1D array corresponds to a channel.
|
||||
"""
|
||||
row_nbytes = 0
|
||||
palette = []
|
||||
fmt = '>'
|
||||
for j in range(num_cols):
|
||||
if bps[j] <= 8:
|
||||
row_nbytes += 1
|
||||
fmt += 'B'
|
||||
palette.append(np.zeros(num_rows, dtype=np.uint8))
|
||||
elif bps[j] <= 16:
|
||||
row_nbytes += 2
|
||||
fmt += 'H'
|
||||
palette.append(np.zeros(num_rows, dtype=np.uint16))
|
||||
elif bps[j] <= 32:
|
||||
row_nbytes += 4
|
||||
fmt += 'I'
|
||||
palette.append(np.zeros(num_rows, dtype=np.uint32))
|
||||
else:
|
||||
msg = 'Unsupported palette bitdepth (%d).'.format(bps[j])
|
||||
raise IOError(msg)
|
||||
|
||||
for j in range(num_rows):
|
||||
row_buffer = read_buffer[(row_nbytes * j):(row_nbytes * (j + 1))]
|
||||
row = struct.unpack(fmt, row_buffer)
|
||||
for k in range(num_cols):
|
||||
palette[k][j] = row[k]
|
||||
|
||||
return palette
|
||||
|
||||
# Map rreq codes to display text.
|
||||
_READER_REQUIREMENTS_DISPLAY = {
|
||||
0: 'File not completely understood',
|
||||
|
|
@ -1434,52 +1460,18 @@ class ReaderRequirementsBox(Jp2kBox):
|
|||
"""
|
||||
read_buffer = fptr.read(1)
|
||||
mask_length, = struct.unpack('>B', read_buffer)
|
||||
if mask_length == 1:
|
||||
mask_format = 'B'
|
||||
elif mask_length == 2:
|
||||
mask_format = 'H'
|
||||
elif mask_length == 4:
|
||||
mask_format = 'I'
|
||||
else:
|
||||
msg = 'Unhandled reader requirements box mask length (%d).'
|
||||
msg %= mask_length
|
||||
raise RuntimeError(msg)
|
||||
|
||||
# Fully Understands Aspect Mask
|
||||
# Decodes Completely Mask
|
||||
read_buffer = fptr.read(2 * mask_length)
|
||||
data = struct.unpack('>' + mask_format * 2, read_buffer)
|
||||
fuam = data[0]
|
||||
dcm = data[1]
|
||||
|
||||
read_buffer = fptr.read(2)
|
||||
num_standard_flags, = struct.unpack('>H', read_buffer)
|
||||
# The mask length tells us the format string to use when unpacking
|
||||
# from the buffer read from file.
|
||||
mask_format = {1: 'B', 2: 'H', 4: 'I'}[mask_length]
|
||||
fuam, dcm = struct.unpack('>' + mask_format * 2, read_buffer)
|
||||
|
||||
# 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))
|
||||
data = struct.unpack('>' + ('H' + mask_format) * num_standard_flags,
|
||||
read_buffer)
|
||||
standard_flag = data[0:num_standard_flags * 2:2]
|
||||
standard_mask = data[1:num_standard_flags * 2:2]
|
||||
|
||||
# Vendor features
|
||||
read_buffer = fptr.read(2)
|
||||
num_vendor_features, = struct.unpack('>H', read_buffer)
|
||||
|
||||
# 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):
|
||||
ubuffer = read_buffer[j * entry_length:(j + 1) * entry_length]
|
||||
vendor_feature.append(uuid.UUID(bytes=ubuffer[0:16]))
|
||||
|
||||
vmask = struct.unpack('>' + mask_format, ubuffer[16:])
|
||||
vendor_mask.append(vmask)
|
||||
standard_flag, standard_mask = _parse_standard_flag(fptr, mask_length)
|
||||
vendor_feature, vendor_mask = _parse_vendor_features(fptr, mask_length)
|
||||
|
||||
box = ReaderRequirementsBox(fuam, dcm, standard_flag, standard_mask,
|
||||
vendor_feature, vendor_mask,
|
||||
|
|
@ -1487,6 +1479,74 @@ class ReaderRequirementsBox(Jp2kBox):
|
|||
return box
|
||||
|
||||
|
||||
def _parse_standard_flag(fptr, mask_length):
|
||||
"""Construct standard flag, standard mask data from the file.
|
||||
|
||||
Specifically working on Reader Requirements box.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fptr : file object
|
||||
File object for JP2K file.
|
||||
mask_length : int
|
||||
Length of standard mask flag
|
||||
"""
|
||||
# The mask length tells us the format string to use when unpacking
|
||||
# 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('>H', read_buffer)
|
||||
|
||||
# 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(fmt, read_buffer)
|
||||
|
||||
standard_flag = data[0:num_standard_flags * 2:2]
|
||||
standard_mask = data[1:num_standard_flags * 2:2]
|
||||
|
||||
return standard_flag, standard_mask
|
||||
|
||||
|
||||
def _parse_vendor_features(fptr, mask_length):
|
||||
"""Construct vendor features, vendor mask data from the file.
|
||||
|
||||
Specifically working on Reader Requirements box.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fptr : file object
|
||||
File object for JP2K file.
|
||||
mask_length : int
|
||||
Length of vendor mask flag
|
||||
"""
|
||||
# The mask length tells us the format string to use when unpacking
|
||||
# from the buffer read from file.
|
||||
mask_format = {1: 'B', 2: 'H', 4: 'I'}[mask_length]
|
||||
|
||||
read_buffer = fptr.read(2)
|
||||
num_vendor_features, = struct.unpack('>H', read_buffer)
|
||||
|
||||
# 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):
|
||||
ubuffer = read_buffer[j * entry_length:(j + 1) * entry_length]
|
||||
vendor_feature.append(uuid.UUID(bytes=ubuffer[0:16]))
|
||||
|
||||
vmask = struct.unpack('>' + mask_format, ubuffer[16:])
|
||||
vendor_mask.append(vmask)
|
||||
|
||||
return vendor_feature, vendor_mask
|
||||
|
||||
|
||||
class ResolutionBox(Jp2kBox):
|
||||
"""Container for Resolution superbox information.
|
||||
|
||||
|
|
|
|||
1273
glymur/jp2k.py
1273
glymur/jp2k.py
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,4 @@
|
|||
"""This package organizes individual libraries employed by glymur."""
|
||||
from . import openjp2 as _openjp2
|
||||
from . import openjpeg as _openjpeg
|
||||
from . import openjp2 as openjp2
|
||||
from . import openjpeg as openjpeg
|
||||
from . import c
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
"""
|
||||
Configure glymur to use installed libraries if possible.
|
||||
"""
|
||||
# configparser is new in python3 (pylint/python-2.7)
|
||||
# pylint: disable=F0401
|
||||
|
||||
import ctypes
|
||||
from ctypes.util import find_library
|
||||
import os
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Wraps individual functions in openjp2 library.
|
||||
"""
|
||||
|
||||
# pylint: disable=C0302,R0903
|
||||
# pylint: disable=C0302,R0903,W0201
|
||||
|
||||
import ctypes
|
||||
import sys
|
||||
|
|
@ -1381,7 +1381,6 @@ def write_tile(codec, tile_index, data, data_size, stream):
|
|||
|
||||
def set_error_message(msg):
|
||||
"""The openjpeg error handler has recorded an error message."""
|
||||
global ERROR_MSG_LST
|
||||
ERROR_MSG_LST.append(msg)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1,3 @@
|
|||
#from .test_openjp2 import TestOpenJP2 as openjp2
|
||||
"""
|
||||
Test suite for openjp2, openjpeg low-level functionality.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
#pylint: disable-all
|
||||
import doctest
|
||||
"""
|
||||
Tests for libopenjp2 wrapping functions.
|
||||
"""
|
||||
# R0904: Seems like pylint is fooled in this situation
|
||||
# W0142: using kwargs is ok in this context
|
||||
# pylint: disable=R0904,W0142
|
||||
|
||||
# unittest2 is python-2.6 only (pylint/python-2.7)
|
||||
# pylint: disable=F0401
|
||||
|
||||
import os
|
||||
import pkg_resources
|
||||
import shutil
|
||||
import struct
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
|
|
@ -15,28 +20,28 @@ else:
|
|||
import numpy as np
|
||||
|
||||
import glymur
|
||||
from glymur.lib import openjp2
|
||||
|
||||
OPENJP2_IS_V2_OFFICIAL = False
|
||||
if glymur.lib.openjp2.OPENJP2 is not None:
|
||||
if not hasattr(glymur.lib.openjp2.OPENJP2,
|
||||
if openjp2.OPENJP2 is not None:
|
||||
if not hasattr(openjp2.OPENJP2,
|
||||
'opj_stream_create_default_file_stream_v3'):
|
||||
OPENJP2_IS_V2_OFFICIAL = True
|
||||
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
@unittest.skipIf(openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
@unittest.skipIf(OPENJP2_IS_V2_OFFICIAL, "API followed here specific to V2.0+")
|
||||
class TestOpenJP2(unittest.TestCase):
|
||||
"""Test openjp2 library functionality.
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
Some tests correspond to those in the openjpeg test suite.
|
||||
"""
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_set_default_encoder_parameters(self):
|
||||
cparams = glymur.lib._openjp2.set_default_encoder_parameters()
|
||||
def test_default_encoder_parameters(self):
|
||||
"""Ensure that the encoder structure is clean upon init."""
|
||||
cparams = openjp2.set_default_encoder_parameters()
|
||||
|
||||
self.assertEqual(cparams.res_spec, 0)
|
||||
self.assertEqual(cparams.cblockw_init, 64)
|
||||
|
|
@ -52,8 +57,9 @@ class TestOpenJP2(unittest.TestCase):
|
|||
|
||||
self.assertEqual(cparams.irreversible, 0)
|
||||
|
||||
def test_set_default_decoder_parameters(self):
|
||||
dparams = glymur.lib._openjp2.set_default_decoder_parameters()
|
||||
def test_default_decoder_parameters(self):
|
||||
"""Tests that the structure is clean upon initialization"""
|
||||
dparams = openjp2.set_default_decoder_parameters()
|
||||
|
||||
self.assertEqual(dparams.DA_x0, 0)
|
||||
self.assertEqual(dparams.DA_y0, 0)
|
||||
|
|
@ -61,35 +67,34 @@ class TestOpenJP2(unittest.TestCase):
|
|||
self.assertEqual(dparams.DA_y1, 0)
|
||||
|
||||
def tile_macro(self, codec, stream, imagep, tidx):
|
||||
# called only by j2k_random_tile_access
|
||||
glymur.lib._openjp2.get_decoded_tile(codec, stream, imagep, tidx)
|
||||
"""called only by j2k_random_tile_access"""
|
||||
openjp2.get_decoded_tile(codec, stream, imagep, tidx)
|
||||
for j in range(imagep.contents.numcomps):
|
||||
self.assertIsNotNone(imagep.contents.comps[j].data)
|
||||
|
||||
def j2k_random_tile_access(self, filename, codec_format=None):
|
||||
# called by the test_rtaX methods
|
||||
dparam = glymur.lib._openjp2.set_default_decoder_parameters()
|
||||
"""fixture called by the test_rtaX methods"""
|
||||
dparam = openjp2.set_default_decoder_parameters()
|
||||
|
||||
infile = filename.encode()
|
||||
nelts = glymur.lib._openjp2.PATH_LEN - len(infile)
|
||||
nelts = openjp2.PATH_LEN - len(infile)
|
||||
infile += b'0' * nelts
|
||||
dparam.infile = infile
|
||||
|
||||
dparam.decod_format = codec_format
|
||||
|
||||
codec = glymur.lib._openjp2.create_decompress(codec_format)
|
||||
codec = openjp2.create_decompress(codec_format)
|
||||
|
||||
glymur.lib._openjp2.set_info_handler(codec, None)
|
||||
glymur.lib._openjp2.set_warning_handler(codec, None)
|
||||
glymur.lib._openjp2.set_error_handler(codec, None)
|
||||
openjp2.set_info_handler(codec, None)
|
||||
openjp2.set_warning_handler(codec, None)
|
||||
openjp2.set_error_handler(codec, None)
|
||||
|
||||
x = (filename, True)
|
||||
stream = glymur.lib._openjp2.stream_create_default_file_stream_v3(*x)
|
||||
stream = openjp2.stream_create_default_file_stream_v3(filename, True)
|
||||
|
||||
glymur.lib._openjp2.setup_decoder(codec, dparam)
|
||||
image = glymur.lib._openjp2.read_header(stream, codec)
|
||||
openjp2.setup_decoder(codec, dparam)
|
||||
image = openjp2.read_header(stream, codec)
|
||||
|
||||
cstr_info = glymur.lib._openjp2.get_cstr_info(codec)
|
||||
cstr_info = openjp2.get_cstr_info(codec)
|
||||
|
||||
tile_ul = 0
|
||||
tile_ur = cstr_info.contents.tw - 1
|
||||
|
|
@ -101,159 +106,39 @@ class TestOpenJP2(unittest.TestCase):
|
|||
self.tile_macro(codec, stream, image, tile_lr)
|
||||
self.tile_macro(codec, stream, image, tile_ll)
|
||||
|
||||
glymur.lib._openjp2.destroy_cstr_info(cstr_info)
|
||||
openjp2.destroy_cstr_info(cstr_info)
|
||||
|
||||
glymur.lib._openjp2.end_decompress(codec, stream)
|
||||
glymur.lib._openjp2.destroy_codec(codec)
|
||||
glymur.lib._openjp2.stream_destroy_v3(stream)
|
||||
glymur.lib._openjp2.image_destroy(image)
|
||||
|
||||
def tile_decoder(self, x0=None, y0=None, x1=None, y1=None, filename=None,
|
||||
codec_format=None):
|
||||
x = (filename, True)
|
||||
stream = glymur.lib._openjp2.stream_create_default_file_stream_v3(*x)
|
||||
dparam = glymur.lib._openjp2.set_default_decoder_parameters()
|
||||
|
||||
dparam.decod_format = codec_format
|
||||
|
||||
# Do not use layer decoding limitation.
|
||||
dparam.cp_layer = 0
|
||||
|
||||
# do not use resolution reductions.
|
||||
dparam.cp_reduce = 0
|
||||
|
||||
codec = glymur.lib._openjp2.create_decompress(codec_format)
|
||||
|
||||
glymur.lib._openjp2.set_info_handler(codec, None)
|
||||
glymur.lib._openjp2.set_warning_handler(codec, None)
|
||||
glymur.lib._openjp2.set_error_handler(codec, None)
|
||||
|
||||
glymur.lib._openjp2.setup_decoder(codec, dparam)
|
||||
image = glymur.lib._openjp2.read_header(stream, codec)
|
||||
glymur.lib._openjp2.set_decode_area(codec, image, x0, y0, x1, y1)
|
||||
|
||||
data = np.zeros((1150, 2048, 3), dtype=np.uint8)
|
||||
while True:
|
||||
rargs = glymur.lib._openjp2.read_tile_header(codec, stream)
|
||||
tidx = rargs[0]
|
||||
sz = rargs[1]
|
||||
go_on = rargs[-1]
|
||||
if not go_on:
|
||||
break
|
||||
glymur.lib._openjp2.decode_tile_data(codec, tidx, data, sz, stream)
|
||||
|
||||
glymur.lib._openjp2.end_decompress(codec, stream)
|
||||
glymur.lib._openjp2.destroy_codec(codec)
|
||||
glymur.lib._openjp2.stream_destroy_v3(stream)
|
||||
glymur.lib._openjp2.image_destroy(image)
|
||||
|
||||
def tile_encoder(self, num_comps=None, tile_width=None, tile_height=None,
|
||||
filename=None, codec=None, comp_prec=None,
|
||||
image_width=None, image_height=None,
|
||||
irreversible=None):
|
||||
num_tiles = (image_width / tile_width) * (image_height / tile_height)
|
||||
tile_size = tile_width * tile_height * num_comps * comp_prec / 8
|
||||
|
||||
data = np.random.random((tile_height, tile_width, num_comps))
|
||||
data = (data * 255).astype(np.uint8)
|
||||
|
||||
l_param = glymur.lib._openjp2.set_default_encoder_parameters()
|
||||
|
||||
l_param.tcp_numlayers = 1
|
||||
l_param.cp_fixed_quality = 1
|
||||
l_param.tcp_distoratio[0] = 20
|
||||
|
||||
# position of the tile grid aligned with the image
|
||||
l_param.cp_tx0 = 0
|
||||
l_param.cp_ty0 = 0
|
||||
|
||||
# tile size, we are using tile based encoding
|
||||
l_param.tile_size_on = 1
|
||||
l_param.cp_tdx = tile_width
|
||||
l_param.cp_tdy = tile_height
|
||||
|
||||
# use irreversible encoding
|
||||
l_param.irreversible = irreversible
|
||||
|
||||
l_param.numresolution = 6
|
||||
|
||||
l_param.prog_order = glymur.core.LRCP
|
||||
|
||||
l_params = (glymur.lib._openjp2.ImageComptParmType * num_comps)()
|
||||
for j in range(num_comps):
|
||||
l_params[j].dx = 1
|
||||
l_params[j].dy = 1
|
||||
l_params[j].h = image_height
|
||||
l_params[j].w = image_width
|
||||
l_params[j].sgnd = 0
|
||||
l_params[j].prec = comp_prec
|
||||
l_params[j].x0 = 0
|
||||
l_params[j].y0 = 0
|
||||
|
||||
codec = glymur.lib._openjp2.create_compress(codec)
|
||||
|
||||
glymur.lib._openjp2.set_info_handler(codec, None)
|
||||
glymur.lib._openjp2.set_warning_handler(codec, None)
|
||||
glymur.lib._openjp2.set_error_handler(codec, None)
|
||||
|
||||
cspace = glymur.lib._openjp2.CLRSPC_SRGB
|
||||
l_image = glymur.lib._openjp2.image_tile_create(l_params, cspace)
|
||||
|
||||
l_image.contents.x0 = 0
|
||||
l_image.contents.y0 = 0
|
||||
l_image.contents.x1 = image_width
|
||||
l_image.contents.y1 = image_height
|
||||
l_image.contents.color_space = glymur.lib._openjp2.CLRSPC_SRGB
|
||||
|
||||
glymur.lib._openjp2.setup_encoder(codec, l_param, l_image)
|
||||
|
||||
x = (filename, False)
|
||||
stream = glymur.lib._openjp2.stream_create_default_file_stream_v3(*x)
|
||||
glymur.lib._openjp2.start_compress(codec, l_image, stream)
|
||||
|
||||
for j in np.arange(num_tiles):
|
||||
glymur.lib._openjp2.write_tile(codec, j, data, tile_size, stream)
|
||||
|
||||
glymur.lib._openjp2.end_compress(codec, stream)
|
||||
glymur.lib._openjp2.stream_destroy_v3(stream)
|
||||
glymur.lib._openjp2.destroy_codec(codec)
|
||||
glymur.lib._openjp2.image_destroy(l_image)
|
||||
|
||||
def tte0_setup(self, filename):
|
||||
kwargs = {'filename': filename,
|
||||
'codec': glymur.lib._openjp2.CODEC_J2K,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 1,
|
||||
'num_comps': 3,
|
||||
'image_height': 200,
|
||||
'image_width': 200,
|
||||
'tile_height': 100,
|
||||
'tile_width': 100}
|
||||
self.tile_encoder(**kwargs)
|
||||
openjp2.end_decompress(codec, stream)
|
||||
openjp2.destroy_codec(codec)
|
||||
openjp2.stream_destroy_v3(stream)
|
||||
openjp2.image_destroy(image)
|
||||
|
||||
def test_tte0(self):
|
||||
# Runs test designated tte0 in OpenJPEG test suite.
|
||||
"""Runs test designated tte0 in OpenJPEG test suite."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
|
||||
self.tte0_setup(tfile.name)
|
||||
ttx0_setup(tfile.name)
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_ttd0(self):
|
||||
# Runs test designated ttd0 in OpenJPEG test suite.
|
||||
"""Runs test designated ttd0 in OpenJPEG test suite."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
|
||||
|
||||
# Produce the tte0 output file for ttd0 input.
|
||||
self.tte0_setup(tfile.name)
|
||||
ttx0_setup(tfile.name)
|
||||
|
||||
kwargs = {'x0': 0,
|
||||
'y0': 0,
|
||||
'x1': 1000,
|
||||
'y1': 1000,
|
||||
'filename': tfile.name,
|
||||
'codec_format': glymur.lib._openjp2.CODEC_J2K}
|
||||
self.tile_decoder(**kwargs)
|
||||
'codec_format': openjp2.CODEC_J2K}
|
||||
tile_decoder(**kwargs)
|
||||
self.assertTrue(True)
|
||||
|
||||
def tte1_setup(self, filename):
|
||||
def xtx1_setup(self, filename):
|
||||
"""Runs tests tte1, rta1."""
|
||||
kwargs = {'filename': filename,
|
||||
'codec': glymur.lib._openjp2.CODEC_J2K,
|
||||
'codec': openjp2.CODEC_J2K,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 1,
|
||||
'num_comps': 3,
|
||||
|
|
@ -261,149 +146,298 @@ class TestOpenJP2(unittest.TestCase):
|
|||
'image_width': 256,
|
||||
'tile_height': 128,
|
||||
'tile_width': 128}
|
||||
self.tile_encoder(**kwargs)
|
||||
tile_encoder(**kwargs)
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_tte1(self):
|
||||
"""Runs test designated tte1 in OpenJPEG test suite."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
|
||||
# Runs test designated tte1 in OpenJPEG test suite.
|
||||
self.tte1_setup(tfile.name)
|
||||
self.xtx1_setup(tfile.name)
|
||||
|
||||
def test_ttd1(self):
|
||||
# Runs test designated ttd1 in OpenJPEG test suite.
|
||||
"""Runs test designated ttd1 in OpenJPEG test suite."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
|
||||
|
||||
# Produce the tte0 output file for ttd0 input.
|
||||
self.tte1_setup(tfile.name)
|
||||
self.xtx1_setup(tfile.name)
|
||||
|
||||
kwargs = {'x0': 0,
|
||||
'y0': 0,
|
||||
'x1': 128,
|
||||
'y1': 128,
|
||||
'filename': tfile.name,
|
||||
'codec_format': glymur.lib._openjp2.CODEC_J2K}
|
||||
self.tile_decoder(**kwargs)
|
||||
'codec_format': openjp2.CODEC_J2K}
|
||||
tile_decoder(**kwargs)
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_rta1(self):
|
||||
"""Runs test designated rta1 in OpenJPEG test suite."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
|
||||
# Runs test designated rta1 in OpenJPEG test suite.
|
||||
self.tte1_setup(tfile.name)
|
||||
self.xtx1_setup(tfile.name)
|
||||
|
||||
kwargs = {'codec_format': glymur.lib._openjp2.CODEC_J2K}
|
||||
self.j2k_random_tile_access(tfile.name, **kwargs)
|
||||
|
||||
def tte2_setup(self, filename):
|
||||
kwargs = {'filename': filename,
|
||||
'codec': glymur.lib._openjp2.CODEC_JP2,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 1,
|
||||
'num_comps': 3,
|
||||
'image_height': 256,
|
||||
'image_width': 256,
|
||||
'tile_height': 128,
|
||||
'tile_width': 128}
|
||||
self.tile_encoder(**kwargs)
|
||||
codec_format = openjp2.CODEC_J2K
|
||||
self.j2k_random_tile_access(tfile.name, codec_format)
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_tte2(self):
|
||||
# Runs test designated tte2 in OpenJPEG test suite.
|
||||
"""Runs test designated tte2 in OpenJPEG test suite."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
self.tte2_setup(tfile.name)
|
||||
xtx2_setup(tfile.name)
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_ttd2(self):
|
||||
# Runs test designated ttd2 in OpenJPEG test suite.
|
||||
"""Runs test designated ttd2 in OpenJPEG test suite."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
# Produce the tte0 output file for ttd0 input.
|
||||
self.tte2_setup(tfile.name)
|
||||
xtx2_setup(tfile.name)
|
||||
|
||||
kwargs = {'x0': 0,
|
||||
'y0': 0,
|
||||
'x1': 128,
|
||||
'y1': 128,
|
||||
'filename': tfile.name,
|
||||
'codec_format': glymur.lib._openjp2.CODEC_JP2}
|
||||
self.tile_decoder(**kwargs)
|
||||
'codec_format': openjp2.CODEC_JP2}
|
||||
tile_decoder(**kwargs)
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_rta2(self):
|
||||
"""Runs test designated rta2 in OpenJPEG test suite."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
# Runs test designated rta2 in OpenJPEG test suite.
|
||||
self.tte2_setup(tfile.name)
|
||||
xtx2_setup(tfile.name)
|
||||
|
||||
kwargs = {'codec_format': glymur.lib._openjp2.CODEC_JP2}
|
||||
self.j2k_random_tile_access(tfile.name, **kwargs)
|
||||
|
||||
def tte3_setup(self, filename):
|
||||
kwargs = {'filename': filename,
|
||||
'codec': glymur.lib._openjp2.CODEC_J2K,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 1,
|
||||
'num_comps': 1,
|
||||
'image_height': 256,
|
||||
'image_width': 256,
|
||||
'tile_height': 128,
|
||||
'tile_width': 128}
|
||||
self.tile_encoder(**kwargs)
|
||||
codec_format = openjp2.CODEC_JP2
|
||||
self.j2k_random_tile_access(tfile.name, codec_format)
|
||||
|
||||
def test_tte3(self):
|
||||
"""Runs test designated tte3 in OpenJPEG test suite."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
|
||||
# Runs test designated tte3 in OpenJPEG test suite.
|
||||
self.tte3_setup(tfile.name)
|
||||
xtx3_setup(tfile.name)
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_rta3(self):
|
||||
# Runs test designated rta3 in OpenJPEG test suite.
|
||||
"""Runs test designated rta3 in OpenJPEG test suite."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
|
||||
self.tte3_setup(tfile.name)
|
||||
xtx3_setup(tfile.name)
|
||||
|
||||
kwargs = {'codec_format': glymur.lib._openjp2.CODEC_J2K}
|
||||
self.j2k_random_tile_access(tfile.name, **kwargs)
|
||||
|
||||
def tte4_setup(self, filename):
|
||||
kwargs = {'filename': filename,
|
||||
'codec': glymur.lib._openjp2.CODEC_J2K,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 0,
|
||||
'num_comps': 1,
|
||||
'image_height': 256,
|
||||
'image_width': 256,
|
||||
'tile_height': 128,
|
||||
'tile_width': 128}
|
||||
self.tile_encoder(**kwargs)
|
||||
codec_format = openjp2.CODEC_J2K
|
||||
self.j2k_random_tile_access(tfile.name, codec_format)
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_tte4(self):
|
||||
# Runs test designated tte4 in OpenJPEG test suite.
|
||||
"""Runs test designated tte4 in OpenJPEG test suite."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
|
||||
self.tte4_setup(tfile.name)
|
||||
xtx4_setup(tfile.name)
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_rta4(self):
|
||||
# Runs test designated rta4 in OpenJPEG test suite.
|
||||
"""Runs test designated rta4 in OpenJPEG test suite."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
|
||||
self.tte4_setup(tfile.name)
|
||||
xtx4_setup(tfile.name)
|
||||
|
||||
kwargs = {'codec_format': glymur.lib._openjp2.CODEC_J2K}
|
||||
self.j2k_random_tile_access(tfile.name, **kwargs)
|
||||
|
||||
def tte5_setup(self, filename):
|
||||
kwargs = {'filename': filename,
|
||||
'codec': glymur.lib._openjp2.CODEC_J2K,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 0,
|
||||
'num_comps': 1,
|
||||
'image_height': 512,
|
||||
'image_width': 512,
|
||||
'tile_height': 256,
|
||||
'tile_width': 256}
|
||||
self.tile_encoder(**kwargs)
|
||||
codec_format = openjp2.CODEC_J2K
|
||||
self.j2k_random_tile_access(tfile.name, codec_format)
|
||||
|
||||
def test_tte5(self):
|
||||
# Runs test designated tte5 in OpenJPEG test suite.
|
||||
"""Runs test designated tte5 in OpenJPEG test suite."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
|
||||
self.tte5_setup(tfile.name)
|
||||
xtx5_setup(tfile.name)
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_rta5(self):
|
||||
# Runs test designated rta5 in OpenJPEG test suite.
|
||||
"""Runs test designated rta5 in OpenJPEG test suite."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".j2k") as tfile:
|
||||
self.tte5_setup(tfile.name)
|
||||
xtx5_setup(tfile.name)
|
||||
|
||||
kwargs = {'codec_format': glymur.lib._openjp2.CODEC_J2K}
|
||||
self.j2k_random_tile_access(tfile.name, **kwargs)
|
||||
codec_format = openjp2.CODEC_J2K
|
||||
self.j2k_random_tile_access(tfile.name, codec_format)
|
||||
|
||||
|
||||
#def tile_encoder(num_comps=None, tile_width=None, tile_height=None,
|
||||
# filename=None, codec=None, comp_prec=None,
|
||||
# image_width=None, image_height=None,
|
||||
# irreversible=None):
|
||||
def tile_encoder(**kwargs):
|
||||
"""Fixture used by many tests."""
|
||||
num_tiles = ((kwargs['image_width'] / kwargs['tile_width']) *
|
||||
(kwargs['image_height'] / kwargs['tile_height']))
|
||||
tile_size = ((kwargs['tile_width'] * kwargs['tile_height']) *
|
||||
(kwargs['num_comps'] * kwargs['comp_prec'] / 8))
|
||||
|
||||
data = np.random.random((kwargs['tile_height'],
|
||||
kwargs['tile_width'],
|
||||
kwargs['num_comps']))
|
||||
data = (data * 255).astype(np.uint8)
|
||||
|
||||
l_param = openjp2.set_default_encoder_parameters()
|
||||
|
||||
l_param.tcp_numlayers = 1
|
||||
l_param.cp_fixed_quality = 1
|
||||
l_param.tcp_distoratio[0] = 20
|
||||
|
||||
# position of the tile grid aligned with the image
|
||||
l_param.cp_tx0 = 0
|
||||
l_param.cp_ty0 = 0
|
||||
|
||||
# tile size, we are using tile based encoding
|
||||
l_param.tile_size_on = 1
|
||||
l_param.cp_tdx = kwargs['tile_width']
|
||||
l_param.cp_tdy = kwargs['tile_height']
|
||||
|
||||
# use irreversible encoding
|
||||
l_param.irreversible = kwargs['irreversible']
|
||||
|
||||
l_param.numresolution = 6
|
||||
|
||||
l_param.prog_order = glymur.core.LRCP
|
||||
|
||||
l_params = (openjp2.ImageComptParmType * kwargs['num_comps'])()
|
||||
for j in range(kwargs['num_comps']):
|
||||
l_params[j].dx = 1
|
||||
l_params[j].dy = 1
|
||||
l_params[j].h = kwargs['image_height']
|
||||
l_params[j].w = kwargs['image_width']
|
||||
l_params[j].sgnd = 0
|
||||
l_params[j].prec = kwargs['comp_prec']
|
||||
l_params[j].x0 = 0
|
||||
l_params[j].y0 = 0
|
||||
|
||||
codec = openjp2.create_compress(kwargs['codec'])
|
||||
|
||||
openjp2.set_info_handler(codec, None)
|
||||
openjp2.set_warning_handler(codec, None)
|
||||
openjp2.set_error_handler(codec, None)
|
||||
|
||||
cspace = openjp2.CLRSPC_SRGB
|
||||
l_image = openjp2.image_tile_create(l_params, cspace)
|
||||
|
||||
l_image.contents.x0 = 0
|
||||
l_image.contents.y0 = 0
|
||||
l_image.contents.x1 = kwargs['image_width']
|
||||
l_image.contents.y1 = kwargs['image_height']
|
||||
l_image.contents.color_space = openjp2.CLRSPC_SRGB
|
||||
|
||||
openjp2.setup_encoder(codec, l_param, l_image)
|
||||
|
||||
stream = openjp2.stream_create_default_file_stream_v3(kwargs['filename'],
|
||||
False)
|
||||
openjp2.start_compress(codec, l_image, stream)
|
||||
|
||||
for j in np.arange(num_tiles):
|
||||
openjp2.write_tile(codec, j, data, tile_size, stream)
|
||||
|
||||
openjp2.end_compress(codec, stream)
|
||||
openjp2.stream_destroy_v3(stream)
|
||||
openjp2.destroy_codec(codec)
|
||||
openjp2.image_destroy(l_image)
|
||||
|
||||
def tile_decoder(**kwargs):
|
||||
"""Fixture called with various configurations by many tests.
|
||||
|
||||
Reads a tile. That's all it does.
|
||||
"""
|
||||
stream = openjp2.stream_create_default_file_stream_v3(kwargs['filename'],
|
||||
True)
|
||||
dparam = openjp2.set_default_decoder_parameters()
|
||||
|
||||
dparam.decod_format = kwargs['codec_format']
|
||||
|
||||
# Do not use layer decoding limitation.
|
||||
dparam.cp_layer = 0
|
||||
|
||||
# do not use resolution reductions.
|
||||
dparam.cp_reduce = 0
|
||||
|
||||
codec = openjp2.create_decompress(kwargs['codec_format'])
|
||||
|
||||
openjp2.set_info_handler(codec, None)
|
||||
openjp2.set_warning_handler(codec, None)
|
||||
openjp2.set_error_handler(codec, None)
|
||||
|
||||
openjp2.setup_decoder(codec, dparam)
|
||||
image = openjp2.read_header(stream, codec)
|
||||
openjp2.set_decode_area(codec, image,
|
||||
kwargs['x0'], kwargs['y0'],
|
||||
kwargs['x1'], kwargs['y1'])
|
||||
|
||||
data = np.zeros((1150, 2048, 3), dtype=np.uint8)
|
||||
while True:
|
||||
rargs = openjp2.read_tile_header(codec, stream)
|
||||
tidx = rargs[0]
|
||||
size = rargs[1]
|
||||
go_on = rargs[-1]
|
||||
if not go_on:
|
||||
break
|
||||
openjp2.decode_tile_data(codec, tidx, data, size, stream)
|
||||
|
||||
openjp2.end_decompress(codec, stream)
|
||||
openjp2.destroy_codec(codec)
|
||||
openjp2.stream_destroy_v3(stream)
|
||||
openjp2.image_destroy(image)
|
||||
|
||||
def ttx0_setup(filename):
|
||||
"""Runs tests tte0, tte0."""
|
||||
kwargs = {'filename': filename,
|
||||
'codec': openjp2.CODEC_J2K,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 1,
|
||||
'num_comps': 3,
|
||||
'image_height': 200,
|
||||
'image_width': 200,
|
||||
'tile_height': 100,
|
||||
'tile_width': 100}
|
||||
tile_encoder(**kwargs)
|
||||
|
||||
def xtx2_setup(filename):
|
||||
"""Runs tests rta2, tte2, ttd2."""
|
||||
kwargs = {'filename': filename,
|
||||
'codec': openjp2.CODEC_JP2,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 1,
|
||||
'num_comps': 3,
|
||||
'image_height': 256,
|
||||
'image_width': 256,
|
||||
'tile_height': 128,
|
||||
'tile_width': 128}
|
||||
tile_encoder(**kwargs)
|
||||
|
||||
def xtx3_setup(filename):
|
||||
"""Runs tests tte3, rta3."""
|
||||
kwargs = {'filename': filename,
|
||||
'codec': openjp2.CODEC_J2K,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 1,
|
||||
'num_comps': 1,
|
||||
'image_height': 256,
|
||||
'image_width': 256,
|
||||
'tile_height': 128,
|
||||
'tile_width': 128}
|
||||
tile_encoder(**kwargs)
|
||||
|
||||
def xtx4_setup(filename):
|
||||
"""Runs tests rta4, tte4."""
|
||||
kwargs = {'filename': filename,
|
||||
'codec': openjp2.CODEC_J2K,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 0,
|
||||
'num_comps': 1,
|
||||
'image_height': 256,
|
||||
'image_width': 256,
|
||||
'tile_height': 128,
|
||||
'tile_width': 128}
|
||||
tile_encoder(**kwargs)
|
||||
|
||||
def xtx5_setup(filename):
|
||||
"""Runs tests rta5, tte5."""
|
||||
kwargs = {'filename': filename,
|
||||
'codec': openjp2.CODEC_J2K,
|
||||
'comp_prec': 8,
|
||||
'irreversible': 0,
|
||||
'num_comps': 1,
|
||||
'image_height': 512,
|
||||
'image_width': 512,
|
||||
'tile_height': 256,
|
||||
'tile_width': 256}
|
||||
tile_encoder(**kwargs)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
#pylint: disable-all
|
||||
"""
|
||||
Tests for OpenJPEG module.
|
||||
"""
|
||||
# unittest2 is python2.6 only (pylint/python-2.7)
|
||||
# pylint: disable=F0401
|
||||
|
||||
# pylint: disable=E1101,R0904
|
||||
|
||||
import ctypes
|
||||
import re
|
||||
import sys
|
||||
|
|
@ -10,43 +17,38 @@ else:
|
|||
|
||||
import glymur
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib._openjpeg.OPENJPEG is None,
|
||||
@unittest.skipIf(glymur.lib.openjpeg.OPENJPEG is None,
|
||||
"Missing openjpeg library.")
|
||||
class TestOpenJPEG(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
"""Test suite for openjpeg functions we choose to expose."""
|
||||
|
||||
def test_version(self):
|
||||
version = glymur.lib._openjpeg.version()
|
||||
"""Only versions 1.3, 1.4, and 1.5 are supported."""
|
||||
version = glymur.lib.openjpeg.version()
|
||||
regex = re.compile('1.[345].[0-9]')
|
||||
if sys.hexversion <= 0x03020000:
|
||||
self.assertRegexpMatches(version, regex)
|
||||
else:
|
||||
self.assertRegex(version, regex)
|
||||
|
||||
def test_set_default_decoder_parameters(self):
|
||||
# Verify that we properly set the default decode parameters.
|
||||
version = glymur.lib._openjpeg.version()
|
||||
def test_default_decoder_parameters(self):
|
||||
"""Verify that we properly set the default decode parameters."""
|
||||
version = glymur.lib.openjpeg.version()
|
||||
minor = int(version.split('.')[1])
|
||||
|
||||
dp = glymur.lib._openjpeg.DecompressionParametersType()
|
||||
glymur.lib._openjpeg.set_default_decoder_parameters(ctypes.byref(dp))
|
||||
dcp = glymur.lib.openjpeg.DecompressionParametersType()
|
||||
glymur.lib.openjpeg.set_default_decoder_parameters(ctypes.byref(dcp))
|
||||
|
||||
self.assertEqual(dp.cp_reduce, 0)
|
||||
self.assertEqual(dp.cp_layer, 0)
|
||||
self.assertEqual(dp.infile, b'')
|
||||
self.assertEqual(dp.outfile, b'')
|
||||
self.assertEqual(dp.decod_format, -1)
|
||||
self.assertEqual(dp.cod_format, -1)
|
||||
self.assertEqual(dp.jpwl_correct, 0)
|
||||
self.assertEqual(dp.jpwl_exp_comps, 0)
|
||||
self.assertEqual(dp.jpwl_max_tiles, 0)
|
||||
self.assertEqual(dp.cp_limit_decoding, 0)
|
||||
self.assertEqual(dcp.cp_reduce, 0)
|
||||
self.assertEqual(dcp.cp_layer, 0)
|
||||
self.assertEqual(dcp.infile, b'')
|
||||
self.assertEqual(dcp.outfile, b'')
|
||||
self.assertEqual(dcp.decod_format, -1)
|
||||
self.assertEqual(dcp.cod_format, -1)
|
||||
self.assertEqual(dcp.jpwl_correct, 0)
|
||||
self.assertEqual(dcp.jpwl_exp_comps, 0)
|
||||
self.assertEqual(dcp.jpwl_max_tiles, 0)
|
||||
self.assertEqual(dcp.cp_limit_decoding, 0)
|
||||
if minor > 4:
|
||||
# Introduced in 1.5.x
|
||||
self.assertEqual(dp.flags, 0)
|
||||
self.assertEqual(dcp.flags, 0)
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ except ImportError:
|
|||
|
||||
def read_image(infile):
|
||||
"""Read image using matplotlib backend.
|
||||
|
||||
Hopefully PIL(low) is installed as matplotlib's backend. It issues
|
||||
|
||||
Hopefully PIL(low) is installed as matplotlib's backend. It issues
|
||||
warnings which we do not care about, so suppress them.
|
||||
"""
|
||||
with warnings.catch_warnings():
|
||||
|
|
@ -101,6 +101,7 @@ def read_pgx(pgx_file):
|
|||
|
||||
return(data.byteswap(swapbytes))
|
||||
|
||||
|
||||
def determine_pgx_datatype(signed, bitdepth):
|
||||
"""Determine the datatype of the PGX file.
|
||||
|
||||
|
|
@ -128,6 +129,7 @@ def determine_pgx_datatype(signed, bitdepth):
|
|||
|
||||
return dtype
|
||||
|
||||
|
||||
def read_pgx_header(pgx_file):
|
||||
"""Open the file in ascii mode (not really) and read the header line.
|
||||
Will look something like
|
||||
|
|
@ -150,4 +152,3 @@ def read_pgx_header(pgx_file):
|
|||
|
||||
header = header.rstrip()
|
||||
return header, pos
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
#pylint: disable-all
|
||||
"""
|
||||
Test suite for openjpeg's callback functions.
|
||||
"""
|
||||
# R0904: Seems like pylint is fooled in this situation
|
||||
# pylint: disable=R0904
|
||||
|
||||
# 'mock' most certainly is in unittest (Python 3.3)
|
||||
# pylint: disable=E0611,F0401
|
||||
|
||||
import os
|
||||
import pkg_resources
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
|
|
@ -24,6 +31,7 @@ import glymur
|
|||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestCallbacks(unittest.TestCase):
|
||||
"""Test suite for callbacks."""
|
||||
|
||||
def setUp(self):
|
||||
self.jp2file = glymur.data.nemo()
|
||||
|
|
@ -34,7 +42,7 @@ class TestCallbacks(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_info_callback_on_write(self):
|
||||
# Verify the messages printed when writing an image in verbose mode.
|
||||
"""Verify messages printed when writing an image in verbose mode."""
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
|
|
@ -47,12 +55,14 @@ class TestCallbacks(unittest.TestCase):
|
|||
expected = '[INFO] tile number 1 / 1'
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_info_warning_callbacks_on_read(self):
|
||||
def test_info_callbacks_on_read(self):
|
||||
"""stdio output when info callback handler is enabled"""
|
||||
|
||||
# Verify that we get the expected stdio output when our internal info
|
||||
# callback handler is enabled.
|
||||
j = glymur.Jp2k(self.j2kfile)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
d = j.read(rlevel=1, verbose=True, area=(0, 0, 200, 150))
|
||||
j.read(rlevel=1, verbose=True, area=(0, 0, 200, 150))
|
||||
actual = fake_out.getvalue().strip()
|
||||
|
||||
lines = ['[INFO] Start to read j2k main header (0).',
|
||||
|
|
@ -80,13 +90,16 @@ class TestCallbacks15(unittest.TestCase):
|
|||
pass
|
||||
|
||||
def test_info_callbacks_on_read(self):
|
||||
# Verify that we get the expected stdio output when our internal info
|
||||
# callback handler is enabled.
|
||||
"""Verify stdout when reading.
|
||||
|
||||
Verify that we get the expected stdio output when our internal info
|
||||
callback handler is enabled.
|
||||
"""
|
||||
with patch('glymur.lib.openjp2.OPENJP2', new=None):
|
||||
# Force to use OPENJPEG instead of OPENJP2.
|
||||
j = glymur.Jp2k(self.j2kfile)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
d = j.read(rlevel=1, verbose=True)
|
||||
j.read(rlevel=1, verbose=True)
|
||||
actual = fake_out.getvalue().strip()
|
||||
|
||||
regex = re.compile(r"""\[INFO\]\stile\s1\sof\s1\s+
|
||||
|
|
@ -97,6 +110,9 @@ class TestCallbacks15(unittest.TestCase):
|
|||
\[INFO\]\s-\stile\sdecoded\sin\s
|
||||
[0-9]+\.[0-9]+\ss""",
|
||||
re.VERBOSE)
|
||||
|
||||
# assertRegex in Python 3.3 (python2.7/pylint issue)
|
||||
# pylint: disable=E1101
|
||||
if sys.hexversion <= 0x03020000:
|
||||
self.assertRegexpMatches(actual, regex)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,16 @@
|
|||
#pylint: disable-all
|
||||
"""
|
||||
Test suite for codestream parsing.
|
||||
"""
|
||||
|
||||
# unittest doesn't work well with R0904.
|
||||
# pylint: disable=R0904
|
||||
|
||||
# tempfile.TemporaryDirectory, unittest.assertWarns introduced in 3.2
|
||||
# pylint: disable=E1101
|
||||
|
||||
# unittest2 is python2.6 only (pylint/python-2.7)
|
||||
# pylint: disable=F0401
|
||||
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
|
|
@ -9,23 +21,21 @@ if sys.hexversion < 0x02070000:
|
|||
else:
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
import pkg_resources
|
||||
|
||||
from glymur import Jp2k
|
||||
import glymur
|
||||
|
||||
try:
|
||||
data_root = os.environ['OPJ_DATA_ROOT']
|
||||
DATA_ROOT = os.environ['OPJ_DATA_ROOT']
|
||||
except KeyError:
|
||||
data_root = None
|
||||
DATA_ROOT = None
|
||||
except:
|
||||
raise
|
||||
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
class TestCodestream(unittest.TestCase):
|
||||
"""Test suite for unusual codestream cases."""
|
||||
|
||||
def setUp(self):
|
||||
self.jp2file = glymur.data.nemo()
|
||||
|
|
@ -35,75 +45,76 @@ class TestCodestream(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_reserved_marker_segment(self):
|
||||
"""Reserved marker segments are ok."""
|
||||
|
||||
# Some marker segments were reserved in FCD15444-1. Since that
|
||||
# standard is old, some of them may have come into use.
|
||||
#
|
||||
# Let's inject a reserved marker segment into a file that
|
||||
# we know something about to make sure we can still parse it.
|
||||
filename = os.path.join(data_root, 'input/conformance/p0_01.j2k')
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/p0_01.j2k')
|
||||
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
|
||||
with open(filename, 'rb') as ifile:
|
||||
# Everything up until the first QCD marker.
|
||||
buffer = ifile.read(45)
|
||||
tfile.write(buffer)
|
||||
read_buffer = ifile.read(45)
|
||||
tfile.write(read_buffer)
|
||||
|
||||
# Write the new marker segment, 0xff6f = 65391
|
||||
buffer = struct.pack('>HHB', int(65391), int(3), int(0))
|
||||
tfile.write(buffer)
|
||||
read_buffer = struct.pack('>HHB', int(65391), int(3), int(0))
|
||||
tfile.write(read_buffer)
|
||||
|
||||
# Get the rest of the input file.
|
||||
buffer = ifile.read()
|
||||
tfile.write(buffer)
|
||||
read_buffer = ifile.read()
|
||||
tfile.write(read_buffer)
|
||||
tfile.flush()
|
||||
|
||||
j = Jp2k(tfile.name)
|
||||
c = j.get_codestream()
|
||||
codestream = Jp2k(tfile.name).get_codestream()
|
||||
|
||||
self.assertEqual(c.segment[2].marker_id, '0xff6f')
|
||||
self.assertEqual(c.segment[2].length, 3)
|
||||
self.assertEqual(c.segment[2]._data, b'\x00')
|
||||
self.assertEqual(codestream.segment[2].marker_id, '0xff6f')
|
||||
self.assertEqual(codestream.segment[2].length, 3)
|
||||
self.assertEqual(codestream.segment[2].data, b'\x00')
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_unknown_marker_segment(self):
|
||||
"""Should warn for an unknown marker."""
|
||||
# Let's inject a marker segment whose marker does not appear to
|
||||
# be valid. We still parse the file, but warn about the offending
|
||||
# marker.
|
||||
filename = os.path.join(data_root, 'input/conformance/p0_01.j2k')
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/p0_01.j2k')
|
||||
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
|
||||
with open(filename, 'rb') as ifile:
|
||||
# Everything up until the first QCD marker.
|
||||
buffer = ifile.read(45)
|
||||
tfile.write(buffer)
|
||||
read_buffer = ifile.read(45)
|
||||
tfile.write(read_buffer)
|
||||
|
||||
# Write the new marker segment, 0xff79 = 65401
|
||||
buffer = struct.pack('>HHB', int(65401), int(3), int(0))
|
||||
tfile.write(buffer)
|
||||
read_buffer = struct.pack('>HHB', int(65401), int(3), int(0))
|
||||
tfile.write(read_buffer)
|
||||
|
||||
# Get the rest of the input file.
|
||||
buffer = ifile.read()
|
||||
tfile.write(buffer)
|
||||
read_buffer = ifile.read()
|
||||
tfile.write(read_buffer)
|
||||
tfile.flush()
|
||||
|
||||
with self.assertWarns(UserWarning):
|
||||
j = Jp2k(tfile.name)
|
||||
c = j.get_codestream()
|
||||
codestream = Jp2k(tfile.name).get_codestream()
|
||||
|
||||
self.assertEqual(c.segment[2].marker_id, '0xff79')
|
||||
self.assertEqual(c.segment[2].length, 3)
|
||||
self.assertEqual(c.segment[2]._data, b'\x00')
|
||||
self.assertEqual(codestream.segment[2].marker_id, '0xff79')
|
||||
self.assertEqual(codestream.segment[2].length, 3)
|
||||
self.assertEqual(codestream.segment[2].data, b'\x00')
|
||||
|
||||
def test_psot_is_zero(self):
|
||||
# Psot=0 in SOT is perfectly legal. Issue #78.
|
||||
filename = os.path.join(data_root,
|
||||
"""Psot=0 in SOT is perfectly legal. Issue #78."""
|
||||
filename = os.path.join(DATA_ROOT,
|
||||
'input/nonregression/123.j2c')
|
||||
j = Jp2k(filename)
|
||||
c = j.get_codestream(header_only=False)
|
||||
codestream = j.get_codestream(header_only=False)
|
||||
|
||||
# The codestream is valid, so we should be able to get the entire
|
||||
# codestream, so the last one is EOC.
|
||||
self.assertEqual(c.segment[-1].marker_id, 'EOC')
|
||||
self.assertEqual(codestream.segment[-1].marker_id, 'EOC')
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,15 @@
|
|||
"""These tests are for edge cases where OPENJPEG does not exist, but
|
||||
OPENJP2 may be present in some form or other.
|
||||
"""
|
||||
#pylint: disable-all
|
||||
# unittest doesn't work well with R0904.
|
||||
# pylint: disable=R0904
|
||||
|
||||
# tempfile.TemporaryDirectory, unittest.assertWarns introduced in 3.2
|
||||
# pylint: disable=E1101
|
||||
|
||||
# unittest.mock only in Python 3.3 (python2.7/pylint import issue)
|
||||
# pylint: disable=E0611,F0401
|
||||
|
||||
|
||||
import imp
|
||||
import os
|
||||
|
|
@ -17,13 +25,9 @@ if sys.hexversion <= 0x03030000:
|
|||
from mock import patch
|
||||
else:
|
||||
from unittest.mock import patch
|
||||
import warnings
|
||||
|
||||
import pkg_resources
|
||||
|
||||
import glymur
|
||||
from glymur import Jp2k
|
||||
from glymur.lib import openjp2 as opj2
|
||||
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
|
|
@ -31,6 +35,7 @@ from glymur.lib import openjp2 as opj2
|
|||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Needs openjp2 library first before these tests make sense.")
|
||||
class TestSuite(unittest.TestCase):
|
||||
"""Test suite for configuration file operation."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
|
@ -56,29 +61,33 @@ class TestSuite(unittest.TestCase):
|
|||
filename = os.path.join(configdir, 'glymurrc')
|
||||
with open(filename, 'wt') as tfile:
|
||||
tfile.write('[library]\n')
|
||||
|
||||
# Need to reliably recover the location of the openjp2 library,
|
||||
# so using '_name' appears to be the only way to do it.
|
||||
# pylint: disable=W0212
|
||||
libloc = glymur.lib.openjp2.OPENJP2._name
|
||||
line = 'openjp2: {0}\n'.format(libloc)
|
||||
tfile.write(line)
|
||||
tfile.flush()
|
||||
with patch.dict('os.environ', {'XDG_CONFIG_HOME': tdir}):
|
||||
imp.reload(glymur.lib.openjp2)
|
||||
j = Jp2k(self.jp2file)
|
||||
Jp2k(self.jp2file)
|
||||
|
||||
def test_config_file_via_environ_is_wrong(self):
|
||||
# A non-existant library location should be rejected.
|
||||
def test_xdg_env_config_file_is_bad(self):
|
||||
"""A non-existant library location should be rejected."""
|
||||
with tempfile.TemporaryDirectory() as tdir:
|
||||
configdir = os.path.join(tdir, 'glymur')
|
||||
os.mkdir(configdir)
|
||||
fname = os.path.join(configdir, 'glymurrc')
|
||||
with open(fname, 'w') as fp:
|
||||
with open(fname, 'w') as fptr:
|
||||
with tempfile.NamedTemporaryFile(suffix='.dylib') as tfile:
|
||||
fp.write('[library]\n')
|
||||
fp.write('openjp2: {0}.not.there\n'.format(tfile.name))
|
||||
fp.flush()
|
||||
fptr.write('[library]\n')
|
||||
fptr.write('openjp2: {0}.not.there\n'.format(tfile.name))
|
||||
fptr.flush()
|
||||
with patch.dict('os.environ', {'XDG_CONFIG_HOME': tdir}):
|
||||
# Misconfigured new configuration file should
|
||||
# be rejected.
|
||||
with self.assertWarns(UserWarning) as cw:
|
||||
with self.assertWarns(UserWarning):
|
||||
imp.reload(glymur.lib.openjp2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -1,9 +1,17 @@
|
|||
"""
|
||||
These tests deal with JPX/JP2/J2K images in the format-corpus repository.
|
||||
"""
|
||||
#pylint: disable-all
|
||||
# R0904: Not too many methods in unittest.
|
||||
# pylint: disable=R0904
|
||||
|
||||
# E1101: assertWarns introduced in python 3.2
|
||||
# pylint: disable=E1101
|
||||
|
||||
# unittest2 is python2.6 only (pylint/python-2.7)
|
||||
# pylint: disable=F0401
|
||||
|
||||
import os
|
||||
from os.path import join
|
||||
import sys
|
||||
|
||||
if sys.hexversion < 0x02070000:
|
||||
|
|
@ -11,106 +19,98 @@ if sys.hexversion < 0x02070000:
|
|||
else:
|
||||
import unittest
|
||||
|
||||
import warnings
|
||||
|
||||
from glymur import Jp2k
|
||||
import glymur
|
||||
|
||||
try:
|
||||
format_corpus_data_root = os.environ['FORMAT_CORPUS_DATA_ROOT']
|
||||
FORMAT_CORPUS_DATA_ROOT = os.environ['FORMAT_CORPUS_DATA_ROOT']
|
||||
except KeyError:
|
||||
format_corpus_data_root = None
|
||||
FORMAT_CORPUS_DATA_ROOT = None
|
||||
|
||||
try:
|
||||
opj_data_root = os.environ['OPJ_DATA_ROOT']
|
||||
OPJ_DATA_ROOT = os.environ['OPJ_DATA_ROOT']
|
||||
except KeyError:
|
||||
opj_data_root = None
|
||||
OPJ_DATA_ROOT = None
|
||||
|
||||
|
||||
@unittest.skipIf(format_corpus_data_root is None,
|
||||
@unittest.skipIf(FORMAT_CORPUS_DATA_ROOT is None,
|
||||
"FORMAT_CORPUS_DATA_ROOT environment variable not set")
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Requires features introduced in 3.2 (assertWarns)")
|
||||
class TestSuiteFormatCorpus(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
"""Test suite for files in format corpus repository."""
|
||||
|
||||
def test_balloon_trunc1(self):
|
||||
# Has one byte shaved off of EOC marker.
|
||||
jfile = os.path.join(format_corpus_data_root,
|
||||
"""Has one byte shaved off of EOC marker."""
|
||||
jfile = os.path.join(FORMAT_CORPUS_DATA_ROOT,
|
||||
'jp2k-test/byteCorruption/balloon_trunc1.jp2')
|
||||
j2k = Jp2k(jfile)
|
||||
with self.assertWarns(UserWarning):
|
||||
c = j2k.get_codestream(header_only=False)
|
||||
codestream = j2k.get_codestream(header_only=False)
|
||||
|
||||
# The last segment is truncated, so there should not be an EOC marker.
|
||||
self.assertNotEqual(c.segment[-1].marker_id, 'EOC')
|
||||
self.assertNotEqual(codestream.segment[-1].marker_id, 'EOC')
|
||||
|
||||
# The codestream is not as long as claimed.
|
||||
with self.assertRaises(OSError):
|
||||
j2k.read(rlevel=-1)
|
||||
|
||||
def test_balloon_trunc2(self):
|
||||
# Shortened by 5000 bytes.
|
||||
jfile = os.path.join(format_corpus_data_root,
|
||||
"""Shortened by 5000 bytes."""
|
||||
jfile = os.path.join(FORMAT_CORPUS_DATA_ROOT,
|
||||
'jp2k-test/byteCorruption/balloon_trunc2.jp2')
|
||||
j2k = Jp2k(jfile)
|
||||
with self.assertWarns(UserWarning):
|
||||
c = j2k.get_codestream(header_only=False)
|
||||
codestream = j2k.get_codestream(header_only=False)
|
||||
|
||||
# The last segment is truncated, so there should not be an EOC marker.
|
||||
self.assertNotEqual(c.segment[-1].marker_id, 'EOC')
|
||||
self.assertNotEqual(codestream.segment[-1].marker_id, 'EOC')
|
||||
|
||||
# The codestream is not as long as claimed.
|
||||
with self.assertRaises(OSError):
|
||||
j2k.read(rlevel=-1)
|
||||
|
||||
def test_balloon_trunc3(self):
|
||||
# Most of last tile is missing.
|
||||
jfile = os.path.join(format_corpus_data_root,
|
||||
"""Most of last tile is missing."""
|
||||
jfile = os.path.join(FORMAT_CORPUS_DATA_ROOT,
|
||||
'jp2k-test/byteCorruption/balloon_trunc3.jp2')
|
||||
j2k = Jp2k(jfile)
|
||||
with self.assertWarns(UserWarning):
|
||||
c = j2k.get_codestream(header_only=False)
|
||||
codestream = j2k.get_codestream(header_only=False)
|
||||
|
||||
# The last segment is truncated, so there should not be an EOC marker.
|
||||
self.assertNotEqual(c.segment[-1].marker_id, 'EOC')
|
||||
self.assertNotEqual(codestream.segment[-1].marker_id, 'EOC')
|
||||
|
||||
# Should error out, it does not.
|
||||
#with self.assertRaises(OSError):
|
||||
# j2k.read(rlevel=-1)
|
||||
|
||||
def test_jp2_brand_vs_any_icc_profile(self):
|
||||
# If 'jp2 ', then the method cannot be any icc profile.
|
||||
jfile = os.path.join(format_corpus_data_root,
|
||||
def test_jp2_brand_any_icc_profile(self):
|
||||
"""If 'jp2 ', then the method cannot be any icc profile."""
|
||||
jfile = os.path.join(FORMAT_CORPUS_DATA_ROOT,
|
||||
'jp2k-test', 'icc',
|
||||
'balloon_eciRGBv2_ps_adobeplugin.jpf')
|
||||
with self.assertWarns(UserWarning):
|
||||
j2k = Jp2k(jfile)
|
||||
Jp2k(jfile)
|
||||
|
||||
def test_jp2_brand_vs_any_icc_profile_multiple_colr(self):
|
||||
# Has colr box, one that conforms, one that does not.
|
||||
def test_jp2_brand_iccpr_mult_colr(self):
|
||||
"""Has colr box, one that conforms, one that does not."""
|
||||
|
||||
# Wrong 'brand' field; contains two versions of ICC profile: one
|
||||
# embedded using "Any ICC" method; other embedded using "Restricted
|
||||
# ICC" method, with description ("Modified eciRGB v2") and profileClass
|
||||
# ("Input Device") changed relative to original profile.
|
||||
lst = [format_corpus_data_root, 'jp2k-test', 'icc',
|
||||
'balloon_eciRGBv2_ps_adobeplugin_jp2compatible.jpf']
|
||||
jfile = os.path.join(*lst)
|
||||
jfile = join(FORMAT_CORPUS_DATA_ROOT, 'jp2k-test', 'icc',
|
||||
'balloon_eciRGBv2_ps_adobeplugin_jp2compatible.jpf')
|
||||
with self.assertWarns(UserWarning):
|
||||
j2k = Jp2k(jfile)
|
||||
Jp2k(jfile)
|
||||
|
||||
|
||||
@unittest.skipIf(opj_data_root is None,
|
||||
@unittest.skipIf(OPJ_DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Requires features introduced in 3.2 (assertWarns)")
|
||||
class TestSuiteOpj(unittest.TestCase):
|
||||
"""Test suite for files in openjpeg repository."""
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
|
@ -118,12 +118,12 @@ class TestSuiteOpj(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_jp2_brand_vs_any_icc_profile(self):
|
||||
# If 'jp2 ', then the method cannot be any icc profile.
|
||||
filename = os.path.join(opj_data_root,
|
||||
def test_jp2_brand_any_icc_profile(self):
|
||||
"""If 'jp2 ', then the method cannot be any icc profile."""
|
||||
filename = os.path.join(OPJ_DATA_ROOT,
|
||||
'input/nonregression/text_GBR.jp2')
|
||||
with self.assertWarns(UserWarning):
|
||||
j2k = Jp2k(filename)
|
||||
Jp2k(filename)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -1,35 +1,38 @@
|
|||
#pylint: disable-all
|
||||
"""
|
||||
ICC profile tests.
|
||||
"""
|
||||
|
||||
# unittest doesn't work well with R0904.
|
||||
# pylint: disable=R0904
|
||||
|
||||
# unittest2 is python2.6 only (pylint/python-2.7)
|
||||
# pylint: disable=F0401
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
if sys.hexversion < 0x02070000:
|
||||
import unittest2 as unittest
|
||||
else:
|
||||
import unittest
|
||||
|
||||
import warnings
|
||||
from xml.etree import cElementTree as ET
|
||||
|
||||
import numpy as np
|
||||
import pkg_resources
|
||||
|
||||
from glymur import Jp2k
|
||||
import glymur
|
||||
|
||||
try:
|
||||
data_root = os.environ['OPJ_DATA_ROOT']
|
||||
DATA_ROOT = os.environ['OPJ_DATA_ROOT']
|
||||
except KeyError:
|
||||
data_root = None
|
||||
DATA_ROOT = None
|
||||
except:
|
||||
raise
|
||||
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
class TestICC(unittest.TestCase):
|
||||
"""ICC profile tests"""
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
|
@ -38,7 +41,8 @@ class TestICC(unittest.TestCase):
|
|||
pass
|
||||
|
||||
def test_file5(self):
|
||||
filename = os.path.join(data_root, 'input/conformance/file5.jp2')
|
||||
"""basic ICC profile"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/file5.jp2')
|
||||
j = Jp2k(filename)
|
||||
profile = j.box[3].box[1].icc_profile
|
||||
self.assertEqual(profile['Size'], 546)
|
||||
|
|
@ -70,10 +74,14 @@ class TestICC(unittest.TestCase):
|
|||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
def test_invalid_profile_header(self):
|
||||
jfile = os.path.join(data_root,
|
||||
"""invalid ICC header data should cause UserWarning"""
|
||||
jfile = os.path.join(DATA_ROOT,
|
||||
'input/nonregression/orb-blue10-lin-jp2.jp2')
|
||||
with self.assertWarns(UserWarning) as cw:
|
||||
j = Jp2k(jfile)
|
||||
|
||||
# assertWarns in Python 3.3 (python2.7/pylint issue)
|
||||
# pylint: disable=E1101
|
||||
with self.assertWarns(UserWarning):
|
||||
Jp2k(jfile)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,21 @@
|
|||
#pylint: disable-all
|
||||
"""
|
||||
Test suite specifically targeting JP2 box layout.
|
||||
"""
|
||||
# E1103: return value from read may be list or np array
|
||||
# pylint: disable=E1103
|
||||
|
||||
# F0401: unittest2 is needed on python-2.6 (pylint on 2.7)
|
||||
# pylint: disable=F0401
|
||||
|
||||
# R0902: More than 7 instance attributes are just fine for testing.
|
||||
# pylint: disable=R0902
|
||||
|
||||
# R0904: Seems like pylint is fooled in this situation
|
||||
# pylint: disable=R0904
|
||||
|
||||
# W0613: load_tests doesn't need to use ignore or loader arguments.
|
||||
# pylint: disable=W0613
|
||||
|
||||
import doctest
|
||||
import os
|
||||
import sys
|
||||
|
|
@ -11,24 +28,25 @@ else:
|
|||
import unittest
|
||||
|
||||
import numpy as np
|
||||
import pkg_resources
|
||||
|
||||
import glymur
|
||||
from glymur import Jp2k
|
||||
from glymur.jp2box import *
|
||||
from glymur.jp2box import ColourSpecificationBox, ContiguousCodestreamBox
|
||||
from glymur.jp2box import FileTypeBox, ImageHeaderBox, JP2HeaderBox
|
||||
from glymur.jp2box import JPEG2000SignatureBox
|
||||
from glymur.core import COLOR, OPACITY
|
||||
from glymur.core import RED, GREEN, BLUE, GREY, WHOLE_IMAGE
|
||||
|
||||
from .fixtures import OPENJP2_IS_V2_OFFICIAL
|
||||
|
||||
try:
|
||||
format_corpus_data_root = os.environ['FORMAT_CORPUS_DATA_ROOT']
|
||||
FORMAT_CORPUS_DATA_ROOT = os.environ['FORMAT_CORPUS_DATA_ROOT']
|
||||
except KeyError:
|
||||
format_corpus_data_root = None
|
||||
FORMAT_CORPUS_DATA_ROOT = None
|
||||
|
||||
|
||||
# Doc tests should be run as well.
|
||||
def load_tests(loader, tests, ignore):
|
||||
"""Run doc tests as well."""
|
||||
if os.name == "nt":
|
||||
# Can't do it on windows, temporary file issue.
|
||||
return tests
|
||||
|
|
@ -42,6 +60,7 @@ def load_tests(loader, tests, ignore):
|
|||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestChannelDefinition(unittest.TestCase):
|
||||
"""Test suite for channel definition boxes."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
|
@ -78,12 +97,12 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
self.j2kfile = glymur.data.goodstuff()
|
||||
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
codestream = j2k.get_codestream()
|
||||
height = codestream.segment[1].ysiz
|
||||
width = codestream.segment[1].xsiz
|
||||
num_components = len(codestream.segment[1].xrsiz)
|
||||
|
||||
self.jP = JPEG2000SignatureBox()
|
||||
self.jp2b = JPEG2000SignatureBox()
|
||||
self.ftyp = FileTypeBox()
|
||||
self.jp2h = JP2HeaderBox()
|
||||
self.jp2c = ContiguousCodestreamBox()
|
||||
|
|
@ -110,7 +129,7 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
association=association)
|
||||
boxes = [self.ihdr, self.colr_rgb, cdef]
|
||||
self.jp2h.box = boxes
|
||||
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
|
||||
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
|
|
@ -133,7 +152,7 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
association=association)
|
||||
boxes = [self.ihdr, self.colr_rgb, cdef]
|
||||
self.jp2h.box = boxes
|
||||
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
|
||||
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
|
|
@ -156,7 +175,7 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
association=association)
|
||||
boxes = [self.ihdr, self.colr_rgb, cdef]
|
||||
self.jp2h.box = boxes
|
||||
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
|
||||
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
|
|
@ -177,9 +196,9 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
association=association)
|
||||
boxes = [self.ihdr, self.colr_rgb, cdef]
|
||||
self.jp2h.box = boxes
|
||||
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
|
||||
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
with self.assertRaises(IOError) as ce:
|
||||
with self.assertRaises(IOError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
def test_grey(self):
|
||||
|
|
@ -191,7 +210,7 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
association=association)
|
||||
boxes = [self.ihdr, self.colr_gr, cdef]
|
||||
self.jp2h.box = boxes
|
||||
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
|
||||
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
|
|
@ -212,7 +231,7 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
association=association)
|
||||
boxes = [self.ihdr, self.colr_gr, cdef]
|
||||
self.jp2h.box = boxes
|
||||
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
|
||||
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
|
|
@ -236,12 +255,12 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
association=association)
|
||||
boxes = [self.ihdr, self.colr_gr, cdef]
|
||||
self.jp2h.box = boxes
|
||||
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
|
||||
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
with self.assertRaises((OSError, IOError)) as ce:
|
||||
with self.assertRaises((OSError, IOError)):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
def test_only_one_cdef_in_jp2_header(self):
|
||||
def test_only_one_cdef_in_jp2h(self):
|
||||
"""There can only be one channel definition box in the jp2 header."""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
|
||||
|
|
@ -253,13 +272,14 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
boxes = [self.ihdr, cdef, self.colr_rgb, cdef]
|
||||
self.jp2h.box = boxes
|
||||
|
||||
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
|
||||
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
with self.assertRaises(IOError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
def test_not_in_jp2_header(self):
|
||||
def test_not_in_jp2h(self):
|
||||
"""need cdef in jp2h"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
boxes = [self.ihdr, self.colr_rgb]
|
||||
self.jp2h.box = boxes
|
||||
|
|
@ -269,34 +289,37 @@ class TestChannelDefinition(unittest.TestCase):
|
|||
cdef = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
|
||||
association=association)
|
||||
|
||||
boxes = [self.jP, self.ftyp, self.jp2h, cdef, self.jp2c]
|
||||
boxes = [self.jp2b, self.ftyp, self.jp2h, cdef, self.jp2c]
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
with self.assertRaises(IOError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
def test_bad_type(self):
|
||||
# Channel types are limited to 0, 1, 2, 65535
|
||||
# Should reject if not all of index, channel_type, association the
|
||||
# same length.
|
||||
"""Channel types are limited to 0, 1, 2, 65535
|
||||
Should reject if not all of index, channel_type, association the
|
||||
same length.
|
||||
"""
|
||||
channel_type = (COLOR, COLOR, 3)
|
||||
association = (RED, GREEN, BLUE)
|
||||
with self.assertRaises(IOError):
|
||||
box = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
|
||||
association=association)
|
||||
glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
|
||||
association=association)
|
||||
|
||||
def test_wrong_lengths(self):
|
||||
# Should reject if not all of index, channel_type, association the
|
||||
# same length.
|
||||
"""Should reject if not all of index, channel_type, association the
|
||||
same length.
|
||||
"""
|
||||
channel_type = (COLOR, COLOR)
|
||||
association = (RED, GREEN, BLUE)
|
||||
with self.assertRaises(IOError):
|
||||
box = glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
|
||||
association=association)
|
||||
glymur.jp2box.ChannelDefinitionBox(channel_type=channel_type,
|
||||
association=association)
|
||||
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
class TestXML(unittest.TestCase):
|
||||
"""Test suite for XML boxes."""
|
||||
|
||||
def setUp(self):
|
||||
self.jp2file = glymur.data.nemo()
|
||||
|
|
@ -331,12 +354,12 @@ class TestXML(unittest.TestCase):
|
|||
self.xmlfile = tfile.name
|
||||
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
codestream = j2k.get_codestream()
|
||||
height = codestream.segment[1].ysiz
|
||||
width = codestream.segment[1].xsiz
|
||||
num_components = len(codestream.segment[1].xrsiz)
|
||||
|
||||
self.jP = JPEG2000SignatureBox()
|
||||
self.jp2b = JPEG2000SignatureBox()
|
||||
self.ftyp = FileTypeBox()
|
||||
self.jp2h = JP2HeaderBox()
|
||||
self.jp2c = ContiguousCodestreamBox()
|
||||
|
|
@ -346,19 +369,17 @@ class TestXML(unittest.TestCase):
|
|||
|
||||
def tearDown(self):
|
||||
os.unlink(self.xmlfile)
|
||||
pass
|
||||
|
||||
def test_negative_both_file_and_xml_provided(self):
|
||||
def test_negative_file_and_xml(self):
|
||||
"""The XML should come from only one source."""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
xml_object = ET.parse(self.xmlfile)
|
||||
with self.assertRaises((IOError, OSError)) as ce:
|
||||
xmlb = glymur.jp2box.XMLBox(filename=self.xmlfile, xml=xml_object)
|
||||
with self.assertRaises((IOError, OSError)):
|
||||
glymur.jp2box.XMLBox(filename=self.xmlfile, xml=xml_object)
|
||||
|
||||
@unittest.skipIf(os.name == "nt",
|
||||
"Problems using NamedTemporaryFile on windows.")
|
||||
def test_basic_xml(self):
|
||||
# Should be able to write an XMLBox.
|
||||
"""Should be able to write a basic XMLBox"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
|
||||
self.jp2h.box = [self.ihdr, self.colr]
|
||||
|
|
@ -368,7 +389,7 @@ class TestXML(unittest.TestCase):
|
|||
self.assertEqual(ET.tostring(xmlb.xml),
|
||||
b'<data>0</data>')
|
||||
|
||||
boxes = [self.jP, self.ftyp, self.jp2h, xmlb, self.jp2c]
|
||||
boxes = [self.jp2b, self.ftyp, self.jp2h, xmlb, self.jp2c]
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
|
@ -380,12 +401,13 @@ class TestXML(unittest.TestCase):
|
|||
@unittest.skipIf(os.name == "nt",
|
||||
"Problems using NamedTemporaryFile on windows.")
|
||||
def test_xml_from_file(self):
|
||||
"""Must be able to create an XML box from an XML file."""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
|
||||
self.jp2h.box = [self.ihdr, self.colr]
|
||||
|
||||
xmlb = glymur.jp2box.XMLBox(filename=self.xmlfile)
|
||||
boxes = [self.jP, self.ftyp, self.jp2h, xmlb, self.jp2c]
|
||||
boxes = [self.jp2b, self.ftyp, self.jp2h, xmlb, self.jp2c]
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
jp2 = Jp2k(tfile.name)
|
||||
|
|
@ -403,17 +425,18 @@ class TestXML(unittest.TestCase):
|
|||
|
||||
|
||||
class TestColourSpecificationBox(unittest.TestCase):
|
||||
"""Test suite for colr box instantiation."""
|
||||
|
||||
def setUp(self):
|
||||
self.j2kfile = glymur.data.goodstuff()
|
||||
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
codestream = j2k.get_codestream()
|
||||
height = codestream.segment[1].ysiz
|
||||
width = codestream.segment[1].xsiz
|
||||
num_components = len(codestream.segment[1].xrsiz)
|
||||
|
||||
self.jP = JPEG2000SignatureBox()
|
||||
self.jp2b = JPEG2000SignatureBox()
|
||||
self.ftyp = FileTypeBox()
|
||||
self.jp2h = JP2HeaderBox()
|
||||
self.jp2c = ContiguousCodestreamBox()
|
||||
|
|
@ -425,10 +448,11 @@ class TestColourSpecificationBox(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(os.name == "nt",
|
||||
"Problems using NamedTemporaryFile on windows.")
|
||||
def test_color_specification_box_with_out_enumerated_colorspace(self):
|
||||
def test_colr_with_out_enum_cspace(self):
|
||||
"""must supply an enumerated colorspace when writing"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
|
||||
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
|
||||
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
|
||||
boxes[2].box = [self.ihdr, ColourSpecificationBox(colorspace=None)]
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
with self.assertRaises(NotImplementedError):
|
||||
|
|
@ -436,47 +460,52 @@ class TestColourSpecificationBox(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_missing_colr_box(self):
|
||||
"""jp2h must have a colr box"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
boxes = [self.jP, self.ftyp, self.jp2h, self.jp2c]
|
||||
boxes = [self.jp2b, self.ftyp, self.jp2h, self.jp2c]
|
||||
boxes[2].box = [self.ihdr]
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
with self.assertRaises(IOError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
def test_default_ColourSpecificationBox(self):
|
||||
b = glymur.jp2box.ColourSpecificationBox(colorspace=glymur.core.SRGB)
|
||||
self.assertEqual(b.method, glymur.core.ENUMERATED_COLORSPACE)
|
||||
self.assertEqual(b.precedence, 0)
|
||||
self.assertEqual(b.approximation, 0)
|
||||
self.assertEqual(b.colorspace, glymur.core.SRGB)
|
||||
self.assertIsNone(b.icc_profile)
|
||||
def test_default_colr(self):
|
||||
"""basic colr instantiation"""
|
||||
colr = ColourSpecificationBox(colorspace=glymur.core.SRGB)
|
||||
self.assertEqual(colr.method, glymur.core.ENUMERATED_COLORSPACE)
|
||||
self.assertEqual(colr.precedence, 0)
|
||||
self.assertEqual(colr.approximation, 0)
|
||||
self.assertEqual(colr.colorspace, glymur.core.SRGB)
|
||||
self.assertIsNone(colr.icc_profile)
|
||||
|
||||
def test_ColourSpecificationBox_with_colorspace_and_icc(self):
|
||||
# Colour specification boxes can't have both.
|
||||
def test_colr_with_cspace_and_icc(self):
|
||||
"""Colour specification boxes can't have both."""
|
||||
with self.assertRaises((OSError, IOError)):
|
||||
colorspace = glymur.core.SRGB
|
||||
icc_profile = b'\x01\x02\x03\x04'
|
||||
b = glymur.jp2box.ColourSpecificationBox(colorspace=colorspace,
|
||||
icc_profile=icc_profile)
|
||||
rawb = b'\x01\x02\x03\x04'
|
||||
glymur.jp2box.ColourSpecificationBox(colorspace=colorspace,
|
||||
icc_profile=rawb)
|
||||
|
||||
def test_ColourSpecificationBox_with_bad_method(self):
|
||||
def test_colr_with_bad_method(self):
|
||||
"""colr must have a valid method field"""
|
||||
colorspace = glymur.core.SRGB
|
||||
method = -1
|
||||
with self.assertRaises(IOError):
|
||||
b = glymur.jp2box.ColourSpecificationBox(colorspace=colorspace,
|
||||
method=method)
|
||||
glymur.jp2box.ColourSpecificationBox(colorspace=colorspace,
|
||||
method=method)
|
||||
|
||||
def test_ColourSpecificationBox_with_bad_approximation(self):
|
||||
def test_colr_with_bad_approx(self):
|
||||
"""colr must have a valid approximation field"""
|
||||
colorspace = glymur.core.SRGB
|
||||
approx = -1
|
||||
with self.assertRaises(IOError):
|
||||
b = glymur.jp2box.ColourSpecificationBox(colorspace=colorspace,
|
||||
approximation=approx)
|
||||
glymur.jp2box.ColourSpecificationBox(colorspace=colorspace,
|
||||
approximation=approx)
|
||||
|
||||
|
||||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestWrap(unittest.TestCase):
|
||||
"""Tests for wrap method."""
|
||||
|
||||
def setUp(self):
|
||||
self.j2kfile = glymur.data.goodstuff()
|
||||
|
|
@ -486,7 +515,7 @@ class TestWrap(unittest.TestCase):
|
|||
pass
|
||||
|
||||
def verify_wrapped_raw(self, jp2file):
|
||||
# Shared method by at least two tests.
|
||||
"""Shared fixture"""
|
||||
jp2 = Jp2k(jp2file)
|
||||
self.assertEqual(len(jp2.box), 4)
|
||||
|
||||
|
|
@ -536,6 +565,7 @@ class TestWrap(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_wrap(self):
|
||||
"""basic test for rewrapping a j2c file, no specified boxes"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
j2k.wrap(tfile.name)
|
||||
|
|
@ -543,6 +573,7 @@ class TestWrap(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_wrap_jp2(self):
|
||||
"""basic test for rewrapping a jp2 file, no specified boxes"""
|
||||
j2k = Jp2k(self.jp2file)
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
jp2 = j2k.wrap(tfile.name)
|
||||
|
|
@ -550,16 +581,17 @@ class TestWrap(unittest.TestCase):
|
|||
self.assertEqual(boxes, ['jP ', 'ftyp', 'jp2h', 'jp2c'])
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_default_layout_but_with_specified_boxes(self):
|
||||
def test_default_layout_with_boxes(self):
|
||||
"""basic test for rewrapping a jp2 file, boxes specified"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
boxes = [JPEG2000SignatureBox(),
|
||||
FileTypeBox(),
|
||||
JP2HeaderBox(),
|
||||
ContiguousCodestreamBox()]
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
codestream = j2k.get_codestream()
|
||||
height = codestream.segment[1].ysiz
|
||||
width = codestream.segment[1].xsiz
|
||||
num_components = len(codestream.segment[1].xrsiz)
|
||||
boxes[2].box = [ImageHeaderBox(height=height,
|
||||
width=width,
|
||||
num_components=num_components),
|
||||
|
|
@ -569,17 +601,17 @@ class TestWrap(unittest.TestCase):
|
|||
self.verify_wrapped_raw(tfile.name)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_image_header_box_not_first_in_jp2_header(self):
|
||||
# The specification says that ihdr must be the first box in jp2h.
|
||||
def test_ihdr_not_first_in_jp2h(self):
|
||||
"""The specification says that ihdr must be the first box in jp2h."""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
boxes = [JPEG2000SignatureBox(),
|
||||
FileTypeBox(),
|
||||
JP2HeaderBox(),
|
||||
ContiguousCodestreamBox()]
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
codestream = j2k.get_codestream()
|
||||
height = codestream.segment[1].ysiz
|
||||
width = codestream.segment[1].xsiz
|
||||
num_components = len(codestream.segment[1].xrsiz)
|
||||
boxes[2].box = [ColourSpecificationBox(colorspace=glymur.core.SRGB),
|
||||
ImageHeaderBox(height=height,
|
||||
width=width,
|
||||
|
|
@ -589,14 +621,15 @@ class TestWrap(unittest.TestCase):
|
|||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_first_2_boxes_not_jP_and_ftyp(self):
|
||||
def test_first_boxes_jp_and_ftyp(self):
|
||||
"""first two boxes must be jP followed by ftyp"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
codestream = j2k.get_codestream()
|
||||
height = codestream.segment[1].ysiz
|
||||
width = codestream.segment[1].xsiz
|
||||
num_components = len(codestream.segment[1].xrsiz)
|
||||
|
||||
jP = JPEG2000SignatureBox()
|
||||
jp2b = JPEG2000SignatureBox()
|
||||
ftyp = FileTypeBox()
|
||||
jp2h = JP2HeaderBox()
|
||||
jp2c = ContiguousCodestreamBox()
|
||||
|
|
@ -604,20 +637,21 @@ class TestWrap(unittest.TestCase):
|
|||
ihdr = ImageHeaderBox(height=height, width=width,
|
||||
num_components=num_components)
|
||||
jp2h.box = [ihdr, colr]
|
||||
boxes = [ftyp, jP, jp2h, jp2c]
|
||||
boxes = [ftyp, jp2b, jp2h, jp2c]
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
with self.assertRaises(IOError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_jp2h_not_preceeding_jp2c(self):
|
||||
"""jp2h must precede jp2c"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
codestream = j2k.get_codestream()
|
||||
height = codestream.segment[1].ysiz
|
||||
width = codestream.segment[1].xsiz
|
||||
num_components = len(codestream.segment[1].xrsiz)
|
||||
|
||||
jP = JPEG2000SignatureBox()
|
||||
jp2b = JPEG2000SignatureBox()
|
||||
ftyp = FileTypeBox()
|
||||
jp2h = JP2HeaderBox()
|
||||
jp2c = ContiguousCodestreamBox()
|
||||
|
|
@ -625,68 +659,74 @@ class TestWrap(unittest.TestCase):
|
|||
ihdr = ImageHeaderBox(height=height, width=width,
|
||||
num_components=num_components)
|
||||
jp2h.box = [ihdr, colr]
|
||||
boxes = [jP, ftyp, jp2c, jp2h]
|
||||
boxes = [jp2b, ftyp, jp2c, jp2h]
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
with self.assertRaises(IOError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_missing_codestream(self):
|
||||
"""Need a codestream box in order to call wrap method."""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
c = j2k.get_codestream()
|
||||
height = c.segment[1].ysiz
|
||||
width = c.segment[1].xsiz
|
||||
num_components = len(c.segment[1].xrsiz)
|
||||
codestream = j2k.get_codestream()
|
||||
height = codestream.segment[1].ysiz
|
||||
width = codestream.segment[1].xsiz
|
||||
num_components = len(codestream.segment[1].xrsiz)
|
||||
|
||||
jP = JPEG2000SignatureBox()
|
||||
jp2k = JPEG2000SignatureBox()
|
||||
ftyp = FileTypeBox()
|
||||
jp2h = JP2HeaderBox()
|
||||
ihdr = ImageHeaderBox(height=height, width=width,
|
||||
num_components=num_components)
|
||||
jp2h.box = [ihdr]
|
||||
boxes = [jP, ftyp, jp2h]
|
||||
boxes = [jp2k, ftyp, jp2h]
|
||||
with tempfile.NamedTemporaryFile(suffix=".jp2") as tfile:
|
||||
with self.assertRaises(IOError):
|
||||
j2k.wrap(tfile.name, boxes=boxes)
|
||||
|
||||
|
||||
class TestJp2Boxes(unittest.TestCase):
|
||||
"""Tests for canonical JP2 boxes."""
|
||||
|
||||
def test_default_JPEG2000SignatureBox(self):
|
||||
# Should be able to instantiate a JPEG2000SignatureBox
|
||||
b = glymur.jp2box.JPEG2000SignatureBox()
|
||||
self.assertEqual(b.signature, (13, 10, 135, 10))
|
||||
def test_default_jp2k(self):
|
||||
"""Should be able to instantiate a JPEG2000SignatureBox"""
|
||||
jp2k = glymur.jp2box.JPEG2000SignatureBox()
|
||||
self.assertEqual(jp2k.signature, (13, 10, 135, 10))
|
||||
|
||||
def test_default_FileTypeBox(self):
|
||||
# Should be able to instantiate a FileTypeBox
|
||||
b = glymur.jp2box.FileTypeBox()
|
||||
self.assertEqual(b.brand, 'jp2 ')
|
||||
self.assertEqual(b.minor_version, 0)
|
||||
self.assertEqual(b.compatibility_list, ['jp2 '])
|
||||
def test_default_ftyp(self):
|
||||
"""Should be able to instantiate a FileTypeBox"""
|
||||
ftyp = glymur.jp2box.FileTypeBox()
|
||||
self.assertEqual(ftyp.brand, 'jp2 ')
|
||||
self.assertEqual(ftyp.minor_version, 0)
|
||||
self.assertEqual(ftyp.compatibility_list, ['jp2 '])
|
||||
|
||||
def test_default_ImageHeaderBox(self):
|
||||
# Should be able to instantiate an image header box.
|
||||
b = glymur.jp2box.ImageHeaderBox(height=512, width=256,
|
||||
def test_default_ihdr(self):
|
||||
"""Should be able to instantiate an image header box."""
|
||||
ihdr = glymur.jp2box.ImageHeaderBox(height=512, width=256,
|
||||
num_components=3)
|
||||
self.assertEqual(b.height, 512)
|
||||
self.assertEqual(b.width, 256)
|
||||
self.assertEqual(b.num_components, 3)
|
||||
self.assertEqual(b.bits_per_component, 8)
|
||||
self.assertFalse(b.signed)
|
||||
self.assertFalse(b.colorspace_unknown)
|
||||
self.assertEqual(ihdr.height, 512)
|
||||
self.assertEqual(ihdr.width, 256)
|
||||
self.assertEqual(ihdr.num_components, 3)
|
||||
self.assertEqual(ihdr.bits_per_component, 8)
|
||||
self.assertFalse(ihdr.signed)
|
||||
self.assertFalse(ihdr.colorspace_unknown)
|
||||
|
||||
def test_default_JP2HeaderBox(self):
|
||||
b1 = JP2HeaderBox()
|
||||
b1.box = [ImageHeaderBox(height=512, width=256),
|
||||
def test_default_jp2headerbox(self):
|
||||
"""Should be able to set jp2h boxes."""
|
||||
box = JP2HeaderBox()
|
||||
box.box = [ImageHeaderBox(height=512, width=256),
|
||||
ColourSpecificationBox(colorspace=glymur.core.GREYSCALE)]
|
||||
self.assertTrue(True)
|
||||
|
||||
def test_default_ContiguousCodestreamBox(self):
|
||||
b = ContiguousCodestreamBox()
|
||||
self.assertEqual(b.box_id, 'jp2c')
|
||||
self.assertIsNone(b.main_header)
|
||||
def test_default_ccodestreambox(self):
|
||||
"""Raw instantiation should not produce a main_header."""
|
||||
box = ContiguousCodestreamBox()
|
||||
self.assertEqual(box.box_id, 'jp2c')
|
||||
self.assertIsNone(box.main_header)
|
||||
|
||||
|
||||
class TestJpxBoxes(unittest.TestCase):
|
||||
"""Tests for JPX boxes."""
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
|
@ -694,11 +734,11 @@ class TestJpxBoxes(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
pass
|
||||
|
||||
@unittest.skipIf(format_corpus_data_root is None,
|
||||
@unittest.skipIf(FORMAT_CORPUS_DATA_ROOT is None,
|
||||
"FORMAT_CORPUS_DATA_ROOT environment variable not set")
|
||||
def test_codestream_header(self):
|
||||
# Should recognize codestream header box.
|
||||
jfile = os.path.join(format_corpus_data_root,
|
||||
"""Should recognize codestream header box."""
|
||||
jfile = os.path.join(FORMAT_CORPUS_DATA_ROOT,
|
||||
'jp2k-formats/balloon.jpf')
|
||||
jpx = Jp2k(jfile)
|
||||
|
||||
|
|
@ -706,11 +746,11 @@ class TestJpxBoxes(unittest.TestCase):
|
|||
self.assertEqual(jpx.box[4].box_id, 'jpch')
|
||||
self.assertEqual(len(jpx.box[4].box), 0)
|
||||
|
||||
@unittest.skipIf(format_corpus_data_root is None,
|
||||
@unittest.skipIf(FORMAT_CORPUS_DATA_ROOT is None,
|
||||
"FORMAT_CORPUS_DATA_ROOT environment variable not set")
|
||||
def test_compositing_layer_header(self):
|
||||
# Should recognize compositing layer header box.
|
||||
jfile = os.path.join(format_corpus_data_root,
|
||||
"""Should recognize compositing layer header box."""
|
||||
jfile = os.path.join(FORMAT_CORPUS_DATA_ROOT,
|
||||
'jp2k-formats/balloon.jpf')
|
||||
jpx = Jp2k(jfile)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,15 @@
|
|||
# pylint: disable-all
|
||||
"""
|
||||
Tests for general glymur functionality.
|
||||
"""
|
||||
# E1101: assertWarns introduced in python 3.2
|
||||
# pylint: disable=E1101
|
||||
|
||||
# R0904: Not too many methods in unittest.
|
||||
# pylint: disable=R0904
|
||||
|
||||
# E0611: unittest.mock is unknown to python2.7/pylint
|
||||
# pylint: disable=E0611,F0401
|
||||
|
||||
import doctest
|
||||
import os
|
||||
import re
|
||||
|
|
@ -25,20 +36,24 @@ import pkg_resources
|
|||
|
||||
import glymur
|
||||
from glymur import Jp2k
|
||||
from glymur.lib import openjp2 as opj2
|
||||
|
||||
from .fixtures import OPENJP2_IS_V2_OFFICIAL
|
||||
|
||||
try:
|
||||
data_root = os.environ['OPJ_DATA_ROOT']
|
||||
DATA_ROOT = os.environ['OPJ_DATA_ROOT']
|
||||
except KeyError:
|
||||
data_root = None
|
||||
DATA_ROOT = None
|
||||
except:
|
||||
raise
|
||||
|
||||
|
||||
# Doc tests should be run as well.
|
||||
def load_tests(loader, tests, ignore):
|
||||
# W0613: "loader" and "ignore" are necessary for the protocol
|
||||
# They are unused here, however.
|
||||
# pylint: disable=W0613
|
||||
|
||||
"""Should run doc tests as well"""
|
||||
if os.name == "nt":
|
||||
# Can't do it on windows, temporary file issue.
|
||||
return tests
|
||||
|
|
@ -54,6 +69,7 @@ def load_tests(loader, tests, ignore):
|
|||
glymur.lib.openjpeg.OPENJPEG is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestConfig(unittest.TestCase):
|
||||
"""Test suite for reading without proper library in place."""
|
||||
|
||||
def setUp(self):
|
||||
self.jp2file = glymur.data.nemo()
|
||||
|
|
@ -62,24 +78,24 @@ class TestConfig(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_read_without_library_backing_us_up(self):
|
||||
def test_read_without_library(self):
|
||||
"""Don't have either openjp2 or openjpeg libraries? Must error out.
|
||||
"""
|
||||
with patch('glymur.lib.openjp2.OPENJP2', new=None):
|
||||
with patch('glymur.lib.openjpeg.OPENJPEG', new=None):
|
||||
with self.assertRaises(glymur.jp2k.LibraryNotFoundError):
|
||||
d = glymur.Jp2k(self.jp2file).read()
|
||||
glymur.Jp2k(self.jp2file).read()
|
||||
|
||||
def test_read_bands_without_library_backing_us_up(self):
|
||||
def test_read_bands_without_library(self):
|
||||
"""Don't have openjp2 library? Must error out.
|
||||
"""
|
||||
with patch('glymur.lib.openjp2.OPENJP2', new=None):
|
||||
with patch('glymur.lib.openjpeg.OPENJPEG', new=None):
|
||||
with self.assertRaises(glymur.jp2k.LibraryNotFoundError):
|
||||
d = glymur.Jp2k(self.jp2file).read_bands()
|
||||
glymur.Jp2k(self.jp2file).read_bands()
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_write_without_library_backing_us_up(self):
|
||||
def test_write_without_library(self):
|
||||
"""Don't have openjp2 library? Must error out.
|
||||
"""
|
||||
data = glymur.Jp2k(self.j2kfile).read()
|
||||
|
|
@ -95,32 +111,34 @@ class TestConfig(unittest.TestCase):
|
|||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestJp2kBadXmlFile(unittest.TestCase):
|
||||
"""Test suite for bad XML box situations"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# Setup a JP2 file with a bad XML box. We only need to do this once
|
||||
# per class rather than once per test.
|
||||
"""Setup a JP2 file with a bad XML box. We only need to do this once
|
||||
per class rather than once per test.
|
||||
"""
|
||||
jp2file = pkg_resources.resource_filename(glymur.__name__,
|
||||
"data/nemo.jp2")
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2', delete=False) as tfile:
|
||||
cls._bad_xml_file = tfile.name
|
||||
with open(jp2file, 'rb') as ifile:
|
||||
# Everything up until the jp2c box.
|
||||
buffer = ifile.read(77)
|
||||
tfile.write(buffer)
|
||||
write_buffer = ifile.read(77)
|
||||
tfile.write(write_buffer)
|
||||
|
||||
# Write the xml box with bad xml
|
||||
# Length = 28, id is 'xml '.
|
||||
buffer = struct.pack('>I4s', int(28), b'xml ')
|
||||
tfile.write(buffer)
|
||||
write_buffer = struct.pack('>I4s', int(28), b'xml ')
|
||||
tfile.write(write_buffer)
|
||||
|
||||
buffer = '<test>this is a test'
|
||||
buffer = buffer.encode()
|
||||
tfile.write(buffer)
|
||||
write_buffer = '<test>this is a test'
|
||||
write_buffer = write_buffer.encode()
|
||||
tfile.write(write_buffer)
|
||||
|
||||
# Get the rest of the input file.
|
||||
buffer = ifile.read()
|
||||
tfile.write(buffer)
|
||||
write_buffer = ifile.read()
|
||||
tfile.write(write_buffer)
|
||||
tfile.flush()
|
||||
|
||||
@classmethod
|
||||
|
|
@ -137,13 +155,12 @@ class TestJp2kBadXmlFile(unittest.TestCase):
|
|||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
def test_invalid_xml_box_warning(self):
|
||||
# Should be able to recover from xml box with bad xml.
|
||||
# Just verify that a warning is issued on 3.3+
|
||||
with self.assertWarns(UserWarning) as cw:
|
||||
jp2k = Jp2k(self._bad_xml_file)
|
||||
"""Should warn in case of bad XML"""
|
||||
with self.assertWarns(UserWarning):
|
||||
Jp2k(self._bad_xml_file)
|
||||
|
||||
def test_invalid_xml_box(self):
|
||||
# Should be able to recover from xml box with bad xml.
|
||||
"""Should be able to recover info from xml box with bad xml."""
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
jp2k = Jp2k(self._bad_xml_file)
|
||||
|
|
@ -157,6 +174,7 @@ class TestJp2kBadXmlFile(unittest.TestCase):
|
|||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
class TestJp2k(unittest.TestCase):
|
||||
"""Test suite for version 2.0/2.0+ of openjpeg"""
|
||||
|
||||
def setUp(self):
|
||||
self.jp2file = glymur.data.nemo()
|
||||
|
|
@ -166,7 +184,7 @@ class TestJp2k(unittest.TestCase):
|
|||
pass
|
||||
|
||||
def test_rlevel_max(self):
|
||||
# Verify that rlevel=-1 gets us the lowest resolution image
|
||||
"""Verify that rlevel=-1 gets us the lowest resolution image"""
|
||||
j = Jp2k(self.j2kfile)
|
||||
thumbnail1 = j.read(rlevel=-1)
|
||||
thumbnail2 = j.read(rlevel=5)
|
||||
|
|
@ -174,43 +192,52 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(thumbnail1.shape, (25, 15, 3))
|
||||
|
||||
def test_bad_area_parameter(self):
|
||||
# Verify that we error out appropriately if given a bad area parameter.
|
||||
"""Should error out appropriately if given a bad area parameter."""
|
||||
j = Jp2k(self.jp2file)
|
||||
with self.assertRaises(IOError):
|
||||
# Start corner must be >= 0
|
||||
d = j.read(area=(-1, -1, 1, 1))
|
||||
j.read(area=(-1, -1, 1, 1))
|
||||
with self.assertRaises(IOError):
|
||||
# End corner must be > 0
|
||||
d = j.read(area=(10, 10, 0, 0))
|
||||
j.read(area=(10, 10, 0, 0))
|
||||
with self.assertRaises(IOError):
|
||||
# End corner must be >= start corner
|
||||
d = j.read(area=(10, 10, 8, 8))
|
||||
j.read(area=(10, 10, 8, 8))
|
||||
|
||||
def test_rlevel_too_high(self):
|
||||
# Verify that we error out appropriately if not given a JPEG 2000 file.
|
||||
"""Should error out appropriately if reduce level too high"""
|
||||
j = Jp2k(self.jp2file)
|
||||
with self.assertRaises(IOError):
|
||||
d = j.read(rlevel=6)
|
||||
j.read(rlevel=6)
|
||||
|
||||
def test_not_JPEG2000(self):
|
||||
# Verify that we error out appropriately if not given a JPEG 2000 file.
|
||||
def test_not_jpeg2000(self):
|
||||
"""Should error out appropriately if not given a JPEG 2000 file."""
|
||||
filename = pkg_resources.resource_filename(glymur.__name__, "jp2k.py")
|
||||
with self.assertRaises(IOError):
|
||||
jp2k = Jp2k(filename)
|
||||
Jp2k(filename)
|
||||
|
||||
def test_file_not_present(self):
|
||||
"""Should error out if reading from a file that does not exist"""
|
||||
# Verify that we error out appropriately if not given an existing file
|
||||
# at all.
|
||||
if sys.hexversion < 0x03030000:
|
||||
error = OSError
|
||||
else:
|
||||
error = IOError
|
||||
with self.assertRaises(error):
|
||||
with self.assertRaises(OSError):
|
||||
filename = 'this file does not actually exist on the file system.'
|
||||
jp2k = Jp2k(filename)
|
||||
Jp2k(filename)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_write_with_jp2_in_caps(self):
|
||||
"""should be able to write with JP2 suffix."""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
expdata = j2k.read()
|
||||
with tempfile.NamedTemporaryFile(suffix='.JP2') as tfile:
|
||||
ofile = Jp2k(tfile.name, 'wb')
|
||||
ofile.write(expdata)
|
||||
actdata = ofile.read()
|
||||
np.testing.assert_array_equal(actdata, expdata)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_write_srgb_without_mct(self):
|
||||
"""should be able to write RGB without specifying mct"""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
expdata = j2k.read()
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
|
|
@ -219,12 +246,12 @@ class TestJp2k(unittest.TestCase):
|
|||
actdata = ofile.read()
|
||||
np.testing.assert_array_equal(actdata, expdata)
|
||||
|
||||
c = ofile.get_codestream()
|
||||
self.assertEqual(c.segment[2].spcod[3], 0) # no mct
|
||||
codestream = ofile.get_codestream()
|
||||
self.assertEqual(codestream.segment[2].spcod[3], 0) # no mct
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_write_grayscale_with_mct(self):
|
||||
# MCT usage makes no sense for grayscale images.
|
||||
"""MCT usage makes no sense for grayscale images."""
|
||||
j2k = Jp2k(self.j2kfile)
|
||||
expdata = j2k.read()
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
|
|
@ -234,6 +261,7 @@ class TestJp2k(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_write_cprl(self):
|
||||
"""Must be able to write a CPRL progression order file"""
|
||||
# Issue 17
|
||||
j = Jp2k(self.jp2file)
|
||||
expdata = j.read(rlevel=1)
|
||||
|
|
@ -243,11 +271,11 @@ class TestJp2k(unittest.TestCase):
|
|||
actdata = ofile.read()
|
||||
np.testing.assert_array_equal(actdata, expdata)
|
||||
|
||||
c = ofile.get_codestream()
|
||||
self.assertEqual(c.segment[2].spcod[0], glymur.core.CPRL)
|
||||
codestream = ofile.get_codestream()
|
||||
self.assertEqual(codestream.segment[2].spcod[0], glymur.core.CPRL)
|
||||
|
||||
def test_jp2_boxes(self):
|
||||
# Verify the boxes of a JP2 file.
|
||||
"""Verify the boxes of a JP2 file. Basic jp2 test."""
|
||||
jp2k = Jp2k(self.jp2file)
|
||||
|
||||
# top-level boxes
|
||||
|
|
@ -305,39 +333,41 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(jp2k.box[2].box[1].colorspace, glymur.core.SRGB)
|
||||
self.assertIsNone(jp2k.box[2].box[1].icc_profile)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_j2k_box(self):
|
||||
"""A J2K/J2C file must not have any boxes."""
|
||||
# Verify that a J2K file has no boxes.
|
||||
filename = os.path.join(data_root, 'input/conformance/p0_01.j2k')
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/p0_01.j2k')
|
||||
jp2k = Jp2k(filename)
|
||||
self.assertEqual(len(jp2k.box), 0)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_64bit_XL_field(self):
|
||||
def test_64bit_xl_field(self):
|
||||
"""XL field should be supported"""
|
||||
# Verify that boxes with the XL field are properly read.
|
||||
# Don't have such a file on hand, so we create one. Copy our example
|
||||
# file, but making the codestream have a 64-bit XL field.
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
with open(self.jp2file, 'rb') as ifile:
|
||||
# Everything up until the jp2c box.
|
||||
buffer = ifile.read(3127)
|
||||
tfile.write(buffer)
|
||||
write_buffer = ifile.read(3127)
|
||||
tfile.write(write_buffer)
|
||||
|
||||
# The L field must be 1 in order to signal the presence of the
|
||||
# XL field. The actual length of the jp2c box increased by 8
|
||||
# (8 bytes for the XL field).
|
||||
L = 1
|
||||
T = b'jp2c'
|
||||
XL = 1133427 + 8
|
||||
buffer = struct.pack('>I4sQ', int(L), T, XL)
|
||||
tfile.write(buffer)
|
||||
length = 1
|
||||
typ = b'jp2c'
|
||||
xlen = 1133427 + 8
|
||||
write_buffer = struct.pack('>I4sQ', int(length), typ, xlen)
|
||||
tfile.write(write_buffer)
|
||||
|
||||
# Get the rest of the input file (minus the 8 bytes for L and
|
||||
# T.
|
||||
ifile.seek(8, 1)
|
||||
buffer = ifile.read()
|
||||
tfile.write(buffer)
|
||||
write_buffer = ifile.read()
|
||||
tfile.write(write_buffer)
|
||||
tfile.flush()
|
||||
|
||||
jp2k = Jp2k(tfile.name)
|
||||
|
|
@ -347,7 +377,8 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(jp2k.box[5].length, 1133427 + 8)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_L_is_zero(self):
|
||||
def test_length_field_is_zero(self):
|
||||
"""L=0 (length field in box header) is allowed"""
|
||||
# Verify that boxes with the L field as zero are correctly read.
|
||||
# This should only happen in the last box of a JPEG 2000 file.
|
||||
# Our example image has its last box at byte 588458.
|
||||
|
|
@ -355,19 +386,19 @@ class TestJp2k(unittest.TestCase):
|
|||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
with open(self.jp2file, 'rb') as ifile:
|
||||
# Everything up until the jp2c box.
|
||||
buffer = ifile.read(588458)
|
||||
tfile.write(buffer)
|
||||
write_buffer = ifile.read(588458)
|
||||
tfile.write(write_buffer)
|
||||
|
||||
L = 0
|
||||
T = b'uuid'
|
||||
buffer = struct.pack('>I4s', int(L), T)
|
||||
tfile.write(buffer)
|
||||
length = 0
|
||||
typ = b'uuid'
|
||||
write_buffer = struct.pack('>I4s', int(length), typ)
|
||||
tfile.write(write_buffer)
|
||||
|
||||
# Get the rest of the input file (minus the 8 bytes for L and
|
||||
# T.
|
||||
ifile.seek(8, 1)
|
||||
buffer = ifile.read()
|
||||
tfile.write(buffer)
|
||||
write_buffer = ifile.read()
|
||||
tfile.write(write_buffer)
|
||||
tfile.flush()
|
||||
|
||||
new_jp2 = Jp2k(tfile.name)
|
||||
|
|
@ -381,31 +412,34 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(new_jp2.box[j].length,
|
||||
baseline_jp2.box[j].length)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_read_differing_subsamples(self):
|
||||
"""should error out with read used on differently subsampled images"""
|
||||
# Verify that we error out appropriately if we use the read method
|
||||
# on an image with differing subsamples
|
||||
#
|
||||
# Issue 86.
|
||||
filename = os.path.join(data_root, 'input/conformance/p0_05.j2k')
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/p0_05.j2k')
|
||||
j = Jp2k(filename)
|
||||
with self.assertRaises(RuntimeError):
|
||||
j.read()
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_empty_box_with_j2k(self):
|
||||
# Verify that the list of boxes in a J2C/J2K file is present, but
|
||||
# empty.
|
||||
filename = os.path.join(data_root, 'input/conformance/p0_05.j2k')
|
||||
"""Verify that the list of boxes in a J2C/J2K file is present, but
|
||||
empty.
|
||||
"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/p0_05.j2k')
|
||||
j = Jp2k(filename)
|
||||
self.assertEqual(j.box, [])
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_code_block_height_different_than_width(self):
|
||||
# Verify that we can set a code block size where height does not equal
|
||||
# width.
|
||||
def test_cblkh_different_than_width(self):
|
||||
"""Verify that we can set a code block size where height does not equal
|
||||
width.
|
||||
"""
|
||||
data = np.zeros((128, 128), dtype=np.uint8)
|
||||
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
|
|
@ -413,49 +447,50 @@ class TestJp2k(unittest.TestCase):
|
|||
# The code block dimensions are given as rows x columns.
|
||||
j.write(data, cbsize=(16, 32))
|
||||
|
||||
c = j.get_codestream()
|
||||
codestream = j.get_codestream()
|
||||
|
||||
# Code block size is reported as XY in the codestream.
|
||||
self.assertEqual(tuple(c.segment[2].spcod[5:7]), (3, 2))
|
||||
self.assertEqual(tuple(codestream.segment[2].spcod[5:7]), (3, 2))
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_negative_too_many_dimensions(self):
|
||||
# OpenJP2 only allows 2D or 3D images.
|
||||
def test_too_many_dimensions(self):
|
||||
"""OpenJP2 only allows 2D or 3D images."""
|
||||
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
with self.assertRaises(IOError) as ce:
|
||||
with self.assertRaises(IOError):
|
||||
data = np.zeros((128, 128, 2, 2), dtype=np.uint8)
|
||||
j.write(data)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_unrecognized_jp2_colorspace(self):
|
||||
# We only allow RGB and GRAYSCALE.
|
||||
def test_unrecognized_jp2_clrspace(self):
|
||||
"""We only allow RGB and GRAYSCALE. Should error out with others"""
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
with self.assertRaises(IOError) as ce:
|
||||
with self.assertRaises(IOError):
|
||||
data = np.zeros((128, 128, 3), dtype=np.uint8)
|
||||
j.write(data, colorspace='cmyk')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_2D_rgb(self):
|
||||
# RGB must have at least 3 components.
|
||||
def test_2d_rgb(self):
|
||||
"""RGB must have at least 3 components."""
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
with self.assertRaises(IOError) as ce:
|
||||
with self.assertRaises(IOError):
|
||||
data = np.zeros((128, 128, 2), dtype=np.uint8)
|
||||
j.write(data, colorspace='rgb')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_colorspace_with_j2k(self):
|
||||
# Specifying a colorspace with J2K does not make sense.
|
||||
"""Specifying a colorspace with J2K does not make sense"""
|
||||
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
with self.assertRaises(IOError) as ce:
|
||||
with self.assertRaises(IOError):
|
||||
data = np.zeros((128, 128, 3), dtype=np.uint8)
|
||||
j.write(data, colorspace='rgb')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_specify_rgb(self):
|
||||
"""specify RGB explicitly"""
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
data = np.zeros((128, 128, 3), dtype=np.uint8)
|
||||
|
|
@ -464,6 +499,7 @@ class TestJp2k(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_specify_gray(self):
|
||||
"""test gray explicitly specified (that's GRAY, not GREY)"""
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
data = np.zeros((128, 128), dtype=np.uint8)
|
||||
|
|
@ -473,6 +509,7 @@ class TestJp2k(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_specify_grey(self):
|
||||
"""test grey explicitly specified"""
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
data = np.zeros((128, 128), dtype=np.uint8)
|
||||
|
|
@ -484,6 +521,7 @@ class TestJp2k(unittest.TestCase):
|
|||
"Does not seem to work on official v2.0.0 release.")
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_grey_with_extra_component(self):
|
||||
"""version 2.0 cannot write gray + extra"""
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
data = np.zeros((128, 128, 2), dtype=np.uint8)
|
||||
|
|
@ -495,7 +533,8 @@ class TestJp2k(unittest.TestCase):
|
|||
glymur.core.GREYSCALE)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_grey_with_two_extra_components(self):
|
||||
def test_grey_with_two_extra_comps(self):
|
||||
"""should be able to write gray + two extra components"""
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
data = np.zeros((128, 128, 3), dtype=np.uint8)
|
||||
|
|
@ -510,6 +549,7 @@ class TestJp2k(unittest.TestCase):
|
|||
"Does not seem to work on official v2.0.0 release.")
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_rgb_with_extra_component(self):
|
||||
"""v2.0+ should be able to write extra components"""
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
data = np.zeros((128, 128, 4), dtype=np.uint8)
|
||||
|
|
@ -522,7 +562,8 @@ class TestJp2k(unittest.TestCase):
|
|||
@unittest.skipIf(OPENJP2_IS_V2_OFFICIAL is False,
|
||||
"Test is specific for v2.0.0 release")
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_extra_components_on_v2_official(self):
|
||||
def test_extra_components_on_v2(self):
|
||||
"""must error out in 1.x with extra components."""
|
||||
# Extra components seems to require 2.0+. Verify that we error out.
|
||||
with self.assertRaises(IOError):
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
|
|
@ -531,48 +572,50 @@ class TestJp2k(unittest.TestCase):
|
|||
j.write(data)
|
||||
|
||||
def test_specify_ycc(self):
|
||||
# We don't support writing YCC at the moment.
|
||||
"""Should reject YCC"""
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
with self.assertRaises(IOError) as ce:
|
||||
with self.assertRaises(IOError):
|
||||
data = np.zeros((128, 128, 3), dtype=np.uint8)
|
||||
j.write(data, colorspace='ycc')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_uinf_ulst_url_boxes(self):
|
||||
"""Verify that we can read UINF, ULST, and URL boxes"""
|
||||
# Verify that we can read UINF, ULST, and URL boxes. I don't have
|
||||
# easy access to such a file, and there's no such file in the
|
||||
# openjpeg repository, so I'll fake one.
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
with open(self.jp2file, 'rb') as ifile:
|
||||
# Everything up until the jp2c box.
|
||||
buffer = ifile.read(77)
|
||||
tfile.write(buffer)
|
||||
write_buffer = ifile.read(77)
|
||||
tfile.write(write_buffer)
|
||||
|
||||
# Write the UINF superbox
|
||||
# Length = 50, id is uinf.
|
||||
buffer = struct.pack('>I4s', int(50), b'uinf')
|
||||
tfile.write(buffer)
|
||||
write_buffer = struct.pack('>I4s', int(50), b'uinf')
|
||||
tfile.write(write_buffer)
|
||||
|
||||
# Write the ULST box.
|
||||
# Length is 26, 1 UUID, hard code that UUID as zeros.
|
||||
buffer = struct.pack('>I4sHIIII', int(26), b'ulst', int(1),
|
||||
int(0), int(0), int(0), int(0))
|
||||
tfile.write(buffer)
|
||||
write_buffer = struct.pack('>I4sHIIII', int(26), b'ulst',
|
||||
int(1), int(0), int(0), int(0),
|
||||
int(0))
|
||||
tfile.write(write_buffer)
|
||||
|
||||
# Write the URL box.
|
||||
# Length is 16, version is one byte, flag is 3 bytes, url
|
||||
# is the rest.
|
||||
buffer = struct.pack('>I4sBBBB',
|
||||
int(16), b'url ',
|
||||
int(0), int(0), int(0), int(0))
|
||||
tfile.write(buffer)
|
||||
buffer = struct.pack('>ssss', b'a', b'b', b'c', b'd')
|
||||
tfile.write(buffer)
|
||||
write_buffer = struct.pack('>I4sBBBB',
|
||||
int(16), b'url ',
|
||||
int(0), int(0), int(0), int(0))
|
||||
tfile.write(write_buffer)
|
||||
write_buffer = struct.pack('>ssss', b'a', b'b', b'c', b'd')
|
||||
tfile.write(write_buffer)
|
||||
|
||||
# Get the rest of the input file.
|
||||
buffer = ifile.read()
|
||||
tfile.write(buffer)
|
||||
write_buffer = ifile.read()
|
||||
tfile.write(write_buffer)
|
||||
tfile.flush()
|
||||
|
||||
jp2k = Jp2k(tfile.name)
|
||||
|
|
@ -596,27 +639,26 @@ class TestJp2k(unittest.TestCase):
|
|||
self.assertEqual(jp2k.box[3].box[1].url, 'abcd')
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_xml_box_with_trailing_nulls(self):
|
||||
# ElementTree does not like trailing null chars after valid XML
|
||||
# text.
|
||||
def test_xml_with_trailing_nulls(self):
|
||||
"""ElementTree doesn't like trailing null chars after valid XML text"""
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
with open(self.jp2file, 'rb') as ifile:
|
||||
# Everything up until the jp2c box.
|
||||
buffer = ifile.read(77)
|
||||
tfile.write(buffer)
|
||||
write_buffer = ifile.read(77)
|
||||
tfile.write(write_buffer)
|
||||
|
||||
# Write the xml box
|
||||
# Length = 36, id is 'xml '.
|
||||
buffer = struct.pack('>I4s', int(36), b'xml ')
|
||||
tfile.write(buffer)
|
||||
write_buffer = struct.pack('>I4s', int(36), b'xml ')
|
||||
tfile.write(write_buffer)
|
||||
|
||||
buffer = '<test>this is a test</test>' + chr(0)
|
||||
buffer = buffer.encode()
|
||||
tfile.write(buffer)
|
||||
write_buffer = '<test>this is a test</test>' + chr(0)
|
||||
write_buffer = write_buffer.encode()
|
||||
tfile.write(write_buffer)
|
||||
|
||||
# Get the rest of the input file.
|
||||
buffer = ifile.read()
|
||||
tfile.write(buffer)
|
||||
write_buffer = ifile.read()
|
||||
tfile.write(write_buffer)
|
||||
tfile.flush()
|
||||
|
||||
jp2k = Jp2k(tfile.name)
|
||||
|
|
@ -629,6 +671,7 @@ class TestJp2k(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_asoc_label_box(self):
|
||||
"""Test asoc and label box"""
|
||||
# Construct a fake file with an asoc and a label box, as
|
||||
# OpenJPEG doesn't have such a file.
|
||||
data = Jp2k(self.jp2file).read(rlevel=1)
|
||||
|
|
@ -639,30 +682,30 @@ class TestJp2k(unittest.TestCase):
|
|||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile2:
|
||||
|
||||
# Offset of the codestream is where we start.
|
||||
buffer = tfile.read(77)
|
||||
tfile2.write(buffer)
|
||||
read_buffer = tfile.read(77)
|
||||
tfile2.write(read_buffer)
|
||||
|
||||
# read the rest of the file, it's the codestream.
|
||||
codestream = tfile.read()
|
||||
|
||||
# Write the asoc superbox.
|
||||
# Length = 36, id is 'asoc'.
|
||||
buffer = struct.pack('>I4s', int(56), b'asoc')
|
||||
tfile2.write(buffer)
|
||||
write_buffer = struct.pack('>I4s', int(56), b'asoc')
|
||||
tfile2.write(write_buffer)
|
||||
|
||||
# Write the contained label box
|
||||
buffer = struct.pack('>I4s', int(13), b'lbl ')
|
||||
tfile2.write(buffer)
|
||||
write_buffer = struct.pack('>I4s', int(13), b'lbl ')
|
||||
tfile2.write(write_buffer)
|
||||
tfile2.write('label'.encode())
|
||||
|
||||
# Write the xml box
|
||||
# Length = 36, id is 'xml '.
|
||||
buffer = struct.pack('>I4s', int(35), b'xml ')
|
||||
tfile2.write(buffer)
|
||||
write_buffer = struct.pack('>I4s', int(35), b'xml ')
|
||||
tfile2.write(write_buffer)
|
||||
|
||||
buffer = '<test>this is a test</test>'
|
||||
buffer = buffer.encode()
|
||||
tfile2.write(buffer)
|
||||
write_buffer = '<test>this is a test</test>'
|
||||
write_buffer = write_buffer.encode()
|
||||
tfile2.write(write_buffer)
|
||||
|
||||
# Now append the codestream.
|
||||
tfile2.write(codestream)
|
||||
|
|
@ -678,10 +721,10 @@ class TestJp2k(unittest.TestCase):
|
|||
@unittest.skipIf(OPENJP2_IS_V2_OFFICIAL,
|
||||
"Segfault on official v2.0.0 release.")
|
||||
def test_openjpeg_library_message(self):
|
||||
# Verify the error message produced by the openjpeg library.
|
||||
"""Verify the error message produced by the openjpeg library"""
|
||||
# This will confirm that the error callback mechanism is working.
|
||||
with open(self.jp2file, 'rb') as fp:
|
||||
data = fp.read()
|
||||
with open(self.jp2file, 'rb') as fptr:
|
||||
data = fptr.read()
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
# Codestream starts at byte 3127. SIZ marker at 3137.
|
||||
# COD marker at 3186. Subsampling at 3180.
|
||||
|
|
@ -705,13 +748,13 @@ class TestJp2k(unittest.TestCase):
|
|||
:\sdx=1\sdy=0''', re.VERBOSE)
|
||||
if sys.hexversion < 0x03020000:
|
||||
with self.assertRaisesRegexp((IOError, OSError), regexp):
|
||||
d = j.read(rlevel=1)
|
||||
j.read(rlevel=1)
|
||||
else:
|
||||
with self.assertRaisesRegex((IOError, OSError), regexp):
|
||||
d = j.read(rlevel=1)
|
||||
j.read(rlevel=1)
|
||||
|
||||
def test_xmp_attribute(self):
|
||||
# Verify that we can read the XMP packet in our shipping example file.
|
||||
"""Verify the XMP packet in the shipping example file can be read."""
|
||||
j = Jp2k(self.jp2file)
|
||||
xmp = j.box[4].data
|
||||
ns0 = '{http://www.w3.org/1999/02/22-rdf-syntax-ns#}'
|
||||
|
|
@ -723,7 +766,7 @@ class TestJp2k(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(os.name == "nt", "NamedTemporaryFile issue on windows")
|
||||
def test_unrecognized_exif_tag(self):
|
||||
# An unrecognized exif tag should be handled gracefully.
|
||||
"""An unrecognized exif tag should be handled gracefully."""
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
shutil.copyfile(self.jp2file, tfile.name)
|
||||
|
||||
|
|
@ -733,10 +776,10 @@ class TestJp2k(unittest.TestCase):
|
|||
# the the Image IFD number of tags, where we finally find the first
|
||||
# tag, "Make" (271). We'll corrupt it by changing it into 171,
|
||||
# which does not correspond to any known Exif Image tag.
|
||||
with open(tfile.name, 'r+b') as fp:
|
||||
fp.seek(117)
|
||||
buffer = struct.pack('<H', int(171))
|
||||
fp.write(buffer)
|
||||
with open(tfile.name, 'r+b') as fptr:
|
||||
fptr.seek(117)
|
||||
write_buffer = struct.pack('<H', int(171))
|
||||
fptr.write(write_buffer)
|
||||
|
||||
# Verify that a warning is issued, but only on python3.
|
||||
# On python2, just suppress the warning.
|
||||
|
|
@ -745,7 +788,7 @@ class TestJp2k(unittest.TestCase):
|
|||
warnings.simplefilter("ignore")
|
||||
j = Jp2k(tfile.name)
|
||||
else:
|
||||
with self.assertWarns(UserWarning) as cw:
|
||||
with self.assertWarns(UserWarning):
|
||||
j = Jp2k(tfile.name)
|
||||
|
||||
exif = j.box[3].data
|
||||
|
|
@ -757,6 +800,7 @@ class TestJp2k(unittest.TestCase):
|
|||
@unittest.skipIf(glymur.lib.openjpeg.OPENJPEG is None,
|
||||
"Missing openjpeg library.")
|
||||
class TestJp2k15(unittest.TestCase):
|
||||
"""Test suite for openjpeg 1.5"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,7 +2,15 @@
|
|||
The tests here do not correspond directly to the OpenJPEG test suite, but
|
||||
seem like logical negative tests to add.
|
||||
"""
|
||||
#pylint: disable-all
|
||||
# E1101: assertWarns introduced in python 3.2
|
||||
# pylint: disable=E1101
|
||||
|
||||
# R0904: Not too many methods in unittest.
|
||||
# pylint: disable=R0904
|
||||
|
||||
# unittest2 is python2.6 only (pylint/python-2.7)
|
||||
# pylint: disable=F0401
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
|
@ -13,9 +21,6 @@ else:
|
|||
import unittest
|
||||
|
||||
import numpy as np
|
||||
import pkg_resources
|
||||
|
||||
from glymur.lib import openjp2 as opj2
|
||||
|
||||
from .fixtures import read_image, NO_READ_BACKEND, NO_READ_BACKEND_MSG
|
||||
|
||||
|
|
@ -23,9 +28,9 @@ from glymur import Jp2k
|
|||
import glymur
|
||||
|
||||
try:
|
||||
data_root = os.environ['OPJ_DATA_ROOT']
|
||||
DATA_ROOT = os.environ['OPJ_DATA_ROOT']
|
||||
except KeyError:
|
||||
data_root = None
|
||||
DATA_ROOT = None
|
||||
except:
|
||||
raise
|
||||
|
||||
|
|
@ -33,9 +38,10 @@ except:
|
|||
@unittest.skipIf(glymur.lib.openjp2.OPENJP2 is None,
|
||||
"Missing openjp2 library.")
|
||||
@unittest.skipIf(NO_READ_BACKEND, NO_READ_BACKEND_MSG)
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
class TestSuiteNegative(unittest.TestCase):
|
||||
"""Test suite for certain negative tests from openjpeg suite."""
|
||||
|
||||
def setUp(self):
|
||||
self.jp2file = glymur.data.nemo()
|
||||
|
|
@ -45,45 +51,50 @@ class TestSuiteNegative(unittest.TestCase):
|
|||
pass
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_negative_psnr_with_cratios(self):
|
||||
# Using psnr with cratios options is not allowed.
|
||||
def test_psnr_with_cratios(self):
|
||||
"""Using psnr with cratios options is not allowed."""
|
||||
# Not an OpenJPEG test, but close.
|
||||
infile = os.path.join(data_root, 'input/nonregression/Bretagne1.ppm')
|
||||
infile = os.path.join(DATA_ROOT, 'input/nonregression/Bretagne1.ppm')
|
||||
data = read_image(infile)
|
||||
with tempfile.NamedTemporaryFile(suffix='.j2k') as tfile:
|
||||
j = Jp2k(tfile.name, 'wb')
|
||||
with self.assertRaises(IOError):
|
||||
j.write(data, psnr=[30, 35, 40], cratios=[2, 3, 4])
|
||||
|
||||
def test_NR_MarkerIsNotCompliant_j2k_dump(self):
|
||||
def test_nr_marker_not_compliant(self):
|
||||
"""non-compliant marker, should still be able to read"""
|
||||
relpath = 'input/nonregression/MarkerIsNotCompliant.j2k'
|
||||
jfile = os.path.join(data_root, relpath)
|
||||
jfile = os.path.join(DATA_ROOT, relpath)
|
||||
jp2k = Jp2k(jfile)
|
||||
c = jp2k.get_codestream(header_only=False)
|
||||
jp2k.get_codestream(header_only=False)
|
||||
self.assertTrue(True)
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
def test_NR_illegalcolortransform_dump(self):
|
||||
# EOC marker is bad
|
||||
def test_nr_illegalclrtransform(self):
|
||||
"""EOC marker is bad"""
|
||||
relpath = 'input/nonregression/illegalcolortransform.j2k'
|
||||
jfile = os.path.join(data_root, relpath)
|
||||
jfile = os.path.join(DATA_ROOT, relpath)
|
||||
jp2k = Jp2k(jfile)
|
||||
with self.assertWarns(UserWarning) as cw:
|
||||
c = jp2k.get_codestream(header_only=False)
|
||||
with self.assertWarns(UserWarning):
|
||||
codestream = jp2k.get_codestream(header_only=False)
|
||||
|
||||
# Verify that the last segment returned in the codestream is SOD,
|
||||
# not EOC. Codestream parsing should stop when we try to jump to
|
||||
# the end of SOT.
|
||||
self.assertEqual(c.segment[-1].marker_id, 'SOD')
|
||||
self.assertEqual(codestream.segment[-1].marker_id, 'SOD')
|
||||
|
||||
def test_NR_Cannotreaddatawithnosizeknown_j2k(self):
|
||||
def test_nr_cannotreadwnosizeknown(self):
|
||||
"""not sure exactly what is wrong with this file"""
|
||||
relpath = 'input/nonregression/Cannotreaddatawithnosizeknown.j2k'
|
||||
jfile = os.path.join(data_root, relpath)
|
||||
jfile = os.path.join(DATA_ROOT, relpath)
|
||||
jp2k = Jp2k(jfile)
|
||||
c = jp2k.get_codestream(header_only=False)
|
||||
jp2k.get_codestream(header_only=False)
|
||||
self.assertTrue(True)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_code_block_dimensions(self):
|
||||
"""don't allow extreme codeblock sizes"""
|
||||
# opj_compress doesn't allow the dimensions of a codeblock
|
||||
# to be too small or too big, so neither will we.
|
||||
data = np.zeros((256, 256), dtype=np.uint8)
|
||||
|
|
@ -91,55 +102,55 @@ class TestSuiteNegative(unittest.TestCase):
|
|||
j = Jp2k(tfile.name, 'wb')
|
||||
|
||||
# opj_compress doesn't allow code block area to exceed 4096.
|
||||
with self.assertRaises(IOError) as cr:
|
||||
with self.assertRaises(IOError):
|
||||
j.write(data, cbsize=(256, 256))
|
||||
|
||||
# opj_compress doesn't allow either dimension to be less than 4.
|
||||
with self.assertRaises(IOError) as cr:
|
||||
with self.assertRaises(IOError):
|
||||
j.write(data, cbsize=(2048, 2))
|
||||
with self.assertRaises(IOError) as cr:
|
||||
with self.assertRaises(IOError):
|
||||
j.write(data, cbsize=(2, 2048))
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x03020000,
|
||||
"Uses features introduced in 3.2.")
|
||||
def test_exceeded_box(self):
|
||||
"""should warn if reading past end of a box"""
|
||||
# Verify that a warning is issued if we read past the end of a box
|
||||
# This file has a palette (pclr) box whose length is impossibly
|
||||
# short.
|
||||
infile = os.path.join(data_root,
|
||||
infile = os.path.join(DATA_ROOT,
|
||||
'input/nonregression/mem-b2ace68c-1381.jp2')
|
||||
with self.assertWarns(UserWarning) as cw:
|
||||
j = Jp2k(infile)
|
||||
with self.assertWarns(UserWarning):
|
||||
Jp2k(infile)
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_precinct_size_not_multiple_of_two(self):
|
||||
# Seems like precinct sizes should be powers of two.
|
||||
def test_precinct_size_not_p2(self):
|
||||
"""precinct sizes should be powers of two."""
|
||||
ifile = Jp2k(self.j2kfile)
|
||||
data = ifile.read(rlevel=2)
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
ofile = Jp2k(tfile.name, 'wb')
|
||||
with self.assertRaises(IOError) as ce:
|
||||
with self.assertRaises(IOError):
|
||||
ofile.write(data, psizes=[(13, 13)])
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_codeblock_size_not_multiple_of_two(self):
|
||||
# Seems like code block sizes should be powers of two.
|
||||
def test_cblk_size_not_power_of_two(self):
|
||||
"""code block sizes should be powers of two."""
|
||||
ifile = Jp2k(self.j2kfile)
|
||||
data = ifile.read(rlevel=2)
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
ofile = Jp2k(tfile.name, 'wb')
|
||||
with self.assertRaises(IOError) as ce:
|
||||
with self.assertRaises(IOError):
|
||||
ofile.write(data, cbsize=(13, 12))
|
||||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_codeblock_size_with_precinct_size(self):
|
||||
# Seems like code block sizes should never exceed half that of
|
||||
# precinct size.
|
||||
def test_cblk_size_precinct_size(self):
|
||||
"""code block sizes should never exceed half that of precinct size."""
|
||||
ifile = Jp2k(self.j2kfile)
|
||||
data = ifile.read(rlevel=2)
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
ofile = Jp2k(tfile.name, 'wb')
|
||||
with self.assertRaises(IOError) as ce:
|
||||
with self.assertRaises(IOError):
|
||||
ofile.write(data,
|
||||
cbsize=(64, 64),
|
||||
psizes=[(64, 64)])
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,15 @@
|
|||
#pylint: disable-all
|
||||
"""Test suite for printing.
|
||||
"""
|
||||
# C0302: don't care too much about having too many lines in a test module
|
||||
# pylint: disable=C0302
|
||||
|
||||
# E061: unittest.mock introduced in 3.3 (python-2.7/pylint issue)
|
||||
# pylint: disable=E0611,F0401
|
||||
|
||||
# R0904: Not too many methods in unittest.
|
||||
# pylint: disable=R0904
|
||||
|
||||
import os
|
||||
import pkg_resources
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
import tempfile
|
||||
|
|
@ -26,9 +34,9 @@ import glymur
|
|||
from glymur import Jp2k
|
||||
|
||||
try:
|
||||
data_root = os.environ['OPJ_DATA_ROOT']
|
||||
DATA_ROOT = os.environ['OPJ_DATA_ROOT']
|
||||
except KeyError:
|
||||
data_root = None
|
||||
DATA_ROOT = None
|
||||
except:
|
||||
raise
|
||||
|
||||
|
|
@ -122,12 +130,13 @@ class TestPrintingNeedsLib(unittest.TestCase):
|
|||
+ '(0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), '
|
||||
+ '(0, 10), (0, 9), (0, 9), (0, 10), (0, 9), (0, 9), '
|
||||
+ '(0, 10)]']
|
||||
self.expectedPlain = '\n'.join(lines)
|
||||
self.expected_plain = '\n'.join(lines)
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_asoc_label_box(self):
|
||||
"""verify printing of asoc, label boxes"""
|
||||
# Construct a fake file with an asoc and a label box, as
|
||||
# OpenJPEG doesn't have such a file.
|
||||
data = glymur.Jp2k(self.jp2file).read(rlevel=1)
|
||||
|
|
@ -138,30 +147,30 @@ class TestPrintingNeedsLib(unittest.TestCase):
|
|||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile2:
|
||||
|
||||
# Offset of the codestream is where we start.
|
||||
buffer = tfile.read(77)
|
||||
tfile2.write(buffer)
|
||||
wbuffer = tfile.read(77)
|
||||
tfile2.write(wbuffer)
|
||||
|
||||
# read the rest of the file, it's the codestream.
|
||||
codestream = tfile.read()
|
||||
|
||||
# Write the asoc superbox.
|
||||
# Length = 36, id is 'asoc'.
|
||||
buffer = struct.pack('>I4s', int(56), b'asoc')
|
||||
tfile2.write(buffer)
|
||||
wbuffer = struct.pack('>I4s', int(56), b'asoc')
|
||||
tfile2.write(wbuffer)
|
||||
|
||||
# Write the contained label box
|
||||
buffer = struct.pack('>I4s', int(13), b'lbl ')
|
||||
tfile2.write(buffer)
|
||||
wbuffer = struct.pack('>I4s', int(13), b'lbl ')
|
||||
tfile2.write(wbuffer)
|
||||
tfile2.write('label'.encode())
|
||||
|
||||
# Write the xml box
|
||||
# Length = 36, id is 'xml '.
|
||||
buffer = struct.pack('>I4s', int(35), b'xml ')
|
||||
tfile2.write(buffer)
|
||||
wbuffer = struct.pack('>I4s', int(35), b'xml ')
|
||||
tfile2.write(wbuffer)
|
||||
|
||||
buffer = '<test>this is a test</test>'
|
||||
buffer = buffer.encode()
|
||||
tfile2.write(buffer)
|
||||
wbuffer = '<test>this is a test</test>'
|
||||
wbuffer = wbuffer.encode()
|
||||
tfile2.write(wbuffer)
|
||||
|
||||
# Now append the codestream.
|
||||
tfile2.write(codestream)
|
||||
|
|
@ -180,6 +189,7 @@ class TestPrintingNeedsLib(unittest.TestCase):
|
|||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_jp2dump(self):
|
||||
"""basic jp2dump test"""
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
glymur.jp2dump(self._plain_nemo_file)
|
||||
actual = fake_out.getvalue().strip()
|
||||
|
|
@ -188,9 +198,10 @@ class TestPrintingNeedsLib(unittest.TestCase):
|
|||
lst = actual.split('\n')
|
||||
lst = lst[1:]
|
||||
actual = '\n'.join(lst)
|
||||
self.assertEqual(actual, self.expectedPlain)
|
||||
self.assertEqual(actual, self.expected_plain)
|
||||
|
||||
def test_entire_file(self):
|
||||
"""verify output from printing entire file"""
|
||||
j = glymur.Jp2k(self._plain_nemo_file)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
print(j)
|
||||
|
|
@ -201,10 +212,11 @@ class TestPrintingNeedsLib(unittest.TestCase):
|
|||
lst = lst[1:]
|
||||
actual = '\n'.join(lst)
|
||||
|
||||
self.assertEqual(actual, self.expectedPlain)
|
||||
self.assertEqual(actual, self.expected_plain)
|
||||
|
||||
|
||||
class TestPrinting(unittest.TestCase):
|
||||
"""Test suite for printing where the libraries are not needed"""
|
||||
|
||||
def setUp(self):
|
||||
# Save sys.stdout.
|
||||
|
|
@ -213,7 +225,8 @@ class TestPrinting(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_COC_segment(self):
|
||||
def test_coc_segment(self):
|
||||
"""verify printing of COC segment"""
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
codestream = j.get_codestream(header_only=False)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -240,7 +253,8 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_COD_segment(self):
|
||||
def test_cod_segment(self):
|
||||
"""verify printing of COD segment"""
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
codestream = j.get_codestream()
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -271,14 +285,13 @@ class TestPrinting(unittest.TestCase):
|
|||
' Segmentation symbols: False']
|
||||
|
||||
expected = '\n'.join(lines)
|
||||
self.actual = actual
|
||||
self.expected = expected
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_icc_profile(self):
|
||||
filename = os.path.join(data_root, 'input/nonregression/text_GBR.jp2')
|
||||
"""verify printing of colr box with ICC profile"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/nonregression/text_GBR.jp2')
|
||||
with warnings.catch_warnings():
|
||||
# brand is 'jp2 ', but has any icc profile.
|
||||
warnings.simplefilter("ignore")
|
||||
|
|
@ -343,24 +356,26 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_CRG(self):
|
||||
filename = os.path.join(data_root, 'input/conformance/p0_03.j2k')
|
||||
def test_crg(self):
|
||||
"""verify printing of CRG segment"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/p0_03.j2k')
|
||||
j = glymur.Jp2k(filename)
|
||||
codestream = j.get_codestream()
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
print(codestream.segment[-5])
|
||||
actual = fake_out.getvalue().strip()
|
||||
lines = ['CRG marker segment at (87, 6)',
|
||||
lines = ['CRG marker segment @ (87, 6)',
|
||||
' Vertical, Horizontal offset: (0.50, 1.00)']
|
||||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_RGN(self):
|
||||
filename = os.path.join(data_root, 'input/conformance/p0_03.j2k')
|
||||
def test_rgn(self):
|
||||
"""verify printing of RGN segment"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/p0_03.j2k')
|
||||
j = glymur.Jp2k(filename)
|
||||
codestream = j.get_codestream(header_only=False)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -373,10 +388,11 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_SOP(self):
|
||||
filename = os.path.join(data_root, 'input/conformance/p0_03.j2k')
|
||||
def test_sop(self):
|
||||
"""verify printing of SOP segment"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/p0_03.j2k')
|
||||
j = glymur.Jp2k(filename)
|
||||
codestream = j.get_codestream(header_only=False)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -387,11 +403,11 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_CME(self):
|
||||
# Test printing a CME or comment marker segment.
|
||||
filename = os.path.join(data_root, 'input/conformance/p0_02.j2k')
|
||||
def test_cme(self):
|
||||
"""Test printing a CME or comment marker segment."""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/p0_02.j2k')
|
||||
j = glymur.Jp2k(filename)
|
||||
codestream = j.get_codestream()
|
||||
# 2nd to last segment in the main header
|
||||
|
|
@ -403,7 +419,8 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_EOC_segment(self):
|
||||
def test_eoc_segment(self):
|
||||
"""verify printing of eoc segment"""
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
codestream = j.get_codestream(header_only=False)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -414,10 +431,11 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_PLT_segment(self):
|
||||
filename = os.path.join(data_root, 'input/conformance/p0_07.j2k')
|
||||
def test_plt_segment(self):
|
||||
"""verify printing of PLT segment"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/p0_07.j2k')
|
||||
j = glymur.Jp2k(filename)
|
||||
codestream = j.get_codestream(header_only=False)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -432,10 +450,11 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_POD_segment(self):
|
||||
filename = os.path.join(data_root, 'input/conformance/p0_13.j2k')
|
||||
def test_pod_segment(self):
|
||||
"""verify printing of POD segment"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/p0_13.j2k')
|
||||
j = glymur.Jp2k(filename)
|
||||
codestream = j.get_codestream()
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -461,10 +480,11 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_PPM_segment(self):
|
||||
filename = os.path.join(data_root, 'input/conformance/p1_03.j2k')
|
||||
def test_ppm_segment(self):
|
||||
"""verify printing of PPM segment"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/p1_03.j2k')
|
||||
j = glymur.Jp2k(filename)
|
||||
codestream = j.get_codestream()
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -478,10 +498,11 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_PPT_segment(self):
|
||||
filename = os.path.join(data_root, 'input/conformance/p1_06.j2k')
|
||||
def test_ppt_segment(self):
|
||||
"""verify printing of ppt segment"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/p1_06.j2k')
|
||||
j = glymur.Jp2k(filename)
|
||||
codestream = j.get_codestream(header_only=False)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -495,7 +516,8 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_QCC_segment(self):
|
||||
def test_qcc_segment(self):
|
||||
"""verify printing of qcc segment"""
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
codestream = j.get_codestream(header_only=False)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -510,7 +532,8 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_QCD_segment_5x3_transform(self):
|
||||
def test_qcd_segment_5x3_transform(self):
|
||||
"""verify printing of qcd segment"""
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
codestream = j.get_codestream()
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -524,7 +547,8 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_SIZ_segment(self):
|
||||
def test_siz_segment(self):
|
||||
"""verify printing of SIZ segment"""
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
codestream = j.get_codestream()
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -545,7 +569,8 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_SOC_segment(self):
|
||||
def test_soc_segment(self):
|
||||
"""verify printing of SOC segment"""
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
codestream = j.get_codestream()
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -556,7 +581,8 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_SOD_segment(self):
|
||||
def test_sod_segment(self):
|
||||
"""verify printing of SOD segment"""
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
codestream = j.get_codestream(header_only=False)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -567,7 +593,8 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_SOT_segment(self):
|
||||
def test_sot_segment(self):
|
||||
"""verify printing of SOT segment"""
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
codestream = j.get_codestream(header_only=False)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -581,13 +608,13 @@ class TestPrinting(unittest.TestCase):
|
|||
' Number of tile parts: 1']
|
||||
|
||||
expected = '\n'.join(lines)
|
||||
self.maxDiff = None
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_TLM_segment(self):
|
||||
filename = os.path.join(data_root, 'input/conformance/p0_15.j2k')
|
||||
def test_tlm_segment(self):
|
||||
"""verify printing of TLM segment"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/p0_15.j2k')
|
||||
j = glymur.Jp2k(filename)
|
||||
codestream = j.get_codestream()
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -605,7 +632,7 @@ class TestPrinting(unittest.TestCase):
|
|||
@unittest.skipIf(sys.hexversion < 0x02070000,
|
||||
"Differences in XML printing between 2.6 and 2.7")
|
||||
def test_xmp(self):
|
||||
# Verify the printing of a UUID/XMP box.
|
||||
"""Verify the printing of a UUID/XMP box."""
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
print(j.box[4])
|
||||
|
|
@ -627,6 +654,7 @@ class TestPrinting(unittest.TestCase):
|
|||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_codestream(self):
|
||||
"""verify printing of entire codestream"""
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
print(j.get_codestream())
|
||||
|
|
@ -672,15 +700,15 @@ class TestPrinting(unittest.TestCase):
|
|||
' CME marker segment @ (3209, 37)',
|
||||
' "Created by OpenJPEG version 2.0.0"']
|
||||
expected = '\n'.join(lst)
|
||||
self.maxDiff = None
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(sys.hexversion < 0x02070000,
|
||||
"Differences in XML printing between 2.6 and 2.7")
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_xml(self):
|
||||
filename = os.path.join(data_root, 'input/conformance/file1.jp2')
|
||||
"""verify printing of XML box"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/file1.jp2')
|
||||
j = glymur.Jp2k(filename)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
print(j.box[2])
|
||||
|
|
@ -707,10 +735,11 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_channel_definition(self):
|
||||
filename = os.path.join(data_root, 'input/conformance/file2.jp2')
|
||||
"""verify printing of cdef box"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/file2.jp2')
|
||||
j = glymur.Jp2k(filename)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
print(j.box[2].box[2])
|
||||
|
|
@ -722,10 +751,11 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_component_mapping(self):
|
||||
filename = os.path.join(data_root, 'input/conformance/file9.jp2')
|
||||
"""verify printing of cmap box"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/file9.jp2')
|
||||
j = glymur.Jp2k(filename)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
print(j.box[2].box[2])
|
||||
|
|
@ -737,10 +767,11 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_palette(self):
|
||||
filename = os.path.join(data_root, 'input/conformance/file9.jp2')
|
||||
def test_palette7(self):
|
||||
"""verify printing of pclr box"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/file9.jp2')
|
||||
j = glymur.Jp2k(filename)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
print(j.box[2].box[1])
|
||||
|
|
@ -750,10 +781,11 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_palette(self):
|
||||
filename = os.path.join(data_root, 'input/conformance/file7.jp2')
|
||||
def test_rreq(self):
|
||||
"""verify printing of reader requirements box"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/file7.jp2')
|
||||
j = glymur.Jp2k(filename)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
print(j.box[2])
|
||||
|
|
@ -773,25 +805,11 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_CRG(self):
|
||||
filename = os.path.join(data_root, 'input/conformance/p0_03.j2k')
|
||||
j = glymur.Jp2k(filename)
|
||||
codestream = j.get_codestream()
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
print(codestream.segment[6])
|
||||
actual = fake_out.getvalue().strip()
|
||||
lines = ['CRG marker segment @ (87, 6)',
|
||||
' Vertical, Horizontal offset: (0.50, 1.00)']
|
||||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_differing_subsamples(self):
|
||||
# Issue 86.
|
||||
filename = os.path.join(data_root, 'input/conformance/p0_05.j2k')
|
||||
"""verify printing of SIZ with different subsampling... Issue 86."""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/p0_05.j2k')
|
||||
j = glymur.Jp2k(filename)
|
||||
codestream = j.get_codestream()
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
@ -810,11 +828,11 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_palette_box(self):
|
||||
# Verify that palette (pclr) boxes are printed without error.
|
||||
filename = os.path.join(data_root, 'input/conformance/file9.jp2')
|
||||
"""Verify that palette (pclr) boxes are printed without error."""
|
||||
filename = os.path.join(DATA_ROOT, 'input/conformance/file9.jp2')
|
||||
j = glymur.Jp2k(filename)
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
print(j.box[2].box[1])
|
||||
|
|
@ -826,54 +844,56 @@ class TestPrinting(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
|
||||
def test_less_common_boxes(self):
|
||||
"""verify uinf, ulst, url, res, resd, resc box printing"""
|
||||
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
|
||||
with open(self.jp2file, 'rb') as ifile:
|
||||
# Everything up until the jp2c box.
|
||||
buffer = ifile.read(77)
|
||||
tfile.write(buffer)
|
||||
wbuffer = ifile.read(77)
|
||||
tfile.write(wbuffer)
|
||||
|
||||
# Write the UINF superbox
|
||||
# Length = 50, id is uinf.
|
||||
buffer = struct.pack('>I4s', int(50), b'uinf')
|
||||
tfile.write(buffer)
|
||||
wbuffer = struct.pack('>I4s', int(50), b'uinf')
|
||||
tfile.write(wbuffer)
|
||||
|
||||
# Write the ULST box.
|
||||
# Length is 26, 1 UUID, hard code that UUID as zeros.
|
||||
buffer = struct.pack('>I4sHIIII', int(26), b'ulst', int(1),
|
||||
int(0), int(0), int(0), int(0))
|
||||
tfile.write(buffer)
|
||||
wbuffer = struct.pack('>I4sHIIII', int(26), b'ulst', int(1),
|
||||
int(0), int(0), int(0), int(0))
|
||||
tfile.write(wbuffer)
|
||||
|
||||
# Write the URL box.
|
||||
# Length is 16, version is one byte, flag is 3 bytes, url
|
||||
# is the rest.
|
||||
buffer = struct.pack('>I4sBBBB',
|
||||
int(16), b'url ',
|
||||
int(0), int(0), int(0), int(0))
|
||||
tfile.write(buffer)
|
||||
buffer = struct.pack('>ssss', b'a', b'b', b'c', b'd')
|
||||
tfile.write(buffer)
|
||||
wbuffer = struct.pack('>I4sBBBB',
|
||||
int(16), b'url ',
|
||||
int(0), int(0), int(0), int(0))
|
||||
tfile.write(wbuffer)
|
||||
|
||||
wbuffer = struct.pack('>ssss', b'a', b'b', b'c', b'd')
|
||||
tfile.write(wbuffer)
|
||||
|
||||
# Start the resolution superbox.
|
||||
buffer = struct.pack('>I4s', int(44), b'res ')
|
||||
tfile.write(buffer)
|
||||
wbuffer = struct.pack('>I4s', int(44), b'res ')
|
||||
tfile.write(wbuffer)
|
||||
|
||||
# Write the capture resolution box.
|
||||
buffer = struct.pack('>I4sHHHHBB',
|
||||
int(18), b'resc',
|
||||
int(1), int(1), int(1), int(1),
|
||||
int(0), int(1))
|
||||
tfile.write(buffer)
|
||||
wbuffer = struct.pack('>I4sHHHHBB',
|
||||
int(18), b'resc',
|
||||
int(1), int(1), int(1), int(1),
|
||||
int(0), int(1))
|
||||
tfile.write(wbuffer)
|
||||
|
||||
# Write the display resolution box.
|
||||
buffer = struct.pack('>I4sHHHHBB',
|
||||
int(18), b'resd',
|
||||
int(1), int(1), int(1), int(1),
|
||||
int(1), int(0))
|
||||
tfile.write(buffer)
|
||||
wbuffer = struct.pack('>I4sHHHHBB',
|
||||
int(18), b'resd',
|
||||
int(1), int(1), int(1), int(1),
|
||||
int(1), int(0))
|
||||
tfile.write(wbuffer)
|
||||
|
||||
# Get the rest of the input file.
|
||||
buffer = ifile.read()
|
||||
tfile.write(buffer)
|
||||
wbuffer = ifile.read()
|
||||
tfile.write(wbuffer)
|
||||
tfile.flush()
|
||||
|
||||
jp2k = glymur.Jp2k(tfile.name)
|
||||
|
|
@ -901,12 +921,13 @@ class TestPrinting(unittest.TestCase):
|
|||
|
||||
@unittest.skipIf(sys.hexversion < 0x03000000,
|
||||
"Ordered dicts not printing well in 2.7")
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_jpx_approximation_with_icc_profile(self):
|
||||
def test_jpx_approx_icc_profile(self):
|
||||
"""verify jpx with approx field equal to zero"""
|
||||
# ICC profiles may be used in JP2, but the approximation field should
|
||||
# be zero unless we have jpx. This file does both.
|
||||
filename = os.path.join(data_root, 'input/nonregression/text_GBR.jp2')
|
||||
filename = os.path.join(DATA_ROOT, 'input/nonregression/text_GBR.jp2')
|
||||
with warnings.catch_warnings():
|
||||
# brand is 'jp2 ', but has any icc profile.
|
||||
warnings.simplefilter("ignore")
|
||||
|
|
@ -945,11 +966,11 @@ class TestPrinting(unittest.TestCase):
|
|||
expected = '\n'.join(lines)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
@unittest.skipIf(data_root is None,
|
||||
@unittest.skipIf(DATA_ROOT is None,
|
||||
"OPJ_DATA_ROOT environment variable not set")
|
||||
def test_uuid(self):
|
||||
# UUID box
|
||||
filename = os.path.join(data_root, 'input/nonregression/text_GBR.jp2')
|
||||
"""verify printing of UUID box"""
|
||||
filename = os.path.join(DATA_ROOT, 'input/nonregression/text_GBR.jp2')
|
||||
with warnings.catch_warnings():
|
||||
# brand is 'jp2 ', but has any icc profile.
|
||||
warnings.simplefilter("ignore")
|
||||
|
|
@ -968,6 +989,7 @@ class TestPrinting(unittest.TestCase):
|
|||
@unittest.skipIf(sys.hexversion < 0x03000000,
|
||||
"Ordered dicts not printing well in 2.7")
|
||||
def test_exif_uuid(self):
|
||||
"""Verify printing of exif information"""
|
||||
j = glymur.Jp2k(self.jp2file)
|
||||
|
||||
with patch('sys.stdout', new=StringIO()) as fake_out:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue