Skip to content

Commit f6a63e3

Browse files
author
Matt Land
committed
working p5 type images
1 parent c43d11b commit f6a63e3

7 files changed

Lines changed: 90 additions & 72 deletions

File tree

adafruit_imageload/pnm/pgm/__init__.py

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,85 +20,92 @@
2020
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
# THE SOFTWARE.
2222
"""
23-
`adafruit_imageload.pnm`
23+
`adafruit_imageload.pnm.pgm`
2424
====================================================
2525
2626
Load pixel values (indices or colors) into a bitmap and colors into a palette.
2727
2828
* Author(s): Matt Land, Brooke Storm, Sam McGahan
2929
3030
"""
31-
#import logging
31+
3232

3333
def load(file, magic_number, header, *, bitmap=None, palette=None):
34+
"""
35+
Perform the load of Netpbm greyscale images
36+
:param file: stream resource with the pointer at the start of data
37+
:param magic_number: string P2 or P6
38+
:param header: list of width, height, max color value
39+
:param bitmap: displayio.Bitmap class object
40+
:param palette: displayio.Paletta class object
41+
:return:
42+
"""
3443
if header[2] > 256:
3544
raise NotImplementedError("16 bit files are not supported")
3645
width = header[0]
3746
height = header[1]
3847

3948
data_start = file.tell() # keep this so we can rewind
40-
#bitmap = bitmap(width, height, max_colors)
4149
palette_colors = set()
4250

43-
if magic_number == b'P2': # To handle ascii PGM files.
44-
# Handle ascii
45-
51+
if magic_number == b"P2": # To handle ascii PGM files.
4652
pixel = bytearray()
47-
byte = True
48-
# scan all colors present in the file
49-
while byte:
50-
byte = file.read(1) # type: byte
53+
# build a set of all colors present in the file, so palette and bitmap can be constructed
54+
while True:
55+
byte = file.read(1)
56+
if byte == b'':
57+
break
5158
if not byte.isdigit():
5259
int_pixel = int("".join(["%c" % char for char in pixel]))
53-
#logging.info(f'color {pixel} {int_pixel}')
54-
#bitmap[x, y] = int_pixel
5560
palette_colors.add(int_pixel)
5661
pixel = bytearray()
5762
pixel += byte
58-
59-
# logging.info(f'{x}, {y}, {byte}, {int_pixel}')
6063
if palette:
61-
palette = palette(len(palette_colors))
62-
for counter, color in enumerate(palette_colors):
63-
palette[counter] = bytes([color, color, color])
64+
palette = build_palette(palette, palette_colors)
6465
if bitmap:
6566
bitmap = bitmap(width, height, len(palette_colors))
6667
palette_colors = list(palette_colors)
6768
file.seek(data_start)
6869
for y in range(height):
6970
for x in range(width):
7071
pixel = bytearray()
71-
# Takes int and converts to an 8 bit
7272
while True:
73-
byte = file.read(1) # type: byte
73+
byte = file.read(1)
7474
if not byte.isdigit():
7575
break
7676
pixel += byte
77-
# convert b'255' to b'\xff'
78-
color = int("".join(["%c" % char for char in pixel]))
79-
#logging.info(f'found color {color} in palette at {palette_colors.index(color)}')
80-
bitmap[x, y] = palette_colors.index(color)
81-
77+
int_pixel = int("".join(["%c" % char for char in pixel]))
78+
bitmap[x, y] = palette_colors.index(int_pixel)
8279
return bitmap, palette
8380

84-
if magic_number == b'P5': # To handle binary PGM files.
85-
for y in range(height):
86-
for x in range(width):
87-
byte = file.read(1)
88-
if byte == b"":
89-
raise ValueError("ran out of file unexpectedly")
90-
int_pixel = int.from_bytes(byte, "little")
91-
bitmap[x, y] = int_pixel
92-
palette_colors.add(int_pixel)
81+
if magic_number == b"P5": # To handle binary PGM files.
82+
while True:
83+
byte = file.read(1)
84+
if byte == b'':
85+
break
86+
int_pixel = int.from_bytes(byte, "little")
87+
palette_colors.add(int_pixel)
9388

9489
if palette:
95-
palette = palette(len(palette_colors))
96-
for counter, color in enumerate(palette_colors):
97-
color_bytearray = bytearray()
98-
for i in range(3):
99-
color_bytearray += bytes([color])
100-
palette[counter] = color_bytearray
101-
90+
palette = build_palette(palette, palette_colors)
91+
if bitmap:
92+
bitmap = bitmap(width, height, len(palette_colors))
93+
palette_colors = list(palette_colors)
94+
file.seek(data_start)
95+
for y in range(height):
96+
for x in range(width):
97+
byte = file.read(1)
98+
if byte == b"":
99+
raise ValueError("ran out of file unexpectedly")
100+
int_pixel = int.from_bytes(byte, "little")
101+
bitmap[x, y] = palette_colors.index(int_pixel)
102102
return bitmap, palette
103103

