Skip to content

Commit b413535

Browse files
authored
Merge pull request #4376 from kmatch98/displayio_bitmap
add fill_region and draw_line to bitmap_tools
2 parents 1b106de + a9afa0d commit b413535

File tree

5 files changed

+292
-2
lines changed

5 files changed

+292
-2
lines changed

locale/circuitpython.pot

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3643,7 +3643,7 @@ msgstr ""
36433643
msgid "out of range of source"
36443644
msgstr ""
36453645

3646-
#: shared-bindings/displayio/Bitmap.c
3646+
#: shared-bindings/bitmaptools/__init__.c shared-bindings/displayio/Bitmap.c
36473647
msgid "out of range of target"
36483648
msgstr ""
36493649

shared-bindings/bitmaptools/__init__.c

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,13 +243,127 @@ STATIC mp_obj_t bitmaptools_obj_rotozoom(size_t n_args, const mp_obj_t *pos_args
243243
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_rotozoom_obj, 0, bitmaptools_obj_rotozoom);
244244
// requires at least 2 arguments (destination bitmap and source bitmap)
245245

246+
//|
247+
//| def fill_region(
248+
//| dest_bitmap: displayio.Bitmap,
249+
//| x1: int, y1: int,
250+
//| x2: int, y2: int,
251+
//| value: int) -> None:
252+
//| """Draws the color value into the destination bitmap within the
253+
//| rectangular region bounded by (x1,y1) and (x2,y2), exclusive.
254+
//|
255+
//| :param bitmap dest_bitmap: Destination bitmap that will be written into
256+
//| :param int x1: x-pixel position of the first corner of the rectangular fill region
257+
//| :param int y1: y-pixel position of the first corner of the rectangular fill region
258+
//| :param int x2: x-pixel position of the second corner of the rectangular fill region (exclusive)
259+
//| :param int y2: y-pixel position of the second corner of the rectangular fill region (exclusive)
260+
//| :param int value: Bitmap palette index that will be written into the rectangular
261+
//| fill region in the destination bitmap"""
262+
//| ...
263+
//|
264+
STATIC mp_obj_t bitmaptools_obj_fill_region(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args){
265+
enum {ARG_dest_bitmap, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_value};
266+
267+
static const mp_arg_t allowed_args[] = {
268+
{MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ},
269+
{MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT},
270+
{MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT},
271+
{MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT},
272+
{MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT},
273+
{MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT},
274+
};
275+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
276+
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
277+
278+
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
279+
280+
uint32_t value, color_depth;
281+
value = args[ARG_value].u_int;
282+
color_depth = (1 << destination->bits_per_value);
283+
if (color_depth <= value) {
284+
mp_raise_ValueError(translate("out of range of target"));
285+
}
286+
287+
int16_t x1 = args[ARG_x1].u_int;
288+
int16_t y1 = args[ARG_y1].u_int;
289+
int16_t x2 = args[ARG_x2].u_int;
290+
int16_t y2 = args[ARG_y2].u_int;
291+
292+
common_hal_bitmaptools_fill_region(destination, x1, y1, x2, y2, value);
293+
294+
return mp_const_none;
295+
}
296+
297+
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_fill_region_obj, 0, bitmaptools_obj_fill_region);
298+
// requires all 6 arguments
299+
300+
//|
301+
//| def draw_line(
302+
//| dest_bitmap: displayio.Bitmap,
303+
//| x1: int, y1: int,
304+
//| x2: int, y2: int,
305+
//| value: int) -> None:
306+
//| """Draws a line into a bitmap specified two endpoints (x1,y1) and (x2,y2).
307+
//|
308+
//| :param bitmap dest_bitmap: Destination bitmap that will be written into
309+
//| :param int x1: x-pixel position of the line's first endpoint
310+
//| :param int y1: y-pixel position of the line's first endpoint
311+
//| :param int x2: x-pixel position of the line's second endpoint
312+
//| :param int y2: y-pixel position of the line's second endpoint
313+
//| :param int value: Bitmap palette index that will be written into the
314+
//| line in the destination bitmap"""
315+
//| ...
316+
//|
317+
STATIC mp_obj_t bitmaptools_obj_draw_line(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args){
318+
enum {ARG_dest_bitmap, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_value};
319+
320+
static const mp_arg_t allowed_args[] = {
321+
{MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ},
322+
{MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT},
323+
{MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT},
324+
{MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT},
325+
{MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT},
326+
{MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT},
327+
};
328+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
329+
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
330+
331+
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
332+
333+
uint32_t value, color_depth;
334+
value = args[ARG_value].u_int;
335+
color_depth = (1 << destination->bits_per_value);
336+
if (color_depth <= value) {
337+
mp_raise_ValueError(translate("out of range of target"));
338+
}
339+
340+
int16_t x1 = args[ARG_x1].u_int;
341+
int16_t y1 = args[ARG_y1].u_int;
342+
int16_t x2 = args[ARG_x2].u_int;
343+
int16_t y2 = args[ARG_y2].u_int;
344+
345+
// verify points are within the bitmap boundary (inclusive)
346+
if ( (x1 < 0) || (x2 < 0) || (y1 < 0) || (y2 < 0) ||
347+
(x1 >= destination->width) || (x2 >= destination->width) ||
348+
(y1 >= destination->height) || (y2 >= destination->height) ) {
349+
mp_raise_ValueError(translate("out of range of target"));
350+
}
351+
352+
common_hal_bitmaptools_draw_line(destination, x1, y1, x2, y2, value);
353+
354+
return mp_const_none;
355+
}
356+
357+
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_draw_line_obj, 0, bitmaptools_obj_draw_line);
358+
// requires all 6 arguments
246359

