Merge branch 'devel'

This commit is contained in:
John Evans 2013-05-31 08:30:46 -04:00
commit f2e67007a3
13 changed files with 213 additions and 121 deletions

View file

@ -1,7 +1,8 @@
May 28, 2013 - Added jp2 boxes to rst docs, XMLBox.indent method made private. May 30, 2013 - v0.1.2. Added XMP UUID read support. Added jp2 boxes to rst
docs, XMLBox.indent method made into a private module method. Precinct
sizes restricted to be multiples of two.
May 27, 2013 - v0.1.1, Changed write example to not rely on matplotlib. Fixed May 27, 2013 - v0.1.1. Changed write example to not rely on matplotlib. Fixed
readthedocs.org setup to build documentation automatically. Can import readthedocs.org setup to build documentation automatically. Can import
glymur without libopenjp2 actually being present. glymur without libopenjp2 actually being present. Changed write example
to not rely on matplotlib.
May 27, 2013 - Changed write example to not rely on matplotlib.

View file

@ -75,7 +75,7 @@ copyright = u'2013, John Evans'
# The short X.Y version. # The short X.Y version.
version = '0.1' version = '0.1'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.1.1' release = '0.1.2'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View file

@ -7,9 +7,9 @@ which allows linux and mac users to read and write JPEG 2000 files. For more
information about OpenJPEG, please consult http://www.openjpeg.org. glymur information about OpenJPEG, please consult http://www.openjpeg.org. glymur
should be considered to be alpha-quality software. should be considered to be alpha-quality software.
glymur tries to support reading (including all metadata) and writing of glymur tries to support reading and writing of JP2 and J2C files. Writing
JP2 and J2C files. Writing J2C/JP2 files is currently limited to images that J2C/JP2 files is currently limited to images that can fit in memory, however.
can fit in memory, however. Of particular focus is metadata retrieval, such as XMP packets.
There is some very limited support for reading JPX There is some very limited support for reading JPX
metadata. For instance, **asoc** and **labl** boxes are recognized, so GMLJP2 metadata. For instance, **asoc** and **labl** boxes are recognized, so GMLJP2

View file

@ -16,24 +16,15 @@ def _glymurrc_fname():
if os.path.exists(fname): if os.path.exists(fname):
return fname return fname
# environ var GLYMURCONFIGDIR # Either GLYMURCONFIGDIR/glymurrc or $HOME/.glymur/glymurrc
if 'GLYMURCONFIGDIR' in os.environ:
path = os.environ['GLYMURCONFIGDIR']
if os.path.exists(path):
fname = os.path.join(path, 'glymurrc')
if os.path.exists(fname):
return fname
else:
msg = "glymurrc file hinted at by GLYMURCONFIGDIR does not "
msg += "exist."
warnings.warn(msg, UserWarning)
# HOME/.glymur/glymurrc
confdir = _get_configdir() confdir = _get_configdir()
if confdir is not None: if confdir is not None:
fname = os.path.join(_get_configdir(), 'glymurrc') fname = os.path.join(confdir, 'glymurrc')
if os.path.exists(fname): if os.path.exists(fname):
return fname return fname
else:
msg = "Configuration file '{0}' does not exist.".format(confdir)
warnings.warn(msg, UserWarning)
# didn't find a configuration file. # didn't find a configuration file.
return None return None

View file

@ -472,8 +472,6 @@ class Codestream:
SPcod = f.read(n) SPcod = f.read(n)
kwargs['SPcod'] = np.frombuffer(SPcod, dtype=np.uint8) kwargs['SPcod'] = np.frombuffer(SPcod, dtype=np.uint8)
# 0:
# 1: layers
params = struct.unpack('>BHBBBBBB', SPcod[0:9]) params = struct.unpack('>BHBBBBBB', SPcod[0:9])
kwargs['_layers'] = params[1] kwargs['_layers'] = params[1]
kwargs['_numresolutions'] = params[3] kwargs['_numresolutions'] = params[3]

Binary file not shown.

View file

