merge branch 'issue311' into devel
This commit is contained in:
commit
bd3f491e20
11 changed files with 355 additions and 116 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
--------
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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']
|
||||
|
|
|
|||
|
|
@ -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']
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue