From 368c355560127afc0edc8797a838a06614f7695f Mon Sep 17 00:00:00 2001 From: John Evans Date: Sun, 20 Oct 2013 07:52:28 -0400 Subject: [PATCH 01/21] Added __repr__ for JPEG2000SignatureBox, FileTypeBox. --- glymur/jp2box.py | 10 ++++++++++ glymur/test/test_jp2box.py | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index bf88e4d..c3f2b63 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -801,6 +801,13 @@ class FileTypeBox(Jp2kBox): self.length = length self.offset = offset + def __repr__(self): + msg = "glymur.jp2box.FileTypeBox(brand='{0}', minor_version={1}, " + msg += "compatibility_list={2})" + msg = msg.format(self.brand, self.minor_version, + self.compatibility_list) + return msg + def __str__(self): lst = [Jp2kBox.__str__(self), ' Brand: {0}', @@ -1141,6 +1148,9 @@ class JPEG2000SignatureBox(Jp2kBox): self.length = length self.offset = offset + def __repr__(self): + return 'glymur.jp2box.JPEG2000SignatureBox()' + def __str__(self): msg = Jp2kBox.__str__(self) msg += '\n Signature: {0:02x}{1:02x}{2:02x}{3:02x}' diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py index ef62460..617a93a 100644 --- a/glymur/test/test_jp2box.py +++ b/glymur/test/test_jp2box.py @@ -677,6 +677,10 @@ class TestJp2Boxes(unittest.TestCase): jp2k = glymur.jp2box.JPEG2000SignatureBox() self.assertEqual(jp2k.signature, (13, 10, 135, 10)) + # Test the representation instantiation. + newbox = eval(repr(jp2k)) + self.assertTrue(isinstance(newbox, glymur.jp2box.JPEG2000SignatureBox)) + def test_default_ftyp(self): """Should be able to instantiate a FileTypeBox""" ftyp = glymur.jp2box.FileTypeBox() @@ -684,6 +688,13 @@ class TestJp2Boxes(unittest.TestCase): self.assertEqual(ftyp.minor_version, 0) self.assertEqual(ftyp.compatibility_list, ['jp2 ']) + # Test the representation instantiation. + newbox = eval(repr(ftyp)) + self.assertTrue(isinstance(newbox, glymur.jp2box.FileTypeBox)) + self.assertEqual(newbox.brand, 'jp2 ') + self.assertEqual(newbox.minor_version, 0) + self.assertEqual(newbox.compatibility_list, ['jp2 ']) + def test_default_ihdr(self): """Should be able to instantiate an image header box.""" ihdr = glymur.jp2box.ImageHeaderBox(height=512, width=256, From cdd00d2c2d5936dd7e0e5bc5596fe63e0b19f8f7 Mon Sep 17 00:00:00 2001 From: John Evans Date: Wed, 23 Oct 2013 06:01:48 -0400 Subject: [PATCH 02/21] added __repr__ for colr, cdef, ihdr boxes. #133 --- glymur/jp2box.py | 45 ++++++++++++++++++++---- glymur/test/test_jp2box.py | 71 ++++++++++++++++++++++++++++++++------ 2 files changed, 99 insertions(+), 17 deletions(-) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index c3f2b63..b7f385f 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -206,6 +206,17 @@ class ColourSpecificationBox(Jp2kBox): self.length = length self.offset = offset + def __repr__(self): + msg = "glymur.jp2box.ColourSpecificationBox(" + msg += "method={0}, precedence={1}, approximation={2}, colorspace={3}, " + msg += "icc_profile={4})" + msg = msg.format(self.method, + self.precedence, + self.approximation, + self.colorspace, + self.icc_profile) + return msg + def __str__(self): msg = Jp2kBox.__str__(self) @@ -426,12 +437,12 @@ class ChannelDefinitionBox(Jp2kBox): offset of the box from the start of the file. longname : str more verbose description of the box. - index : int + index : list number of the channel. Defaults to monotonically increasing sequence, i.e. [0, 1, 2, ...] - channel_type : int + channel_type : list type of the channel - association : int + association : list index of the associated color """ def __init__(self, index=None, channel_type=None, association=None, @@ -458,9 +469,9 @@ class ChannelDefinitionBox(Jp2kBox): msg += " 65535 - unspecified" raise IOError(msg) - self.index = index - self.channel_type = channel_type - self.association = association + self.index = tuple(index) + self.channel_type = tuple(channel_type) + self.association = tuple(association) self.__dict__.update(**kwargs) def __str__(self): @@ -475,6 +486,12 @@ class ChannelDefinitionBox(Jp2kBox): msg = msg.format(self.index[j], color_type_string, assn) return msg + def __repr__(self): + msg = "glymur.jp2box.ChannelDefinitionBox(" + msg += "index={0}, channel_type={1}, association={2})" + msg = msg.format(self.index, self.channel_type, self.association) + return msg + def write(self, fptr): """Write a channel definition box to file. """ @@ -921,6 +938,22 @@ class ImageHeaderBox(Jp2kBox): self.length = length self.offset = offset + def __repr__(self): + msg = "glymur.jp2box.ImageHeaderBox(" + msg += "{height}, {width}, num_components={num_components}, " + msg += "signed={signed}, bits_per_component={bits_per_component}, " + msg += "compression={compression}, " + msg += "colorspace_unknown={colorspace_unknown}, " + msg += "ip_provided={ip_provided})" + msg = msg.format(height=self.height, width=self.width, + num_components=self.num_components, + signed=self.signed, + bits_per_component=self.bits_per_component, + compression=self.compression, + colorspace_unknown=self.colorspace_unknown, + ip_provided=self.ip_provided) + return msg + def __str__(self): msg = Jp2kBox.__str__(self) msg = "{0}" diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py index 617a93a..c6de126 100644 --- a/glymur/test/test_jp2box.py +++ b/glymur/test/test_jp2box.py @@ -677,10 +677,6 @@ class TestJp2Boxes(unittest.TestCase): jp2k = glymur.jp2box.JPEG2000SignatureBox() self.assertEqual(jp2k.signature, (13, 10, 135, 10)) - # Test the representation instantiation. - newbox = eval(repr(jp2k)) - self.assertTrue(isinstance(newbox, glymur.jp2box.JPEG2000SignatureBox)) - def test_default_ftyp(self): """Should be able to instantiate a FileTypeBox""" ftyp = glymur.jp2box.FileTypeBox() @@ -688,13 +684,6 @@ class TestJp2Boxes(unittest.TestCase): self.assertEqual(ftyp.minor_version, 0) self.assertEqual(ftyp.compatibility_list, ['jp2 ']) - # Test the representation instantiation. - newbox = eval(repr(ftyp)) - self.assertTrue(isinstance(newbox, glymur.jp2box.FileTypeBox)) - self.assertEqual(newbox.brand, 'jp2 ') - self.assertEqual(newbox.minor_version, 0) - self.assertEqual(newbox.compatibility_list, ['jp2 ']) - def test_default_ihdr(self): """Should be able to instantiate an image header box.""" ihdr = glymur.jp2box.ImageHeaderBox(height=512, width=256, @@ -720,6 +709,66 @@ class TestJp2Boxes(unittest.TestCase): self.assertIsNone(box.main_header) +class TestRepr(unittest.TestCase): + """Tests for __repr__ methods.""" + def test_default_jp2k(self): + """Should be able to eval a JPEG2000SignatureBox""" + jp2k = glymur.jp2box.JPEG2000SignatureBox() + + # Test the representation instantiation. + newbox = eval(repr(jp2k)) + self.assertTrue(isinstance(newbox, glymur.jp2box.JPEG2000SignatureBox)) + self.assertEqual(newbox.signature, (13, 10, 135, 10)) + + def test_default_ftyp(self): + """Should be able to instantiate a FileTypeBox""" + ftyp = glymur.jp2box.FileTypeBox() + + # Test the representation instantiation. + newbox = eval(repr(ftyp)) + self.assertTrue(isinstance(newbox, glymur.jp2box.FileTypeBox)) + self.assertEqual(newbox.brand, 'jp2 ') + self.assertEqual(newbox.minor_version, 0) + self.assertEqual(newbox.compatibility_list, ['jp2 ']) + + def test_colourspecification_box(self): + """Verify __repr__ method on colr box.""" + # TODO: add icc_profile + box = ColourSpecificationBox(colorspace=glymur.core.SRGB) + + newbox = eval(repr(box)) + self.assertEqual(newbox.method, glymur.core.ENUMERATED_COLORSPACE) + self.assertEqual(newbox.precedence, 0) + self.assertEqual(newbox.approximation, 0) + self.assertEqual(newbox.colorspace, glymur.core.SRGB) + self.assertIsNone(newbox.icc_profile) + + def test_channeldefinition_box(self): + """Verify __repr__ method on cdef box.""" + channel_type = [COLOR, COLOR, COLOR] + association = [RED, GREEN, BLUE] + cdef = glymur.jp2box.ChannelDefinitionBox(index=[0, 1, 2], + channel_type=channel_type, + association=association) + newbox = eval(repr(cdef)) + self.assertEqual(newbox.index, (0, 1, 2)) + self.assertEqual(newbox.channel_type, (COLOR, COLOR, COLOR)) + self.assertEqual(newbox.association, (RED, GREEN, BLUE)) + + def test_imageheader_box(self): + """Verify __repr__ method on ihdr box.""" + ihdr = ImageHeaderBox(100, 200, num_components=3) + newbox = eval(repr(ihdr)) + self.assertEqual(newbox.height, 100) + self.assertEqual(newbox.width, 200) + self.assertEqual(newbox.num_components, 3) + self.assertFalse(newbox.signed) + self.assertEqual(newbox.bits_per_component, 8) + self.assertEqual(newbox.compression, 7) + self.assertFalse(newbox.colorspace_unknown) + self.assertFalse(newbox.ip_provided) + + class TestJpxBoxes(unittest.TestCase): """Tests for JPX boxes.""" From 18818495d24643806fbd3bd3db3471cc5a1b3ae9 Mon Sep 17 00:00:00 2001 From: John Evans Date: Wed, 23 Oct 2013 06:41:31 -0400 Subject: [PATCH 03/21] Added jp2h __repr__ method. #133 --- glymur/jp2box.py | 8 ++++++-- glymur/test/test_jp2box.py | 13 ++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index b7f385f..7f75f60 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -1102,11 +1102,15 @@ class JP2HeaderBox(Jp2kBox): box : list List of boxes contained in this superbox. """ - def __init__(self, length=0, offset=-1): + def __init__(self, box=[], length=0, offset=-1): Jp2kBox.__init__(self, box_id='jp2h', longname='JP2 Header') self.length = length self.offset = offset - self.box = [] + self.box = box + + def __repr__(self): + msg = "glymur.jp2box.JP2HeaderBox(box={0})".format(self.box) + return msg def __str__(self): msg = Jp2kBox.__str__(self) diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py index c6de126..fb748f7 100644 --- a/glymur/test/test_jp2box.py +++ b/glymur/test/test_jp2box.py @@ -755,9 +755,20 @@ class TestRepr(unittest.TestCase): self.assertEqual(newbox.channel_type, (COLOR, COLOR, COLOR)) self.assertEqual(newbox.association, (RED, GREEN, BLUE)) - def test_imageheader_box(self): + def test_jp2header_box(self): """Verify __repr__ method on ihdr box.""" ihdr = ImageHeaderBox(100, 200, num_components=3) + colr = ColourSpecificationBox(colorspace=glymur.core.SRGB) + jp2h = JP2HeaderBox(box=[ihdr, colr]) + newbox = eval(repr(jp2h)) + self.assertEqual(newbox.box_id, 'jp2h') + self.assertEqual(newbox.box[0].box_id, 'ihdr') + self.assertEqual(newbox.box[1].box_id, 'colr') + + def test_imageheader_box(self): + """Verify __repr__ method on jhdr box.""" + ihdr = ImageHeaderBox(100, 200, num_components=3) + newbox = eval(repr(ihdr)) self.assertEqual(newbox.height, 100) self.assertEqual(newbox.width, 200) From 3ad31c91b84d28244f7c8aee2fcfafe87f4219f6 Mon Sep 17 00:00:00 2001 From: John Evans Date: Wed, 23 Oct 2013 08:07:15 -0400 Subject: [PATCH 04/21] Added support for jplh, jpch, cmap, res , resd, resc #133 --- glymur/jp2box.py | 48 +++++++++++++++++++++++++++++++------- glymur/test/test_jp2box.py | 43 +++++++++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 9 deletions(-) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index 7f75f60..3c775c0 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -554,11 +554,15 @@ class CodestreamHeaderBox(Jp2kBox): box : list List of boxes contained in this superbox. """ - def __init__(self, length=0, offset=-1): + def __init__(self, box=[], length=0, offset=-1): Jp2kBox.__init__(self, box_id='jpch', longname='Codestream Header') self.length = length self.offset = offset - self.box = [] + self.box = box + + def __repr__(self): + msg = "glymur.jp2box.CodestreamHeaderBox(box={0})".format(self.box) + return msg def __str__(self): msg = Jp2kBox.__str__(self) @@ -612,13 +616,18 @@ class CompositingLayerHeaderBox(Jp2kBox): box : list List of boxes contained in this superbox. """ - def __init__(self, length=0, offset=-1): + def __init__(self, box=[], length=0, offset=-1): Jp2kBox.__init__(self, box_id='jplh', longname='Compositing Layer Header') self.length = length self.offset = offset self.box = [] + def __repr__(self): + msg = "glymur.jp2box.CompositingLayerHeaderBox(box={0})" + msg = msg.format(self.box) + return msg + def __str__(self): msg = Jp2kBox.__str__(self) for box in self.box: @@ -667,11 +676,11 @@ class ComponentMappingBox(Jp2kBox): Offset of the box from the start of the file. longname : str Verbose description of the box. - component_index : int + component_index : tuple Index of component in codestream that is mapped to this channel. - mapping_type : int + mapping_type : tuple mapping type, either direct use (0) or palette (1) - palette_index : int + palette_index : tuple Index component from palette """ def __init__(self, component_index, mapping_type, palette_index, @@ -683,6 +692,14 @@ class ComponentMappingBox(Jp2kBox): self.length = length self.offset = offset + def __repr__(self): + msg = "glymur.jp2box.ComponentMappingBox(" + msg += "component_index={0}, mapping_type={1}, palette_index={2})" + msg = msg.format(self.component_index, + self.mapping_type, + self.palette_index) + return msg + def __str__(self): msg = Jp2kBox.__str__(self) @@ -1610,11 +1627,16 @@ class ResolutionBox(Jp2kBox): box : list List of boxes contained in this superbox. """ - def __init__(self, length=0, offset=-1): + def __init__(self, box=[], length=0, offset=-1): Jp2kBox.__init__(self, box_id='res ', longname='Resolution') self.length = length self.offset = offset - self.box = [] + self.box = box + + def __repr__(self): + msg = "glymur.jp2box.ResolutionBox(box={0})" + msg = msg.format(self.box) + return msg def __str__(self): msg = Jp2kBox.__str__(self) @@ -1676,6 +1698,11 @@ class CaptureResolutionBox(Jp2kBox): self.length = length self.offset = offset + def __repr__(self): + msg = "glymur.jp2box.CaptureResolutionBox({0}, {1})" + msg = msg.format(self.vertical_resolution, self.horizontal_resolution) + return msg + def __str__(self): msg = Jp2kBox.__str__(self) msg += '\n VCR: {0}'.format(self.vertical_resolution) @@ -1733,6 +1760,11 @@ class DisplayResolutionBox(Jp2kBox): self.length = length self.offset = offset + def __repr__(self): + msg = "glymur.jp2box.DisplayResolutionBox({0}, {1})" + msg = msg.format(self.vertical_resolution, self.horizontal_resolution) + return msg + def __str__(self): msg = Jp2kBox.__str__(self) msg += '\n VDR: {0}'.format(self.vertical_resolution) diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py index fb748f7..0373b01 100644 --- a/glymur/test/test_jp2box.py +++ b/glymur/test/test_jp2box.py @@ -40,7 +40,7 @@ from glymur.jp2box import JPEG2000SignatureBox from glymur.core import COLOR, OPACITY from glymur.core import RED, GREEN, BLUE, GREY, WHOLE_IMAGE -from .fixtures import OPENJP2_IS_V2_OFFICIAL +from .fixtures import OPENJP2_IS_V2_OFFICIAL, opj_data_file try: FORMAT_CORPUS_DATA_ROOT = os.environ['FORMAT_CORPUS_DATA_ROOT'] @@ -779,6 +779,47 @@ class TestRepr(unittest.TestCase): self.assertFalse(newbox.colorspace_unknown) self.assertFalse(newbox.ip_provided) + def test_codestreamheader_box(self): + """Verify __repr__ method on jpch box.""" + jpch = glymur.jp2box.CodestreamHeaderBox() + newbox = eval(repr(jpch)) + self.assertEqual(newbox.box_id, 'jpch') + self.assertEqual(len(newbox.box), 0) + + def test_compositinglayerheader_box(self): + """Verify __repr__ method on jplh box.""" + jplh = glymur.jp2box.CompositingLayerHeaderBox() + newbox = eval(repr(jplh)) + self.assertEqual(newbox.box_id, 'jplh') + self.assertEqual(len(newbox.box), 0) + + def test_componentmapping_box(self): + """Verify __repr__ method on cmap box.""" + cmap = glymur.jp2box.ComponentMappingBox(component_index=(0, 0, 0), + mapping_type=(1, 1, 1), + palette_index=(0, 1, 2)) + newbox = eval(repr(cmap)) + self.assertEqual(newbox.box_id, 'cmap') + self.assertEqual(newbox.component_index, (0, 0, 0)) + self.assertEqual(newbox.mapping_type, (1, 1, 1)) + self.assertEqual(newbox.palette_index, (0, 1, 2)) + + def test_resolution_boxes(self): + """Verify __repr__ method on resolution boxes.""" + resc = glymur.jp2box.CaptureResolutionBox(0.5, 2.5) + resd = glymur.jp2box.DisplayResolutionBox(2.5, 0.5) + res_super_box = glymur.jp2box.ResolutionBox(box=[resc, resd]) + + newbox = eval(repr(res_super_box)) + + self.assertEqual(newbox.box_id, 'res ') + self.assertEqual(newbox.box[0].box_id, 'resc') + self.assertEqual(newbox.box[0].vertical_resolution, 0.5) + self.assertEqual(newbox.box[0].horizontal_resolution, 2.5) + self.assertEqual(newbox.box[1].box_id, 'resd') + self.assertEqual(newbox.box[1].vertical_resolution, 2.5) + self.assertEqual(newbox.box[1].horizontal_resolution, 0.5) + class TestJpxBoxes(unittest.TestCase): """Tests for JPX boxes.""" From 74420e587ccbb592ec97ee2e8641a83c928feebd Mon Sep 17 00:00:00 2001 From: John Evans Date: Wed, 23 Oct 2013 08:17:17 -0400 Subject: [PATCH 05/21] Added 'url ', 'lbl ' box support. #133 --- glymur/jp2box.py | 9 +++++++++ glymur/test/test_jp2box.py | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index 3c775c0..52ad263 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -1826,6 +1826,10 @@ class LabelBox(Jp2kBox): msg += '\n Label: {0}'.format(self.label) return msg + def __repr__(self): + msg = 'glymur.jp2box.LabelBox("{0}")'.format(self.label) + return msg + @staticmethod def parse(fptr, offset, length): """Parse Label box. @@ -2109,6 +2113,11 @@ class DataEntryURLBox(Jp2kBox): self.length = length self.offset = offset + def __repr__(self): + msg = "glymur.jp2box.DataEntryURLBox({0}, {1}, '{2}')" + msg = msg.format(self.version, self.flag, self.url) + return msg + def __str__(self): msg = Jp2kBox.__str__(self) msg += '\n ' diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py index 0373b01..55a7b02 100644 --- a/glymur/test/test_jp2box.py +++ b/glymur/test/test_jp2box.py @@ -820,6 +820,25 @@ class TestRepr(unittest.TestCase): self.assertEqual(newbox.box[1].vertical_resolution, 2.5) self.assertEqual(newbox.box[1].horizontal_resolution, 0.5) + def test_label_box(self): + """Verify __repr__ method on label box.""" + lbl = glymur.jp2box.LabelBox("this is a test") + newbox = eval(repr(lbl)) + self.assertEqual(newbox.box_id, 'lbl ') + self.assertEqual(newbox.label, "this is a test") + + def test_data_entry_url_box(self): + """Verify __repr__ method on data entry url box.""" + version = 0 + flag = (0, 0, 0) + url = "http://readthedocs.glymur.org" + box = glymur.jp2box.DataEntryURLBox(version, flag, url) + newbox = eval(repr(box)) + self.assertEqual(newbox.box_id, 'url ') + self.assertEqual(newbox.version, version) + self.assertEqual(newbox.flag, flag) + self.assertEqual(newbox.url, url) + class TestJpxBoxes(unittest.TestCase): """Tests for JPX boxes.""" From 7ac1134872952ef999ad8cde07460807bf7397dd Mon Sep 17 00:00:00 2001 From: John Evans Date: Wed, 23 Oct 2013 18:58:09 -0400 Subject: [PATCH 06/21] Added ulst and uinf repr support. #133 --- CHANGES.txt | 3 +++ glymur/jp2box.py | 12 ++++++++++-- glymur/test/test_jp2box.py | 19 +++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 40846e4..7e7c53c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,6 @@ +Oct 22, 2013 - v0.5.7 Super boxes constructors now take optional box list + argument. + Oct 13, 2013 - v0.5.6 Fixed handling of non-ascii chars in XML boxes. Fixed some docstring errors in jp2box module. diff --git a/glymur/jp2box.py b/glymur/jp2box.py index 52ad263..8303981 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -1989,6 +1989,10 @@ class UUIDListBox(Jp2kBox): self.length = length self.offset = offset + def __repr__(self): + msg = "glymur.jp2box.UUIDListBox({0})".format(self.ulst) + return msg + def __str__(self): msg = Jp2kBox.__str__(self) for j, uuid_item in enumerate(self.ulst): @@ -2040,11 +2044,15 @@ class UUIDInfoBox(Jp2kBox): box : list List of boxes contained in this superbox. """ - def __init__(self, length=0, offset=-1): + def __init__(self, box=[], length=0, offset=-1): Jp2kBox.__init__(self, box_id='uinf', longname='UUIDInfo') self.length = length self.offset = offset - self.box = [] + self.box = box + + def __repr__(self): + msg = "glymur.jp2box.UUIDInfoBox(box={0})".format(self.box) + return msg def __str__(self): msg = Jp2kBox.__str__(self) diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py index 55a7b02..b82af47 100644 --- a/glymur/test/test_jp2box.py +++ b/glymur/test/test_jp2box.py @@ -23,6 +23,7 @@ import struct import sys import tempfile import uuid +from uuid import UUID import xml.etree.cElementTree as ET if sys.hexversion < 0x02070000: @@ -839,6 +840,24 @@ class TestRepr(unittest.TestCase): self.assertEqual(newbox.flag, flag) self.assertEqual(newbox.url, url) + def test_uuidinfo_box(self): + """Verify __repr__ method on uinf box.""" + uinf = glymur.jp2box.UUIDInfoBox() + newbox = eval(repr(uinf)) + self.assertEqual(newbox.box_id, 'uinf') + self.assertEqual(len(newbox.box), 0) + + def test_uuidlist_box(self): + """Verify __repr__ method on ulst box.""" + uuid1 = uuid.UUID('00000000-0000-0000-0000-000000000001') + uuid2 = uuid.UUID('00000000-0000-0000-0000-000000000002') + uuids = [uuid1, uuid2] + ulst = glymur.jp2box.UUIDListBox(ulst=uuids) + newbox = eval(repr(ulst)) + self.assertEqual(newbox.box_id, 'ulst') + self.assertEqual(newbox.ulst[0], uuid1) + self.assertEqual(newbox.ulst[1], uuid2) + class TestJpxBoxes(unittest.TestCase): """Tests for JPX boxes.""" From d3dd654c17aa4924f2ba27f3089594f6949d2b56 Mon Sep 17 00:00:00 2001 From: John Evans Date: Thu, 24 Oct 2013 08:21:14 -0400 Subject: [PATCH 07/21] Proper repr support for SIZ segment. SIZ segment constructor change. The SIZ segment was taking raw buffer arguments, which are difficult for eval(repr()) to deal with, so the constructor was changed to make the arguments more explicit. #133 --- CHANGES.txt | 4 +- glymur/codestream.py | 113 +++++++++++++++++++++------------ glymur/test/test_codestream.py | 44 +++++++++++++ 3 files changed, 119 insertions(+), 42 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 7e7c53c..0d23501 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,5 @@ -Oct 22, 2013 - v0.5.7 Super boxes constructors now take optional box list - argument. +Oct 22, 2013 - v0.5.7 Super box constructors now take optional box list + argument. Removed ssiz attribute from SIZsegment class. Oct 13, 2013 - v0.5.6 Fixed handling of non-ascii chars in XML boxes. Fixed some docstring errors in jp2box module. diff --git a/glymur/codestream.py b/glymur/codestream.py index e83c5cc..d01795f 100644 --- a/glymur/codestream.py +++ b/glymur/codestream.py @@ -646,16 +646,50 @@ class Codestream(object): length, = struct.unpack('>H', read_buffer) xy_buffer = fptr.read(36) + data = struct.unpack('>HIIIIIIIIH', xy_buffer) - num_components, = struct.unpack('>H', xy_buffer[-2:]) + rsiz = data[0] + xysiz = (data[1], data[2]) + xyosiz = (data[3], data[4]) + xytsiz = (data[5], data[6]) + xytosiz = (data[7], data[8]) - component_buffer = fptr.read(num_components * 3) + # Csiz is the number of components + Csiz = data[9] - segment = SIZsegment(xy_buffer, component_buffer, length, offset) + component_buffer = fptr.read(Csiz * 3) + data = struct.unpack('>' + 'B' * len(component_buffer), + component_buffer) + + bitdepth = tuple(((x & 0x7f) + 1) for x in data[0::3]) + signed = tuple(((x & 0xb0) > 0) for x in data[0::3]) + + xrsiz = data[1::3] + yrsiz = data[2::3] + + for j, subsampling in enumerate(zip(xrsiz, yrsiz)): + if 0 in subsampling: + msg = "Invalid subsampling value for component {0}: " + msg += "dx={1}, dy={2}." + msg = msg.format(j, subsampling[0], subsampling[1]) + warnings.warn(msg) + + kwargs = {'rsiz': rsiz, + 'xysiz': xysiz, + 'xyosiz': xyosiz, + 'xytsiz': xytsiz, + 'xytosiz': xytosiz, + 'Csiz': Csiz, + 'bitdepth': bitdepth, + 'signed': signed, + 'xyrsiz': (xrsiz, yrsiz), + 'length': length, + 'offset': offset} + segment = SIZsegment(**kwargs) # Need to keep track of the number of components from SIZ for - # other markers - self._csiz = len(segment.ssiz) + # other markers. + self._csiz = Csiz return segment @@ -1441,8 +1475,8 @@ class SIZsegment(Segment): Width and height of reference tile with respect to the reference grid. xtosiz, ytosiz : int Horizontal and vertical offsets of tile from origin of reference grid. - ssiz : iterable bytes - Encoded precision (depth) in bits and sign of each component. + Csiz : int + Number of components in image. bitdepth : iterable bytes Precision (depth) in bits of each component. signed : iterable bool @@ -1457,21 +1491,20 @@ class SIZsegment(Segment): 15444-1:2004 - Information technology -- JPEG 2000 image coding system: Core coding system """ - def __init__(self, xy_buffer, component_buffer, length, offset): - Segment.__init__(self, marker_id='SIZ') + def __init__(self, rsiz=-1, xysiz=None, xyosiz=-1, xytsiz=-1, xytosiz=-1, + Csiz=-1, bitdepth=None, signed=None, xyrsiz=-1, length=-1, + offset=-1): + Segment.__init__(self, marker_id='SIZ', length=length, offset=offset) - data = struct.unpack('>HIIIIIIIIH', xy_buffer) - - self.rsiz = data[0] - self.xsiz = data[1] - self.ysiz = data[2] - self.xosiz = data[3] - self.yosiz = data[4] - self.xtsiz = data[5] - self.ytsiz = data[6] - self.xtosiz = data[7] - self.ytosiz = data[8] - # disregarding the last element in data + self.rsiz = rsiz + self.xsiz, self.ysiz = xysiz + self.xosiz, self.yosiz = xyosiz + self.xtsiz, self.ytsiz = xytsiz + self.xtosiz, self.ytosiz = xytosiz + self.Csiz = Csiz + self.bitdepth = bitdepth + self.signed = signed + self.xrsiz, self.yrsiz = xyrsiz num_tiles_x = (self.xsiz - self.xosiz) / (self.xtsiz - self.xtosiz) num_tiles_y = (self.ysiz - self.yosiz) / (self.ytsiz - self.ytosiz) @@ -1480,26 +1513,23 @@ class SIZsegment(Segment): msg = "Invalid number of tiles ({0}).".format(numtiles) warnings.warn(msg) - data = struct.unpack('>' + 'B' * len(component_buffer), - component_buffer) - - self.ssiz = data[0::3] - - for j, subsampling in enumerate(list(zip(data[1::3], data[2::3]))): - if 0 in subsampling: - msg = "Invalid subsampling value for component {0}: " - msg += "dx={1}, dy={2}." - msg = msg.format(j, subsampling[0], subsampling[1]) - warnings.warn(msg) - self.xrsiz = data[1::3] - self.yrsiz = data[2::3] - - self.bitdepth = tuple(((x & 0x7f) + 1) for x in self.ssiz) - self.signed = tuple(((x & 0xb0) > 0) for x in self.ssiz) - - self.length = length - self.offset = offset + def __repr__(self): + msg = "glymur.codestream.SIZsegment(rsiz={rsiz}, xysiz={xysiz}, " + msg += "xyosiz={xyosiz}, xytsiz={xytsiz}, xytosiz={xytosiz}, " + msg += "Csiz={Csiz}, bitdepth={bitdepth}, signed={signed}, " + msg += "xyrsiz={xyrsiz})" + msg = msg.format(rsiz=self.rsiz, + xysiz=(self.xsiz, self.ysiz), + xyosiz=(self.xosiz, self.yosiz), + xytsiz=(self.xtsiz, self.ytsiz), + xytosiz=(self.xtosiz, self.ytosiz), + Csiz=self.Csiz, + bitdepth=self.bitdepth, + signed=self.signed, + xyrsiz=(self.xrsiz, self.yrsiz)) + return msg + def __str__(self): msg = Segment.__str__(self) msg += '\n ' @@ -1549,6 +1579,9 @@ class SOCsegment(Segment): Segment.__init__(self, marker_id='SOC') self.__dict__.update(**kwargs) + def __repr__(self): + msg = "glymur.codestream.SOCsegment()" + return msg class SODsegment(Segment): """Container for Start of Data (SOD) segment information. diff --git a/glymur/test/test_codestream.py b/glymur/test/test_codestream.py index 8db5039..76042b9 100644 --- a/glymur/test/test_codestream.py +++ b/glymur/test/test_codestream.py @@ -116,5 +116,49 @@ class TestCodestream(unittest.TestCase): # codestream, so the last one is EOC. self.assertEqual(codestream.segment[-1].marker_id, 'EOC') + +class TestCodestreamRepr(unittest.TestCase): + + def setUp(self): + self.jp2file = glymur.data.nemo() + + def tearDown(self): + pass + + def test_soc(self): + """Test SOC segment repr""" + segment = glymur.codestream.SOCsegment() + newseg = eval(repr(segment)) + self.assertEqual(newseg.marker_id, 'SOC') + + def test_siz(self): + """Test SIZ segment repr""" + kwargs = {'rsiz': 0, + 'xysiz': (2592, 1456), + 'xyosiz': (0, 0), + 'xytsiz': (2592, 1456), + 'xytosiz': (0, 0), + 'Csiz': 3, + 'bitdepth': (8, 8, 8), + 'signed': (False, False, False), + 'xyrsiz': ((1, 1, 1), (1, 1, 1))} + segment = glymur.codestream.SIZsegment(**kwargs) + newseg = eval(repr(segment)) + self.assertEqual(newseg.marker_id, 'SIZ') + self.assertEqual(newseg.xsiz, 2592) + self.assertEqual(newseg.ysiz, 1456) + self.assertEqual(newseg.xosiz, 0) + self.assertEqual(newseg.yosiz, 0) + self.assertEqual(newseg.xtsiz, 2592) + self.assertEqual(newseg.ytsiz, 1456) + self.assertEqual(newseg.xtosiz, 0) + self.assertEqual(newseg.ytosiz, 0) + + self.assertEqual(newseg.xrsiz, (1, 1, 1)) + self.assertEqual(newseg.yrsiz, (1, 1, 1)) + self.assertEqual(newseg.bitdepth, (8, 8, 8)) + self.assertEqual(newseg.signed, (False, False, False)) + + if __name__ == "__main__": unittest.main() From 9799762fb5ae56a63659ce5a62ed6524cb72c385 Mon Sep 17 00:00:00 2001 From: John Evans Date: Thu, 24 Oct 2013 08:48:14 -0400 Subject: [PATCH 08/21] Added repr support for Jp2k class. #133 --- glymur/jp2k.py | 4 ++++ glymur/test/test_jp2k.py | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/glymur/jp2k.py b/glymur/jp2k.py index 1bd36a4..a9927da 100644 --- a/glymur/jp2k.py +++ b/glymur/jp2k.py @@ -72,6 +72,10 @@ class Jp2k(Jp2kBox): if mode == 'rb': self.parse() + def __repr__(self): + msg = "glymur.Jp2k('{0}')".format(self.filename) + return msg + def __str__(self): metadata = ['File: ' + os.path.basename(self.filename)] if len(self.box) > 0: diff --git a/glymur/test/test_jp2k.py b/glymur/test/test_jp2k.py index 636ea9a..15da73d 100644 --- a/glymur/test/test_jp2k.py +++ b/glymur/test/test_jp2k.py @@ -67,6 +67,15 @@ class TestJp2k(unittest.TestCase): def tearDown(self): pass + def test_repr(self): + """Verify that results of __repr__ are eval-able.""" + j = Jp2k(self.j2kfile) + newjp2 = eval(repr(j)) + + self.assertEqual(newjp2.filename, self.j2kfile) + self.assertEqual(newjp2.mode, 'rb') + self.assertEqual(len(newjp2.box), 0) + def test_rlevel_max(self): """Verify that rlevel=-1 gets us the lowest resolution image""" j = Jp2k(self.j2kfile) From c8fe9ed7763ed46e90e3feca56a2688a3dc2269f Mon Sep 17 00:00:00 2001 From: John Evans Date: Thu, 24 Oct 2013 09:29:45 -0400 Subject: [PATCH 09/21] Added proper repr support for association box. #133 --- glymur/jp2box.py | 8 ++++++-- glymur/test/test_jp2box.py | 7 +++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index 8303981..6466a63 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -1061,11 +1061,15 @@ class AssociationBox(Jp2kBox): box : list List of boxes contained in this superbox. """ - def __init__(self, length=0, offset=-1): + def __init__(self, box=[], length=0, offset=-1): Jp2kBox.__init__(self, box_id='asoc', longname='Association') self.length = length self.offset = offset - self.box = [] + self.box = box + + def __repr__(self): + msg = "glymur.jp2box.AssociationBox(box={0})".format(self.box) + return msg def __str__(self): msg = Jp2kBox.__str__(self) diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py index b82af47..bf14789 100644 --- a/glymur/test/test_jp2box.py +++ b/glymur/test/test_jp2box.py @@ -780,6 +780,13 @@ class TestRepr(unittest.TestCase): self.assertFalse(newbox.colorspace_unknown) self.assertFalse(newbox.ip_provided) + def test_association_box(self): + """Verify __repr__ method on asoc box.""" + asoc = glymur.jp2box.AssociationBox() + newbox = eval(repr(asoc)) + self.assertEqual(newbox.box_id, 'asoc') + self.assertEqual(len(newbox.box), 0) + def test_codestreamheader_box(self): """Verify __repr__ method on jpch box.""" jpch = glymur.jp2box.CodestreamHeaderBox() From dc994377e1bf2c425ddee2072e94c01771ccd9f6 Mon Sep 17 00:00:00 2001 From: jevans Date: Sat, 26 Oct 2013 21:43:32 -0400 Subject: [PATCH 10/21] Added palette and xml box repr support. #133 --- glymur/jp2box.py | 16 +++++++++++++++- glymur/test/test_jp2box.py | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index 6466a63..c7d69d5 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -75,6 +75,12 @@ class Jp2kBox(object): self.offset = offset self.longname = longname + def __repr__(self): + msg = "glymur.jp2box.Jp2kBox(box_id='{0}', offset={1}, length={2}, " + msg += "longname='{3}')" + msg = msg.format(self.box_id, self.offset, self.length, self.longname) + return msg + def __str__(self): msg = "{0} Box ({1})".format(self.longname, self.box_id) msg += " @ ({0}, {1})".format(self.offset, self.length) @@ -1273,6 +1279,12 @@ class PaletteBox(Jp2kBox): self.length = length self.offset = offset + def __repr__(self): + msg = "glymur.jp2box.PaletteBox({0}, bits_per_component={1}, " + msg += "signed={2})" + msg = msg.format(self.palette, self.bits_per_component, self.signed) + return msg + def __str__(self): msg = Jp2kBox.__str__(self) msg += '\n Size: ({0} x {1})'.format(len(self.palette[0]), @@ -1895,6 +1907,9 @@ class XMLBox(Jp2kBox): self.length = length self.offset = offset + def __repr__(self): + return "glymur.jp2box.XMLBox(xml={0})".format(self.xml) + def __str__(self): msg = Jp2kBox.__str__(self) xml = self.xml @@ -1953,7 +1968,6 @@ class XMLBox(Jp2kBox): msg = msg.format(offset, ude.reason) warnings.warn(msg, UserWarning) - # Strip out any trailing nulls, as they can foul up XML parsing. text = text.rstrip(chr(0)) diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py index bf14789..117d52b 100644 --- a/glymur/test/test_jp2box.py +++ b/glymur/test/test_jp2box.py @@ -18,6 +18,7 @@ Test suite specifically targeting JP2 box layout. import doctest import os +import re import shutil import struct import sys @@ -414,7 +415,7 @@ class TestAppend(unittest.TestCase): jp2 = Jp2k(tfile.name) the_xml = ET.fromstring('0') - xmlbox = glymur.jp2box.XMLBox(xml=the_xml) + xmlbox = glymur.jp2box.XMLBox(xml=ET.ElementTree(the_xml)) jp2.append(xmlbox) # The sequence of box IDs should be the same as before, but with an @@ -865,6 +866,36 @@ class TestRepr(unittest.TestCase): self.assertEqual(newbox.ulst[0], uuid1) self.assertEqual(newbox.ulst[1], uuid2) + def test_jp2k_box(self): + """Verify Superclass repr.""" + box = glymur.jp2box.Jp2kBox(box_id='one', offset=2, length=3, + longname='four') + newbox = eval(repr(box)) + self.assertEqual(newbox.box_id, 'one') + self.assertEqual(newbox.offset, 2) + self.assertEqual(newbox.length, 3) + self.assertEqual(newbox.longname, 'four') + + def test_palette_box(self): + """Verify Palette box repr.""" + palette = np.array([[255, 0, 1000], [0, 255, 0]], dtype=np.int32) + bps = (8, 8, 16) + signed = (True, False, True) + box = glymur.jp2box.PaletteBox(palette=palette, bits_per_component=bps, + signed=(True, False, True)) + # The palette can't be reinstantiated thru eval/repr. + s = repr(box) + self.assertTrue(True) + + def test_xml_box(self): + """Verify xml box repr.""" + elt = ET.fromstring('0') + tree = ET.ElementTree(elt) + box = glymur.jp2box.XMLBox(xml=tree) + + regexp = "glymur.jp2box.XMLBox\(xml= Date: Sat, 26 Oct 2013 22:16:01 -0400 Subject: [PATCH 11/21] Regexp tests can only run on 2.7 and 3.3. #133 --- glymur/test/test_jp2box.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py index 117d52b..94c3f73 100644 --- a/glymur/test/test_jp2box.py +++ b/glymur/test/test_jp2box.py @@ -887,15 +887,21 @@ class TestRepr(unittest.TestCase): s = repr(box) self.assertTrue(True) + @unittest.skipIf(sys.hexversion < 0x02070000, "Requires 2.7+") def test_xml_box(self): """Verify xml box repr.""" elt = ET.fromstring('0') tree = ET.ElementTree(elt) box = glymur.jp2box.XMLBox(xml=tree) - regexp = "glymur.jp2box.XMLBox\(xml= Date: Sun, 27 Oct 2013 06:09:39 -0400 Subject: [PATCH 12/21] Added rreg repr support. #133 --- glymur/jp2box.py | 12 ++++++++++++ glymur/test/test_jp2box.py | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index c7d69d5..00e2a1e 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -1506,6 +1506,18 @@ class ReaderRequirementsBox(Jp2kBox): self.length = length self.offset = offset + def __repr__(self): + msg = "glymur.jp2box.ReaderRequirementsBox(fuam={fuam}, dcm={dcm}, " + msg += "standard_flag={standard_flag}, standard_mask={standard_mask}, " + msg += "vendor_feature={vendor_feature}, vendor_mask={vendor_mask})" + msg = msg.format(fuam=self.fuam, + dcm=self.dcm, + standard_flag=self.standard_flag, + standard_mask=self.standard_mask, + vendor_feature=self.vendor_feature, + vendor_mask=self.vendor_mask) + return msg + def __str__(self): msg = Jp2kBox.__str__(self) diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py index 94c3f73..648e37c 100644 --- a/glymur/test/test_jp2box.py +++ b/glymur/test/test_jp2box.py @@ -903,6 +903,22 @@ class TestRepr(unittest.TestCase): else: self.assertRegex(repr(box), regexp) + def test_readerrequirements_box(self): + """Verify rreq repr method.""" + box = glymur.jp2box.ReaderRequirementsBox(fuam=160, dcm=192, + standard_flag=(5, 61, 43), + standard_mask=(128, 96, 64), + vendor_feature=[], + vendor_mask=[]) + newbox = eval(repr(box)) + self.assertEqual(box.fuam, newbox.fuam) + self.assertEqual(box.dcm, newbox.dcm) + self.assertEqual(box.standard_flag, newbox.standard_flag) + self.assertEqual(box.standard_mask, newbox.standard_mask) + self.assertEqual(box.vendor_feature, newbox.vendor_feature) + self.assertEqual(box.vendor_mask, newbox.vendor_mask) + + class TestJpxBoxes(unittest.TestCase): """Tests for JPX boxes.""" From 5e5bff39c3bd3e22dea650d18b2fb60140e776fa Mon Sep 17 00:00:00 2001 From: John Evans Date: Sun, 27 Oct 2013 14:00:40 -0400 Subject: [PATCH 13/21] Added UUIDBox and ContiguousCodeStreamBox repr support. Closes #133 --- glymur/jp2box.py | 12 +++++++++++- glymur/test/test_jp2box.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/glymur/jp2box.py b/glymur/jp2box.py index 00e2a1e..b363c76 100644 --- a/glymur/jp2box.py +++ b/glymur/jp2box.py @@ -773,6 +773,10 @@ class ContiguousCodestreamBox(Jp2kBox): self.length = length self.offset = offset + def __repr__(self): + msg = "glymur.jp2box.ContiguousCodeStreamBox(main_header={0})" + return msg.format(repr(self.main_header)) + def __str__(self): msg = Jp2kBox.__str__(self) msg += '\n Main header:' @@ -978,7 +982,6 @@ class ImageHeaderBox(Jp2kBox): return msg def __str__(self): - msg = Jp2kBox.__str__(self) msg = "{0}" msg += '\n Size: [{1} {2} {3}]' msg += '\n Bitdepth: {4}' @@ -2238,6 +2241,7 @@ class UUIDBox(Jp2kBox): """ Jp2kBox.__init__(self, box_id='uuid', longname='UUID') self.uuid = the_uuid + self.raw_data = raw_data if the_uuid == uuid.UUID('be7acfcb-97a9-42e8-9c71-999491e3afac'): # XMP data. Parse as XML. Seems to be a difference between @@ -2262,6 +2266,12 @@ class UUIDBox(Jp2kBox): self.length = length self.offset = offset + def __repr__(self): + msg = "glymur.jp2box.UUIDBox(the_uuid={0}, " + msg += "raw_data=)" + return msg.format(repr(self.uuid), len(self.raw_data)) + + def __str__(self): msg = '{0}\n' msg += ' UUID: {1}{2}\n' diff --git a/glymur/test/test_jp2box.py b/glymur/test/test_jp2box.py index 648e37c..05c0a83 100644 --- a/glymur/test/test_jp2box.py +++ b/glymur/test/test_jp2box.py @@ -918,6 +918,42 @@ class TestRepr(unittest.TestCase): self.assertEqual(box.vendor_feature, newbox.vendor_feature) self.assertEqual(box.vendor_mask, newbox.vendor_mask) + @unittest.skipIf(sys.hexversion < 0x02070000, "Requires 2.7+") + def test_uuid_box(self): + """Verify uuid repr method.""" + uuid_instance = uuid.UUID('00000000-0000-0000-0000-000000000000') + data = b'0123456789' + box = glymur.jp2box.UUIDBox(the_uuid=uuid_instance, raw_data=data) + + # Since the raw_data parameter is a sequence of bytes which could be + # quite long, don't bother trying to make it conform to eval(repr()). + regexp = "glymur.jp2box.UUIDBox\(" + regexp += "the_uuid=UUID\('00000000-0000-0000-0000-000000000000'\),\s" + regexp += "raw_data=\)" + + if sys.hexversion < 0x03000000: + self.assertRegexpMatches(repr(box), regexp) + else: + self.assertRegex(repr(box), regexp) + + @unittest.skipIf(sys.hexversion < 0x02070000, "Requires 2.7+") + def test_contiguous_codestream_box(self): + """Verify contiguous codestream box repr method.""" + jp2file = glymur.data.nemo() + jp2 = Jp2k(jp2file) + box = jp2.box[-1] + + # Difficult to eval(repr()) this, so just match the general pattern. + regexp = "glymur.jp2box.ContiguousCodeStreamBox" + regexp += "\(main_header= Date: Tue, 29 Oct 2013 09:17:32 -0400 Subject: [PATCH 14/21] Add additional path existance check to avoid unnecessary warning. #138 The warnings would come about if running on mac or windows where the library could not be found via ctypes or the configuration file. --- glymur/lib/config.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/glymur/lib/config.py b/glymur/lib/config.py index 2a85cbe..69d258e 100644 --- a/glymur/lib/config.py +++ b/glymur/lib/config.py @@ -45,6 +45,12 @@ def glymurrc_fname(): def load_openjpeg(path): """Load the openjpeg library, falling back on defaults if necessary. + + Parameters + ---------- + path : str + Path to openjpeg 1.5 library as specified by configuration file. Will + be None if no configuration file specified. """ if path is None: # Let ctypes try to find it. @@ -84,7 +90,9 @@ def load_openjp2(path): def load_library_handle(path): """Load the library, return the ctypes handle.""" - if path is None: + if path is None or (path is not None and not os.path.exists(path)): + # Either could not find a library via ctypes or user-configuration-file, + # or we could not find it in any of the default locations. return None try: @@ -93,10 +101,10 @@ def load_library_handle(path): else: opj_lib = ctypes.CDLL(path) except (TypeError, OSError): - msg = '"Library {0}" could not be loaded. Operating in degraded mode.' - msg = msg.format(path) - warnings.warn(msg, UserWarning) - opj_lib = None + msg = '"Library {0}" could not be loaded. Operating in degraded mode.' + msg = msg.format(path) + warnings.warn(msg, UserWarning) + opj_lib = None return opj_lib From 453e00db8c1fb01191e66db0591a801ff05b8a8d Mon Sep 17 00:00:00 2001 From: John Evans Date: Tue, 29 Oct 2013 09:29:39 -0400 Subject: [PATCH 15/21] Prepping for 0.5.8 --- CHANGES.txt | 3 +++ docs/source/conf.py | 2 +- glymur/version.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 68fe102..981672d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,6 @@ +Oct 29, 2013 - v0.5.8 Fixed unnecessary warnings when default locations for + openjpeg libraries on mac do not specify the actual library. + Oct 28, 2013 - v0.5.7 Fixed bad import error message when libopenjpeg library not installed on mac. diff --git a/docs/source/conf.py b/docs/source/conf.py index 90db6a3..0338c5a 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -78,7 +78,7 @@ copyright = u'2013, John Evans' # The short X.Y version. version = '0.5' # The full version, including alpha/beta/rc tags. -release = '0.5.7' +release = '0.5.8' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/glymur/version.py b/glymur/version.py index 6068a93..0fb4b86 100644 --- a/glymur/version.py +++ b/glymur/version.py @@ -15,7 +15,7 @@ from .lib import openjp2 as opj2 # Do not change the format of this next line! Doing so risks breaking # setup.py -version = "0.5.7" +version = "0.5.8" _sv = LooseVersion(version) version_tuple = _sv.version From 75cb8957fc45453c2d91cded649c638bcb1e27ce Mon Sep 17 00:00:00 2001 From: John Evans Date: Tue, 29 Oct 2013 10:04:47 -0400 Subject: [PATCH 16/21] Have to put the check for path existance into the library default stanza. Issue #138 --- glymur/lib/config.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/glymur/lib/config.py b/glymur/lib/config.py index 69d258e..fdb5a92 100644 --- a/glymur/lib/config.py +++ b/glymur/lib/config.py @@ -59,6 +59,7 @@ def load_openjpeg(path): # If we could not find it, then look in some likely locations on mac # and win. if path is None: + # Could not find a library via ctypes if platform.system() == 'Darwin': # MacPorts path = '/opt/local/lib/libopenjpeg.dylib' @@ -66,6 +67,10 @@ def load_openjpeg(path): path = os.path.join('C:\\', 'Program files', 'OpenJPEG 1.5', 'bin', 'openjpeg.dll') + if path is not None and not os.path.exists(path): + # the mac/win default location does not exist. + return None + return load_library_handle(path) @@ -73,10 +78,11 @@ def load_openjp2(path): """Load the openjp2 library, falling back on defaults if necessary. """ if path is None: - # No help from the config file, try to find it ourselves. + # No help from the config file, try to find it via ctypes. path = find_library('openjp2') if path is None: + # Could not find a library via ctypes if platform.system() == 'Darwin': # MacPorts path = '/opt/local/lib/libopenjp2.dylib' @@ -84,15 +90,20 @@ def load_openjp2(path): path = os.path.join('C:\\', 'Program files', 'OpenJPEG 2.0', 'bin', 'openjp2.dll') + if path is not None and not os.path.exists(path): + # the mac/win default location does not exist. + return None + return load_library_handle(path) def load_library_handle(path): """Load the library, return the ctypes handle.""" - if path is None or (path is not None and not os.path.exists(path)): + if path is None: # Either could not find a library via ctypes or user-configuration-file, # or we could not find it in any of the default locations. + # This is probably a very old linux. return None try: From f551646af8072037179e12cf1846c7f6ba7f8ad1 Mon Sep 17 00:00:00 2001 From: John Evans Date: Tue, 29 Oct 2013 10:15:24 -0400 Subject: [PATCH 17/21] Prepping 0.5.9 release. --- CHANGES.txt | 2 ++ docs/source/conf.py | 2 +- glymur/version.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 981672d..5e62c1c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,5 @@ +Oct 29, 2013 - v0.5.9 Fixed bad library load on linux as a result of 0.5.8 + Oct 29, 2013 - v0.5.8 Fixed unnecessary warnings when default locations for openjpeg libraries on mac do not specify the actual library. diff --git a/docs/source/conf.py b/docs/source/conf.py index 0338c5a..b14af27 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -78,7 +78,7 @@ copyright = u'2013, John Evans' # The short X.Y version. version = '0.5' # The full version, including alpha/beta/rc tags. -release = '0.5.8' +release = '0.5.9' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/glymur/version.py b/glymur/version.py index 0fb4b86..6116920 100644 --- a/glymur/version.py +++ b/glymur/version.py @@ -15,7 +15,7 @@ from .lib import openjp2 as opj2 # Do not change the format of this next line! Doing so risks breaking # setup.py -version = "0.5.8" +version = "0.5.9" _sv = LooseVersion(version) version_tuple = _sv.version From d41f019c590ab21857f553429cea8a24beb7c577 Mon Sep 17 00:00:00 2001 From: jevans Date: Tue, 29 Oct 2013 19:41:59 -0400 Subject: [PATCH 18/21] Removed class-0 conformance tests. Closes #139 Keeps us in sync with upstream openjpeg. See r2350. --- glymur/test/test_opj_suite.py | 299 +--------------------------------- 1 file changed, 4 insertions(+), 295 deletions(-) diff --git a/glymur/test/test_opj_suite.py b/glymur/test/test_opj_suite.py index 37d6b73..97b68e1 100644 --- a/glymur/test/test_opj_suite.py +++ b/glymur/test/test_opj_suite.py @@ -62,266 +62,6 @@ class TestSuite(unittest.TestCase): def tearDown(self): pass - def test_ETS_C0P0_p0_01_j2k(self): - jfile = opj_data_file('input/conformance/p0_01.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) - - pgxfile = opj_data_file('baseline/conformance/c0p0_01.pgx') - pgxdata = read_pgx(pgxfile) - np.testing.assert_array_equal(jpdata, pgxdata) - - def test_ETS_C0P0_p0_02_j2k(self): - jfile = opj_data_file('input/conformance/p0_02.j2k') - jp2k = Jp2k(jfile) - with warnings.catch_warnings(): - # Invalid marker ID. - warnings.simplefilter("ignore") - jpdata = jp2k.read(rlevel=0) - - pgxfile = opj_data_file('baseline/conformance/c0p0_02.pgx') - pgxdata = read_pgx(pgxfile) - np.testing.assert_array_equal(jpdata, pgxdata) - - @unittest.skip("Known failure in OPENJPEG test suite.") - def test_ETS_C0P0_p0_03_j2k(self): - jfile = opj_data_file('input/conformance/p0_03.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) - - pgxfile = opj_data_file('baseline/conformance/c0p0_03r0.pgx') - pgxdata = read_pgx(pgxfile) - np.testing.assert_array_equal(jpdata, pgxdata) - - def test_ETS_C0P0_p0_03_j2k_r1(self): - jfile = opj_data_file('input/conformance/p0_03.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=1) - - pgxfile = opj_data_file('baseline/conformance/c0p0_03r1.pgx') - pgxdata = read_pgx(pgxfile) - np.testing.assert_array_equal(jpdata, pgxdata) - - @unittest.skip("Known failure in OPENJPEG test suite.") - def test_ETS_C0P0_p0_04_j2k(self): - jfile = opj_data_file('input/conformance/p0_04.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=3) - - pgxfile = opj_data_file('baseline/conformance/c0p0_04.pgx') - pgxdata = read_pgx(pgxfile) - - self.assertTrue(peak_tolerance(jpdata[:, :, 2], pgxdata) < 33) - self.assertTrue(mse(jpdata[:, :, 2], pgxdata) < 55.8) - - @unittest.skip("Known failure in OPENJPEG test suite.") - def test_ETS_C0P0_p0_07_j2k(self): - jfile = opj_data_file('input/conformance/p0_07.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read() - - pgxfile = opj_data_file('baseline/conformance/c0p0_07.pgx') - pgxdata = read_pgx(pgxfile) - - self.assertTrue(peak_tolerance(jpdata[:, :, 0], pgxdata) < 10) - self.assertTrue(mse(jpdata[:, :, 0], pgxdata) < 0.34) - - @unittest.skip("8-bit pgx data vs 12-bit j2k data") - def test_ETS_C0P0_p0_08_j2k(self): - jfile = opj_data_file('input/conformance/p0_08.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=5) - - pgxfile = opj_data_file('baseline/conformance/c0p0_08.pgx') - pgxdata = read_pgx(pgxfile) - - self.assertTrue(peak_tolerance(jpdata[:, :, 0], pgxdata) < 7) - self.assertTrue(mse(jpdata[:, :, 0], pgxdata) < 6.72) - - def test_ETS_C0P0_p0_09_j2k(self): - jfile = opj_data_file('input/conformance/p0_09.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=2) - - pgxfile = opj_data_file('baseline/conformance/c0p0_09.pgx') - pgxdata = read_pgx(pgxfile) - - self.assertTrue(peak_tolerance(jpdata, pgxdata) < 4) - self.assertTrue(mse(jpdata, pgxdata) < 1.47) - - @unittest.skip("Known failure in OPENJPEG test suite.") - def test_ETS_C0P0_p0_10_j2k(self): - jfile = opj_data_file('input/conformance/p0_10.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) - - pgxfile = opj_data_file('baseline/conformance/c0p0_10.pgx') - pgxdata = read_pgx(pgxfile) - - self.assertTrue(peak_tolerance(jpdata[:, :, 0], pgxdata) < 10) - self.assertTrue(mse(jpdata[:, :, 0], pgxdata) < 2.84) - - def test_ETS_C0P0_p0_11_j2k(self): - jfile = opj_data_file('input/conformance/p0_11.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) - - pgxfile = opj_data_file('baseline/conformance/c0p0_11.pgx') - pgxdata = read_pgx(pgxfile) - - np.testing.assert_array_equal(jpdata, pgxdata) - - @unittest.skip("fprintf stderr output in r2343.") - def test_ETS_C0P0_p0_12_j2k(self): - jfile = opj_data_file('input/conformance/p0_12.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) - - pgxfile = opj_data_file('baseline/conformance/c0p0_12.pgx') - pgxdata = read_pgx(pgxfile) - - np.testing.assert_array_equal(jpdata, pgxdata) - - @unittest.skip("Known failure in OPENJPEG test suite.") - def test_ETS_C0P0_p0_13_j2k(self): - jfile = opj_data_file('input/conformance/p0_13.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) - - pgxfile = opj_data_file('baseline/conformance/c0p0_13.pgx') - pgxdata = read_pgx(pgxfile) - - np.testing.assert_array_equal(jpdata[:, :, 0], pgxdata) - - @unittest.skip("Known failure in OPENJPEG test suite.") - def test_ETS_C0P0_p0_14_j2k(self): - jfile = opj_data_file('input/conformance/p0_14.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=2) - - pgxfile = opj_data_file('baseline/conformance/c0p0_14.pgx') - pgxdata = read_pgx(pgxfile) - - np.testing.assert_array_equal(jpdata[:, :, 0], pgxdata) - - @unittest.skip("Known failure in OPENJPEG test suite.") - def test_ETS_C0P0_p0_15_j2k(self): - jfile = opj_data_file('input/conformance/p0_15.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) - - pgxfile = opj_data_file('baseline/conformance/c0p0_15r0.pgx') - pgxdata = read_pgx(pgxfile) - - np.testing.assert_array_equal(jpdata, pgxdata) - - def test_ETS_C0P0_p0_15_j2k_r1(self): - jfile = opj_data_file('input/conformance/p0_15.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=1) - - pgxfile = opj_data_file('baseline/conformance/c0p0_15r1.pgx') - pgxdata = read_pgx(pgxfile) - - np.testing.assert_array_equal(jpdata, pgxdata) - - def test_ETS_C0P0_p0_16_j2k(self): - jfile = opj_data_file('input/conformance/p0_16.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) - - pgxfile = opj_data_file('baseline/conformance/c0p0_16.pgx') - pgxdata = read_pgx(pgxfile) - - np.testing.assert_array_equal(jpdata, pgxdata) - - def test_ETS_C0P1_p1_01_j2k(self): - jfile = opj_data_file('input/conformance/p1_01.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) - - pgxfile = opj_data_file('baseline/conformance/c0p1_01.pgx') - pgxdata = read_pgx(pgxfile) - - np.testing.assert_array_equal(jpdata, pgxdata) - - @unittest.skip("Known failure in OPENJPEG test suite operation.") - def test_ETS_C0P1_p1_02_j2k(self): - jfile = opj_data_file('input/conformance/p1_02.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=3) - - pgxfile = opj_data_file('baseline/conformance/c0p1_02.pgx') - pgxdata = read_pgx(pgxfile) - - self.assertTrue(peak_tolerance(jpdata[:, :, 0], pgxdata) < 35) - self.assertTrue(mse(jpdata[:, :, 0], pgxdata) < 74) - - @unittest.skip("Known failure in OPENJPEG test suite operation.") - def test_ETS_C0P1_p1_04_j2k(self): - jfile = opj_data_file('input/conformance/p1_04.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) - - pgxfile = opj_data_file('baseline/conformance/c0p1_04r0.pgx') - pgxdata = read_pgx(pgxfile) - - print(peak_tolerance(jpdata, pgxdata)) - self.assertTrue(peak_tolerance(jpdata, pgxdata) < 2) - self.assertTrue(mse(jpdata, pgxdata) < 0.55) - - @unittest.skip("Known failure in OPENJPEG test suite, precision issue.") - def test_ETS_C0P1_p1_04_j2k_r3(self): - jfile = opj_data_file('input/conformance/p1_04.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=3) - - pgxfile = opj_data_file('baseline/conformance/c0p1_04r3.pgx') - pgxdata = read_pgx(pgxfile) - - print(peak_tolerance(jpdata, pgxdata)) - self.assertTrue(peak_tolerance(jpdata, pgxdata) < 2) - self.assertTrue(mse(jpdata, pgxdata) < 0.55) - - @unittest.skip("Known failure in OPENJPEG test suite operation.") - def test_ETS_C0P1_p1_05_j2k(self): - jfile = opj_data_file('input/conformance/p1_05.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=4) - - pgxfile = opj_data_file('baseline/conformance/c0p1_05.pgx') - pgxdata = read_pgx(pgxfile) - - print(peak_tolerance(jpdata[:, :, 0], pgxdata)) - print(peak_tolerance(jpdata[:, :, 1], pgxdata)) - self.assertTrue(peak_tolerance(jpdata[:, :, 0], pgxdata) < 128) - self.assertTrue(mse(jpdata[:, :, 0], pgxdata) < 16384) - - @unittest.skip("Known failure in OPENJPEG test suite operation.") - def test_ETS_C0P1_p1_06_j2k(self): - jfile = opj_data_file('input/conformance/p1_06.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=1) - - pgxfile = opj_data_file('baseline/conformance/c0p1_06.pgx') - pgxdata = read_pgx(pgxfile) - - print(peak_tolerance(jpdata[:, :, 0], pgxdata)) - print(peak_tolerance(jpdata[:, :, 1], pgxdata)) - self.assertTrue(peak_tolerance(jpdata[:, :, 0], pgxdata) < 128) - self.assertTrue(mse(jpdata[:, :, 0], pgxdata) < 16384) - - @unittest.skip("fprintf stderr output in r2345.") - def test_ETS_C0P1_p1_07_j2k(self): - jfile = opj_data_file('input/conformance/p1_07.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read_bands(rlevel=0) - - pgxfile = opj_data_file('baseline/conformance/c0p1_07.pgx') - pgxdata = read_pgx(pgxfile) - - np.testing.assert_array_equal(jpdata[0], pgxdata) - def test_ETS_C1P0_p0_01_j2k(self): jfile = opj_data_file('input/conformance/p0_01.j2k') jp2k = Jp2k(jfile) @@ -332,10 +72,13 @@ class TestSuite(unittest.TestCase): np.testing.assert_array_equal(jpdata, pgxdata) + @unittest.skipIf(sys.hexversion < 0x03020000, + "Uses features introduced in 3.2.") def test_ETS_C1P0_p0_02_j2k(self): jfile = opj_data_file('input/conformance/p0_02.j2k') jp2k = Jp2k(jfile) - jpdata = jp2k.read(rlevel=0) + with self.assertWarns(UserWarning): + jpdata = jp2k.read(rlevel=0) pgxfile = opj_data_file('baseline/conformance/c1p0_02_0.pgx') pgxdata = read_pgx(pgxfile) @@ -6728,40 +6471,6 @@ class TestSuite_bands(unittest.TestCase): def tearDown(self): pass - def test_ETS_C0P0_p0_05_j2k(self): - jfile = opj_data_file('input/conformance/p0_05.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read_bands(rlevel=3) - - pgxfile = opj_data_file('baseline/conformance/c0p0_05.pgx') - pgxdata = read_pgx(pgxfile) - self.assertTrue(peak_tolerance(jpdata[0], pgxdata) < 54) - self.assertTrue(mse(jpdata[0], pgxdata) < 68) - - @unittest.skip("8-bit pgx data vs 12-bit j2k data") - def test_ETS_C0P0_p0_06_j2k(self): - jfile = opj_data_file('input/conformance/p0_06.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read_bands(rlevel=3) - - pgxfile = opj_data_file('baseline/conformance/c0p0_06.pgx') - pgxdata = read_pgx(pgxfile) - tol = peak_tolerance(jpdata[0], pgxdata) - self.assertTrue(tol < 109) - m = mse(jpdata[0], pgxdata) - self.assertTrue(m < 743) - - def test_ETS_C0P1_p1_03_j2k(self): - jfile = opj_data_file('input/conformance/p1_03.j2k') - jp2k = Jp2k(jfile) - jpdata = jp2k.read_bands(rlevel=3) - - pgxfile = opj_data_file('baseline/conformance/c0p1_03.pgx') - pgxdata = read_pgx(pgxfile) - - self.assertTrue(peak_tolerance(jpdata[0], pgxdata) < 28) - self.assertTrue(mse(jpdata[0], pgxdata) < 18.8) - def test_ETS_C1P1_p1_03_j2k(self): jfile = opj_data_file('input/conformance/p1_03.j2k') jp2k = Jp2k(jfile) From fb63b8956ee48e74b50f64e4116dc02efe08545e Mon Sep 17 00:00:00 2001 From: jevans Date: Tue, 29 Oct 2013 19:52:00 -0400 Subject: [PATCH 19/21] Changelog update --- CHANGES.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 5e62c1c..8441cae 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,6 @@ +Oct 29, 2013 - v0.5.10 Palette box now a 2D numpy array instead of a list of + 1D arrays. + Oct 29, 2013 - v0.5.9 Fixed bad library load on linux as a result of 0.5.8 Oct 29, 2013 - v0.5.8 Fixed unnecessary warnings when default locations for From 2465a212a138e29a3eb470afbf1363e576c82f9e Mon Sep 17 00:00:00 2001 From: jevans Date: Wed, 6 Nov 2013 20:33:44 -0500 Subject: [PATCH 20/21] Fixed too-short underlines. --- docs/source/how_do_i.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/how_do_i.rst b/docs/source/how_do_i.rst index 212862d..f34264e 100644 --- a/docs/source/how_do_i.rst +++ b/docs/source/how_do_i.rst @@ -4,7 +4,7 @@ How do I...? ... read the lowest resolution thumbnail? -===================================== +========================================= Printing the Jp2k object should reveal the number of resolutions (look in the COD segment section), but you can take a shortcut by supplying -1 as the resolution level. :: @@ -15,7 +15,7 @@ resolution level. :: >>> thumbnail = j.read(rlevel=-1) ... display metadata? -================= +===================== There are two ways. From the unix command line, the script *jp2dump* is available. :: @@ -35,7 +35,7 @@ codestream box, only the main header is printed. It is possible to print >>> print(j.get_codestream()) ... add XML metadata? -================= +===================== You can append any number of XML boxes to a JP2 file (not to a raw codestream). Consider the following XML file `data.xml` : :: @@ -67,7 +67,7 @@ The **append** method can add an XML box as shown below:: >>> print(jp2) ... add metadata in a more general fashion? -======================================= +=========================================== An existing raw codestream (or JP2 file) can be wrapped (re-wrapped) in a user-defined set of JP2 boxes. To get just a minimal JP2 jacket on the codestream provided by `goodstuff.j2k` (a file consisting of a raw codestream), @@ -158,7 +158,7 @@ while **append** modifies an existing file and is currently limited to XML boxes. ... create an image with an alpha layer? -==================================== +======================================== OpenJPEG can create JP2 files with more than 3 components (requires the development version of OpenJPEG), but by default, any extra components are From e471f25a6e0f84aee41534b08f55de11cbbd4ab9 Mon Sep 17 00:00:00 2001 From: jevans Date: Wed, 6 Nov 2013 20:34:03 -0500 Subject: [PATCH 21/21] Updated for upstream openjpeg r2354. #139 --- docs/source/detailed_installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/detailed_installation.rst b/docs/source/detailed_installation.rst index 3e4d9dc..92810b7 100644 --- a/docs/source/detailed_installation.rst +++ b/docs/source/detailed_installation.rst @@ -13,7 +13,7 @@ both read and write JPEG 2000 files, but you may wish to install version 2.0 or the 2.0+ version from OpenJPEG's development trunk for better performance. If you do that, you should compile it as a shared library (named *openjp2* instead of *openjpeg*) from the developmental source that you can retrieve -via subversion. As of this time of writing, svn revision 2347 works. +via subversion. As of this time of writing, svn revision r2354 works. You should also download the test data for the purpose of configuring and running OpenJPEG's test suite, check their instructions for all this. You should set the **OPJ_DATA_ROOT** environment variable for the purpose