Skip to content

Commit c43d11b

Browse files
author
Matt Land
committed
p2 ascii working
1 parent 5cf152e commit c43d11b

6 files changed

Lines changed: 108 additions & 56 deletions

File tree

adafruit_imageload/pnm/pgm/__init__.py

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -28,56 +28,72 @@
2828
* Author(s): Matt Land, Brooke Storm, Sam McGahan
2929
3030
"""
31-
31+
#import logging
3232

3333
def load(file, magic_number, header, *, bitmap=None, palette=None):
34-
# TODO: remove unused variables later
34+
if header[2] > 256:
35+
raise NotImplementedError("16 bit files are not supported")
3536
width = header[0]
3637
height = header[1]
37-
max_colors = 6 #header[2]
38-
bitmap = bitmap(width, height, max_colors)
39-
colors = set()
40-
4138

42-
if max_colors > 256:
43-
# raise exception
44-
raise NotImplementedError("16 bit grayscale not supported")
39+
data_start = file.tell() # keep this so we can rewind
40+
#bitmap = bitmap(width, height, max_colors)
41+
palette_colors = set()
4542

46-
if magic_number == b'P2': # To handle ascii PGM files.
43+
if magic_number == b'P2': # To handle ascii PGM files.
4744
# Handle ascii
48-
for y in range(height):
49-
for x in range(width):
45+
46+
pixel = bytearray()
47+
byte = True
48+
# scan all colors present in the file
49+
while byte:
50+
byte = file.read(1) # type: byte
51+
if not byte.isdigit():
52+
int_pixel = int("".join(["%c" % char for char in pixel]))
53+
#logging.info(f'color {pixel} {int_pixel}')
54+
#bitmap[x, y] = int_pixel
55+
palette_colors.add(int_pixel)
5056
pixel = bytearray()
51-
# Takes int and converts to an 8 bit
52-
while True:
53-
byte = file.read(1) # type: byte
54-
if not byte.isdigit():
55-
break
56-
pixel += byte
57-
# convert b'255' to b'\xff'
58-
int_pixel = bytes([int("".join(["%c" % char for char in pixel]))])
59-
bitmap[x, y] = int_pixel
60-
colors.add(int_pixel)
61-
# logging.info(f'{x}, {y}, {byte}, {int_pixel}')
57+
pixel += byte
58+
59+
# logging.info(f'{x}, {y}, {byte}, {int_pixel}')
6260
if palette:
63-
palette = palette(len(colors))
64-
for counter, color in enumerate(colors):
65-
palette[counter] = color
61+
palette = palette(len(palette_colors))
62+
for counter, color in enumerate(palette_colors):
63+
palette[counter] = bytes([color, color, color])
64+
if bitmap:
65+
bitmap = bitmap(width, height, len(palette_colors))
66+
palette_colors = list(palette_colors)
67+
file.seek(data_start)
68+
for y in range(height):
69+
for x in range(width):
70+
pixel = bytearray()
71+
# Takes int and converts to an 8 bit
72+
while True:
73+
byte = file.read(1) # type: byte
74+
if not byte.isdigit():
75+
break
76+
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+
6682
return bitmap, palette
6783

68-
if magic_number == b'P5': # To handle binary PGM files.
84+
if magic_number == b'P5': # To handle binary PGM files.
6985
for y in range(height):
7086
for x in range(width):
7187
byte = file.read(1)
7288
if byte == b"":
7389
raise ValueError("ran out of file unexpectedly")
7490
int_pixel = int.from_bytes(byte, "little")
7591
bitmap[x, y] = int_pixel
76-
colors.add(int_pixel)
92+
palette_colors.add(int_pixel)
7793

7894
if palette:
79-
palette = palette(len(colors))
80-
for counter, color in enumerate(colors):
95+
palette = palette(len(palette_colors))
96+
for counter, color in enumerate(palette_colors):
8197
color_bytearray = bytearray()
8298
for i in range(3):
8399
color_bytearray += bytes([color])

adafruit_imageload/tests/displayio_shared_bindings.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,16 @@ def __setitem__(self, key: tuple, value: int):
2626
self.__setitem__(self._abs_pos(key[0], key[1]), value)
2727
return
2828
if not isinstance(value, (int)):
29-
raise RuntimeError(f"set value as int or bytes, not {type(value)}")
29+
raise RuntimeError(f"set value as int, not {type(value)}")
3030
if value > 255:
3131
raise ValueError(f'pixel value {value} too large')
3232
self.data[key] = value
3333

3434
def __getitem__(self, item: tuple) -> bytearray:
3535
if isinstance(item, tuple):
3636
return self.__getitem__(self._abs_pos(item[0], item[1]))
37-
# if item > self.height * self.width:
38-
# raise RuntimeError('illegal item position {}'.format(item))
37+
if item > self.height * self.width:
38+
raise RuntimeError(f'get position out of range {item}')
3939
try:
4040
return self.data[item]
4141
except KeyError:
@@ -69,17 +69,29 @@ def __init__(self, num_colors):
6969
self.colors = {}
7070

7171
def __setitem__(self, key, value):
72+
if key >= self.num_colors:
73+
raise ValueError(f'palette index {key} is greater than allowed by num_colors {self.num_colors}')
74+
if not isinstance(value, (bytes, int)):
75+
raise ValueError(f'palette color should be bytes, not {type(value)}')
76+
if isinstance(value, int) and value > 255:
77+
raise ValueError(f'palette color int {value} is too large')
78+
if self.colors.get(key):
79+
raise ValueError(f'palette color {key} was already set, should not reassign')
7280
self.colors[key] = value
7381

7482
def validate(self):
7583
if not self.colors:
7684
raise ValueError("no palette colors were set")
7785
if len(self.colors) > self.num_colors:
7886
raise ValueError("too many colors inserted into palette")
79-
if len(self.colors) < self.num_colors:
80-
raise ValueError("too few colors inserted into palette")
8187
for i in range(self.num_colors):
8288
try:
8389
self.colors
8490
except IndexError:
8591
raise ValueError('missing color `{}` in palette color list'.format(i))
92+
93+
def __str__(self):
94+
out = "\nPalette:\n"
95+
for y in range(len(self.colors)):
96+
out += f" [{y}] {self.colors[y]}\n"
97+
return out
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import os
2+
from unittest import TestCase
3+
from adafruit_imageload import load
4+
from .displayio_shared_bindings import Bitmap_C_Interface, Palette_C_Interface
5+
6+
7+
class TestBmpIndexedLoad(TestCase):
8+
def test_load_works_p1_ascii(self):
9+
test_file = os.path.join(
10+
os.path.dirname(__file__),
11+
"..",
12+
"..",
13+
"examples",
14+
"images",
15+
"4bit.bmp",
16+
)
17+
18+
bitmap, palette = load(filename=test_file, bitmap=Bitmap_C_Interface, palette=Palette_C_Interface)
19+
self.assertTrue(isinstance(bitmap, Bitmap_C_Interface), bitmap)
20+
self.assertEqual(16, bitmap.colors)
21+
self.assertEqual(15, bitmap.width)
22+
self.assertEqual(17, bitmap.height)
23+
24+
bitmap.validate()
25+
# uncomment line below to see a string representation of the object
26+
#self.fail(str(bitmap))
27+
self.assertEqual(5, bitmap[0]) # check first row
28+
self.assertEqual(5, bitmap[11, 1]) # check second row
29+
30+
self.assertEqual(16, palette.num_colors)
31+
palette.validate()
32+
# uncomment line below to see a string representation of the object
33+
#self.fail(str(palette))

adafruit_imageload/tests/test_pbm_load.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
import os
2+
from io import BytesIO
13
from unittest import TestCase
24
from adafruit_imageload import pnm
3-
from io import BytesIO
4-
import os
55
from .displayio_shared_bindings import Bitmap_C_Interface, Palette_C_Interface
66

77

adafruit_imageload/tests/test_pgm_load.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ def test_load_works_p2_ascii(self):
2626
bitmap.validate()
2727
self.assertEqual(6, palette.num_colors)
2828
palette.validate()
29+
#self.fail(str(palette))
2930

30-
def test_load_works_p5_binary(self):
31+
def _test_load_works_p5_binary(self):
3132
test_file = os.path.join(
3233
os.path.dirname(__file__),
3334
"..",
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,12 @@
1+
import os
2+
import logging
13
from unittest import TestCase
24
from adafruit_imageload import pnm
3-
from io import BytesIO
4-
import logging
5-
import os
65
from .displayio_shared_bindings import Bitmap_C_Interface, Palette_C_Interface
76

8-
9-
107
logging.getLogger().setLevel(logging.INFO)
118

12-
13-
14-
15-
16-
17-
18-
19-
20-
21-
22-
class TestPPMLoad(TestCase):
9+
class TestPpmLoad(TestCase):
2310
def test_load_works_p3_ascii(self):
2411
test_file = os.path.join(
2512
os.path.dirname(__file__),
@@ -30,13 +17,14 @@ def test_load_works_p3_ascii(self):
3017
"netpbm_p3_rgb_ascii.ppm",
3118
)
3219
with open(test_file, "rb") as f:
33-
bitmap, palette = pnm.load(f, b"P3", bitmap=Bitmap_C_Interface)
20+
bitmap, palette = pnm.load(f, b"P3", bitmap=Bitmap_C_Interface, palette=Palette_C_Interface)
3421
self.assertTrue(isinstance(bitmap, Bitmap_C_Interface), bitmap)
3522
self.assertEqual(16777216, bitmap.colors)
3623
self.assertEqual(16, bitmap.width)
3724
self.assertEqual(16, bitmap.height)
3825
bitmap.validate()
3926
str(bitmap)
27+
palette.validate()
4028

4129
def test_load_works_p6_binary(self):
4230
test_file = os.path.join(
@@ -48,10 +36,12 @@ def test_load_works_p6_binary(self):
4836
"netpbm_p6_binary.ppm",
4937
)
5038
with open(test_file, "rb") as f:
51-
bitmap, palette = pnm.load(f, b"P6", bitmap=Bitmap_C_Interface)
39+
bitmap, palette = pnm.load(f, b"P6", bitmap=Bitmap_C_Interface, palette=Palette_C_Interface)
5240
self.assertTrue(isinstance(bitmap, Bitmap_C_Interface), bitmap)
5341
self.assertEqual(16777216, bitmap.colors)
5442
self.assertEqual(16, bitmap.width)
5543
self.assertEqual(16, bitmap.height)
5644
bitmap.validate()
5745
str(bitmap)
46+
palette.validate()
47+

0 commit comments

Comments
 (0)