Skip to content

adding skip_self_index argument to bitmap.blit() #8136

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 5 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
127 changes: 127 additions & 0 deletions shared-bindings/bitmaptools/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,132 @@ STATIC mp_obj_t bitmaptools_obj_draw_circle(size_t n_args, const mp_obj_t *pos_a

MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_draw_circle_obj, 0, bitmaptools_obj_draw_circle);

//| def blit(
//| dest_bitmap: displayio.Bitmap,
//| source_bitmap: displayio.Bitmap,
//| x: int,
//| y: int,
//| *,
//| x1: int,
//| y1: int,
//| x2: int,
//| y2: int,
//| skip_source_index: int,
//| skip_dest_index: int
//| ) -> None:
//| """Inserts the source_bitmap region defined by rectangular boundaries
//| (x1,y1) and (x2,y2) into the bitmap at the specified (x,y) location.
//|
//| :param bitmap dest_bitmap: Destination bitmap that the area will be copied into.
//| :param bitmap source_bitmap: Source bitmap that contains the graphical region to be copied
//| :param int x: Horizontal pixel location in bitmap where source_bitmap upper-left
//| corner will be placed
//| :param int y: Vertical pixel location in bitmap where source_bitmap upper-left
//| corner will be placed
//| :param int x1: Minimum x-value for rectangular bounding box to be copied from the source bitmap
//| :param int y1: Minimum y-value for rectangular bounding box to be copied from the source bitmap
//| :param int x2: Maximum x-value (exclusive) for rectangular bounding box to be copied from the source bitmap
//| :param int y2: Maximum y-value (exclusive) for rectangular bounding box to be copied from the source bitmap
//| :param int skip_source_index: bitmap palette index in the source that will not be copied,
//| set to None to copy all pixels
//| :param int skip_dest_index: bitmap palette index in the destination bitmap that will not get overwritten
//| by the pixels from the source"""
//| ...
//|
STATIC mp_obj_t bitmaptools_obj_blit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum {ARG_destination, ARG_source, ARG_x, ARG_y, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_skip_source_index, ARG_skip_dest_index};
static const mp_arg_t allowed_args[] = {
{MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} },
{MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} },
{MP_QSTR_x1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{MP_QSTR_y1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{MP_QSTR_x2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->width
{MP_QSTR_y2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->height
{MP_QSTR_skip_source_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{MP_QSTR_skip_dest_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
// mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);

// displayio_bitmap_t *self = MP_OBJ_TO_PTR(pos_args[0]);
displayio_bitmap_t *destination = mp_arg_validate_type(args[ARG_destination].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap);
// check_for_deinit(destination);

// Check x,y are within self (target) bitmap boundary
int16_t x = mp_arg_validate_int_range(args[ARG_x].u_int, 0, MAX(0, destination->width - 1), MP_QSTR_x);
int16_t y = mp_arg_validate_int_range(args[ARG_y].u_int, 0, MAX(0, destination->height - 1), MP_QSTR_y);


displayio_bitmap_t *source = mp_arg_validate_type(args[ARG_source].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap);


// ensure that the target bitmap (self) has at least as many `bits_per_value` as the source
if (destination->bits_per_value < source->bits_per_value) {
mp_raise_ValueError(translate("source palette too large"));
}

// Check x1,y1,x2,y2 are within source bitmap boundary
int16_t x1 = mp_arg_validate_int_range(args[ARG_x1].u_int, 0, MAX(0, source->width - 1), MP_QSTR_x1);
int16_t y1 = mp_arg_validate_int_range(args[ARG_y1].u_int, 0, MAX(0, source->height - 1), MP_QSTR_y1);
int16_t x2, y2;
// if x2 or y2 is None, then set as the maximum size of the source bitmap
if (args[ARG_x2].u_obj == mp_const_none) {
x2 = source->width;
} else {
x2 = mp_arg_validate_int_range(mp_obj_get_int(args[ARG_x2].u_obj), 0, source->width, MP_QSTR_x2);
}
// int16_t y2;
if (args[ARG_y2].u_obj == mp_const_none) {
y2 = source->height;
} else {
y2 = mp_arg_validate_int_range(mp_obj_get_int(args[ARG_y2].u_obj), 0, source->height, MP_QSTR_y2);
}

// Ensure x1 < x2 and y1 < y2
if (x1 > x2) {
int16_t temp = x2;
x2 = x1;
x1 = temp;
}
if (y1 > y2) {
int16_t temp = y2;
y2 = y1;
y1 = temp;
}

uint32_t skip_source_index;
bool skip_source_index_none; // flag whether skip_value was None

if (args[ARG_skip_source_index].u_obj == mp_const_none) {
skip_source_index = 0;
skip_source_index_none = true;
} else {
skip_source_index = mp_obj_get_int(args[ARG_skip_source_index].u_obj);
skip_source_index_none = false;
}

uint32_t skip_dest_index;
bool skip_dest_index_none; // flag whether skip_self_value was None

if (args[ARG_skip_dest_index].u_obj == mp_const_none) {
skip_dest_index = 0;
skip_dest_index_none = true;
} else {
skip_dest_index = mp_obj_get_int(args[ARG_skip_dest_index].u_obj);
skip_dest_index_none = false;
}

common_hal_bitmaptools_blit(destination, source, x, y, x1, y1, x2, y2, skip_source_index, skip_source_index_none, skip_dest_index,
skip_dest_index_none);

return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_blit_obj, 1, bitmaptools_obj_blit);


STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bitmaptools) },
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&bitmaptools_readinto_obj) },
Expand All @@ -960,6 +1086,7 @@ STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) },
{ MP_ROM_QSTR(MP_QSTR_draw_polygon), MP_ROM_PTR(&bitmaptools_draw_polygon_obj) },
{ MP_ROM_QSTR(MP_QSTR_draw_circle), MP_ROM_PTR(&bitmaptools_draw_circle_obj) },
{ MP_ROM_QSTR(MP_QSTR_blit), MP_ROM_PTR(&bitmaptools_blit_obj) },
{ MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&bitmaptools_dither_obj) },
{ MP_ROM_QSTR(MP_QSTR_DitherAlgorithm), MP_ROM_PTR(&bitmaptools_dither_algorithm_type) },
};
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 @@ -69,6 +69,10 @@ void common_hal_bitmaptools_draw_circle(displayio_bitmap_t *destination,
int16_t radius,
uint32_t value);

