8000 Merge pull request #5145 from FoamyGuy/bitmaptools_paint_fill · adafruit/circuitpython@7587a52 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7587a52

Browse files
authored
Merge pull request #5145 from FoamyGuy/bitmaptools_paint_fill
Bitmaptools boundary_fill
2 parents fa9a98d + 80c7a15 commit 7587a52

File tree

6 files changed

+217
-1
lines changed

6 files changed

+217
-1
lines changed

locale/circuitpython.pot

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2575,6 +2575,10 @@ msgstr ""
25752575
msgid "axis too long"
25762576
msgstr ""
25772577

2578+
#: shared-bindings/bitmaptools/__init__.c
2579+
msgid "background value out of range of target"
2580+
msgstr ""
2581+
25782582
#: py/builtinevex.c
25792583
msgid "bad compile mode"
25802584
msgstr ""
@@ -3926,6 +3930,7 @@ msgstr ""
39263930
#: ports/esp32s2/boards/gravitech_cucumber_rs/mpconfigboard.h
39273931
#: ports/esp32s2/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
39283932
#: ports/esp32s2/boards/microdev_micro_s2/mpconfigboard.h
3933+
#: ports/esp32s2/boards/morpheans_morphesp-240/mpconfigboard.h
39293934
#: ports/esp32s2/boards/muselab_nanoesp32_s2_wroom/mpconfigboard.h
39303935
#: ports/esp32s2/boards/muselab_nanoesp32_s2_wrover/mpconfigboard.h
39313936
#: ports/esp32s2/boards/targett_module_clip_wroom/mpconfigboard.h
@@ -4367,6 +4372,10 @@ msgstr ""
43674372
msgid "value must fit in %d byte(s)"
43684373
msgstr ""
43694374

4375+
#: shared-bindings/bitmaptools/__init__.c
4376+
msgid "value out of range of target"
4377+
msgstr ""
4378+
43704379
#: shared-bindings/displayio/Bitmap.c
43714380
msgid "value_count must be > 0"
43724381
msgstr ""

ports/stm/boards/pyb_nano_v2/mpconfigboard.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ CIRCUITPY_AUDIOPWMIO = 0
1919
CIRCUITPY_KEYPAD = 0
2020
CIRCUITPY_MIDI = 0
2121
CIRCUITPY_MSGPACK = 0
22+
CIRCUITPY_BITMAPTOOLS = 0

ports/stm/boards/stm32f411ve_discovery/mpconfigboard.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ CIRCUITPY_AUDIOPWMIO = 0
1818
CIRCUITPY_KEYPAD = 0
1919
CIRCUITPY_MIDI = 0
2020
CIRCUITPY_MSGPACK = 0
21+
CIRCUITPY_BITMAPTOOLS = 0

shared-bindings/bitmaptools/__init__.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,68 @@ STATIC mp_obj_t bitmaptools_obj_fill_region(size_t n_args, const mp_obj_t *pos_a
296296
}
297297

298298
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_fill_region_obj, 0, bitmaptools_obj_fill_region);
299+
//|
300+
//| def boundary_fill(
301+
//| dest_bitmap: displayio.Bitmap,
302+
//| x: int, y: int,
303+
//| fill_color_value: int, replaced_color_value: int) -> None:
304+
//| """Draws the color value into the destination bitmap enclosed
305+
//| area of pixels of the background_value color. Like "Paint Bucket"
306+
//| fill tool.
307+
//|
308+
//| :param bitmap dest_bitmap: Destination bitmap that will be written into
309+
//| :param int x: x-pixel position of the first pixel to check and fill if needed
310+
//| :param int y: y-pixel position of the first pixel to check and fill if needed
311+
//| :param int fill_color_value: Bitmap palette index that will be written into the
312+
//| enclosed area in the destination bitmap
313+
//| :param int replaced_color_value: Bitmap palette index that will filled with the
314+
//| value color in the enclosed area in the destination bitmap"""
315+
//| ...
316+
//|
317+
STATIC mp_obj_t bitmaptools_obj_boundary_fill(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
318+
enum {ARG_dest_bitmap, ARG_x, ARG_y, ARG_fill_color_value, ARG_replaced_color_value};
319+
320+
static const mp_arg_t allowed_args[] = {
321+
{MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ},
322+
{MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT},
323+
{MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT},
324+
{MP_QSTR_fill_color_value, MP_ARG_REQUIRED | MP_ARG_INT},
325+
{MP_QSTR_replaced_color_value, MP_ARG_INT, {.u_int = INT_MAX} },
326+
};
327+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
328+
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
329+
330+
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap
331+
332+
uint32_t fill_color_value, color_depth;
333+
fill_color_value = args[ARG_fill_color_value].u_int;
334+
color_depth = (1 << destination->bits_per_value);
335+
if (color_depth <= fill_color_value) {
336+
mp_raise_ValueError(translate("value out of range of target"));
337+
}
338+
339+
uint32_t replaced_color_value;
340+
replaced_color_value = args[ARG_replaced_color_value].u_int;
341+
if (replaced_color_value != INT_MAX && color_depth <= replaced_color_value) {
342+
mp_raise_ValueError(translate("background value out of range of target"));
343+
}
344+
345+
int16_t x = args[ARG_x].u_int;
346+
int16_t y = args[ARG_y].u_int;
347+
348+
if (x < 0 || x >= destination->width) {
349+
mp_raise_ValueError(translate("out of range of target"));
350+
}
351+
if (y < 0 || y >= destination->height) {
352+
mp_raise_ValueError(translate("out of range of target"));
353+
}
354+
355+
common_hal_bitmaptools_boundary_fill(destination, x, y, fill_color_value, replaced_color_value);
356+
357+
return mp_const_none;
358+
}
359+
360+
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_boundary_fill_obj, 0, bitmaptools_obj_boundary_fill);
299361
// requires all 6 arguments
300362

