Merge branch 'release-0.3.1'

This commit is contained in:
jevans 2013-08-14 20:25:30 -04:00
commit 8204706a86
28 changed files with 3622 additions and 3106 deletions

View file

@ -1,3 +1,7 @@
Aug 14, 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

View file

@ -76,9 +76,9 @@ copyright = u'2013, John Evans'
# built documents.
#
# The short X.Y version.
version = '0.2'
version = '0.3'
# The full version, including alpha/beta/rc tags.
release = '0.3.0'
release = '0.3.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View file

@ -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.
"""

File diff suppressed because it is too large Load diff

View file

@ -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.
@ -1791,14 +1851,15 @@ class XMLBox(Jp2kBox):
read_buffer = fptr.read(num_bytes)
text = read_buffer.decode('utf-8')
# Strip out any trailing nulls.
text = text.rstrip('\0')
# Strip out any trailing nulls, as they can foul up XML parsing.
text = text.rstrip(chr(0))
try:
elt = ET.fromstring(text)
xml = ET.ElementTree(elt)
except ParseError as parse_error:
msg = 'A problem was encountered while parsing an XML box: "{0}"'
msg = 'A problem was encountered while parsing an XML box:'
msg += '\n\n\t"{0}"\n\nNo XML was retrieved.'
msg = msg.format(str(parse_error))
warnings.warn(msg, UserWarning)
xml = None

View file

@ -1,6 +1,7 @@
"""
Entry point for jp2dump script.
"""
import warnings
from .jp2k import Jp2k
@ -15,8 +16,21 @@ def jp2dump(filename, codestream=False):
codestream : optional, logical scalar
Whether or not to dump codestream contents.
"""
j = Jp2k(filename)
if codestream:
print(j.get_codestream(header_only=False))
else:
print(j)
with warnings.catch_warnings(record=True) as wctx:
# JP2 metadata can be extensive, so don't print any warnings until we
# are done with the metadata.
j = Jp2k(filename)
if codestream:
print(j.get_codestream(header_only=False))
else:
print(j)
# Re-emit any warnings that may have been suppressed.
if len(wctx) > 0:
print("\n")
for warning in wctx:
print("{0}:{1}: {2}: {3}".format(warning.filename,
warning.lineno,
warning.category.__name__,
warning.message))

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -1 +1,3 @@
#from .test_openjp2 import TestOpenJP2 as openjp2
"""
Test suite for openjp2, openjpeg low-level functionality.
"""

View file

@ -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()

View file

@ -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)

View file

@ -0,0 +1,3 @@
"""
Test suite for glymur high-level functionality.
"""

View file

