1 # SPDX-FileCopyrightText: 2020 Melissa LeBlanc-Williams for Adafruit Industries
3 # SPDX-License-Identifier: MIT
7 ================================================================================
11 **Software and Dependencies:**
14 https://github.com/adafruit/Adafruit_Blinka/releases
16 * Author(s): Melissa LeBlanc-Williams
20 from recordclass import recordclass
23 __version__ = "0.0.0-auto.0"
24 __repo__ = "https://github.com/adafruit/Adafruit_Blinka_displayio.git"
26 Rectangle = recordclass("Rectangle", "x1 y1 x2 y2")
30 """Stores values of a certain size in a 2D array"""
32 def __init__(self, width, height, value_count):
33 """Create a Bitmap object with the given fixed size. Each pixel stores a value that is
34 used to index into a corresponding palette. This enables differently colored sprites to
35 share the underlying Bitmap. value_count is used to minimize the memory used to store
38 self._bmp_width = width
39 self._bmp_height = height
40 self._read_only = False
43 raise ValueError("value_count must be > 0")
46 while (value_count - 1) >> bits:
52 self._bits_per_value = bits
55 self._bits_per_value > 8
56 and self._bits_per_value != 16
57 and self._bits_per_value != 32
59 raise NotImplementedError("Invalid bits per value")
61 self._image = Image.new("P", (width, height), 0)
62 self._dirty_area = Rectangle(0, 0, width, height)
64 def __getitem__(self, index):
66 Returns the value at the given index. The index can either be
67 an x,y tuple or an int equal to `y * width + x`.
69 if isinstance(index, (tuple, list)):
71 elif isinstance(index, int):
72 x = index % self._bmp_width
73 y = index // self._bmp_width
75 raise TypeError("Index is not an int, list, or tuple")
77 if x > self._image.width or y > self._image.height:
78 raise ValueError("Index {} is out of range".format(index))
79 return self._image.getpixel((x, y))
81 def __setitem__(self, index, value):
83 Sets the value at the given index. The index can either be
84 an x,y tuple or an int equal to `y * width + x`.
87 raise RuntimeError("Read-only object")
88 if isinstance(index, (tuple, list)):
91 index = y * self._bmp_width + x
92 elif isinstance(index, int):
93 x = index % self._bmp_width
94 y = index // self._bmp_width
95 self._image.putpixel((x, y), value)
96 if self._dirty_area.x1 == self._dirty_area.x2:
97 self._dirty_area.x1 = x
98 self._dirty_area.x2 = x + 1
99 self._dirty_area.y1 = y
100 self._dirty_area.y2 = y + 1
102 if x < self._dirty_area.x1:
103 self._dirty_area.x1 = x
104 elif x >= self._dirty_area.x2:
105 self._dirty_area.x2 = x + 1
106 if y < self._dirty_area.y1:
107 self._dirty_area.y1 = y
108 elif y >= self._dirty_area.y2:
109 self._dirty_area.y2 = y + 1
111 def _finish_refresh(self):
112 self._dirty_area.x1 = 0
113 self._dirty_area.x2 = 0
115 def fill(self, value):
116 """Fills the bitmap with the supplied palette index value."""
117 self._image = Image.new("P", (self._bmp_width, self._bmp_height), value)
118 self._dirty_area = Rectangle(0, 0, self._bmp_width, self._bmp_height)
122 """Width of the bitmap. (read only)"""
123 return self._bmp_width
127 """Height of the bitmap. (read only)"""
128 return self._bmp_height