301363
//|
@@ -520,6 +582,7 @@ STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = {
520582
{ MP_ROM_QSTR(MP_QSTR_rotozoom), MP_ROM_PTR(&bitmaptools_rotozoom_obj) },
521583
{ MP_ROM_QSTR(MP_QSTR_arrayblit), MP_ROM_PTR(&bitmaptools_arrayblit_obj) },
522584
{ MP_ROM_QSTR(MP_QSTR_fill_region), MP_ROM_PTR( EF5E &bitmaptools_fill_region_obj) },
585+
{ MP_ROM_QSTR(MP_QSTR_boundary_fill), MP_ROM_PTR(&bitmaptools_boundary_fill_obj) },
523586
{ MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) },
524587
};
525588
STATIC MP_DEFINE_CONST_DICT(bitmaptools_module_globals, bitmaptools_module_globals_table);

shared-bindings/bitmaptools/__init__.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ void common_hal_bitmaptools_fill_region(displayio_bitmap_t *destination,
4646
int16_t x2, int16_t y2,
4747
uint32_t value);
4848

49+
void common_hal_bitmaptools_boundary_fill(displayio_bitmap_t *destination,
50+
int16_t x, int16_t y,
51+
uint32_t fill_color_value, uint32_t replaced_color_value);
52+
4953
void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination,
5054
int16_t x0, int16_t y0,
5155
int16_t x1, int16_t y1,

shared-module/bitmaptools/__init__.c

Lines changed: 139 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
* THE SOFTWARE.
2525
*/
2626

27-
2827
#include "shared-bindings/bitmaptools/__init__.h"
2928
#include "shared-bindings/displayio/Bitmap.h"
3029
#include "shared-module/displayio/Bitmap.h"
@@ -252,6 +251,145 @@ void common_hal_bitmaptools_fill_region(displayio_bitmap_t *destination,
252251
}
253252
}
254253

