refactor bitmap.blit into bitmaptools

This commit is contained in:
foamyguy 2023-07-02 14:35:40 -05:00
parent abf15125ff
commit 96d3e662b3
6 changed files with 198 additions and 190 deletions

View File

@ -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: Bitmap,
//| source_bitmap: Bitmap,
//| x: int,
//| y: int,
//| *,
//| x1: int,
//| y1: int,
//| x2: int,
//| y2: int,
//| skip_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_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_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_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_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;
}
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_index, skip_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) },
@ -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) },
};

View File

@ -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_index, bool skip_index_none, uint32_t skip_self_index, bool skip_self_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);

View File

@ -186,125 +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,
//| skip_self_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
//| :param int skip_self_index: bitmap palette index in the self bitmap that will not get overwritten
//| by the pixels from the source"""
//| ...
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, ARG_skip_self_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_QSTR_skip_self_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;
}
uint32_t skip_self_index;
bool skip_self_index_none; // flag whether skip_self_value was None
if (args[ARG_skip_self_index].u_obj == mp_const_none) {
skip_self_index = 0;
skip_self_index_none = true;
} else {
skip_self_index = mp_obj_get_int(args[ARG_skip_self_index].u_obj);
skip_self_index_none = false;
}
common_hal_displayio_bitmap_blit(self, x, y, source, x1, y1, x2, y2, skip_index, skip_index_none, skip_self_index,
skip_self_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."""
//| ...
@ -379,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) },

View File

@ -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 skip_self_index, bool skip_self_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);

View File

@ -982,3 +982,70 @@ 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_index, bool skip_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_index_none) || (value != skip_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_index_none) || (value != skip_index)) { // write if skip_value_none is True
displayio_bitmap_write_pixel(destination, xd_index, yd_index, value);
}
}
}
}
}
}
}
}

View File

@ -174,73 +174,6 @@ void displayio_bitmap_write_pixel(displayio_bitmap_t *self, int16_t x, int16_t y
}
}
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 skip_self_index,
bool skip_self_index_none) {
if (self->read_only) {
mp_raise_RuntimeError(translate("Read-only"));
}
// Copy region of "source" bitmap into "self" bitmap at location x,y in the "self"
// 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 > self->width) {
dirty_x_max = self->width;
}
int16_t dirty_y_max = y + (y2 - y1);
if (dirty_y_max > self->height) {
dirty_y_max = self->height;
}
displayio_area_t a = { x, y, dirty_x_max, dirty_y_max, NULL};
displayio_bitmap_set_dirty_area(self, &a);
bool x_reverse = false;
bool y_reverse = false;
// Add reverse direction option to protect blitting of self bitmap back into self 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 < self->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 < self->height)) {
uint32_t value = common_hal_displayio_bitmap_get_pixel(source, xs_index, ys_index);
if (skip_self_index_none) { // if skip_self_index is none, then only check source skip
if ((skip_index_none) || (value != skip_index)) { // write if skip_value_none is True
displayio_bitmap_write_pixel(self, xd_index, yd_index, value);
}
} else { // check dest_value index against skip_self_index and skip if they match
uint32_t dest_value = common_hal_displayio_bitmap_get_pixel(self, xd_index, yd_index);
if (dest_value != skip_self_index) {
if ((skip_index_none) || (value != skip_index)) { // write if skip_value_none is True
displayio_bitmap_write_pixel(self, xd_index, yd_index, value);
}
}
}
}
}
}
}
}
void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *self, int16_t x, int16_t y, uint32_t value) {
if (self->read_only) {
mp_raise_RuntimeError(translate("Read-only"));