merge branch 'issue311' into devel

This commit is contained in:
John Evans 2015-01-07 08:20:51 -05:00
commit bd3f491e20
11 changed files with 355 additions and 116 deletions

View file

@ -6,5 +6,7 @@ Changes in 0.8.0
=================
* Simplified writing images by moving data and options into the
constructor. This is backwards-incompatible with 0.7.x.
constructor.
* The main_header attribute of the ContiguousCodestream class is now called
codestream.
* Deprecated :py:meth:`read` method in favor of array-style slicing.

View file

@ -5,7 +5,7 @@ import argparse
import os
import warnings
from . import Jp2k, set_printoptions, lib
from . import Jp2k, set_printoptions, set_parseoptions, lib
def main():
@ -13,23 +13,25 @@ def main():
Entry point for console script jp2dump.
"""
description = 'Print JPEG2000 metadata.'
parser = argparse.ArgumentParser(description=description)
kwargs = {'description': 'Print JPEG2000 metadata.',
'formatter_class': argparse.ArgumentDefaultsHelpFormatter}
parser = argparse.ArgumentParser(**kwargs)
parser.add_argument('-x', '--noxml',
help='Suppress XML.',
help='suppress XML',
action='store_true')
parser.add_argument('-s', '--short',
help='Only print box id, offset, and length.',
help='only print box id, offset, and length',
action='store_true')
chelp = 'Level of codestream information. 0 suppressed all details, '
chelp += '1 prints headers, 2 prints the full codestream'
chelp = 'Level of codestream information. 0 suppresses all details, '
chelp += '1 prints the main header, 2 prints the full codestream.'
parser.add_argument('-c', '--codestream',
help=chelp,
metavar='LEVEL',
nargs=1,
type=int,
default=[0])
default=[1])
parser.add_argument('filename')
@ -45,11 +47,8 @@ def main():
if codestream_level == 0:
set_printoptions(codestream=False)
print_full_codestream = False
elif codestream_level == 1:
print_full_codestream = False
else:
print_full_codestream = True
elif codestream_level == 2:
set_parseoptions(full_codestream=True)
filename = args.filename
@ -58,11 +57,14 @@ def main():
# JP2 metadata can be extensive, so don't print any warnings until we
# are done with the metadata.
jp2 = Jp2k(filename)
if (((jp2._codec_format == lib.openjp2.CODEC_J2K) and
(codestream_level == 0))):
print('File: {0}'.format(os.path.basename(filename)))
elif print_full_codestream:
print(jp2.get_codestream(header_only=False))
if jp2._codec_format == lib.openjp2.CODEC_J2K:
if codestream_level == 0:
print('File: {0}'.format(os.path.basename(filename)))
elif codestream_level == 1:
print(jp2)
elif codestream_level == 2:
print('File: {0}'.format(os.path.basename(filename)))
print(jp2.get_codestream(header_only=False))
else:
print(jp2)

View file

@ -1001,18 +1001,19 @@ class ContiguousCodestreamBox(Jp2kBox):
offset of the box from the start of the file.
longname : str
more verbose description of the box.
main_header : Codestream object
contains list of main header marker/segments
codestream : Codestream object
Contains list of codestream marker/segments. By default, only the main
header is retrieved.
main_header_offset : int
offset of main header from start of file
"""
box_id = 'jp2c'
longname = 'Contiguous Codestream'
def __init__(self, main_header=None, main_header_offset=None, length=0,
def __init__(self, codestream=None, main_header_offset=None, length=0,
offset=-1):
Jp2kBox.__init__(self)
self._main_header = main_header
self._codestream = codestream
self.length = length
self.offset = offset
self.main_header_offset = main_header_offset
@ -1021,20 +1022,23 @@ class ContiguousCodestreamBox(Jp2kBox):
self._filename = None
@property
def main_header(self):
if self._main_header is None:
def codestream(self):
if _parseoptions['full_codestream'] is True:
header_only = False
else:
header_only = True
if self._codestream is None:
if self._filename is not None:
with open(self._filename, 'rb') as fptr:
fptr.seek(self.main_header_offset)
main_header = Codestream(fptr,
self._length,
header_only=True)
self._main_header = main_header
return self._main_header
codestream = Codestream(fptr, self._length,
header_only=header_only)
self._codestream = codestream
return self._codestream
def __repr__(self):
msg = "glymur.jp2box.ContiguousCodeStreamBox(main_header={0})"
return msg.format(repr(self.main_header))
msg = "glymur.jp2box.ContiguousCodeStreamBox(codestream={0})"
return msg.format(repr(self.codestream))
def __str__(self):
msg = Jp2kBox.__str__(self)
@ -1043,9 +1047,8 @@ class ContiguousCodestreamBox(Jp2kBox):
if _printoptions['codestream'] is False:
return msg
msg += '\n Main header:'
for segment in self.main_header.segment:
msg += '\n' + self._indent(str(segment), indent_level=8)
for segment in self.codestream.segment:
msg += '\n' + self._indent(str(segment), indent_level=4)
return msg
@ -1067,11 +1070,11 @@ class ContiguousCodestreamBox(Jp2kBox):
ContiguousCodestreamBox instance
"""
main_header_offset = fptr.tell()
if _parseoptions['codestream'] is True:
main_header = Codestream(fptr, length, header_only=True)
if _parseoptions['full_codestream'] is True:
codestream = Codestream(fptr, length, header_only=False)
else:
main_header = None
box = cls(main_header, main_header_offset=main_header_offset,
codestream = None
box = cls(codestream, main_header_offset=main_header_offset,
length=length, offset=offset)
box._filename = fptr.name
box._length = length
@ -1320,7 +1323,7 @@ class FileTypeBox(Jp2kBox):
if sys.hexversion >= 0x03000000:
try:
entry = entry.decode('utf-8')
except UnicodeDecodeError as err:
except UnicodeDecodeError:
# The entry is invalid, but we've got code to catch this
# later on.
pass
@ -3314,19 +3317,20 @@ _BOX_WITH_ID = {
b'uuid': UUIDBox,
b'xml ': XMLBox}
_parseoptions = {'codestream': True}
_parseoptions = {'full_codestream': False}
def set_parseoptions(codestream=True):
def set_parseoptions(full_codestream=True):
"""Set parsing options.
These options determine the way JPEG 2000 boxes are parsed.
Parameters
----------
codestream : bool, defaults to True
When False, the codestream header is only parsed when accessed. This
can results in faster JP2/JPX parsing.
full_codestream : bool, defaults to True
When False, only the codestream header is parsed for metadata. This
can results in faster JP2/JPX parsing. When True, the entire
codestream is parsed for metadata.
See also
--------
@ -3337,9 +3341,9 @@ def set_parseoptions(codestream=True):
To put back the default options, you can use:
>>> import glymur
>>> glymur.set_parseoptions(codestream=True)
>>> glymur.set_parseoptions(full_codestream=True)
"""
_parseoptions['codestream'] = codestream
_parseoptions['full_codestream'] = full_codestream
def get_parseoptions():
@ -3378,7 +3382,9 @@ def set_printoptions(**kwargs):
When False, printing of the XML contents of any XML boxes or UUID XMP
boxes is suppressed.
codestream : bool, optional
When False, printing of the codestream contents is suppressed.
When False, only the codestream header is printed. When True, the
entire codestream is printed. This option has no effect when the
'short' option is set to True.
See also
--------

View file

@ -2,6 +2,7 @@
Test fixtures common to more than one test point.
"""
import os
import platform
import re
import sys
import textwrap
@ -33,6 +34,14 @@ elif re.match('1.[0-6]', six.__version__) is not None:
WARNING_INFRASTRUCTURE_ISSUE = True
msg = "Cannot run test with version {0} of python-six"
WARNING_INFRASTRUCTURE_MSG = msg.format(six.__version__)
elif ((re.match('1.8', six.__version__) is not None) and
(sys.platform.startswith('linux')) and
(platform.linux_distribution() == ('LinuxMint', '17', 'qiana'))):
WARNING_INFRASTRUCTURE_ISSUE = True
linux_distribution = platform.linux_distribution()
msg = "Cannot run test with version {0} of python-six on {1}"
WARNING_INFRASTRUCTURE_MSG = msg.format(six.__version__,
platform.linux_distribution)
# Cannot reopen a named temporary file in windows.
WINDOWS_TMP_FILE_MSG = "cannot use NamedTemporaryFile like this in windows"
@ -709,6 +718,190 @@ UUID Box (uuid) @ (77, 3146)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
Contiguous Codestream Box (jp2c) @ (3223, 1132296)"""
nemo = """JPEG 2000 Signature Box (jP ) @ (0, 12)
Signature: 0d0a870a
File Type Box (ftyp) @ (12, 20)
Brand: jp2
Compatibility: ['jp2 ']
JP2 Header Box (jp2h) @ (32, 45)
Image Header Box (ihdr) @ (40, 22)
Size: [1456 2592 3]
Bitdepth: 8
Signed: False
Compression: wavelet
Colorspace Unknown: False
Colour Specification Box (colr) @ (62, 15)
Method: enumerated colorspace
Precedence: 0
Colorspace: sRGB
UUID Box (uuid) @ (77, 3146)
UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)
UUID Data:
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<ns0:xmpmeta xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:ns0="adobe:ns:meta/" xmlns:ns2="http://ns.adobe.com/xap/1.0/" xmlns:ns3="http://ns.adobe.com/tiff/1.0/" xmlns:ns4="http://ns.adobe.com/exif/1.0/" xmlns:ns5="http://ns.adobe.com/photoshop/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ns0:xmptk="Exempi + XMP Core 5.1.2">
<rdf:RDF>
<rdf:Description rdf:about="">
<ns2:CreatorTool>Google</ns2:CreatorTool>
<ns2:CreateDate>2013-02-09T14:47:53</ns2:CreateDate>
</rdf:Description>
<rdf:Description rdf:about="">
<ns3:YCbCrPositioning>1</ns3:YCbCrPositioning>
<ns3:XResolution>72/1</ns3:XResolution>
<ns3:YResolution>72/1</ns3:YResolution>
<ns3:ResolutionUnit>2</ns3:ResolutionUnit>
<ns3:Make>HTC</ns3:Make>
<ns3:Model>HTC Glacier</ns3:Model>
<ns3:ImageWidth>2592</ns3:ImageWidth>
<ns3:ImageLength>1456</ns3:ImageLength>
<ns3:BitsPerSample>
<rdf:Seq>
<rdf:li>8</rdf:li>
<rdf:li>8</rdf:li>
<rdf:li>8</rdf:li>
</rdf:Seq>
</ns3:BitsPerSample>
<ns3:PhotometricInterpretation>2</ns3:PhotometricInterpretation>
<ns3:SamplesPerPixel>3</ns3:SamplesPerPixel>
<ns3:WhitePoint>
<rdf:Seq>
<rdf:li>1343036288/4294967295</rdf:li>
<rdf:li>1413044224/4294967295</rdf:li>
</rdf:Seq>
</ns3:WhitePoint>
<ns3:PrimaryChromaticities>
<rdf:Seq>
<rdf:li>2748779008/4294967295</rdf:li>
<rdf:li>1417339264/4294967295</rdf:li>
<rdf:li>1288490240/4294967295</rdf:li>
<rdf:li>2576980480/4294967295</rdf:li>
<rdf:li>644245120/4294967295</rdf:li>
<rdf:li>257698032/4294967295</rdf:li>
</rdf:Seq>
</ns3:PrimaryChromaticities>
</rdf:Description>
<rdf:Description rdf:about="">
<ns4:ColorSpace>1</ns4:ColorSpace>
<ns4:PixelXDimension>2528</ns4:PixelXDimension>
<ns4:PixelYDimension>1424</ns4:PixelYDimension>
<ns4:FocalLength>353/100</ns4:FocalLength>
<ns4:GPSAltitudeRef>0</ns4:GPSAltitudeRef>
<ns4:GPSAltitude>0/1</ns4:GPSAltitude>
<ns4:GPSMapDatum>WGS-84</ns4:GPSMapDatum>
<ns4:DateTimeOriginal>2013-02-09T14:47:53</ns4:DateTimeOriginal>
<ns4:ISOSpeedRatings>
<rdf:Seq>
<rdf:li>76</rdf:li>
</rdf:Seq>
</ns4:ISOSpeedRatings>
<ns4:ExifVersion>0220</ns4:ExifVersion>
<ns4:FlashpixVersion>0100</ns4:FlashpixVersion>
<ns4:ComponentsConfiguration>
<rdf:Seq>
<rdf:li>1</rdf:li>
<rdf:li>2</rdf:li>
<rdf:li>3</rdf:li>
<rdf:li>0</rdf:li>
</rdf:Seq>
</ns4:ComponentsConfiguration>
<ns4:GPSLatitude>42,20.56N</ns4:GPSLatitude>
<ns4:GPSLongitude>71,5.29W</ns4:GPSLongitude>
<ns4:GPSTimeStamp>2013-02-09T19:47:53Z</ns4:GPSTimeStamp>
<ns4:GPSProcessingMethod>NETWORK</ns4:GPSProcessingMethod>
</rdf:Description>
<rdf:Description rdf:about="">
<ns5:DateCreated>2013-02-09T14:47:53</ns5:DateCreated>
</rdf:Description>
<rdf:Description rdf:about="">
<dc:Creator>
<rdf:Seq>
<rdf:li>Glymur</rdf:li>
<rdf:li>Python XMP Toolkit</rdf:li>
</rdf:Seq>
</dc:Creator>
</rdf:Description>
</rdf:RDF>
</ns0:xmpmeta>
<?xpacket end="w"?>
Contiguous Codestream Box (jp2c) @ (3223, 1132296)
SOC marker segment @ (3231, 0)
SIZ marker segment @ (3233, 47)
Profile: no profile
Reference Grid Height, Width: (1456 x 2592)
Vertical, Horizontal Reference Grid Offset: (0 x 0)
Reference Tile Height, Width: (1456 x 2592)
Vertical, Horizontal Reference Tile Offset: (0 x 0)
Bitdepth: (8, 8, 8)
Signed: (False, False, False)
Vertical, Horizontal Subsampling: ((1, 1), (1, 1), (1, 1))
COD marker segment @ (3282, 12)
Coding style:
Entropy coder, without partitions
SOP marker segments: False
EPH marker segments: False
Coding style parameters:
Progression order: LRCP
Number of layers: 2
Multiple component transformation usage: reversible
Number of resolutions: 2
Code block height, width: (64 x 64)
Wavelet transform: 5-3 reversible
Precinct size: default, 2^15 x 2^15
Code block context:
Selective arithmetic coding bypass: False
Reset context probabilities on coding pass boundaries: False
Termination on each coding pass: False
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False
QCD marker segment @ (3296, 7)
Quantization style: no quantization, 2 guard bits
Step size: [(0, 8), (0, 9), (0, 9), (0, 10)]
CME marker segment @ (3305, 37)
"Created by OpenJPEG version 2.0.0"
SOT marker segment @ (3344, 10)
Tile part index: 0
Tile part length: 1132173
Tile part instance: 0
Number of tile parts: 1
COC marker segment @ (3356, 9)
Associated component: 1
Coding style for this component: Entropy coder, PARTITION = 0
Coding style parameters:
Number of resolutions: 2
Code block height, width: (64 x 64)
Wavelet transform: 5-3 reversible
Code block context:
Selective arithmetic coding bypass: False
Reset context probabilities on coding pass boundaries: False
Termination on each coding pass: False
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False
QCC marker segment @ (3367, 8)
Associated Component: 1
Quantization style: no quantization, 2 guard bits
Step size: [(0, 8), (0, 9), (0, 9), (0, 10)]
COC marker segment @ (3377, 9)
Associated component: 2
Coding style for this component: Entropy coder, PARTITION = 0
Coding style parameters:
Number of resolutions: 2
Code block height, width: (64 x 64)
Wavelet transform: 5-3 reversible
Code block context:
Selective arithmetic coding bypass: False
Reset context probabilities on coding pass boundaries: False
Termination on each coding pass: False
Vertically stripe causal context: False
Predictable termination: False
Segmentation symbols: False
QCC marker segment @ (3388, 8)
Associated Component: 2
Quantization style: no quantization, 2 guard bits
Step size: [(0, 8), (0, 9), (0, 9), (0, 10)]
SOD marker segment @ (3398, 0)
EOC marker segment @ (1135517, 0)"""
# Output of reader requirements printing for text_GBR.jp2
text_GBR_rreq = r"""Reader Requirements Box (rreq) @ (40, 109)
Fully Understands Aspect Mask: 0xffff

