diff --git a/CHANGES.txt b/CHANGES.txt index 8af21bd..76abc9b 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -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 - glymur without libopenjp2 actually being present. - -May 27, 2013 - Changed write example to not rely on matplotlib. + glymur without libopenjp2 actually being present. Changed write example + to not rely on matplotlib. diff --git a/docs/source/conf.py b/docs/source/conf.py index a467ed2..8d48cf2 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -75,7 +75,7 @@ copyright = u'2013, John Evans' # The short X.Y version. version = '0.1' # 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 # for a list of supported languages. diff --git a/docs/source/introduction.rst b/docs/source/introduction.rst index 5f4ccb3..d07943f 100644 --- a/docs/source/introduction.rst +++ b/docs/source/introduction.rst @@ -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 should be considered to be alpha-quality software. -glymur tries to support reading (including all metadata) and writing of -JP2 and J2C files. Writing J2C/JP2 files is currently limited to images that -can fit in memory, however. +glymur tries to support reading and writing of JP2 and J2C files. Writing +J2C/JP2 files is currently limited to images that can fit in memory, however. +Of particular focus is metadata retrieval, such as XMP packets. There is some very limited support for reading JPX metadata. For instance, **asoc** and **labl** boxes are recognized, so GMLJP2 diff --git a/glymur/__init__.py b/glymur/__init__.py index 29e8cc4..3525b6a 100644 --- a/glymur/__init__.py +++ b/glymur/__init__.py @@ -16,24 +16,15 @@ def _glymurrc_fname(): if os.path.exists(fname): return fname - # environ var GLYMURCONFIGDIR - 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 + # Either GLYMURCONFIGDIR/glymurrc or $HOME/.glymur/glymurrc confdir = _get_configdir() if confdir is not None: - fname = os.path.join(_get_configdir(), 'glymurrc') + fname = os.path.join(confdir, 'glymurrc') if os.path.exists(fname): return fname + else: + msg = "Configuration file '{0}' does not exist.".format(confdir) + warnings.warn(msg, UserWarning) # didn't find a configuration file. return None diff --git a/glymur/codestream.py b/glymur/codestream.py index 506450d..f433eca 100644 --- a/glymur/codestream.py +++ b/glymur/codestream.py @@ -472,8 +472,6 @@ class Codestream: SPcod = f.read(n) kwargs['SPcod'] = np.frombuffer(SPcod, dtype=np.uint8) - # 0: - # 1: layers params = struct.unpack('>BHBBBBBB', SPcod[0:9]) kwargs['_layers'] = params[1] kwargs['_numresolutions'] = params[3] diff --git a/glymur/data/nemo.jp2 b/glymur/data/nemo.jp2 index 1b97d0d..2bb8638 100644 Binary files a/glymur/data/nemo.jp2 and b/glymur/data/nemo.jp2 differ diff --git a/glymur/jp2box.py b/glymur/jp2box.py index 47f7bda..a435f67 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -1288,37 +1288,11 @@ class XMLBox(Jp2kBox): Jp2kBox.__init__(self, id='', longname='XML') 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): msg = Jp2kBox.__str__(self) xml = self.xml if self.xml is not None: - xml = copy.deepcopy(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) + msg += _pretty_print_xml(self.xml) else: msg += '\n {0}'.format(xml) return msg @@ -1581,17 +1555,30 @@ class UUIDBox(Jp2kBox): more verbose description of the box. uuid : uuid.UUID 16-byte UUID - data : bytes - Vendor-specific UUID data. + data : bytes or ElementTree.Element + Vendor-specific UUID data. XMP UUIDs are interpreted as standard XML. """ def __init__(self, **kwargs): Jp2kBox.__init__(self, id='', longname='UUID') self.__dict__.update(**kwargs) def __str__(self): - msg = Jp2kBox.__str__(self) - msg += '\n UUID: {0}'.format(self.uuid) - msg += '\n UUID Data: {0} bytes'.format(len(self.data)) + msg = '{0}\n' + msg += ' UUID: {1}{2}\n' + 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 @staticmethod @@ -1622,7 +1609,17 @@ class UUIDBox(Jp2kBox): n = offset + length - f.tell() 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) return box @@ -1649,3 +1646,34 @@ _box_with_id = { 'url ': DataEntryURLBox, 'uuid': UUIDBox, '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) diff --git a/glymur/jp2k.py b/glymur/jp2k.py index dbfc74d..8d5272b 100644 --- a/glymur/jp2k.py +++ b/glymur/jp2k.py @@ -8,6 +8,7 @@ if sys.hexversion >= 0x03030000: else: from contextlib2 import ExitStack import ctypes +import math import os import struct import warnings @@ -152,7 +153,7 @@ class Jp2k(Jp2kBox): data : array Image data to be written to file. 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 default, OpenJPEG warning and error messages are captured by Python's own warning and error mechanisms. @@ -181,7 +182,8 @@ class Jp2k(Jp2kBox): psnr : list, optional Different PSNR for successive layers. psizes : list, optional - List of precinct sizes. + List of precinct sizes. Each precinct size tuple is defined in + (height x width). sop : bool, optional If true, write SOP marker before each packet. subsam : tuple, optional @@ -266,9 +268,15 @@ class Jp2k(Jp2kBox): cparams.cp_fixed_quality = 1 if psizes is not None: - for j, precinct in enumerate(psizes): - cparams.prcw_init[j] = precinct[0] - cparams.prch_init[j] = precinct[1] + for j, (prch, prcw) in enumerate(psizes): + if ((math.log(prch, 2) != math.floor(math.log(prch, 2)) or + 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.res_spec = len(psizes) @@ -634,7 +642,7 @@ class Jp2k(Jp2kBox): >>> jp = glymur.Jp2k(jfile) >>> codestream = jp.get_codestream() >>> print(codestream.segment[1]) - SIZ marker segment @ (87, 47) + SIZ marker segment @ (3137, 47) Profile: 2 Reference Grid Height, Width: (1456 x 2592) Vertical, Horizontal Reference Grid Offset: (0 x 0) diff --git a/glymur/test/test_callbacks.py b/glymur/test/test_callbacks.py index 1c70743..aae4ddc 100644 --- a/glymur/test/test_callbacks.py +++ b/glymur/test/test_callbacks.py @@ -53,7 +53,7 @@ class TestCallbacks(unittest.TestCase): d = j.read(reduce=3, verbose=True, area=(0, 0, 512, 1024)) 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] Setting decoding area to 0,0,1024,512', '[INFO] Header of tile 0 / 17 has been read.', diff --git a/glymur/test/test_jp2k.py b/glymur/test/test_jp2k.py index 5234e0b..64355fa 100644 --- a/glymur/test/test_jp2k.py +++ b/glymur/test/test_jp2k.py @@ -50,19 +50,13 @@ def chdir(dirname=None): class TestJp2k(unittest.TestCase): - def setUp(self): - self.jp2file = pkg_resources.resource_filename(glymur.__name__, - "data/nemo.jp2") - - def tearDown(self): - pass - - @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: + @classmethod + def setUpClass(cls): + jp2file = pkg_resources.resource_filename(glymur.__name__, + "data/nemo.jp2") + with tempfile.NamedTemporaryFile(suffix='.jp2', delete=False) as tfile: + cls._bad_xml_file = tfile.name + with open(jp2file, 'rb') as ifile: # Everything up until the jp2c box. buffer = ifile.read(77) tfile.write(buffer) @@ -81,13 +75,35 @@ class TestJp2k(unittest.TestCase): tfile.write(buffer) tfile.flush() - with self.assertWarns(UserWarning) as cw: - jp2k = Jp2k(tfile.name) + @classmethod + def tearDownClass(cls): + os.unlink(cls._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 setUp(self): + self.jp2file = pkg_resources.resource_filename(glymur.__name__, + "data/nemo.jp2") + + 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): # Verify that we error out appropriately if given a bad area parameter. @@ -139,7 +155,7 @@ class TestJp2k(unittest.TestCase): jp2k = Jp2k(self.jp2file) # 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].offset, 0) @@ -156,9 +172,17 @@ class TestJp2k(unittest.TestCase): self.assertEqual(jp2k.box[2].length, 45) 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].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 self.assertEqual(len(jp2k.box[2].box), 2) @@ -200,7 +224,7 @@ class TestJp2k(unittest.TestCase): with tempfile.NamedTemporaryFile(suffix='.jp2') as tfile: with open(self.jp2file, 'rb') as ifile: # Everything up until the jp2c box. - buffer = ifile.read(77) + buffer = ifile.read(3127) tfile.write(buffer) # 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) - self.assertEqual(jp2k.box[3].id, 'jp2c') - self.assertEqual(jp2k.box[3].offset, 77) - self.assertEqual(jp2k.box[3].length, 1133427 + 8) + self.assertEqual(jp2k.box[5].id, 'jp2c') + self.assertEqual(jp2k.box[5].offset, 3127) + self.assertEqual(jp2k.box[5].length, 1133427 + 8) def test_L_is_zero(self): # Verify that boxes with the L field as zero are correctly read. @@ -513,10 +537,9 @@ class TestJp2k(unittest.TestCase): # Now append the codestream. tfile2.write(codestream) + tfile2.flush() - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - jasoc = Jp2k(tfile2.name) + jasoc = Jp2k(tfile2.name) self.assertEqual(jasoc.box[3].id, 'asoc') self.assertEqual(jasoc.box[3].box[0].id, 'lbl ') self.assertEqual(jasoc.box[3].box[0].label, 'label') @@ -528,17 +551,19 @@ class TestJp2k(unittest.TestCase): with open(self.jp2file, 'rb') as fp: data = fp.read() 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 # a subsampling factor is zero, which is illegal. tfile.write(b'\x00') - tfile.write(data[130:132]) + tfile.write(data[3180:3182]) tfile.write(b'\x00') - tfile.write(data[134:136]) + tfile.write(data[3184:3186]) tfile.write(b'\x00') - tfile.write(data[136:]) + tfile.write(data[3186:]) tfile.flush() with warnings.catch_warnings(): warnings.simplefilter("ignore") @@ -597,6 +622,17 @@ class TestJp2k(unittest.TestCase): with self.assertWarns(UserWarning) as cw: 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__": unittest.main() diff --git a/glymur/test/test_opj_suite_neg.py b/glymur/test/test_opj_suite_neg.py index 8296861..f33b981 100644 --- a/glymur/test/test_opj_suite_neg.py +++ b/glymur/test/test_opj_suite_neg.py @@ -9,6 +9,7 @@ import unittest import warnings import numpy as np +import pkg_resources from ..lib import openjp2 as opj2 @@ -62,7 +63,8 @@ def read_image(infile): class TestSuiteNegative(unittest.TestCase): def setUp(self): - pass + self.jp2file = pkg_resources.resource_filename(glymur.__name__, + "data/nemo.jp2") def tearDown(self): pass @@ -150,5 +152,14 @@ class TestSuiteNegative(unittest.TestCase): with self.assertWarns(UserWarning) as cw: 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__": unittest.main() diff --git a/glymur/test/test_printing.py b/glymur/test/test_printing.py index 299085d..0278d63 100644 --- a/glymur/test/test_printing.py +++ b/glymur/test/test_printing.py @@ -47,10 +47,26 @@ class TestPrinting(unittest.TestCase): ' Method: enumerated colorspace', ' Precedence: 0', ' 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: ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + 'Contiguous Codestream Box (jp2c) @ (3127, 1133427)', ' Main header:', - ' SOC marker segment @ (85, 0)', - ' SIZ marker segment @ (87, 47)', + ' SOC marker segment @ (3135, 0)', + ' SIZ marker segment @ (3137, 47)', ' Profile: 2', ' Reference Grid Height, Width: (1456 x 2592)', ' Vertical, Horizontal Reference Grid Offset: ' @@ -62,7 +78,7 @@ class TestPrinting(unittest.TestCase): ' Signed: (False, False, False)', ' Vertical, Horizontal Subsampling: ' + '((1, 1), (1, 1), (1, 1))', - ' COD marker segment @ (136, 12)', + ' COD marker segment @ (3186, 12)', ' Coding style:', ' Entropy coder, without partitions', ' SOP marker segments: False', @@ -86,7 +102,7 @@ class TestPrinting(unittest.TestCase): + 'False', ' Predictable termination: False', ' Segmentation symbols: False', - ' QCD marker segment @ (150, 19)', + ' QCD marker segment @ (3200, 19)', ' Quantization style: no quantization, ' + '2 guard bits', ' Step size: [(0, 8), (0, 9), (0, 9), ' @@ -98,10 +114,13 @@ class TestPrinting(unittest.TestCase): def tearDown(self): # Restore stdout. sys.stdout = self.stdout + #import pdb; pdb.set_trace() def test_jp2dump(self): glymur.jp2dump(self.jp2file) actual = sys.stdout.getvalue().strip() + self.actual = actual + self.expected = self.expectedNemo self.assertEqual(actual, self.expectedNemo) def test_COC_segment(self): @@ -110,7 +129,7 @@ class TestPrinting(unittest.TestCase): print(codestream.segment[5]) actual = sys.stdout.getvalue().strip() - lines = ['COC marker segment @ (183, 9)', + lines = ['COC marker segment @ (3233, 9)', ' Associated component: 1', ' Coding style for this component: ' + 'Entropy coder, PARTITION = 0', @@ -136,7 +155,7 @@ class TestPrinting(unittest.TestCase): print(codestream.segment[2]) actual = sys.stdout.getvalue().strip() - lines = ['COD marker segment @ (136, 12)', + lines = ['COD marker segment @ (3186, 12)', ' Coding style:', ' Entropy coder, without partitions', ' SOP marker segments: False', @@ -226,7 +245,7 @@ class TestPrinting(unittest.TestCase): print(codestream.segment[-1]) actual = sys.stdout.getvalue().strip() - lines = ['EOC marker segment @ (1133502, 0)'] + lines = ['EOC marker segment @ (1136552, 0)'] expected = '\n'.join(lines) self.assertEqual(actual, expected) @@ -313,7 +332,7 @@ class TestPrinting(unittest.TestCase): print(codestream.segment[6]) actual = sys.stdout.getvalue().strip() - lines = ['QCC marker segment @ (194, 20)', + lines = ['QCC marker segment @ (3244, 20)', ' Associated Component: 1', ' Quantization style: no quantization, 2 guard bits', ' Step size: [(0, 8), (0, 9), (0, 9), (0, 10), (0, 9), ' @@ -329,7 +348,7 @@ class TestPrinting(unittest.TestCase): print(codestream.segment[3]) actual = sys.stdout.getvalue().strip() - lines = ['QCD marker segment @ (150, 19)', + lines = ['QCD marker segment @ (3200, 19)', ' Quantization style: no quantization, 2 guard bits', ' Step size: [(0, 8), (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]) actual = sys.stdout.getvalue().strip() - lines = ['SIZ marker segment @ (87, 47)', + lines = ['SIZ marker segment @ (3137, 47)', ' Profile: 2', ' Reference Grid Height, Width: (1456 x 2592)', ' Vertical, Horizontal Reference Grid Offset: (0 x 0)', @@ -364,7 +383,7 @@ class TestPrinting(unittest.TestCase): print(codestream.segment[0]) actual = sys.stdout.getvalue().strip() - lines = ['SOC marker segment @ (85, 0)'] + lines = ['SOC marker segment @ (3135, 0)'] expected = '\n'.join(lines) self.assertEqual(actual, expected) @@ -374,7 +393,7 @@ class TestPrinting(unittest.TestCase): print(codestream.segment[9]) actual = sys.stdout.getvalue().strip() - lines = ['SOD marker segment @ (249, 0)'] + lines = ['SOD marker segment @ (3299, 0)'] expected = '\n'.join(lines) self.assertEqual(actual, expected) @@ -384,7 +403,7 @@ class TestPrinting(unittest.TestCase): print(codestream.segment[4]) actual = sys.stdout.getvalue().strip() - lines = ['SOT marker segment @ (171, 10)', + lines = ['SOT marker segment @ (3221, 10)', ' Tile part index: 0', ' Tile part length: 78629', ' Tile part instance: 0', @@ -422,8 +441,8 @@ class TestPrinting(unittest.TestCase): actual = sys.stdout.getvalue().strip() lst = ['Codestream:', - ' SOC marker segment @ (85, 0)', - ' SIZ marker segment @ (87, 47)', + ' SOC marker segment @ (3135, 0)', + ' SIZ marker segment @ (3137, 47)', ' Profile: 2', ' Reference Grid Height, Width: (1456 x 2592)', ' Vertical, Horizontal Reference Grid Offset: (0 x 0)', @@ -433,7 +452,7 @@ class TestPrinting(unittest.TestCase): ' Signed: (False, False, False)', ' Vertical, Horizontal Subsampling: ' + '((1, 1), (1, 1), (1, 1))', - ' COD marker segment @ (136, 12)', + ' COD marker segment @ (3186, 12)', ' Coding style:', ' Entropy coder, without partitions', ' SOP marker segments: False', @@ -455,7 +474,7 @@ class TestPrinting(unittest.TestCase): ' Vertically stripe causal context: False', ' Predictable termination: False', ' Segmentation symbols: False', - ' QCD marker segment @ (150, 19)', + ' QCD marker segment @ (3200, 19)', ' Quantization style: no quantization, ' + '2 guard bits', ' Step size: [(0, 8), (0, 9), (0, 9), ' diff --git a/setup.py b/setup.py index 48ef364..97c7fb8 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,9 @@ from distutils.core import setup -kwargs = {'name': 'glymur', - 'version': '0.1.1', - 'description': 'Tools for manipulating JPEG2000 files', - 'long_description': open('README').read(), +kwargs = {'name': 'Glymur', + 'version': '0.1.2', + 'description': 'Tools for accessing JPEG2000 files', + 'long_description': open('README.md').read(), 'author': 'John Evans', 'author_email': 'johnevans938 at gmail dot com', 'url': 'https://github.com/quintusdias/glymur',