254+
void common_hal_bitmaptools_boundary_fill(displayio_bitmap_t *destination,
255+
int16_t x, int16_t y,
256+
uint32_t fill_color_value, uint32_t replaced_color_value) {
257+
258+
if (fill_color_value == replaced_color_value) {
259+
// There is nothing to do
260+
return;
261+
}
262+
263+
uint32_t current_point_color_value;
264+
265+
// the list of points that we'll check
266+
mp_obj_t fill_area = mp_obj_new_list(0, NULL);
267+
268+
// first point is the one user passed in
269+
mp_obj_t point[] = { mp_obj_new_int(x), mp_obj_new_int(y) };
270+
mp_obj_list_append(
271+
fill_area,
272+
mp_obj_new_tuple(2, point)
273+
);
274+
275+
int16_t minx = x;
276+
int16_t miny = y;
277+
int16_t maxx = x;
278+
int16_t maxy = y;
279+
280+
if (replaced_color_value == INT_MAX) {
281+
current_point_color_value = common_hal_displayio_bitmap_get_pixel(
282+
destination,
283+
mp_obj_get_int(point[0]),
284+
mp_obj_get_int(point[1]));
285+
replaced_color_value = (uint32_t)current_point_color_value;
286+
}
287+
288+
mp_obj_t *fill_points;
289+
size_t list_length = 0;
290+
mp_obj_list_get(fill_area, &list_length, &fill_points);
291+
292+
mp_obj_t current_point;
293+
294+
size_t tuple_len = 0;
295+
mp_obj_t *tuple_items;
296+
297+
int cur_x, cur_y;
298+
299+
// while there are still points to check
300+
while (list_length > 0) {
301+
mp_obj_list_get(fill_area, &list_length, &fill_points);
302+
current_point = mp_obj_list_pop(fill_area, 0);
303+
mp_obj_tuple_get(current_point, &tuple_len, &tuple_items);
304+
current_point_color_value = common_hal_displayio_bitmap_get_pixel(
305+
destination,
306+
mp_obj_get_int(tuple_items[0]),
307+
mp_obj_get_int(tuple_items[1]));
308+
309+
// if the current point is not background color ignore it
310+
if (current_point_color_value != replaced_color_value) {
311+
mp_obj_list_get(fill_area, &list_length, &fill_points);
312+
continue;
313+
}
314+
315+
cur_x = mp_obj_int_get_checked(tuple_items[0]);
316+
cur_y = mp_obj_int_get_checked(tuple_items[1]);
317+
318+
if (cur_x < minx) {
319+
minx = (int16_t)cur_x;
320+
}
321+
if (cur_x > maxx) {
322+
maxx = (int16_t)cur_x;
323+
}
324+
if (cur_y < miny) {
325+
miny = (int16_t)cur_y;
326+
}
327+
if (cur_y > maxy) {
328+
maxy = (int16_t)cur_y;
329+
}
330+
331+
// fill the current point with fill color
332+
displayio_bitmap_write_pixel(
333+
destination,
334+
mp_obj_get_int(tuple_items[0]),
335+
mp_obj_get_int(tuple_items[1]),
336+
fill_color_value);
337+
338+
// add all 4 surrounding points to the list to check
339+
340+
// ignore points outside of the bitmap
341+
if (mp_obj_int_get_checked(tuple_items[1]) - 1 >= 0) {
342+
mp_obj_t above_point[] = {
343+
tuple_items[0],
344+
MP_OBJ_NEW_SMALL_INT(mp_obj_int_get_checked(tuple_items[1]) - 1)
345+
};
346+
mp_obj_list_append(
347+
fill_area,
348+
mp_obj_new_tuple(2, above_point));
349+
}
350+
351+
// ignore points outside of the bitmap
352+
if (mp_obj_int_get_checked(tuple_items[0]) - 1 >= 0) {
353+
mp_obj_t left_point[] = {
354+
MP_OBJ_NEW_SMALL_INT(mp_obj_int_get_checked(tuple_items[0]) - 1),
355+
tuple_items[1]
356+
};
357+
mp_obj_list_append(
358+
fill_area,
359+
mp_obj_new_tuple(2, left_point));
360+
}
361+
362+
// ignore points outside of the bitmap
363+
if (mp_obj_int_get_checked(tuple_items[0]) + 1 < destination->width) {
364+
mp_obj_t right_point[] = {
365+
MP_OBJ_NEW_SMALL_INT(mp_obj_int_get_checked(tuple_items[0]) + 1),
366+
tuple_items[1]
367+
};
368+
mp_obj_list_append(
369+
fill_area,
370+
mp_obj_new_tuple(2, right_point));
371+
}
372+
373+
// ignore points outside of the bitmap
374+
if (mp_obj_int_get_checked(tuple_items[1]) + 1 < destination->height) {
375+
mp_obj_t below_point[] = {
376+
tuple_items[0],
377+
MP_OBJ_NEW_SMALL_INT(mp_obj_int_get_checked(tuple_items[1]) + 1)
378+
};
379+
mp_obj_list_append(
380+
fill_area,
381+
mp_obj_new_tuple(2, below_point));
382+
}
383+
384+
mp_obj_list_get(fill_area, &list_length, &fill_points);
385+
}
386+
387+
// set dirty the area so displayio will draw
388+
displayio_area_t area = { minx, miny, maxx + 1, maxy + 1};
389+
displayio_bitmap_set_dirty_area(destination, &area);
390+
391+
}
392+
255393
void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination,
256394
int16_t x0, int16_t y0,
257395
int16_t x1, int16_t y1,

0 commit comments

Comments
 (0)
0