View file

@ -20,6 +20,13 @@ from .fixtures import WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG
class TestWarnings(unittest.TestCase):
"""Test suite for warnings issued by glymur."""
def test_invalid_compatibility_list_entry(self):
"""should not error out with invalid compatibility list entry"""
filename = opj_data_file('input/nonregression/issue397.jp2')
with self.assertWarns(UserWarning):
Jp2k(filename)
self.assertTrue(True)
def test_exceeded_box_length(self):
"""
should warn if reading past end of a box
@ -62,7 +69,7 @@ class TestWarnings(unittest.TestCase):
\(\d+\)\.""",
re.VERBOSE)
with self.assertWarnsRegex(UserWarning, regex):
Jp2k(jfile)
Jp2k(jfile).get_codestream()
@unittest.skipIf(re.match("1.5|2.0.0", glymur.version.openjpeg_version),
"Test not passing on 1.5.x, not introduced until 2.x")
@ -77,7 +84,7 @@ class TestWarnings(unittest.TestCase):
\(\d+\)\.""",
re.VERBOSE)
with self.assertWarnsRegex(UserWarning, regex):
Jp2k(jfile)
Jp2k(jfile).get_codestream()
def test_NR_gdal_fuzzer_check_comp_dx_dy_jp2_dump(self):
"""
@ -90,7 +97,7 @@ class TestWarnings(unittest.TestCase):
dx=\d+,\s*dy=\d+""",
re.VERBOSE)
with self.assertWarnsRegex(UserWarning, regex):
Jp2k(jfile)
Jp2k(jfile).get_codestream()
def test_NR_gdal_fuzzer_assert_in_opj_j2k_read_SQcd_SQcc_patch_jp2(self):
lst = ['input', 'nonregression',
@ -100,32 +107,32 @@ class TestWarnings(unittest.TestCase):
number\sof\scomponents\sis\sonly\s\d+""",
re.VERBOSE)
with self.assertWarnsRegex(UserWarning, regex):
Jp2k(jfile)
Jp2k(jfile).get_codestream()
def test_bad_rsiz(self):
"""Should warn if RSIZ is bad. Issue196"""
filename = opj_data_file('input/nonregression/edf_c2_1002767.jp2')
with self.assertWarnsRegex(UserWarning, 'Invalid profile'):
Jp2k(filename)
Jp2k(filename).get_codestream()
def test_bad_wavelet_transform(self):
"""Should warn if wavelet transform is bad. Issue195"""
filename = opj_data_file('input/nonregression/edf_c2_10025.jp2')
with self.assertWarnsRegex(UserWarning, 'Invalid wavelet transform'):
Jp2k(filename)
Jp2k(filename).get_codestream()
def test_invalid_progression_order(self):
"""Should still be able to parse even if prog order is invalid."""
jfile = opj_data_file('input/nonregression/2977.pdf.asan.67.2198.jp2')
with self.assertWarnsRegex(UserWarning, 'Invalid progression order'):
Jp2k(jfile)
Jp2k(jfile).get_codestream()
def test_tile_height_is_zero(self):
"""Zero tile height should not cause an exception."""
filename = 'input/nonregression/2539.pdf.SIGFPE.706.1712.jp2'
filename = opj_data_file(filename)
with self.assertWarnsRegex(UserWarning, 'Invalid tile dimensions'):
Jp2k(filename)
Jp2k(filename).get_codestream()
@unittest.skipIf(os.name == "nt", "Temporary file issue on window.")
def test_unknown_marker_segment(self):