@ -1288,37 +1288,11 @@ class XMLBox(Jp2kBox):
Jp2kBox.__init__(self, id='', longname='XML') Jp2kBox.__init__(self, id='', longname='XML')
self.__dict__.update(**kwargs) self.__dict__.update(**kwargs)
def _indent(self, elem, level=0):
"""recipe for pretty printing XML. Please see
http://effbot.org/zone/element-lib.htm#prettyprint
"""
i = "\n" + level * " "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + " "
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
self._indent(elem, level + 1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
def __str__(self): def __str__(self):
msg = Jp2kBox.__str__(self) msg = Jp2kBox.__str__(self)
xml = self.xml xml = self.xml
if self.xml is not None: if self.xml is not None:
xml = copy.deepcopy(self.xml) msg += _pretty_print_xml(self.xml)
self._indent(xml)
xmltext = ET.tostring(xml).decode('utf-8')
# Indent it a bit.
lst = [(' ' + x) for x in xmltext.split('\n')]
xml = '\n'.join(lst)
msg += '\n{0}'.format(xml)
else: else:
msg += '\n {0}'.format(xml) msg += '\n {0}'.format(xml)
return msg return msg
@ -1581,17 +1555,30 @@ class UUIDBox(Jp2kBox):
more verbose description of the box. more verbose description of the box.
uuid : uuid.UUID uuid : uuid.UUID
16-byte UUID 16-byte UUID
data : bytes data : bytes or ElementTree.Element
Vendor-specific UUID data. Vendor-specific UUID data. XMP UUIDs are interpreted as standard XML.
""" """
def __init__(self, **kwargs): def __init__(self, **kwargs):
Jp2kBox.__init__(self, id='', longname='UUID') Jp2kBox.__init__(self, id='', longname='UUID')
self.__dict__.update(**kwargs) self.__dict__.update(**kwargs)
def __str__(self): def __str__(self):
msg = Jp2kBox.__str__(self) msg = '{0}\n'
msg += '\n UUID: {0}'.format(self.uuid) msg += ' UUID: {1}{2}\n'
msg += '\n UUID Data: {0} bytes'.format(len(self.data)) msg += ' UUID Data: {3}'
if self.uuid == uuid.UUID('be7acfcb-97a9-42e8-9c71-999491e3afac'):
uuid_type = ' (XMP)'
uuid_data = _pretty_print_xml(self.data)
else:
uuid_type = ''
uuid_data = '{0} bytes'.format(len(self.data))
msg = msg.format(Jp2kBox.__str__(self),
self.uuid,
uuid_type,
uuid_data)
return msg return msg
@staticmethod @staticmethod
@ -1622,7 +1609,17 @@ class UUIDBox(Jp2kBox):
n = offset + length - f.tell() n = offset + length - f.tell()
buffer = f.read(n) buffer = f.read(n)
kwargs['data'] = buffer if kwargs['uuid'] == uuid.UUID('be7acfcb-97a9-42e8-9c71-999491e3afac'):
# XMP data. Parse as XML. Seems to be a difference between
# ElementTree in version 2.7 and 3.3.
if sys.hexversion < 0x03000000:
parser = ET.XMLParser(encoding='utf-8')
kwargs['data'] = ET.fromstringlist(buffer, parser=parser)
else:
text = buffer.decode('utf-8')
kwargs['data'] = ET.fromstring(text)
else:
kwargs['data'] = buffer
box = UUIDBox(**kwargs) box = UUIDBox(**kwargs)
return box return box
@ -1649,3 +1646,34 @@ _box_with_id = {
'url ': DataEntryURLBox, 'url ': DataEntryURLBox,
'uuid': UUIDBox, 'uuid': UUIDBox,
'xml ': XMLBox} 'xml ': XMLBox}
def _indent(elem, level=0):
"""Recipe for pretty printing XML. Please see
http://effbot.org/zone/element-lib.htm#prettyprint
"""
i = "\n" + level * " "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + " "
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
_indent(elem, level + 1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
def _pretty_print_xml(xml, level=0):
"""Pretty print XML data.
"""
xml = copy.deepcopy(xml)
_indent(xml, level=level)
xmltext = ET.tostring(xml).decode('utf-8')
# Indent it a bit.
lst = [(' ' + x) for x in xmltext.split('\n')]
xml = '\n'.join(lst)
return '\n{0}'.format(xml)

View file

@ -8,6 +8,7 @@ if sys.hexversion >= 0x03030000:
else: else:
from contextlib2 import ExitStack from contextlib2 import ExitStack
import ctypes import ctypes
import math
import os import os
import struct import struct
import warnings import warnings
@ -152,7 +153,7 @@ class Jp2k(Jp2kBox):
data : array data : array
Image data to be written to file. Image data to be written to file.
callbacks : bool, optional callbacks : bool, optional
If true, enable default info handler such that INFO messages If true, enable default info handler such that INFO messages
produced by the OpenJPEG library are output to the console. By produced by the OpenJPEG library are output to the console. By
default, OpenJPEG warning and error messages are captured by default, OpenJPEG warning and error messages are captured by
Python's own warning and error mechanisms. Python's own warning and error mechanisms.
@ -181,7 +182,8 @@ class Jp2k(Jp2kBox):
psnr : list, optional psnr : list, optional
Different PSNR for successive layers. Different PSNR for successive layers.
psizes : list, optional psizes : list, optional
List of precinct sizes. List of precinct sizes. Each precinct size tuple is defined in
(height x width).
sop : bool, optional sop : bool, optional
If true, write SOP marker before each packet. If true, write SOP marker before each packet.
subsam : tuple, optional subsam : tuple, optional
@ -266,9 +268,15 @@ class Jp2k(Jp2kBox):
cparams.cp_fixed_quality = 1 cparams.cp_fixed_quality = 1
if psizes is not None: if psizes is not None:
for j, precinct in enumerate(psizes): for j, (prch, prcw) in enumerate(psizes):
cparams.prcw_init[j] = precinct[0] if ((math.log(prch, 2) != math.floor(math.log(prch, 2)) or
cparams.prch_init[j] = precinct[1] math.log(prcw, 2) != math.floor(math.log(prcw, 2)))):
msg = "Bad precinct size ({0}, {1}), "
msg += "must be multiple of 2."
raise IOError(msg.format(prch, prcw))
cparams.prcw_init[j] = prcw
cparams.prch_init[j] = prch
cparams.csty |= 0x01 cparams.csty |= 0x01
cparams.res_spec = len(psizes) cparams.res_spec = len(psizes)
@ -634,7 +642,7 @@ class Jp2k(Jp2kBox):
>>> jp = glymur.Jp2k(jfile) >>> jp = glymur.Jp2k(jfile)
>>> codestream = jp.get_codestream() >>> codestream = jp.get_codestream()
>>> print(codestream.segment[1]) >>> print(codestream.segment[1])
SIZ marker segment @ (87, 47) SIZ marker segment @ (3137, 47)
Profile: 2 Profile: 2
Reference Grid Height, Width: (1456 x 2592) Reference Grid Height, Width: (1456 x 2592)
Vertical, Horizontal Reference Grid Offset: (0 x 0) Vertical, Horizontal Reference Grid Offset: (0 x 0)

View file

@ -53,7 +53,7 @@ class TestCallbacks(unittest.TestCase):
d = j.read(reduce=3, verbose=True, area=(0, 0, 512, 1024)) d = j.read(reduce=3, verbose=True, area=(0, 0, 512, 1024))
actual = sys.stdout.getvalue().strip() actual = sys.stdout.getvalue().strip()
lines = ['[INFO] Start to read j2k main header (85).', lines = ['[INFO] Start to read j2k main header (3135).',
'[INFO] Main header has been correctly decoded.', '[INFO] Main header has been correctly decoded.',
'[INFO] Setting decoding area to 0,0,1024,512', '[INFO] Setting decoding area to 0,0,1024,512',
'[INFO] Header of tile 0 / 17 has been read.', '[INFO] Header of tile 0 / 17 has been read.',

View file

@ -50,19 +50,13 @@ def chdir(dirname=None):
class TestJp2k(unittest.TestCase): class TestJp2k(unittest.TestCase):
def setUp(self): @classmethod
self.jp2file = pkg_resources.resource_filename(glymur.__name__, def setUpClass(cls):
"data/nemo.jp2") jp2file = pkg_resources.resource_filename(glymur.__name__,
"data/nemo.jp2")
def tearDown(self): with tempfile.NamedTemporaryFile(suffix='.jp2', delete=False) as tfile:
pass cls._bad_xml_file = tfile.name
with open(jp2file, 'rb') as ifile:
@unittest.skipIf(sys.hexversion < 0x03020000,
"Uses features introduced in 3.2.")
def test_invalid_xml_box(self):
# Should be able to recover from xml box with bad xml.
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
with open(self.jp2file, 'rb') as ifile:
# Everything up until the jp2c box. # Everything up until the jp2c box.
buffer = ifile.read(77) buffer = ifile.read(77)
tfile.write(buffer) tfile.write(buffer)
@ -81,13 +75,35 @@ class TestJp2k(unittest.TestCase):
tfile.write(buffer) tfile.write(buffer)
tfile.flush() tfile.flush()
with self.assertWarns(UserWarning) as cw: @classmethod
jp2k = Jp2k(tfile.name) def tearDownClass(cls):
os.unlink(cls._bad_xml_file)
self.assertEqual(jp2k.box[3].id, 'xml ') def setUp(self):
self.assertEqual(jp2k.box[3].offset, 77) self.jp2file = pkg_resources.resource_filename(glymur.__name__,
self.assertEqual(jp2k.box[3].length, 28) "data/nemo.jp2")
self.assertIsNone(jp2k.box[3].xml)
def tearDown(self):
pass
@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.2+
with self.assertWarns(UserWarning) as cw:
jp2k = Jp2k(self._bad_xml_file)
def test_invalid_xml_box(self):
# Should be able to recover from xml box with bad xml.
with warnings.catch_warnings():
warnings.simplefilter("ignore")
jp2k = Jp2k(self._bad_xml_file)
self.assertEqual(jp2k.box[3].id, 'xml ')
self.assertEqual(jp2k.box[3].offset, 77)
self.assertEqual(jp2k.box[3].length, 28)
self.assertIsNone(jp2k.box[3].xml)
def test_bad_area_parameter(self): def test_bad_area_parameter(self):
# Verify that we error out appropriately if given a bad area parameter. # Verify that we error out appropriately if given a bad area parameter.
@ -139,7 +155,7 @@ class TestJp2k(unittest.TestCase):
jp2k = Jp2k(self.jp2file) jp2k = Jp2k(self.jp2file)
# top-level boxes # top-level boxes
self.assertEqual(len(jp2k.box), 4) self.assertEqual(len(jp2k.box), 6)
self.assertEqual(jp2k.box[0].id, 'jP ') self.assertEqual(jp2k.box[0].id, 'jP ')
self.assertEqual(jp2k.box[0].offset, 0) self.assertEqual(jp2k.box[0].offset, 0)
@ -156,9 +172,17 @@ class TestJp2k(unittest.TestCase):
self.assertEqual(jp2k.box[2].length, 45) self.assertEqual(jp2k.box[2].length, 45)
self.assertEqual(jp2k.box[2].longname, 'JP2 Header') self.assertEqual(jp2k.box[2].longname, 'JP2 Header')
self.assertEqual(jp2k.box[3].id, 'jp2c') self.assertEqual(jp2k.box[3].id, 'uuid')
self.assertEqual(jp2k.box[3].offset, 77) self.assertEqual(jp2k.box[3].offset, 77)
self.assertEqual(jp2k.box[3].length, 1133427) self.assertEqual(jp2k.box[3].length, 638)
self.assertEqual(jp2k.box[4].id, 'uuid')
self.assertEqual(jp2k.box[4].offset, 715)
self.assertEqual(jp2k.box[4].length, 2412)
self.assertEqual(jp2k.box[5].id, 'jp2c')
self.assertEqual(jp2k.box[5].offset, 3127)
self.assertEqual(jp2k.box[5].length, 1133427)
# jp2h super box # jp2h super box
self.assertEqual(len(jp2k.box[2].box), 2) self.assertEqual(len(jp2k.box[2].box), 2)
@ -200,7 +224,7 @@ class TestJp2k(unittest.TestCase):
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
with open(self.jp2file, 'rb') as ifile: with open(self.jp2file, 'rb') as ifile:
# Everything up until the jp2c box. # Everything up until the jp2c box.
buffer = ifile.read(77) buffer = ifile.read(3127)
tfile.write(buffer) tfile.write(buffer)
# The L field must be 1 in order to signal the presence of the # The L field must be 1 in order to signal the presence of the
@ -221,9 +245,9 @@ class TestJp2k(unittest.TestCase):
jp2k = Jp2k(tfile.name) jp2k = Jp2k(tfile.name)
self.assertEqual(jp2k.box[3].id, 'jp2c') self.assertEqual(jp2k.box[5].id, 'jp2c')
self.assertEqual(jp2k.box[3].offset, 77) self.assertEqual(jp2k.box[5].offset, 3127)
self.assertEqual(jp2k.box[3].length, 1133427 + 8) self.assertEqual(jp2k.box[5].length, 1133427 + 8)
def test_L_is_zero(self): def test_L_is_zero(self):
# Verify that boxes with the L field as zero are correctly read. # Verify that boxes with the L field as zero are correctly read.
@ -513,10 +537,9 @@ class TestJp2k(unittest.TestCase):
# Now append the codestream. # Now append the codestream.
tfile2.write(codestream) tfile2.write(codestream)
tfile2.flush()
with warnings.catch_warnings(): jasoc = Jp2k(tfile2.name)
warnings.simplefilter("ignore")
jasoc = Jp2k(tfile2.name)
self.assertEqual(jasoc.box[3].id, 'asoc') self.assertEqual(jasoc.box[3].id, 'asoc')
self.assertEqual(jasoc.box[3].box[0].id, 'lbl ') self.assertEqual(jasoc.box[3].box[0].id, 'lbl ')
self.assertEqual(jasoc.box[3].box[0].label, 'label') self.assertEqual(jasoc.box[3].box[0].label, 'label')
@ -528,17 +551,19 @@ class TestJp2k(unittest.TestCase):
with open(self.jp2file, 'rb') as fp: with open(self.jp2file, 'rb') as fp:
data = fp.read() data = fp.read()
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
tfile.write(data[0:129]) # Codestream starts at byte 3127. SIZ marker at 3137.
# COD marker at 3186. Subsampling at 3180.
tfile.write(data[0:3179])
# Make the DY bytes of the SIZ segment zero. That means that # Make the DY bytes of the SIZ segment zero. That means that
# a subsampling factor is zero, which is illegal. # a subsampling factor is zero, which is illegal.
tfile.write(b'\x00') tfile.write(b'\x00')
tfile.write(data[130:132]) tfile.write(data[3180:3182])
tfile.write(b'\x00') tfile.write(b'\x00')
tfile.write(data[134:136]) tfile.write(data[3184:3186])
tfile.write(b'\x00') tfile.write(b'\x00')
tfile.write(data[136:]) tfile.write(data[3186:])
tfile.flush() tfile.flush()
with warnings.catch_warnings(): with warnings.catch_warnings():
warnings.simplefilter("ignore") warnings.simplefilter("ignore")
@ -597,6 +622,17 @@ class TestJp2k(unittest.TestCase):
with self.assertWarns(UserWarning) as cw: with self.assertWarns(UserWarning) as cw:
imp.reload(glymur) imp.reload(glymur)
@unittest.skipIf(sys.hexversion < 0x03020000,
"Uses features introduced in 3.2.")
def test_home_dir_missing_config_dir(self):
# Verify no exception is raised if $HOME is missing .glymur directory.
with tempfile.TemporaryDirectory() as tdir:
with patch.dict('os.environ', {'HOME': tdir}):
# Misconfigured new configuration file should
# be rejected.
with self.assertWarns(UserWarning) as cw:
imp.reload(glymur)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -9,6 +9,7 @@ import unittest
import warnings import warnings
import numpy as np import numpy as np
import pkg_resources
from ..lib import openjp2 as opj2 from ..lib import openjp2 as opj2
@ -62,7 +63,8 @@ def read_image(infile):
class TestSuiteNegative(unittest.TestCase): class TestSuiteNegative(unittest.TestCase):
def setUp(self): def setUp(self):
pass self.jp2file = pkg_resources.resource_filename(glymur.__name__,
"data/nemo.jp2")
def tearDown(self): def tearDown(self):
pass pass
@ -150,5 +152,14 @@ class TestSuiteNegative(unittest.TestCase):
with self.assertWarns(UserWarning) as cw: with self.assertWarns(UserWarning) as cw:
j = Jp2k(infile) j = Jp2k(infile)
def test_precinct_size_not_multiple_of_two(self):
# Seems like precinct size should be a multiple of two.
ifile = Jp2k(self.jp2file)
data = ifile.read(reduce=3)
with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile:
ofile = Jp2k(tfile.name, 'wb')
with self.assertRaises(IOError) as ce:
ofile.write(data, psizes=[(13, 13)])
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -47,10 +47,26 @@ class TestPrinting(unittest.TestCase):
' Method: enumerated colorspace', ' Method: enumerated colorspace',
' Precedence: 0', ' Precedence: 0',
' Colorspace: sRGB', ' Colorspace: sRGB',
'Contiguous Codestream Box (jp2c) @ (77, 1133427)', 'UUID Box (uuid) @ (77, 638)',
' UUID: 4a706754-6966-6645-7869-662d3e4a5032',
' UUID Data: 614 bytes',
'UUID Box (uuid) @ (715, 2412)',
' UUID: be7acfcb-97a9-42e8-9c71-999491e3afac (XMP)',
' UUID Data: ',
' <ns0:xmpmeta xmlns:ns0="adobe:ns:meta/" '
+ 'xmlns:ns2="http://ns.adobe.com/xap/1.0/" '
+ 'xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" '
+ 'ns0:xmptk="XMP Core 4.4.0-Exiv2">',
' <rdf:RDF>',
' <rdf:Description ns2:CreatorTool="glymur" '
+ 'rdf:about="" />',
' </rdf:RDF>',
' </ns0:xmpmeta>',
' ',
'Contiguous Codestream Box (jp2c) @ (3127, 1133427)',
' Main header:', ' Main header:',
' SOC marker segment @ (85, 0)', ' SOC marker segment @ (3135, 0)',
' SIZ marker segment @ (87, 47)', ' SIZ marker segment @ (3137, 47)',
' Profile: 2', ' Profile: 2',
' Reference Grid Height, Width: (1456 x 2592)', ' Reference Grid Height, Width: (1456 x 2592)',
' Vertical, Horizontal Reference Grid Offset: ' ' Vertical, Horizontal Reference Grid Offset: '
@ -62,7 +78,7 @@ class TestPrinting(unittest.TestCase):
' Signed: (False, False, False)', ' Signed: (False, False, False)',
' Vertical, Horizontal Subsampling: ' ' Vertical, Horizontal Subsampling: '
+ '((1, 1), (1, 1), (1, 1))', + '((1, 1), (1, 1), (1, 1))',
' COD marker segment @ (136, 12)', ' COD marker segment @ (3186, 12)',
' Coding style:', ' Coding style:',
' Entropy coder, without partitions', ' Entropy coder, without partitions',
' SOP marker segments: False', ' SOP marker segments: False',
@ -86,7 +102,7 @@ class TestPrinting(unittest.TestCase):
+ 'False', + 'False',
' Predictable termination: False', ' Predictable termination: False',
' Segmentation symbols: False', ' Segmentation symbols: False',
' QCD marker segment @ (150, 19)', ' QCD marker segment @ (3200, 19)',
' Quantization style: no quantization, ' ' Quantization style: no quantization, '
+ '2 guard bits', + '2 guard bits',
' Step size: [(0, 8), (0, 9), (0, 9), ' ' Step size: [(0, 8), (0, 9), (0, 9), '
@ -98,10 +114,13 @@ class TestPrinting(unittest.TestCase):
def tearDown(self): def tearDown(self):
# Restore stdout. # Restore stdout.
sys.stdout = self.stdout sys.stdout = self.stdout
#import pdb; pdb.set_trace()
def test_jp2dump(self): def test_jp2dump(self):
glymur.jp2dump(self.jp2file) glymur.jp2dump(self.jp2file)
actual = sys.stdout.getvalue().strip() actual = sys.stdout.getvalue().strip()
self.actual = actual
self.expected = self.expectedNemo
self.assertEqual(actual, self.expectedNemo) self.assertEqual(actual, self.expectedNemo)
def test_COC_segment(self): def test_COC_segment(self):
@ -110,7 +129,7 @@ class TestPrinting(unittest.TestCase):
print(codestream.segment[5]) print(codestream.segment[5])
actual = sys.stdout.getvalue().strip() actual = sys.stdout.getvalue().strip()
lines = ['COC marker segment @ (183, 9)', lines = ['COC marker segment @ (3233, 9)',
' Associated component: 1', ' Associated component: 1',
' Coding style for this component: ' ' Coding style for this component: '
+ 'Entropy coder, PARTITION = 0', + 'Entropy coder, PARTITION = 0',
@ -136,7 +155,7 @@ class TestPrinting(unittest.TestCase):
print(codestream.segment[2]) print(codestream.segment[2])
actual = sys.stdout.getvalue().strip() actual = sys.stdout.getvalue().strip()
lines = ['COD marker segment @ (136, 12)', lines = ['COD marker segment @ (3186, 12)',
' Coding style:', ' Coding style:',
' Entropy coder, without partitions', ' Entropy coder, without partitions',
' SOP marker segments: False', ' SOP marker segments: False',
@ -226,7 +245,7 @@ class TestPrinting(unittest.TestCase):
print(codestream.segment[-1]) print(codestream.segment[-1])
actual = sys.stdout.getvalue().strip() actual = sys.stdout.getvalue().strip()
lines = ['EOC marker segment @ (1133502, 0)'] lines = ['EOC marker segment @ (1136552, 0)']
expected = '\n'.join(lines) expected = '\n'.join(lines)
self.assertEqual(actual, expected) self.assertEqual(actual, expected)
@ -313,7 +332,7 @@ class TestPrinting(unittest.TestCase):
print(codestream.segment[6]) print(codestream.segment[6])
actual = sys.stdout.getvalue().strip() actual = sys.stdout.getvalue().strip()
lines = ['QCC marker segment @ (194, 20)', lines = ['QCC marker segment @ (3244, 20)',
' Associated Component: 1', ' Associated Component: 1',
' Quantization style: no quantization, 2 guard bits', ' Quantization style: no quantization, 2 guard bits',
' Step size: [(0, 8), (0, 9), (0, 9), (0, 10), (0, 9), ' ' Step size: [(0, 8), (0, 9), (0, 9), (0, 10), (0, 9), '
@ -329,7 +348,7 @@ class TestPrinting(unittest.TestCase):
print(codestream.segment[3]) print(codestream.segment[3])
actual = sys.stdout.getvalue().strip() actual = sys.stdout.getvalue().strip()
lines = ['QCD marker segment @ (150, 19)', lines = ['QCD marker segment @ (3200, 19)',
' Quantization style: no quantization, 2 guard bits', ' Quantization style: no quantization, 2 guard bits',
' Step size: [(0, 8), (0, 9), (0, 9), (0, 10), (0, 9), ' ' Step size: [(0, 8), (0, 9), (0, 9), (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), (0, 9), '
@ -344,7 +363,7 @@ class TestPrinting(unittest.TestCase):
print(codestream.segment[1]) print(codestream.segment[1])
actual = sys.stdout.getvalue().strip() actual = sys.stdout.getvalue().strip()
lines = ['SIZ marker segment @ (87, 47)', lines = ['SIZ marker segment @ (3137, 47)',
' Profile: 2', ' Profile: 2',
' Reference Grid Height, Width: (1456 x 2592)', ' Reference Grid Height, Width: (1456 x 2592)',
' Vertical, Horizontal Reference Grid Offset: (0 x 0)', ' Vertical, Horizontal Reference Grid Offset: (0 x 0)',
@ -364,7 +383,7 @@ class TestPrinting(unittest.TestCase):
print(codestream.segment[0]) print(codestream.segment[0])
actual = sys.stdout.getvalue().strip() actual = sys.stdout.getvalue().strip()
lines = ['SOC marker segment @ (85, 0)'] lines = ['SOC marker segment @ (3135, 0)']
expected = '\n'.join(lines) expected = '\n'.join(lines)
self.assertEqual(actual, expected) self.assertEqual(actual, expected)
@ -374,7 +393,7 @@ class TestPrinting(unittest.TestCase):
print(codestream.segment[9]) print(codestream.segment[9])
actual = sys.stdout.getvalue().strip() actual = sys.stdout.getvalue().strip()
lines = ['SOD marker segment @ (249, 0)'] lines = ['SOD marker segment @ (3299, 0)']
expected = '\n'.join(lines) expected = '\n'.join(lines)
self.assertEqual(actual, expected) self.assertEqual(actual, expected)
@ -384,7 +403,7 @@ class TestPrinting(unittest.TestCase):
print(codestream.segment[4]) print(codestream.segment[4])
actual = sys.stdout.getvalue().strip() actual = sys.stdout.getvalue().strip()
lines = ['SOT marker segment @ (171, 10)', lines = ['SOT marker segment @ (3221, 10)',
' Tile part index: 0', ' Tile part index: 0',
' Tile part length: 78629', ' Tile part length: 78629',
' Tile part instance: 0', ' Tile part instance: 0',
@ -422,8 +441,8 @@ class TestPrinting(unittest.TestCase):
actual = sys.stdout.getvalue().strip() actual = sys.stdout.getvalue().strip()
lst = ['Codestream:', lst = ['Codestream:',
' SOC marker segment @ (85, 0)', ' SOC marker segment @ (3135, 0)',
' SIZ marker segment @ (87, 47)', ' SIZ marker segment @ (3137, 47)',
' Profile: 2', ' Profile: 2',
' Reference Grid Height, Width: (1456 x 2592)', ' Reference Grid Height, Width: (1456 x 2592)',
' Vertical, Horizontal Reference Grid Offset: (0 x 0)', ' Vertical, Horizontal Reference Grid Offset: (0 x 0)',
@ -433,7 +452,7 @@ class TestPrinting(unittest.TestCase):
' Signed: (False, False, False)', ' Signed: (False, False, False)',
' Vertical, Horizontal Subsampling: ' ' Vertical, Horizontal Subsampling: '
+ '((1, 1), (1, 1), (1, 1))', + '((1, 1), (1, 1), (1, 1))',
' COD marker segment @ (136, 12)', ' COD marker segment @ (3186, 12)',
' Coding style:', ' Coding style:',
' Entropy coder, without partitions', ' Entropy coder, without partitions',
' SOP marker segments: False', ' SOP marker segments: False',
@ -455,7 +474,7 @@ class TestPrinting(unittest.TestCase):
' Vertically stripe causal context: False', ' Vertically stripe causal context: False',
' Predictable termination: False', ' Predictable termination: False',
' Segmentation symbols: False', ' Segmentation symbols: False',
' QCD marker segment @ (150, 19)', ' QCD marker segment @ (3200, 19)',
' Quantization style: no quantization, ' ' Quantization style: no quantization, '
+ '2 guard bits', + '2 guard bits',
' Step size: [(0, 8), (0, 9), (0, 9), ' ' Step size: [(0, 8), (0, 9), (0, 9), '

View file

@ -1,9 +1,9 @@
from distutils.core import setup from distutils.core import setup
kwargs = {'name': 'glymur', kwargs = {'name': 'Glymur',
'version': '0.1.1', 'version': '0.1.2',
'description': 'Tools for manipulating JPEG2000 files', 'description': 'Tools for accessing JPEG2000 files',
'long_description': open('README').read(), 'long_description': open('README.md').read(),
'author': 'John Evans', 'author': 'John Evans',
'author_email': 'johnevans938 at gmail dot com', 'author_email': 'johnevans938 at gmail dot com',
'url': 'https://github.com/quintusdias/glymur', 'url': 'https://github.com/quintusdias/glymur',