8000 Bitmaptools boundary_fill by FoamyGuy · Pull Request #5145 · adafruit/circuitpython · GitHub
[go: up one dir, main page]

Skip to content

Bitmaptools boundary_fill #5145

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Aug 23, 2021
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -2566,6 +2566,10 @@ msgstr ""
msgid "axis too long"
msgstr ""

#: shared-bindings/bitmaptools/__init__.c
msgid "background value out of range of target"
msgstr ""

#: py/builtinevex.c
msgid "bad compile mode"
msgstr ""
Expand Down Expand Up @@ -3917,6 +3921,7 @@ msgstr ""
#: ports/esp32s2/boards/gravitech_cucumber_rs/mpconfigboard.h
#: ports/esp32s2/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
#: ports/esp32s2/boards/microdev_micro_s2/mpconfigboard.h
#: ports/esp32s2/boards/morpheans_morphesp-240/mpconfigboard.h
#: ports/esp32s2/boards/muselab_nanoesp32_s2_wroom/mpconfigboard.h
#: ports/esp32s2/boards/muselab_nanoesp32_s2_wrover/mpconfigboard.h
#: ports/esp32s2/boards/targett_module_clip_wroom/mpconfigboard.h
Expand Down Expand Up @@ -4358,6 +4363,10 @@ msgstr ""
msgid "value must fit in %d byte(s)"
msgstr ""

#: shared-bindings/bitmaptools/__init__.c
msgid "value out of range of target"
msgstr ""

#: shared-bindings/displayio/Bitmap.c
msgid "value_count must be > 0"
msgstr ""
Expand Down
1 change: 1 addition & 0 deletions ports/stm/boards/pyb_nano_v2/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ CIRCUITPY_AUDIOPWMIO = 0
CIRCUITPY_KEYPAD = 0
CIRCUITPY_MIDI = 0
CIRCUITPY_MSGPACK = 0
CIRCUITPY_BITMAPTOOLS = 0
1 change: 1 addition & 0 deletions ports/stm/boards/stm32f411ve_discovery/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ CIRCUITPY_AUDIOPWMIO = 0
CIRCUITPY_KEYPAD = 0
CIRCUITPY_MIDI = 0
CIRCUITPY_MSGPACK = 0
CIRCUITPY_BITMAPTOOLS = 0
63 changes: 63 additions & 0 deletions shared-bindings/bitmaptools/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,68 @@ STATIC mp_obj_t bitmaptools_obj_fill_region(size_t n_args, const mp_obj_t *pos_a
}

MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_fill_region_obj, 0, bitmaptools_obj_fill_region);
//|
//| def boundary_fill(
//| dest_bitmap: displayio.Bitmap,
//| x: int, y: int,
//| fill_color_value: int, replaced_color_value: int) -> None:
//| """Draws the color value into the destination bitmap enclosed
//| area of pixels of the background_value color. Like "Paint Bucket"
//| fill tool.
//|
//| :param bitmap dest_bitmap: Destination bitmap that will be written into
//| :param int x: x-pixel position of the first pixel to check and fill if needed
//| :param int y: y-pixel position of the first pixel to check and fill if needed
//| :param int fill_color_value: Bitmap palette index that will be written into the
//| enclosed area in the destination bitmap
//| :param int replaced_color_value: Bitmap palette index that will filled with the
//| value color in the enclosed area in the destination bitmap"""
//| ...
//|
STATIC mp_obj_t bitmaptools_obj_boundary_fill(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum {ARG_dest_bitmap, ARG_x, ARG_y, ARG_fill_color_value, ARG_replaced_color_value};

static const mp_arg_t allowed_args[] = {
{MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ},
{MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT},
{MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT},
{MP_QSTR_fill_color_value, MP_ARG_REQUIRED | MP_ARG_INT},
{MP_QSTR_replaced_color_value, MP_ARG_INT, {.u_int = INT_MAX} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);

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

uint32_t fill_color_value, color_depth;
fill_color_value = args[ARG_fill_color_value].u_int;
color_depth = (1 << destination->bits_per_value);
if (color_depth <= fill_color_value) {
mp_raise_ValueError(translate("value out of range of target"));
}

uint32_t replaced_color_value;
replaced_color_value = args[ARG_replaced_color_value].u_int;
if (replaced_color_value != INT_MAX && color_depth <= replaced_color_value) {
mp_raise_ValueError(translate("background value out of range of target"));
}

int16_t x = args[ARG_x].u_int;
int16_t y = args[ARG_y].u_int;

if (x < 0 || x >= destination->width) {
mp_raise_ValueError(translate("out of range of target"));
}
if (y < 0 || y >= destination->height) {
mp_raise_ValueError(translate("out of range of target"));
}

common_hal_bitmaptools_boundary_fill(destination, x, y, fill_color_value, replaced_color_value);

return mp_const_none;
}

MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_boundary_fill_obj, 0, bitmaptools_obj_boundary_fill);
// requires all 6 arguments

