From d3dd654c17aa4924f2ba27f3089594f6949d2b56 Mon Sep 17 00:00:00 2001 From: John Evans Date: Thu, 24 Oct 2013 08:21:14 -0400 Subject: [PATCH] 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()