]> Repositories - hackapet/Adafruit_Blinka_Displayio.git/blob - displayio/bitmap.py
Split module into multiple files
[hackapet/Adafruit_Blinka_Displayio.git] / displayio / bitmap.py
1 # The MIT License (MIT)
2 #
3 # Copyright (c) 2020 Melissa LeBlanc-Williams for Adafruit Industries
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining a copy
6 # of this software and associated documentation files (the "Software"), to deal
7 # in the Software without restriction, including without limitation the rights
8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 # copies of the Software, and to permit persons to whom the Software is
10 # furnished to do so, subject to the following conditions:
11 #
12 # The above copyright notice and this permission notice shall be included in
13 # all copies or substantial portions of the Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 # THE SOFTWARE.
22
23 """
24 `displayio`
25 ================================================================================
26
27 displayio for Blinka
28
29 **Software and Dependencies:**
30
31 * Adafruit Blinka:
32   https://github.com/adafruit/Adafruit_Blinka/releases
33
34 * Author(s): Melissa LeBlanc-Williams
35
36 """
37
38 from displayio import Rectangle
39
40 __version__ = "0.0.0-auto.0"
41 __repo__ = "https://github.com/adafruit/Adafruit_Blinka_displayio.git"
42
43
44 class Bitmap:
45     """Stores values of a certain size in a 2D array"""
46
47     def __init__(self, width, height, value_count):
48         """Create a Bitmap object with the given fixed size. Each pixel stores a value that is
49         used to index into a corresponding palette. This enables differently colored sprites to
50         share the underlying Bitmap. value_count is used to minimize the memory used to store
51         the Bitmap.
52         """
53         self._width = width
54         self._height = height
55         self._read_only = False
56
57         if value_count < 0:
58             raise ValueError("value_count must be > 0")
59
60         bits = 1
61         while (value_count - 1) >> bits:
62             if bits < 8:
63                 bits = bits << 1
64             else:
65                 bits += 8
66
67         self._bits_per_value = bits
68
69         if (
70             self._bits_per_value > 8
71             and self._bits_per_value != 16
72             and self._bits_per_value != 32
73         ):
74             raise NotImplementedError("Invalid bits per value")
75
76         self._data = (width * height) * [0]
77         self._dirty_area = Rectangle(0, 0, width, height)
78
79     def __getitem__(self, index):
80         """
81         Returns the value at the given index. The index can either be
82         an x,y tuple or an int equal to `y * width + x`.
83         """
84         if isinstance(index, (tuple, list)):
85             index = (index[1] * self._width) + index[0]
86         if index >= len(self._data):
87             raise ValueError("Index {} is out of range".format(index))
88         return self._data[index]
89
90     def __setitem__(self, index, value):
91         """
92         Sets the value at the given index. The index can either be
93         an x,y tuple or an int equal to `y * width + x`.
94         """
95         if self._read_only:
96             raise RuntimeError("Read-only object")
97         if isinstance(index, (tuple, list)):
98             x = index[0]
99             y = index[1]
100             index = y * self._width + x
101         elif isinstance(index, int):
102             x = index % self._width
103             y = index // self._width
104         self._data[index] = value
105         if self._dirty_area.x1 == self._dirty_area.x2:
106             self._dirty_area.x1 = x
107             self._dirty_area.x2 = x + 1
108             self._dirty_area.y1 = y
109             self._dirty_area.y2 = y + 1
110         else:
111             if x < self._dirty_area.x1:
112                 self._dirty_area.x1 = x
113             elif x >= self._dirty_area.x2:
114                 self._dirty_area.x2 = x + 1
115             if y < self._dirty_area.y1:
116                 self._dirty_area.y1 = y
117             elif y >= self._dirty_area.y2:
118                 self._dirty_area.y2 = y + 1
119
120     def _finish_refresh(self):
121         self._dirty_area.x1 = 0
122         self._dirty_area.x2 = 0
123
124     def fill(self, value):
125         """Fills the bitmap with the supplied palette index value."""
126         self._data = (self._width * self._height) * [value]
127         self._dirty_area = Rectangle(0, 0, self._width, self._height)
128
129     @property
130     def width(self):
131         """Width of the bitmap. (read only)"""
132         return self._width
133
134     @property
135     def height(self):
136         """Height of the bitmap. (read only)"""
137         return self._height