//|
Expand Down Expand Up @@ -520,6 +582,7 @@ STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_rotozoom), MP_ROM_PTR(&bitmaptools_rotozoom_obj) },
{ MP_ROM_QSTR(MP_QSTR_arrayblit), MP_ROM_PTR(&bitmaptools_arrayblit_obj) },
{ MP_ROM_QSTR(MP_QSTR_fill_region), MP_ROM_PTR(&bitmaptools_fill_region_obj) },
{ MP_ROM_QSTR(MP_QSTR_boundary_fill), MP_ROM_PTR(&bitmaptools_boundary_fill_obj) },
{ MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) },
};
STATIC MP_DEFINE_CONST_DICT(bitmaptools_module_globals, bitmaptools_module_globals_table);
Expand Down
4 changes: 4 additions & 0 deletions shared-bindings/bitmaptools/__init__.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ void common_hal_bitmaptools_fill_region(displayio_bitmap_t *destination,
int16_t x2, int16_t y2,
uint32_t value);

void common_hal_bitmaptools_boundary_fill(displayio_bitmap_t *destination,
int16_t x, int16_t y,
uint32_t fill_color_value, uint32_t replaced_color_value);

void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination,
int16_t x0, int16_t y0,
int16_t x1, int16_t y1,
Expand Down
143 changes: 142 additions & 1 deletion shared-module/bitmaptools/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
* THE SOFTWARE.
*/


#include "shared-bindings/bitmaptools/__init__.h"
#include "shared-bindings/displayio/Bitmap.h"
#include "shared-module/displayio/Bitmap.h"
Expand Down Expand Up @@ -252,6 +251,148 @@ void common_hal_bitmaptools_fill_region(displayio_bitmap_t *destination,
}
}

