]> Repositories - hackapet/Adafruit_Blinka_Displayio.git/blob - bitmaptools/__init__.py
starting bitmaptools implementation
[hackapet/Adafruit_Blinka_Displayio.git] / bitmaptools / __init__.py
1 from displayio import Bitmap
2 import circuitpython_typing
3
4 def fill_region(dest_bitmap: Bitmap, x1: int, y1: int, x2: int, y2: int, value: int):
5     for y in range(y1, y2):
6         for x in range(x1, x2):
7             dest_bitmap[x,y] = value
8
9 def draw_line(dest_bitmap: Bitmap, x1: int, y1: int, x2: int, y2: int, value: int):
10     dx = abs(x2 - x1)
11     sx = 1 if x1 < x2 else -1
12     dy = -abs(y2 - y1)
13     sy = 1 if y1 < y2 else -1
14     error = dx + dy
15
16     while True:
17         dest_bitmap[x1, y1] = value
18         if x1 == x2 and y1 == y2:
19             break
20         e2 = 2 * error
21         if e2 >= dy:
22             error += dy
23             x1 += sx
24         if e2 <= dx:
25             error += dx
26             y1 += sy
27
28 def draw_circle(dest_bitmap: Bitmap, x: int, y: int, radius: int, value: int):
29     x = max(0, min(x, dest_bitmap.width - 1))
30     y = max(0, min(y, dest_bitmap.height - 1))
31
32     xb = 0
33     yb = radius
34     d = 3 - 2 * radius
35
36     # Bresenham's circle algorithm
37     while xb <= yb:
38         dest_bitmap[xb + x, yb + y] = value
39         dest_bitmap[-xb + x, -yb + y] = value
40         dest_bitmap[-xb + x, yb + y] = value
41         dest_bitmap[xb + x, -yb + y] = value
42         dest_bitmap[yb + x, xb + y] = value
43         dest_bitmap[-yb + x, xb + y] = value
44         dest_bitmap[-yb + x, -xb + y] = value
45         dest_bitmap[yb + x, -xb + y] = value
46
47         if d <= 0:
48             d = d + (4 * xb) + 6
49         else:
50             d = d + 4 * (xb - yb) + 10
51             yb = yb - 1
52         xb += 1
53
54
55 def draw_polygon(dest_bitmap: Bitmap,
56                  xs: circuitpython_typing.ReadableBuffer,
57                  ys: circuitpython_typing.ReadableBuffer,
58                  value: int, close: bool | None = True):
59
60     if len(xs) != len(ys):
61         raise ValueError("Length of xs and ys must be equal.")
62
63     for i in range(len(xs)-1):
64         cur_point = (xs[i], ys[i])
65         next_point = (xs[i+1], ys[i+1])
66         print(f"cur: {cur_point}, next: {next_point}")
67         draw_line(dest_bitmap=dest_bitmap,
68                   x1=cur_point[0], y1=cur_point[1],
69                   x2=next_point[0], y2=next_point[1],
70                   value=value)
71
72     if close:
73         print(f"close: {(xs[0], ys[0])} - {(xs[-1], ys[-1])}")
74         draw_line(dest_bitmap=dest_bitmap,
75                   x1=xs[0], y1=ys[0],
76                   x2=xs[-1], y2=ys[-1],
77                   value=value)
78
79 def blit(dest_bitmap: Bitmap, source_bitmap: Bitmap,
80          x: int, y: int, *,
81          x1: int = 0, y1: int = 0,
82          x2: int | None = None, y2: int | None = None,
83          skip_source_index: int | None = None,
84          skip_dest_index: int | None = None):
85
86     """Inserts the source_bitmap region defined by rectangular boundaries"""
87     # pylint: disable=invalid-name
88     if x2 is None:
89         x2 = source_bitmap.width
90     if y2 is None:
91         y2 = source_bitmap.height
92
93     # Rearrange so that x1 < x2 and y1 < y2
94     if x1 > x2:
95         x1, x2 = x2, x1
96     if y1 > y2:
97         y1, y2 = y2, y1
98
99     # Ensure that x2 and y2 are within source bitmap size
100     x2 = min(x2, source_bitmap.width)
101     y2 = min(y2, source_bitmap.height)
102
103     for y_count in range(y2 - y1):
104         for x_count in range(x2 - x1):
105             x_placement = x + x_count
106             y_placement = y + y_count
107
108             if (dest_bitmap.width > x_placement >= 0) and (
109                     dest_bitmap.height > y_placement >= 0
110             ):  # ensure placement is within target bitmap
111                 # get the palette index from the source bitmap
112                 this_pixel_color = source_bitmap[
113                     y1 + (y_count * source_bitmap.width) + x1 + x_count
114                 ]
115
116                 if (skip_source_index is None) or (this_pixel_color != skip_source_index):
117                     if (skip_dest_index is None) or (dest_bitmap[y_placement * dest_bitmap.width + x_placement] != skip_dest_index):
118                         dest_bitmap[  # Direct index into a bitmap array is speedier than [x,y] tuple
119                             y_placement * dest_bitmap.width + x_placement
120                         ] = this_pixel_color
121             elif y_placement > dest_bitmap.height:
122                 break