void common_hal_bitmaptools_blit(displayio_bitmap_t *destination, displayio_bitmap_t *source, int16_t x, int16_t y,
int16_t x1, int16_t y1, int16_t x2, int16_t y2,
uint32_t skip_source_index, bool skip_source_index_none, uint32_t skip_dest_index, bool skip_dest_index_none);

void common_hal_bitmaptools_draw_polygon(displayio_bitmap_t *destination, void *xs, void *ys, size_t points_len, int point_size, uint32_t value, bool close);
void common_hal_bitmaptools_readinto(displayio_bitmap_t *self, mp_obj_t *file, int element_size, int bits_per_pixel, bool reverse_pixels_in_word, bool swap_bytes, bool reverse_rows);
void common_hal_bitmaptools_arrayblit(displayio_bitmap_t *self, void *data, int element_size, int x1, int y1, int x2, int y2, bool skip_specified, uint32_t skip_index);
Expand Down
104 changes: 0 additions & 104 deletions shared-bindings/displayio/Bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,109 +186,6 @@ STATIC mp_obj_t bitmap_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t val
return mp_const_none;
}

//| def blit(
//| self,
//| x: int,
//| y: int,
//| source_bitmap: Bitmap,
//| *,
//| x1: int,
//| y1: int,
//| x2: int,
//| y2: int,
//| skip_index: int
//| ) -> None:
//| """Inserts the source_bitmap region defined by rectangular boundaries
//| (x1,y1) and (x2,y2) into the bitmap at the specified (x,y) location.
//|
//| :param int x: Horizontal pixel location in bitmap where source_bitmap upper-left
//| corner will be placed
//| :param int y: Vertical pixel location in bitmap where source_bitmap upper-left
//| corner will be placed
//| :param bitmap source_bitmap: Source bitmap that contains the graphical region to be copied
//| :param int x1: Minimum x-value for rectangular bounding box to be copied from the source bitmap
//| :param int y1: Minimum y-value for rectangular bounding box to be copied from the source bitmap
//| :param int x2: Maximum x-value (exclusive) for rectangular bounding box to be copied from the source bitmap
//| :param int y2: Maximum y-value (exclusive) for rectangular bounding box to be copied from the source bitmap
//| :param int skip_index: bitmap palette index in the source that will not be copied,
//| set to None to copy all pixels"""
//| ...
STATIC mp_obj_t displayio_bitmap_obj_blit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum {ARG_x, ARG_y, ARG_source, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_skip_index};
static const mp_arg_t allowed_args[] = {
{MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} },
{MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} },
{MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{MP_QSTR_x1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{MP_QSTR_y1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{MP_QSTR_x2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->width
{MP_QSTR_y2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->height
{MP_QSTR_skip_index, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);

displayio_bitmap_t *self = MP_OBJ_TO_PTR(pos_args[0]);
check_for_deinit(self);

// Check x,y are within self (target) bitmap boundary
int16_t x = mp_arg_validate_int_range(args[ARG_x].u_int, 0, MAX(0, self->width - 1), MP_QSTR_x);
int16_t y = mp_arg_validate_int_range(args[ARG_y].u_int, 0, MAX(0, self->height - 1), MP_QSTR_y);

displayio_bitmap_t *source = mp_arg_validate_type(args[ARG_source].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap);


// ensure that the target bitmap (self) has at least as many `bits_per_value` as the source
if (self->bits_per_value < source->bits_per_value) {
mp_raise_ValueError(translate("source palette too large"));
}

// Check x1,y1,x2,y2 are within source bitmap boundary
int16_t x1 = mp_arg_validate_int_range(args[ARG_x1].u_int, 0, MAX(0, source->width - 1), MP_QSTR_x1);
int16_t y1 = mp_arg_validate_int_range(args[ARG_y1].u_int, 0, MAX(0, source->height - 1), MP_QSTR_y1);
int16_t x2, y2;
// if x2 or y2 is None, then set as the maximum size of the source bitmap
if (args[ARG_x2].u_obj == mp_const_none) {
x2 = source->width;
} else {
x2 = mp_arg_validate_int_range(mp_obj_get_int(args[ARG_x2].u_obj), 0, source->width, MP_QSTR_x2);
}
// int16_t y2;
if (args[ARG_y2].u_obj == mp_const_none) {
y2 = source->height;
} else {
y2 = mp_arg_validate_int_range(mp_obj_get_int(args[ARG_y2].u_obj), 0, source->height, MP_QSTR_y2);
}

// Ensure x1 < x2 and y1 < y2
if (x1 > x2) {
int16_t temp = x2;
x2 = x1;
x1 = temp;
}
if (y1 > y2) {
int16_t temp = y2;
y2 = y1;
y1 = temp;
}

uint32_t skip_index;
bool skip_index_none; // flag whether skip_value was None

if (args[ARG_skip_index].u_obj == mp_const_none) {
skip_index = 0;
skip_index_none = true;
} else {
skip_index = mp_obj_get_int(args[ARG_skip_index].u_obj);
skip_index_none = false;
}

common_hal_displayio_bitmap_blit(self, x, y, source, x1, y1, x2, y2, skip_index, skip_index_none);

return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(displayio_bitmap_blit_obj, 1, displayio_bitmap_obj_blit);

//| def fill(self, value: int) -> None:
//| """Fills the bitmap with the supplied palette index value."""
//| ...
Expand Down Expand Up @@ -363,7 +260,6 @@ MP_DEFINE_CONST_FUN_OBJ_1(displayio_bitmap_deinit_obj, displayio_bitmap_obj_dein
STATIC const mp_rom_map_elem_t displayio_bitmap_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_bitmap_height_obj) },
{ MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_bitmap_width_obj) },
{ MP_ROM_QSTR(MP_QSTR_blit), MP_ROM_PTR(&displayio_bitmap_blit_obj) },
{ MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&displayio_bitmap_fill_obj) },
{ MP_ROM_QSTR(MP_QSTR_dirty), MP_ROM_PTR(&displayio_bitmap_dirty_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&displayio_bitmap_deinit_obj) },
Expand Down
3 changes: 0 additions & 3 deletions shared-bindings/displayio/Bitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,6 @@ uint16_t common_hal_displayio_bitmap_get_height(displayio_bitmap_t *self);
uint16_t common_hal_displayio_bitmap_get_width(displayio_bitmap_t *self);
uint32_t common_hal_displayio_bitmap_get_bits_per_value(displayio_bitmap_t *self);
void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *bitmap, int16_t x, int16_t y, uint32_t value);
void common_hal_displayio_bitmap_blit(displayio_bitmap_t *self, int16_t x, int16_t y, displayio_bitmap_t *source,
int16_t x1, int16_t y1, int16_t x2, int16_t y2,
uint32_t skip_index, bool skip_index_none);
uint32_t common_hal_displayio_bitmap_get_pixel(displayio_bitmap_t *bitmap, int16_t x, int16_t y);
void common_hal_displayio_bitmap_fill(displayio_bitmap_t *bitmap, uint32_t value);
int common_hal_displayio_bitmap_get_buffer(displayio_bitmap_t *self, mp_buffer_info_t *bufinfo, mp_uint_t flags);
Expand Down
68 changes: 68 additions & 0 deletions shared-module/bitmaptools/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -982,3 +982,71 @@ void common_hal_bitmaptools_draw_circle(displayio_bitmap_t *destination,

draw_circle(destination, x, y, radius, value);
}

void common_hal_bitmaptools_blit(displayio_bitmap_t *destination, displayio_bitmap_t *source, int16_t x, int16_t y,
int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint32_t skip_source_index, bool skip_source_index_none, uint32_t skip_dest_index,
bool skip_dest_index_none) {

if (destination->read_only) {
mp_raise_RuntimeError(translate("Read-only"));
}
// Copy region of "source" bitmap into "destination" bitmap at location x,y in the "destination"
// If skip_value is encountered in the source bitmap, it will not be copied.
// If skip_value is `None`, then all pixels are copied.
// This function assumes input checks were performed for pixel index entries.

// Update the dirty area
int16_t dirty_x_max = (x + (x2 - x1));
if (dirty_x_max > destination->width) {
dirty_x_max = destination->width;
}
int16_t dirty_y_max = y + (y2 - y1);
if (dirty_y_max > destination->height) {
dirty_y_max = destination->height;
}

displayio_area_t a = { x, y, dirty_x_max, dirty_y_max, NULL};
displayio_bitmap_set_dirty_area(destination, &a);

bool x_reverse = false;
bool y_reverse = false;

// Add reverse direction option to protect blitting of destination bitmap back into destination bitmap
if (x > x1) {
x_reverse = true;
}
if (y > y1) {
y_reverse = true;
}

// simplest version - use internal functions for get/set pixels
for (int16_t i = 0; i < (x2 - x1); i++) {

const int xs_index = x_reverse ? ((x2) - i - 1) : x1 + i; // x-index into the source bitmap
const int xd_index = x_reverse ? ((x + (x2 - x1)) - i - 1) : x + i; // x-index into the destination bitmap

if ((xd_index >= 0) && (xd_index < destination->width)) {
for (int16_t j = 0; j < (y2 - y1); j++) {

const int ys_index = y_reverse ? ((y2) - j - 1) : y1 + j; // y-index into the source bitmap
const int yd_index = y_reverse ? ((y + (y2 - y1)) - j - 1) : y + j; // y-index into the destination bitmap

if ((yd_index >= 0) && (yd_index < destination->height)) {
uint32_t value = common_hal_displayio_bitmap_get_pixel(source, xs_index, ys_index);
if (skip_dest_index_none) { // if skip_dest_index is none, then only check source skip
if ((skip_source_index_none) || (value != skip_source_index)) { // write if skip_value_none is True
displayio_bitmap_write_pixel(destination, xd_index, yd_index, value);
}
} else { // check dest_value index against skip_dest_index and skip if they match
uint32_t dest_value = common_hal_displayio_bitmap_get_pixel(destination, xd_index, yd_index);
if (dest_value != skip_dest_index) {
if ((skip_source_index_none) || (value != skip_source_index)) { // write if skip_value_none is True
displayio_bitmap_write_pixel(destination, xd_index, yd_index, value);
}
}
}
}
}
}
}
}
Loading