void common_hal_bitmaptools_boundary_fill(displayio_bitmap_t *destination,
int16_t x, int16_t y,
uint32_t fill_color_value, uint32_t replaced_color_value) {

if (fill_color_value == replaced_color_value) {
// There is nothing to do
return;
}




uint32_t current_point_color_value;

// the list of points that we'll check
mp_obj_t fill_area = mp_obj_new_list(0, NULL);

// first point is the one user passed in
mp_obj_t point[] = { mp_obj_new_int(x), mp_obj_new_int(y) };
mp_obj_list_append(
fill_area,
mp_obj_new_tuple(2, point)
);

int16_t minx = x;
int16_t miny = x;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't miny = y and maxx = x respectively?
With the current setting say a 1 point fill at (5,10) would mark the dirty area as (5,5) to (10,10) instead of just (5,10) to (5,10). Or another way if x starts at 5 but moves 2 wide to 7, the maxx is still 10 which is larger then the changes area.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whoops, yes each should be their own respective values. Thank you

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed this with latest commit

int16_t maxx = y;
int16_t maxy = y;

if (replaced_color_value == INT_MAX) {
current_point_color_value = common_hal_displayio_bitmap_get_pixel(
destination,
mp_obj_get_int(point[0]),
mp_obj_get_int(point[1]));
replaced_color_value = (uint32_t)current_point_color_value;
}

mp_obj_t *fill_points;
size_t list_length = 0;
mp_obj_list_get(fill_area, &list_length, &fill_points);

mp_obj_t current_point;

size_t tuple_len = 0;
mp_obj_t *tuple_items;

int cur_x, cur_y;

// while there are still points to check
while (list_length > 0) {
mp_obj_list_get(fill_area, &list_length, &fill_points);
current_point = mp_obj_list_pop(fill_area, 0);
mp_obj_tuple_get(current_point, &tuple_len, &tuple_items);
current_point_color_value = common_hal_displayio_bitmap_get_pixel(
destination,
mp_obj_get_int(tuple_items[0]),
mp_obj_get_int(tuple_items[1]));

// if the current point is not background color ignore it
if (current_point_color_value != replaced_color_value) {
mp_obj_list_get(fill_area, &list_length, &fill_points);
continue;
}

cur_x = mp_obj_int_get_checked(tuple_items[0]);
cur_y = mp_obj_int_get_checked(tuple_items[1]);

if (cur_x < minx) {
minx = (int16_t)cur_x;
}
if (cur_x > maxx) {
maxx = (int16_t)cur_x;
}
if (cur_y < miny) {
miny = (int16_t)cur_y;
}
if (cur_y > maxy) {
maxy = (int16_t)cur_y;
}

// fill the current point with fill color
displayio_bitmap_write_pixel(
destination,
mp_obj_get_int(tuple_items[0]),
mp_obj_get_int(tuple_items[1]),
fill_color_value);

// add all 4 surrounding points to the list to check

// ignore points outside of the bitmap
if (mp_obj_int_get_checked(tuple_items[1]) - 1 >= 0) {
mp_obj_t above_point[] = {
tuple_items[0],
MP_OBJ_NEW_SMALL_INT(mp_obj_int_get_checked(tuple_items[1]) - 1)
};
mp_obj_list_append(
fill_area,
mp_obj_new_tuple(2, above_point));
}

// ignore points outside of the bitmap
if (mp_obj_int_get_checked(tuple_items[0]) - 1 >= 0) {
mp_obj_t left_point[] = {
MP_OBJ_NEW_SMALL_INT(mp_obj_int_get_checked(tuple_items[0]) - 1),
tuple_items[1]
};
mp_obj_list_append(
fill_area,
mp_obj_new_tuple(2, left_point));
}

// ignore points outside of the bitmap
if (mp_obj_int_get_checked(tuple_items[0]) + 1 < destination->width) {
mp_obj_t right_point[] = {
MP_OBJ_NEW_SMALL_INT(mp_obj_int_get_checked(tuple_items[0]) + 1),
tuple_items[1]
};
mp_obj_list_append(
fill_area,
mp_obj_new_tuple(2, right_point));
}

// ignore points outside of the bitmap
if (mp_obj_int_get_checked(tuple_items[1]) + 1 < destination->height) {
mp_obj_t below_point[] = {
tuple_items[0],
MP_OBJ_NEW_SMALL_INT(mp_obj_int_get_checked(tuple_items[1]) + 1)
};
mp_obj_list_append(
fill_area,
mp_obj_new_tuple(2, below_point));
}

mp_obj_list_get(fill_area, &list_length, &fill_points);
}

// set dirty the area so displayio will draw
displayio_area_t area = { minx, miny, maxx + 1, maxy + 1};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason the max x/y is +1 that maybe I'm missing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not 100% sure about the reason, it seems like displayio_bitmap_set_dirty_area might be inclusive on one end and exclusive on the other, I don't see anything documenting that though. And it's not consistent on every fill which definitely seems odd to me.

I did try initially without the +1s and some of the fills are not showing the far right and bottom edge lines of pixels being filled. Most of the logic was copied from the rotozoom function which does also have the +1s in it's dirty area as well.

displayio_bitmap_set_dirty_area(destination, &area);

}

void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination,
int16_t x0, int16_t y0,
int16_t x1, int16_t y1,
Expand Down
0