104104
raise NotImplementedError("Was not able to send image")
105+
106+
107+
def build_palette(palette_class, palette_colors):
108+
palette = palette_class(len(palette_colors))
109+
for counter, color in enumerate(palette_colors):
110+
palette[counter] = bytes([color, color, color])
111+
return palette

adafruit_imageload/tests/displayio_shared_bindings.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
2-
31
class Bitmap_C_Interface(object):
42
"""
53
Simulates the displayio.Bitmap class for testing
64
"""
5+
76
def __init__(self, width, height, colors):
87
self.width = width
98
self.height = height
@@ -28,14 +27,14 @@ def __setitem__(self, key: tuple, value: int):
2827
if not isinstance(value, (int)):
2928
raise RuntimeError(f"set value as int, not {type(value)}")
3029
if value > 255:
31-
raise ValueError(f'pixel value {value} too large')
30+
raise ValueError(f"pixel value {value} too large")
3231
self.data[key] = value
3332

3433
def __getitem__(self, item: tuple) -> bytearray:
3534
if isinstance(item, tuple):
3635
return self.__getitem__(self._abs_pos(item[0], item[1]))
3736
if item > self.height * self.width:
38-
raise RuntimeError(f'get position out of range {item}')
37+
raise RuntimeError(f"get position out of range {item}")
3938
try:
4039
return self.data[item]
4140
except KeyError:
@@ -64,19 +63,24 @@ class Palette_C_Interface(object):
6463
"""
6564
Simulates the displayio.Palette class for testing
6665
"""
66+
6767
def __init__(self, num_colors):
6868
self.num_colors = num_colors
6969
self.colors = {}
7070

7171
def __setitem__(self, key, value):
7272
if key >= self.num_colors:
73-
raise ValueError(f'palette index {key} is greater than allowed by num_colors {self.num_colors}')
73+
raise ValueError(
74+
f"palette index {key} is greater than allowed by num_colors {self.num_colors}"
75+
)
7476
if not isinstance(value, (bytes, int)):
75-
raise ValueError(f'palette color should be bytes, not {type(value)}')
77+
raise ValueError(f"palette color should be bytes, not {type(value)}")
7678
if isinstance(value, int) and value > 255:
77-
raise ValueError(f'palette color int {value} is too large')
79+
raise ValueError(f"palette color int {value} is too large")
7880
if self.colors.get(key):
79-
raise ValueError(f'palette color {key} was already set, should not reassign')
81+
raise ValueError(
82+
f"palette color {key} was already set, should not reassign"
83+
)
8084
self.colors[key] = value
8185

8286
def validate(self):
@@ -88,7 +92,7 @@ def validate(self):
8892
try:
8993
self.colors
9094
except IndexError:
91-
raise ValueError('missing color `{}` in palette color list'.format(i))
95+
raise ValueError("missing color `{}` in palette color list".format(i))
9296

9397
def __str__(self):
9498
out = "\nPalette:\n"

adafruit_imageload/tests/test_bitmap_c_interface.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def test_init(self):
1111

1212
def test_abs(self):
1313
b = Bitmap_C_Interface(5, 2, 1)
14-
self.assertEqual(9, b._abs_pos(4,1))
14+
self.assertEqual(9, b._abs_pos(4, 1))
1515

1616
def test_set_tuple(self):
1717
b = Bitmap_C_Interface(2, 4, 1)

adafruit_imageload/tests/test_bmp_indexed_load.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,24 @@
77
class TestBmpIndexedLoad(TestCase):
88
def test_load_works_p1_ascii(self):
99
test_file = os.path.join(
10-
os.path.dirname(__file__),
11-
"..",
12-
"..",
13-
"examples",
14-
"images",
15-
"4bit.bmp",
10+
os.path.dirname(__file__), "..", "..", "examples", "images", "4bit.bmp"
1611
)
1712

18-
bitmap, palette = load(filename=test_file, bitmap=Bitmap_C_Interface, palette=Palette_C_Interface)
13+
bitmap, palette = load(
14+
filename=test_file, bitmap=Bitmap_C_Interface, palette=Palette_C_Interface
15+
)
1916
self.assertTrue(isinstance(bitmap, Bitmap_C_Interface), bitmap)
2017
self.assertEqual(16, bitmap.colors)
2118
self.assertEqual(15, bitmap.width)
2219
self.assertEqual(17, bitmap.height)
2320

2421
bitmap.validate()
2522
# uncomment line below to see a string representation of the object
26-
#self.fail(str(bitmap))
23+
# self.fail(str(bitmap))
2724
self.assertEqual(5, bitmap[0]) # check first row
2825
self.assertEqual(5, bitmap[11, 1]) # check second row
2926

3027
self.assertEqual(16, palette.num_colors)
3128
palette.validate()
3229
# uncomment line below to see a string representation of the object
33-
#self.fail(str(palette))
30+
# self.fail(str(palette))