@ -1,5 +1,9 @@
"""
Test fixtures common to more than one test point.
"""
import re
import sys
import warnings
import numpy as np
@ -20,6 +24,28 @@ if glymur.lib.openjp2.OPENJP2 is not None:
OPENJP2_IS_V2_OFFICIAL = True
NO_READ_BACKEND_MSG = "Matplotlib with the PIL backend must be available in "
NO_READ_BACKEND_MSG += "order to run the tests in this suite."
try:
from matplotlib.pyplot import imread
NO_READ_BACKEND = False
except ImportError:
NO_READ_BACKEND = True
def read_image(infile):
"""Read image using matplotlib backend.
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():
warnings.simplefilter("ignore")
data = imread(infile)
return data
def mse(amat, bmat):
"""Mean Square Error"""
diff = amat.astype(np.double) - bmat.astype(np.double)
@ -36,28 +62,10 @@ def peak_tolerance(amat, bmat):
def read_pgx(pgx_file):
"""Helper function for reading the PGX comparison files.
Open the file in ascii mode and read the header line.
Will look something like
PG ML + 8 128 128
PG%[ \t]%c%c%[ \t+-]%d%[ \t]%d%[ \t]%d"
"""
header = ''
with open(pgx_file, 'rb') as fptr:
while True:
char = fptr.read(1)
if char[0] == 10 or char == '\n':
pos = fptr.tell()
break
else:
if sys.hexversion < 0x03000000:
header += char
else:
header += chr(char[0])
header, pos = read_pgx_header(pgx_file)
header = header.rstrip()
tokens = re.split('\s', header)
tokens = re.split(r'\s', header)
if (tokens[1][0] == 'M') and (sys.byteorder == 'little'):
swapbytes = True
@ -81,6 +89,29 @@ def read_pgx(pgx_file):
nrows = int(tokens[4])
ncols = int(tokens[3])
dtype = determine_pgx_datatype(signed, bitdepth)
shape = [nrows, ncols]
# Reopen the file in binary mode and seek to the start of the binary
# data
with open(pgx_file, 'rb') as fptr:
fptr.seek(pos)
data = np.fromfile(file=fptr, dtype=dtype).reshape(shape)
return(data.byteswap(swapbytes))
def determine_pgx_datatype(signed, bitdepth):
"""Determine the datatype of the PGX file.
Parameters
----------
signed : bool
True if the datatype is signed, false otherwise
bitdepth : int
How many bits are used to make up an image plane. Should be 8 or 16.
"""
if signed:
if bitdepth <= 8:
dtype = np.int8
@ -96,12 +127,28 @@ def read_pgx(pgx_file):
else:
raise RuntimeError("unhandled bitdepth")
shape = [nrows, ncols]
return dtype
# Reopen the file in binary mode and seek to the start of the binary
# data
def read_pgx_header(pgx_file):
"""Open the file in ascii mode (not really) and read the header line.
Will look something like
PG ML + 8 128 128
PG%[ \t]%c%c%[ \t+-]%d%[ \t]%d%[ \t]%d"
"""
header = ''
with open(pgx_file, 'rb') as fptr:
fptr.seek(pos)
data = np.fromfile(file=fptr, dtype=dtype).reshape(shape)
while True:
char = fptr.read(1)
if char[0] == 10 or char == '\n':
pos = fptr.tell()
break
else:
if sys.hexversion < 0x03000000:
header += char
else:
header += chr(char[0])
return(data.byteswap(swapbytes))
header = header.rstrip()
return header, pos

View file

@ -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,15 +90,18 @@ 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+
\[INFO\]\s-\stiers-1\stook\s
[0-9]+\.[0-9]+\ss\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:

View file

@ -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(os.name == "nt", "Temporary file issue on window.")
@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) as cw:
j = Jp2k(tfile.name)
c = j.get_codestream()
with self.assertWarns(UserWarning):
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()

View file

@ -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__":

View file

@ -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()

View file

@ -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()

View file

@ -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)

View file

@ -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
@ -7,6 +18,7 @@ import struct
import sys
import tempfile
import uuid
from xml.etree import cElementTree as ET
if sys.hexversion < 0x02070000:
import unittest2 as unittest
@ -24,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
@ -53,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()
@ -61,29 +78,29 @@ 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 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 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()
with patch('glymur.lib.openjp2.OPENJP2', new=None):
with patch('glymur.lib.openjpeg.OPENJPEG', new=None):
with patch('glymur.lib.openjpeg.OPENJPEG', new=None):
with self.assertRaises(glymur.jp2k.LibraryNotFoundError):
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
ofile = Jp2k(tfile.name, 'wb')
@ -94,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
@ -136,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)
@ -156,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()
@ -165,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)
@ -173,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:
@ -218,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:
@ -233,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)
@ -242,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
@ -304,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)
@ -346,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.
@ -354,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)
@ -380,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')
@ -412,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)
@ -463,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)
@ -472,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)
@ -483,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)
@ -494,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)
@ -509,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)
@ -521,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:
@ -530,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)
@ -595,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)
@ -623,9 +666,12 @@ class TestJp2k(unittest.TestCase):
self.assertEqual(jp2k.box[3].box_id, 'xml ')
self.assertEqual(jp2k.box[3].offset, 77)
self.assertEqual(jp2k.box[3].length, 36)
self.assertEqual(ET.tostring(jp2k.box[3].xml.getroot()),
b'<test>this is a test</test>')
@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)
@ -636,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)
@ -675,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.
@ -702,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#}'
@ -720,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)
@ -730,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.
@ -742,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
@ -754,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

View file

@ -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
@ -12,48 +20,28 @@ if sys.hexversion < 0x02070000:
else:
import unittest
import warnings
import numpy as np
import pkg_resources
from glymur.lib import openjp2 as opj2
msg = "Matplotlib with the PIL backend must be available in order to run the "
msg += "tests in this suite."
no_read_backend_msg = msg
try:
from PIL import Image
from matplotlib.pyplot import imread
no_read_backend = False
except:
no_read_backend = True
from .fixtures import read_image, NO_READ_BACKEND, NO_READ_BACKEND_MSG
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
def read_image(infile):
# PIL issues warnings which we do not care about, so suppress them.
with warnings.catch_warnings():
warnings.simplefilter("ignore")
data = imread(infile)
return data
@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(NO_READ_BACKEND, NO_READ_BACKEND_MSG)
@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()
@ -63,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)
@ -109,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

View file

@ -1,6 +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 struct
import sys
import tempfile
@ -25,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
@ -121,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)
@ -137,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)
@ -179,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()
@ -187,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)
@ -200,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.
@ -212,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:
@ -239,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:
@ -270,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")
@ -342,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:
@ -372,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:
@ -386,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
@ -402,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:
@ -413,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:
@ -431,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:
@ -460,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:
@ -477,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:
@ -494,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:
@ -509,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:
@ -523,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:
@ -544,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:
@ -555,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:
@ -566,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:
@ -580,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:
@ -604,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])
@ -626,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())
@ -671,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])
@ -706,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])
@ -721,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])
@ -736,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])
@ -749,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])
@ -772,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:
@ -809,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])
@ -825,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)
@ -900,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")
@ -944,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")
@ -967,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:
@ -1026,5 +1049,6 @@ class TestPrinting(unittest.TestCase):
self.assertEqual(actual, expected)
if __name__ == "__main__":
unittest.main()

View file

@ -1,59 +0,0 @@
| OS | Python | Python | Python | Notes |
| | 2.6 | 2.7 | 3.3 | |
+-----------+--------+--------+--------+--------------------------------------+
| Windows | | X | | WinPython with OpenJPEG 1.5.1 and |
| | | | | OpenJPEG 2.0.0. 267 of 455 tests |
| | | | | pass. |
+-----------+--------+--------+--------+--------------------------------------+
| Windows | | | X | WinPython with OpenJPEG 1.5.1 and |
| | | | | OpenJPEG svn. 307 of 455 tests |
| | | | | pass. |
+-----------+--------+--------+--------+--------------------------------------+
| Mac | X | | | MacPorts with both OpenJPEG 1.5.1 |
| 10.6.8 | | | | and OpenJPEG svn. 354 of 456 tests |
| | | | | should pass. |
+-----------+--------+--------+--------+--------------------------------------+
| Mac | X | | | MacPorts with both OpenJPEG 1.5.1 |
| 10.6.8 | | | | and OpenJPEG 2.0. 315 of 456 tests |
| | | | | should pass. |
+-----------+--------+--------+--------+--------------------------------------+
| Mac | | X | | MacPorts with both OpenJPEG 1.5.1 |
| 10.6.8 | | | | and OpenJPEG svn. 379 of 461 tests |
| | | | | should pass. |
+-----------+--------+--------+--------+--------------------------------------+
| Mac | | X | | MacPorts with both OpenJPEG 1.5.1 |
| 10.6.8 | | | | and OpenJPEG 2.0. 340 of 461 tests |
| | | | | should pass. |
+-----------+--------+--------+--------+--------------------------------------+
| Mac | | | X | MacPorts with both OpenJPEG 1.5.1 |
| 10.6.8 | | | | and OpenJPEG svn. 407 of 461 |
| | | | | tests should pass. |
+-----------+--------+--------+--------+--------------------------------------+
| Mac | | | X | MacPorts with both OpenJPEG 1.5.1 |
| 10.6.8 | | | | and OpenJPEG 2.0. 355 of 461 |
| | | | | tests should pass. |
+-----------+--------+--------+-----------------------------------------------+
| Fedora 19 | | | X | Ships with 1.5.1, openjp2 svn built, |
| | | | | too. 407 of 461 tests should pass. |
+-----------+--------+--------+--------+--------------------------------------+
| Fedora 18 | | X | | Ships with 1.5.1. 173 of 456 tests |
| | | | | should pass. |
+-----------+--------+--------+--------+--------------------------------------+
| Fedora 17 | | X | | Ships with 1.4.0. 171 of 456 tests |
| | | | | should pass. |
+-----------+--------+--------+--------+--------------------------------------+
| CentOS | X | | | Ships with 1.3.0. 169 of 456 tests |
| 6.3 | | | | should pass. |
+-----------+--------+--------+--------+--------------------------------------+
| Raspberry | | X | | Ships with 1.3.0. 171 of 456 tests |
| Pi | | | | should pass. |
| Debian 7 | | | | |
+-----------+--------+--------+--------+--------------------------------------+
Make release branch, qualify on all platforms.
Pylint on entire package should exceed 0.95.
pep8 should be pass cleanly.
Coverage should exceed 95%.
Make release candidate, push to Pypi, qualify in virtual environment.
Merge release branch to master, tag, push to master, push to Pypi.

View file

@ -2,7 +2,7 @@ from setuptools import setup, find_packages
import sys
kwargs = {'name': 'Glymur',
'version': '0.3.0',
'version': '0.3.1',
'description': 'Tools for accessing JPEG2000 files',
'long_description': open('README.md').read(),
'author': 'John Evans',
@ -12,7 +12,7 @@ kwargs = {'name': 'Glymur',
'glymur.lib.test'],
'package_data': {'glymur': ['data/*.jp2', 'data/*.j2k']},
'scripts': ['bin/jp2dump'],
'license': 'LICENSE.txt',
'license': 'MIT',
'test_suite': 'glymur.test',
'platforms': ['darwin']}