247360
STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = {
248361
{ MP_ROM_QSTR(MP_QSTR_rotozoom), MP_ROM_PTR(&bitmaptools_rotozoom_obj) },
362+
{ MP_ROM_QSTR(MP_QSTR_fill_region), MP_ROM_PTR(&bitmaptools_fill_region_obj) },
363+
{ MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) },
249364
};
250365
STATIC MP_DEFINE_CONST_DICT(bitmaptools_module_globals, bitmaptools_module_globals_table);
251366

252-
253367
const mp_obj_module_t bitmaptools_module = {
254368
.base = {&mp_type_module },
255369
.globals = (mp_obj_dict_t*)&bitmaptools_module_globals,

shared-bindings/bitmaptools/__init__.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,14 @@ void common_hal_bitmaptools_rotozoom(displayio_bitmap_t *self, int16_t ox, int16
3939
float scale,
4040
uint32_t skip_index, bool skip_index_none);
4141

42+
void common_hal_bitmaptools_fill_region(displayio_bitmap_t *destination,
43+
int16_t x1, int16_t y1,
44+
int16_t x2, int16_t y2,
45+
uint32_t value);
46+
47+
void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination,
48+
int16_t x0, int16_t y0,
49+
int16_t x1, int16_t y1,
50+
uint32_t value);
51+
4252
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H

shared-module/bitmaptools/__init__.c

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@
2626

2727

2828
#include "shared-bindings/displayio/Bitmap.h"
29+
#include "shared-module/displayio/Bitmap.h"
2930

3031
#include "py/runtime.h"
3132

3233
#include "math.h"
34+
#include "stdlib.h"
3335