View file

@ -1016,7 +1016,7 @@ class TestJp2Boxes(unittest.TestCase):
"""Raw instantiation should not produce a main_header."""
box = ContiguousCodestreamBox()
self.assertEqual(box.box_id, 'jp2c')
self.assertIsNone(box.main_header)
self.assertIsNone(box.codestream)
def test_codestream_main_header_offset(self):
"""main_header_offset is an attribute of the CCS box"""
@ -1318,7 +1318,7 @@ class TestRepr(MetadataBase):
# Difficult to eval(repr()) this, so just match the general pattern.
regexp = "glymur.jp2box.ContiguousCodeStreamBox"
regexp += "[(]main_header=<glymur.codestream.Codestream\sobject\s"
regexp += "[(]codestream=<glymur.codestream.Codestream\sobject\s"
regexp += "at\s0x([a-fA-F0-9]*)>[)]"
if sys.hexversion < 0x03000000:

View file

@ -36,6 +36,9 @@ from .fixtures import OPJ_DATA_ROOT, opj_data_file
from . import fixtures
def docTearDown(doctest_obj):
glymur.set_parseoptions(full_codestream=False)
# Doc tests should be run as well.
def load_tests(loader, tests, ignore):
"""Should run doc tests as well"""
@ -43,7 +46,8 @@ def load_tests(loader, tests, ignore):
# Can't do it on windows, temporary file issue.
return tests
if glymur.lib.openjp2.OPENJP2 is not None:
tests.addTests(doctest.DocTestSuite('glymur.jp2k'))
tests.addTests(doctest.DocTestSuite('glymur.jp2k',
tearDown=docTearDown))
return tests
@ -272,15 +276,6 @@ class TestJp2k(unittest.TestCase):
jp2 = Jp2k(jfile)
self.assertEqual(jp2.shape, (128, 128))
@unittest.skipIf(OPJ_DATA_ROOT is None,
"OPJ_DATA_ROOT environment variable not set")
def test_invalid_compatibility_list_entry(self):
"""should not error out with invalid compatibility list entry"""
filename = opj_data_file('input/nonregression/issue397.jp2')
with self.assertWarns(UserWarning):
Jp2k(filename)
self.assertTrue(True)
def test_shape_j2k(self):
"""verify shape attribute for J2K file
"""
@ -1052,31 +1047,30 @@ class TestParsing(unittest.TestCase):
def setUp(self):
self.jp2file = glymur.data.nemo()
# Reset parseoptions for every test.
glymur.set_parseoptions(codestream=True)
glymur.set_parseoptions(full_codestream=False)
def tearDown(self):
glymur.set_parseoptions(codestream=True)
glymur.set_parseoptions(full_codestream=False)
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
def test_bad_rsiz(self):
"""Should not warn if RSIZ when parsing is turned off."""
filename = opj_data_file('input/nonregression/edf_c2_1002767.jp2')
glymur.set_parseoptions(codestream=False)
glymur.set_parseoptions(full_codestream=False)
Jp2k(filename)
glymur.set_parseoptions(codestream=True)
glymur.set_parseoptions(full_codestream=True)
with self.assertWarnsRegex(UserWarning, 'Invalid profile'):
Jp2k(filename)
def test_main_header(self):
"""Verify that the main header isn't loaded when parsing turned off."""
"""verify that the main header isn't loaded during normal parsing"""
# The hidden _main_header attribute should show up after accessing it.
glymur.set_parseoptions(codestream=False)
jp2 = Jp2k(self.jp2file)
jp2c = jp2.box[4]
self.assertIsNone(jp2c._main_header)
jp2c.main_header
self.assertIsNotNone(jp2c._main_header)
self.assertIsNone(jp2c._codestream)
jp2c.codestream
self.assertIsNotNone(jp2c._codestream)
@unittest.skipIf(WARNING_INFRASTRUCTURE_ISSUE, WARNING_INFRASTRUCTURE_MSG)
@ -1085,6 +1079,9 @@ class TestParsing(unittest.TestCase):
class TestJp2kOpjDataRootWarnings(unittest.TestCase):
"""These tests should be run by just about all configuration."""
def tearDown(self):
glymur.set_parseoptions(full_codestream=False)
def test_undecodeable_box_id(self):
"""Should warn in case of undecodeable box ID but not error out."""
filename = opj_data_file('input/nonregression/edf_c2_1013627.jp2')

