Merge branch 'issue135' into devel

This commit is contained in:
John Evans 2013-10-24 16:55:49 -04:00
commit 638c2451b8
2 changed files with 29 additions and 82 deletions

View file

@ -1193,8 +1193,8 @@ class PaletteBox(Jp2kBox):
offset of the box from the start of the file.
longname : str
more verbose description of the box.
palette : list
Colormap represented as list of 1D arrays, one per color component.
palette : ndarray
Colormap array.
"""
def __init__(self, palette, bits_per_component, signed, length=0,
offset=-1):
@ -1207,8 +1207,7 @@ class PaletteBox(Jp2kBox):
def __str__(self):
msg = Jp2kBox.__str__(self)
msg += '\n Size: ({0} x {1})'.format(len(self.palette[0]),
len(self.palette))
msg += '\n Size: ({0} x {1})'.format(*self.palette.shape)
return msg
@staticmethod
@ -1238,68 +1237,29 @@ class PaletteBox(Jp2kBox):
bps = [((x & 0x07f) + 1) for x in data]
signed = [((x & 0x80) > 1) for x in data]
fmt = '>'
for bits in bps:
if bits <= 8:
fmt += 'B'
elif bits <= 16:
fmt += 'H'
elif bits <= 32:
fmt += 'I'
# Each palette component is padded out to the next largest byte.
# That means a list comprehension does this in one shot.
row_nbytes = sum([int(math.ceil(x/8.0)) for x in bps])
# Form the format string so that we can intelligently unpack the
# colormap. We have to do this because it is possible that the
# colormap columns could have different datatypes.
#
# This means that we store the palette as a list of 1D arrays,
# which reverses the usual indexing scheme.
read_buffer = fptr.read(num_entries * row_nbytes)
palette = _buffer2palette(read_buffer, num_entries, num_columns, bps)
palette = np.zeros((num_entries, num_columns), dtype=np.int32)
for j in range(num_entries):
palette[j] = struct.unpack_from(fmt, read_buffer,
offset=j * row_nbytes)
box = PaletteBox(palette, bps, signed, length=length, offset=offset)
return box
def _buffer2palette(read_buffer, num_rows, num_cols, bps):
"""Construct the palette from the buffer read from file.
Parameters
----------
read_buffer : iterable
Byte array of palette information read from file.
num_rows, num_cols : int
Size of palette.
bps : iterable
Bits per sample for each channel.
Returns
-------
palette : list of 1D arrays
Each 1D array corresponds to a channel.
"""
row_nbytes = 0
palette = []
fmt = '>'
for j in range(num_cols):
if bps[j] <= 8:
row_nbytes += 1
fmt += 'B'
palette.append(np.zeros(num_rows, dtype=np.uint8))
elif bps[j] <= 16:
row_nbytes += 2
fmt += 'H'
palette.append(np.zeros(num_rows, dtype=np.uint16))
elif bps[j] <= 32:
row_nbytes += 4
fmt += 'I'
palette.append(np.zeros(num_rows, dtype=np.uint32))
else:
msg = 'Unsupported palette bitdepth (%d).'.format(bps[j])
raise IOError(msg)
for j in range(num_rows):
row_buffer = read_buffer[(row_nbytes * j):(row_nbytes * (j + 1))]
row = struct.unpack(fmt, row_buffer)
for k in range(num_cols):
palette[k][j] = row[k]
return palette
# Map rreq codes to display text.
_READER_REQUIREMENTS_DISPLAY = {
0: 'File not completely understood',

View file

@ -3797,19 +3797,16 @@ class TestSuiteDump(unittest.TestCase):
self.assertEqual(jp2.box[2].box[0].ip_provided, False)
# Palette box.
self.assertEqual(len(jp2.box[2].box[1].palette), 3)
self.assertEqual(len(jp2.box[2].box[1].palette[0]), 256)
self.assertEqual(len(jp2.box[2].box[1].palette[1]), 256)
self.assertEqual(len(jp2.box[2].box[1].palette[2]), 256)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[0][0], 0)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[1][0], 0)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[2][0], 0)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[0][128], 73)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[1][128], 92)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[2][128], 53)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[0][-1], 245)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[1][-1], 245)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[2][-1], 245)
self.assertEqual(jp2.box[2].box[1].palette.shape, (256, 3))
np.testing.assert_array_equal(jp2.box[2].box[1].palette[0, 0], 0)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[0, 1], 0)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[0, 2], 0)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[128, 0], 73)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[128, 1], 92)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[128, 2], 53)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[255, 0], 245)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[255, 1], 245)
np.testing.assert_array_equal(jp2.box[2].box[1].palette[255, 2], 245)
# Component mapping box
self.assertEqual(jp2.box[2].box[2].component_index, (0, 0, 0))
@ -5699,10 +5696,7 @@ class TestSuiteDump(unittest.TestCase):
# Jp2 Header
# Palette box.
self.assertEqual(len(jp2.box[3].box[2].palette), 3)
self.assertEqual(len(jp2.box[3].box[2].palette[0]), 256)
self.assertEqual(len(jp2.box[3].box[2].palette[1]), 256)
self.assertEqual(len(jp2.box[3].box[2].palette[2]), 256)
self.assertEqual(jp2.box[3].box[2].palette.shape, (256, 3))
# Jp2 Header
# Component mapping box
@ -6127,11 +6121,7 @@ class TestSuiteDump(unittest.TestCase):
# Jp2 Header
# Palette box.
self.assertEqual(len(jp2.box[3].box[2].palette), 4)
self.assertEqual(len(jp2.box[3].box[2].palette[0]), 1)
self.assertEqual(len(jp2.box[3].box[2].palette[1]), 1)
self.assertEqual(len(jp2.box[3].box[2].palette[2]), 1)
self.assertEqual(len(jp2.box[3].box[2].palette[3]), 1)
self.assertEqual(jp2.box[3].box[2].palette.shape, (1, 4))
# Jp2 Header
# Component mapping box
@ -6242,10 +6232,7 @@ class TestSuiteDump(unittest.TestCase):
# Jp2 Header
# Palette box.
# 3 columns with 16 entries.
self.assertEqual(len(jp2.box[3].box[2].palette), 3)
self.assertEqual(len(jp2.box[3].box[2].palette[0]), 16)
self.assertEqual(len(jp2.box[3].box[2].palette[1]), 16)
self.assertEqual(len(jp2.box[3].box[2].palette[2]), 16)
self.assertEqual(jp2.box[3].box[2].palette.shape, (16, 3))
# Jp2 Header
# Component mapping box