3436
void common_hal_bitmaptools_rotozoom(displayio_bitmap_t *self, int16_t ox, int16_t oy,
3537
int16_t dest_clip0_x, int16_t dest_clip0_y,
@@ -172,3 +174,165 @@ void common_hal_bitmaptools_rotozoom(displayio_bitmap_t *self, int16_t ox, int16
172174
rowv += dvCol;
173175
}
174176
}
177+
178+
int16_t constrain(int16_t input, int16_t min, int16_t max) {
179+
// constrain the input between the min and max values
180+
if (input < min) {
181+
return min;
182+
}
183+
if (input > max) {
184+
return max;
185+
}
186+
return input;
187+
}
188+
189+
void common_hal_bitmaptools_fill_region(displayio_bitmap_t *destination,
190+
int16_t x1, int16_t y1,
191+
int16_t x2, int16_t y2,
192+
uint32_t value) {
193+
// writes the value (a bitmap color index) into a bitmap in the specified rectangular region
194+
//
195+
// input checks should ensure that x1 < x2 and y1 < y2 and are within the bitmap region
196+
197+
if (destination->read_only) {
198+
mp_raise_RuntimeError(translate("Read-only object"));
199+
}
200+
201+
// Ensure x1 < x2 and y1 < y2
202+
if (x1 > x2) {
203+
int16_t temp=x2;
204+
x2=x1;
205+
x1=temp;
206+
}
207+
if (y1 > y2) {
208+
int16_t temp=y2;
209+
y2=y1;
210+
y1=temp;
211+
}
212+
213+
// constrain to bitmap dimensions
214+
x1 = constrain(x1, 0, destination->width);
215+
x2 = constrain(x2, 0, destination->width);
216+
y1 = constrain(y1, 0, destination->height);
217+
y2 = constrain(y2, 0, destination->height);
218+
219+
// update the dirty rectangle
220+
displayio_bitmap_set_dirty_area(destination, x1, y1, x2, y2);
221+
222+
int16_t x, y;
223+
for (x = x1; x < x2; x++) {
224+
for (y = y1; y < y2; y++ ) {
225+
displayio_bitmap_write_pixel(destination, x, y, value);
226+
}
227+
}
228+
}
229+
230+
void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination,
231+
int16_t x0, int16_t y0,
232+
int16_t x1, int16_t y1,
233+
uint32_t value) {
234+
235+
if (destination->read_only) {
236+
mp_raise_RuntimeError(translate("Read-only object"));
237+
}
238+
239+
//
240+
// adapted from Adafruit_CircuitPython_Display_Shapes.Polygon._line
241+
//
242+
243+
// update the dirty rectangle
244+
int16_t xbb0, xbb1, ybb0, ybb1;
245+
if (x0 < x1) {
246+
xbb0 = x0;
247+
xbb1 = x1 + 1;
248+
} else {
249+
xbb0 = x1;
250+
xbb1 = x0 + 1;
251+
}
252+
if (y0 < y1) {
253+
ybb0 = y0;
254+
ybb1 = y1 + 1;
255+
} else {
256+
ybb0 = y1;
257+
ybb1 = y0 + 1;
258+
}
259+
260+
xbb0 = constrain(xbb0, 0, destination->width);
261+
xbb1 = constrain(xbb1, 0, destination->width);
262+
ybb0 = constrain(ybb0, 0, destination->height);
263+
ybb1 = constrain(ybb1, 0, destination->height);
264+
265+
displayio_bitmap_set_dirty_area(destination, xbb0, ybb0, xbb1, ybb1);
266+
267+
int16_t temp, x, y;
268+
269+
if (x0 == x1) { // vertical line
270+
if (y0 > y1) { // ensure y1 > y0
271+
temp = y0;
272+
y0 = y1;
273+
y1 = temp;
274+
}
275+
for (y = y0; y < (y1 + 1); y++) { // write a horizontal line
276+
displayio_bitmap_write_pixel(destination, x0, y, value);
277+
}
278+
}
279+
else if (y0 == y1) { // horizontal line
280+
if (x0 > x1) { // ensure y1 > y0
281+
temp = x0;
282+
x0 = x1;
283+
x1 = temp;
284+
}
285+
for (x = x0; x < (x1 + 1); x++) { // write a horizontal line
286+
displayio_bitmap_write_pixel(destination, x, y0, value);
287+
}
288+
}
289+
else {
290+
bool steep;
291+
steep = ( abs(y1 - y0) > abs(x1 - x0) );
292+
293+
if ( steep ) { // flip x0<->y0 and x1<->y1
294+
temp = x0;
295+
x0 = y0;
296+
y0 = temp;
297+
temp = x1;
298+
x1 = y1;
299+
y1 = temp;
300+
}
301+
302+
if (x0 > x1) { // flip x0<->x1 and y0<->y1
303+
temp = x0;
304+
x0 = x1;
305+
x1 = temp;
306+
temp = y0;
307+
y0 = y1;
308+
y1 = temp;
309+
}
310+
311+
int16_t dx, dy, ystep;
312+
dx = x1 - x0;
313+
dy = abs(y1 - y0);
314+
315+
float err = dx / 2;
316+
317+
if (y0 < y1) {
318+
ystep = 1;
319+
}
320+
else {
321+
ystep = -1;
322+
}
323+
324+
for (x = x0; x < (x1 + 1); x++) {
325+
if (steep) {
326+
displayio_bitmap_write_pixel(destination, y0, x, value);
327+
}
328+
else {
329+
displayio_bitmap_write_pixel(destination, x, y0, value);
330+
}
331+
err -= dy;
332+
if (err < 0) {
333+
y0 += ystep;
334+
err += dx;
335+
}
336+
}
337+
}
338+
}

shared-module/displayio/Bitmap.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,7 @@ typedef struct {
4949

5050
void displayio_bitmap_finish_refresh(displayio_bitmap_t *self);
5151
displayio_area_t* displayio_bitmap_get_refresh_areas(displayio_bitmap_t *self, displayio_area_t* tail);
52+
void displayio_bitmap_set_dirty_area(displayio_bitmap_t *self, int16_t x1, int16_t y1, int16_t x2, int16_t y2);
53+
void displayio_bitmap_write_pixel(displayio_bitmap_t *self, int16_t x, int16_t y, uint32_t value);
5254

5355
#endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_BITMAP_H

0 commit comments

Comments
 (0)