View file

@ -385,7 +385,7 @@ class TestSuiteWarns(MetadataBase):
expected = ColourSpecificationBox(colorspace=glymur.core.SRGB)
self.verifyColourSpecificationBox(jp2.box[2].box[1], expected)
c = jp2.box[3].main_header
c = jp2.box[3].codestream
ids = [x.marker_id for x in c.segment]
expected = ['SOC', 'SIZ', 'CME', 'COD', 'QCD', 'QCC', 'QCC']

View file

@ -4,6 +4,7 @@ suite.
"""
import re
import unittest
import warnings
import numpy as np
@ -52,7 +53,7 @@ class TestSuite(MetadataBase):
colr = glymur.jp2box.ColourSpecificationBox(colorspace=glymur.core.YCC)
self.verifyColourSpecificationBox(jp2.box[2].box[1], colr)
c = jp2.box[3].main_header
c = jp2.box[3].codestream
ids = [x.marker_id for x in c.segment]
expected = ['SOC', 'SIZ', 'COD', 'QCD']
@ -2584,7 +2585,7 @@ class TestSuite(MetadataBase):
self.assertEqual(jp2.box[3].box[3].mapping_type, (1, 1, 1))
self.assertEqual(jp2.box[3].box[3].palette_index, (0, 1, 2))
c = jp2.box[4].main_header
c = jp2.box[4].codestream
ids = [x.marker_id for x in c.segment]
expected = ['SOC', 'SIZ', 'COD', 'QCD']
@ -2648,7 +2649,7 @@ class TestSuite(MetadataBase):
precedence=2)
self.verifyColourSpecificationBox(jp2.box[3].box[1], colr)
c = jp2.box[4].main_header
c = jp2.box[4].codestream
ids = [x.marker_id for x in c.segment]
expected = ['SOC', 'SIZ', 'COD', 'QCD']
@ -2711,7 +2712,7 @@ class TestSuite(MetadataBase):
self.assertEqual(jp2.box[2].box[2].channel_type, (0, 1)) # opacity
self.assertEqual(jp2.box[2].box[2].association, (0, 0)) # both main
c = jp2.box[3].main_header
c = jp2.box[3].codestream
ids = [x.marker_id for x in c.segment]
expected = ['SOC', 'SIZ', 'COD', 'QCD', 'CME']
@ -2794,7 +2795,7 @@ class TestSuite(MetadataBase):
self.assertEqual(jp2.box[3].box[3].mapping_type, (1, 1, 1))
self.assertEqual(jp2.box[3].box[3].palette_index, (0, 1, 2))
c = jp2.box[4].main_header
c = jp2.box[4].codestream
ids = [x.marker_id for x in c.segment]
expected = ['SOC', 'SIZ', 'COD', 'QCD']
@ -2848,7 +2849,7 @@ class TestSuite(MetadataBase):
colr = glymur.jp2box.ColourSpecificationBox(colorspace=glymur.core.YCC)
self.verifyColourSpecificationBox(jp2.box[2].box[1], colr)
c = jp2.box[3].main_header
c = jp2.box[3].codestream
ids = [x.marker_id for x in c.segment]
expected = ['SOC', 'SIZ', 'COD', 'QCD', 'POD']
@ -2913,21 +2914,29 @@ class TestSuiteWarns(MetadataBase):
def test_NR_broken4_jp2_dump(self):
jfile = opj_data_file('input/nonregression/broken4.jp2')
with self.assertWarns(UserWarning):
jp2 = Jp2k(jfile)
self.assertEqual(jp2.box[-1].main_header.segment[-1].marker_id, 'QCC')
with warnings.catch_warnings():
# Suppress a warning, all we really care is parsing the entire
# file.
warnings.simplefilter("ignore")
with self.assertWarns(UserWarning):
jp2 = Jp2k(jfile)
self.assertEqual(jp2.box[-1].codestream.segment[-1].marker_id,
'QCC')
def test_NR_broken2_jp2_dump(self):
"""
Invalid marker ID in the codestream.
"""
jfile = opj_data_file('input/nonregression/broken2.jp2')
with self.assertWarns(UserWarning):
# Invalid marker ID on codestream.
jp2 = Jp2k(jfile)
self.assertEqual(jp2.box[-1].main_header.segment[-1].marker_id, 'QCC')
with warnings.catch_warnings():
# Suppress a warning, all we really care is parsing the entire
# file.
warnings.simplefilter("ignore")
with self.assertWarns(UserWarning):
# Invalid marker ID on codestream.
jp2 = Jp2k(jfile)
self.assertEqual(jp2.box[-1].codestream.segment[-1].marker_id,
'QCC')
def test_NR_file1_dump(self):
jfile = opj_data_file('input/conformance/file1.jp2')
@ -3243,7 +3252,7 @@ class TestSuiteWarns(MetadataBase):
# Skip the 4th box, it is uknown.
c = jp2.box[4].main_header
c = jp2.box[4].codestream
ids = [x.marker_id for x in c.segment]
expected = ['SOC', 'SIZ', 'COD', 'QCD', 'CME', 'CME']
@ -3303,7 +3312,7 @@ class TestSuiteWarns(MetadataBase):
self.assertIsNone(jp2.box[2].box[1].icc_profile)
self.assertIsNone(jp2.box[2].box[1].colorspace)
c = jp2.box[3].main_header
c = jp2.box[3].codestream
ids = [x.marker_id for x in c.segment]
expected = ['SOC', 'SIZ', 'COD', 'QCD']
@ -3366,7 +3375,7 @@ class TestSuiteWarns(MetadataBase):
self.assertIsNone(jp2.box[2].box[1].icc_profile)
self.assertIsNone(jp2.box[2].box[1].colorspace)
c = jp2.box[3].main_header
c = jp2.box[3].codestream
ids = [x.marker_id for x in c.segment]
expected = ['SOC', 'SIZ', 'COD', 'QCD']

View file

@ -632,7 +632,7 @@ class TestSuiteWrite(fixtures.MetadataBase):
self.assertIsNone(jp2.box[2].box[1].icc_profile)
self.assertEqual(jp2.box[2].box[1].colorspace, glymur.core.SRGB)
codestream = jp2.box[3].main_header
codestream = jp2.box[3].codestream
kwargs = {'rsiz': 0, 'xysiz': (640, 480), 'xyosiz': (0, 0),
'xytsiz': (640, 480), 'xytosiz': (0, 0),

View file

@ -42,7 +42,7 @@ class TestPrinting(unittest.TestCase):
glymur.set_printoptions(short=False, xml=True, codestream=True)
def tearDown(self):
pass
glymur.set_parseoptions(full_codestream=False)
def test_version_info(self):
"""Should be able to print(glymur.version.info)"""
@ -854,7 +854,7 @@ class TestPrintingOpjDataRootWarns(unittest.TestCase):
"""Should still be able to print if rsiz is bad, issue196"""
filename = opj_data_file('input/nonregression/edf_c2_1002767.jp2')
with self.assertWarns(UserWarning):
j = Jp2k(filename)
j = Jp2k(filename).get_codestream()
with patch('sys.stdout', new=StringIO()):
print(j)
@ -1040,9 +1040,10 @@ class TestJp2dump(unittest.TestCase):
# Reset printoptions for every test.
glymur.set_printoptions(short=False, xml=True, codestream=True)
glymur.set_parseoptions(full_codestream=False)
def tearDown(self):
pass
glymur.set_parseoptions(full_codestream=False)
def run_jp2dump(self, args):
sys.argv = args
@ -1055,25 +1056,51 @@ class TestJp2dump(unittest.TestCase):
return actual
def test_default_nemo(self):
"""Should be able to dump a JP2 file's metadata with no codestream."""
"""by default one should get the main header"""
actual = self.run_jp2dump(['', self.jp2file])
self.assertEqual(actual, fixtures.nemo_dump_no_codestream)
# shave off the non-main-header segments
lines = fixtures.nemo.split('\n')
expected = lines[0:140]
expected = '\n'.join(expected)
self.assertEqual(actual, expected)
def test_codestream_0(self):
@unittest.skipIf(sys.hexversion < 0x03000000, "assertRegex not in 2.7")
def test_jp2_codestream_0(self):
"""Verify dumping with -c 0, supressing all codestream details."""
actual = self.run_jp2dump(['', '-c', '0', self.jp2file])
expected = fixtures.nemo_dump_no_codestream
self.assertEqual(actual, expected)
def test_codestream_1(self):
def test_jp2_codestream_1(self):
"""Verify dumping with -c 1, print just the header."""
actual = self.run_jp2dump(['', '-c', '1', self.jp2file])
self.assertEqual(actual, fixtures.nemo_with_codestream_header)
# shave off the non-main-header segments
lines = fixtures.nemo.split('\n')
expected = lines[0:140]
expected = '\n'.join(expected)
self.assertEqual(actual, expected)
def test_codestream_2(self):
def test_jp2_codestream_2(self):
"""Verify dumping with -c 2, print entire jp2 jacket, codestream."""
actual = self.run_jp2dump(['', '-c', '2', self.jp2file])
# shave off the non-main-header segments
expected = fixtures.nemo
self.assertEqual(actual, expected)
@unittest.skipIf(sys.hexversion < 0x03000000, "assertRegex not in 2.7")
def test_j2k_codestream_0(self):
"""-c 0 should print just a single line when used on a codestream."""
sys.argv = ['', '-c', '0', self.j2kfile]
with patch('sys.stdout', new=StringIO()) as fake_out:
command_line.main()
actual = fake_out.getvalue().strip()
self.assertRegex(actual, "File: .*")
def test_j2k_codestream_2(self):
"""Verify dumping with -c 2, full details."""
with patch('sys.stdout', new=StringIO()) as fake_out:
sys.argv = ['', '-c', '2', self.j2kfile]
@ -1098,13 +1125,9 @@ class TestJp2dump(unittest.TestCase):
"""Verify dumping with -x, suppress XML."""
actual = self.run_jp2dump(['', '-x', self.jp2file])
self.assertEqual(actual, fixtures.nemo_dump_no_codestream_no_xml)
@unittest.skipIf(sys.hexversion < 0x03000000, "assertRegex not in 2.7")
def test_codestream_0_with_j2k_file(self):
"""-c 0 should print just a single line when used on a codestream."""
sys.argv = ['', '-c', '0', self.j2kfile]
with patch('sys.stdout', new=StringIO()) as fake_out:
command_line.main()
actual = fake_out.getvalue().strip()
self.assertRegex(actual, "File: .*")
# shave off the XML and non-main-header segments
lines = fixtures.nemo.split('\n')
expected = lines[0:18]
expected.extend(lines[104:140])
expected = '\n'.join(expected)
self.assertEqual(actual, expected)