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 13 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
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
118 changes: 118 additions & 0 deletions shared-module/bitmaptools/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
* THE SOFTWARE.
*/

#include <string.h>
Copy link
Member

Choose a reason for hiding this comment

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

Was this needed or a debug artifact no longer required? I didn't see anything called that required string.h.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good catch thank you. I've removed this in the latest version but will wait to make a new commit until I address the below feedback as well.


#include "shared-bindings/bitmaptools/__init__.h"
#include "shared-bindings/displayio/Bitmap.h"
Expand Down Expand Up @@ -252,6 +253,123 @@ 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)
);

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;

// 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;
}

// 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 = { 0, 0, destination->width, destination->height };
Copy link
Member

Choose a reason for hiding this comment

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

Were you setting the entire display dirty on purpose? Not saying you need to for this but could track the min/max x and y values to mark only the changed area dirty.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yep I think this is correct it should be efficient to track min/max values as is works and then only make dirty the area that actually did get changed. I'll work on that and then make a new commit once it's complete.

Thanks again for taking a look!

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