adafruit_imageload/tests/test_pbm_load.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ def test_load_works_p1_ascii(self):
2525
"netpbm_p1_mono_ascii.pbm",
2626
)
2727
with open(test_file, "rb") as f:
28-
bitmap, palette = pnm.load(f, b"P1", bitmap=Bitmap_C_Interface, palette=Palette_C_Interface)
28+
bitmap, palette = pnm.load(
29+
f, b"P1", bitmap=Bitmap_C_Interface, palette=Palette_C_Interface
30+
)
2931
self.assertTrue(isinstance(bitmap, Bitmap_C_Interface), bitmap)
3032
self.assertEqual(1, bitmap.colors)
3133
self.assertEqual(13, bitmap.width)
Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
import os
2-
import logging
32
from unittest import TestCase
43
from adafruit_imageload import pnm
54
from .displayio_shared_bindings import Bitmap_C_Interface, Palette_C_Interface
65

7-
logging.getLogger().setLevel(logging.DEBUG)
8-
96

107
class TestPgmLoad(TestCase):
118
def test_load_works_p2_ascii(self):
@@ -18,17 +15,19 @@ def test_load_works_p2_ascii(self):
1815
"netpbm_p2_ascii.pgm",
1916
)
2017
with open(test_file, "rb") as f:
21-
bitmap, palette = pnm.load(f, b"P2", bitmap=Bitmap_C_Interface, palette=Palette_C_Interface)
18+
bitmap, palette = pnm.load(
19+
f, b"P2", bitmap=Bitmap_C_Interface, palette=Palette_C_Interface
20+
)
2221
self.assertTrue(isinstance(bitmap, Bitmap_C_Interface), bitmap)
2322
self.assertEqual(6, bitmap.colors)
2423
self.assertEqual(8, bitmap.width)
2524
self.assertEqual(8, bitmap.height)
2625
bitmap.validate()
2726
self.assertEqual(6, palette.num_colors)
2827
palette.validate()
29-
#self.fail(str(palette))
28+
# self.fail(str(palette))
3029

31-
def _test_load_works_p5_binary(self):
30+
def test_load_works_p5_binary(self):
3231
test_file = os.path.join(
3332
os.path.dirname(__file__),
3433
"..",
@@ -38,11 +37,16 @@ def _test_load_works_p5_binary(self):
3837
"netpbm_p5_binary.pgm",
3938
)
4039
with open(test_file, "rb") as f:
41-
bitmap, palette = pnm.load(f, b"P5", bitmap=Bitmap_C_Interface, palette=Palette_C_Interface)
40+
bitmap, palette = pnm.load(
41+
f, b"P5", bitmap=Bitmap_C_Interface, palette=Palette_C_Interface
42+
)
4243
self.assertTrue(isinstance(bitmap, Bitmap_C_Interface), bitmap)
44+
# self.fail(str(palette))
45+
46+
self.assertEqual(8, palette.num_colors)
47+
palette.validate()
4348
self.assertEqual(8, bitmap.colors)
4449
self.assertEqual(8, bitmap.width)
4550
self.assertEqual(8, bitmap.height)
4651
bitmap.validate()
47-
self.assertEqual(8, palette.num_colors)
48-
palette.validate()
52+
# self.fail(str(bitmap))

adafruit_imageload/tests/test_ppm_load.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
logging.getLogger().setLevel(logging.INFO)
88

9+
910
class TestPpmLoad(TestCase):
1011
def test_load_works_p3_ascii(self):
1112
test_file = os.path.join(
@@ -17,7 +18,9 @@ def test_load_works_p3_ascii(self):
1718
"netpbm_p3_rgb_ascii.ppm",
1819
)
1920
with open(test_file, "rb") as f:
20-
bitmap, palette = pnm.load(f, b"P3", bitmap=Bitmap_C_Interface, palette=Palette_C_Interface)
21+
bitmap, palette = pnm.load(
22+
f, b"P3", bitmap=Bitmap_C_Interface, palette=Palette_C_Interface
23+
)
2124
self.assertTrue(isinstance(bitmap, Bitmap_C_Interface), bitmap)
2225
self.assertEqual(16777216, bitmap.colors)
2326
self.assertEqual(16, bitmap.width)
@@ -36,12 +39,13 @@ def test_load_works_p6_binary(self):
3639
"netpbm_p6_binary.ppm",
3740
)
3841
with open(test_file, "rb") as f:
39-
bitmap, palette = pnm.load(f, b"P6", bitmap=Bitmap_C_Interface, palette=Palette_C_Interface)
42+
bitmap, palette = pnm.load(
43+
f, b"P6", bitmap=Bitmap_C_Interface, palette=Palette_C_Interface
44+
)
4045
self.assertTrue(isinstance(bitmap, Bitmap_C_Interface), bitmap)
4146
self.assertEqual(16777216, bitmap.colors)
4247
self.assertEqual(16, bitmap.width)
4348
self.assertEqual(16, bitmap.height)
4449
bitmap.validate()
4550
str(bitmap)
4651
palette.validate()
47-

0 commit comments

Comments
 (0)