Skip to content

Commit 3ec9f8a

Browse files
authored
Merge pull request #8136 from FoamyGuy/blit_skip_self_index
adding skip_self_index argument to bitmap.blit()
2 parents a2002e3 + 7285799 commit 3ec9f8a

File tree

6 files changed

+199
-164
lines changed

6 files changed

+199
-164
lines changed

shared-bindings/bitmaptools/__init__.c

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,132 @@ STATIC mp_obj_t bitmaptools_obj_draw_circle(size_t n_args, const mp_obj_t *pos_a
949949

950950
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_draw_circle_obj, 0, bitmaptools_obj_draw_circle);
951951

952+
//| def blit(
953+
//| dest_bitmap: displayio.Bitmap,
954+
//| source_bitmap: displayio.Bitmap,
955+
//| x: int,
956+
//| y: int,
957+
//| *,
958+
//| x1: int,
959+
//| y1: int,
960+
//| x2: int,
961+
//| y2: int,
962+
//| skip_source_index: int,
963+
//| skip_dest_index: int
964+
//| ) -> None:
965+
//| """Inserts the source_bitmap region defined by rectangular boundaries
966+
//| (x1,y1) and (x2,y2) into the bitmap at the specified (x,y) location.
967+
//|
968+
//| :param bitmap dest_bitmap: Destination bitmap that the area will be copied into.
969+
//| :param bitmap source_bitmap: Source bitmap that contains the graphical region to be copied
970+
//| :param int x: Horizontal pixel location in bitmap where source_bitmap upper-left
971+
//| corner will be placed
972+
//| :param int y: Vertical pixel location in bitmap where source_bitmap upper-left
973+
//| corner will be placed
974+
//| :param int x1: Minimum x-value for rectangular bounding box to be copied from the source bitmap
975+
//| :param int y1: Minimum y-value for rectangular bounding box to be copied from the source bitmap
976+
//| :param int x2: Maximum x-value (exclusive) for rectangular bounding box to be copied from the source bitmap
977+
//| :param int y2: Maximum y-value (exclusive) for rectangular bounding box to be copied from the source bitmap
978+
//| :param int skip_source_index: bitmap palette index in the source that will not be copied,
979+
//| set to None to copy all pixels
980+
//| :param int skip_dest_index: bitmap palette index in the destination bitmap that will not get overwritten
981+
//| by the pixels from the source"""
982+
//| ...
983+
//|
984+
STATIC mp_obj_t bitmaptools_obj_blit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
985+
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};
986+
static const mp_arg_t allowed_args[] = {
987+
{MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
988+
{MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
989+
{MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} },
990+
{MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} },
991+
{MP_QSTR_x1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
992+
{MP_QSTR_y1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
993+
{MP_QSTR_x2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->width
994+
{MP_QSTR_y2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->height
995+
{MP_QSTR_skip_source_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
996+
{MP_QSTR_skip_dest_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
997+
};
998+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
999+
// mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
1000+
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
1001+
1002+
// displayio_bitmap_t *self = MP_OBJ_TO_PTR(pos_args[0]);
1003+
displayio_bitmap_t *destination = mp_arg_validate_type(args[ARG_destination].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap);
1004+
// check_for_deinit(destination);
1005+
1006+
// Check x,y are within self (target) bitmap boundary
1007+
int16_t x = mp_arg_validate_int_range(args[ARG_x].u_int, 0, MAX(0, destination->width - 1), MP_QSTR_x);
1008+
int16_t y = mp_arg_validate_int_range(args[ARG_y].u_int, 0, MAX(0, destination->height - 1), MP_QSTR_y);
1009+
1010+
1011+
displayio_bitmap_t *source = mp_arg_validate_type(args[ARG_source].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap);
1012+
1013+
1014+
// ensure that the target bitmap (self) has at least as many `bits_per_value` as the source
1015+
if (destination->bits_per_value < source->bits_per_value) {
1016+
mp_raise_ValueError(translate("source palette too large"));
1017+
}
1018+
1019+
// Check x1,y1,x2,y2 are within source bitmap boundary
1020+
int16_t x1 = mp_arg_validate_int_range(args[ARG_x1].u_int, 0, MAX(0, source->width - 1), MP_QSTR_x1);
1021+
int16_t y1 = mp_arg_validate_int_range(args[ARG_y1].u_int, 0, MAX(0, source->height - 1), MP_QSTR_y1);
1022+
int16_t x2, y2;
1023+
// if x2 or y2 is None, then set as the maximum size of the source bitmap
1024+
if (args[ARG_x2].u_obj == mp_const_none) {
1025+
x2 = source->width;
1026+
} else {
1027+
x2 = mp_arg_validate_int_range(mp_obj_get_int(args[ARG_x2].u_obj), 0, source->width, MP_QSTR_x2);
1028+
}
1029+
// int16_t y2;
1030+
if (args[ARG_y2].u_obj == mp_const_none) {
1031+
y2 = source->height;
1032+
} else {
1033+
y2 = mp_arg_validate_int_range(mp_obj_get_int(args[ARG_y2].u_obj), 0, source->height, MP_QSTR_y2);
1034+
}
1035+
1036+
// Ensure x1 < x2 and y1 < y2
1037+
if (x1 > x2) {
1038+
int16_t temp = x2;
1039+
x2 = x1;
1040+
x1 = temp;
1041+
}
1042+
if (y1 > y2) {
1043+
int16_t temp = y2;
1044+
y2 = y1;
1045+
y1 = temp;
1046+
}
1047+
1048+
uint32_t skip_source_index;
1049+
bool skip_source_index_none; // flag whether skip_value was None
1050+
1051+
if (args[ARG_skip_source_index].u_obj == mp_const_none) {
1052+
skip_source_index = 0;
1053+
skip_source_index_none = true;
1054+
} else {
1055+
skip_source_index = mp_obj_get_int(args[ARG_skip_source_index].u_obj);
1056+
skip_source_index_none = false;
1057+
}
1058+
1059+
uint32_t skip_dest_index;
1060+
bool skip_dest_index_none; // flag whether skip_self_value was None
1061+
1062+
if (args[ARG_skip_dest_index].u_obj == mp_const_none) {
1063+
skip_dest_index = 0;
1064+
skip_dest_index_none = true;
1065+
} else {
1066+
skip_dest_index = mp_obj_get_int(args[ARG_skip_dest_index].u_obj);
1067+
skip_dest_index_none = false;
1068+
}
1069+
1070+
common_hal_bitmaptools_blit(destination, source, x, y, x1, y1, x2, y2, skip_source_index, skip_source_index_none, skip_dest_index,
1071+
skip_dest_index_none);
1072+
1073+
return mp_const_none;
1074+
}
1075+
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_blit_obj, 1, bitmaptools_obj_blit);
1076+
1077+
9521078
STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = {
9531079
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bitmaptools) },
9541080
{ 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[] = {
9601086
{ MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) },
9611087
{ MP_ROM_QSTR(MP_QSTR_draw_polygon), MP_ROM_PTR(&bitmaptools_draw_polygon_obj) },
9621088
{ MP_ROM_QSTR(MP_QSTR_draw_circle), MP_ROM_PTR(&bitmaptools_draw_circle_obj) },
1089+
{ MP_ROM_QSTR(MP_QSTR_blit), MP_ROM_PTR(&bitmaptools_blit_obj) },
9631090
{ MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&bitmaptools_dither_obj) },
9641091
{ MP_ROM_QSTR(MP_QSTR_DitherAlgorithm), MP_ROM_PTR(&bitmaptools_dither_algorithm_type) },
9651092
};

shared-bindings/bitmaptools/__init__.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ void common_hal_bitmaptools_draw_circle(displayio_bitmap_t *destination,
6969
int16_t radius,
7070
uint32_t value);
7171

72+
void common_hal_bitmaptools_blit(displayio_bitmap_t *destination, displayio_bitmap_t *source, int16_t x, int16_t y,
73+
int16_t x1, int16_t y1, int16_t x2, int16_t y2,
74+
uint32_t skip_source_index, bool skip_source_index_none, uint32_t skip_dest_index, bool skip_dest_index_none);
75+
7276
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);
7377
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);
7478
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);

shared-bindings/displayio/Bitmap.c

Lines changed: 0 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -186,109 +186,6 @@ STATIC mp_obj_t bitmap_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t val
186186
return mp_const_none;
187187
}
188188

189-
//| def blit(
190-
//| self,
191-
//| x: int,
192-
//| y: int,
193-
//| source_bitmap: Bitmap,
194-
//| *,
195-
//| x1: int,
196-
//| y1: int,
197-
//| x2: int,
198-
//| y2: int,
199-
//| skip_index: int
200-
//| ) -> None:
201-
//| """Inserts the source_bitmap region defined by rectangular boundaries
202-
//| (x1,y1) and (x2,y2) into the bitmap at the specified (x,y) location.
203-
//|
204-
//| :param int x: Horizontal pixel location in bitmap where source_bitmap upper-left
205-
//| corner will be placed
206-
//| :param int y: Vertical pixel location in bitmap where source_bitmap upper-left
207-
//| corner will be placed
208-
//| :param bitmap source_bitmap: Source bitmap that contains the graphical region to be copied
209-
//| :param int x1: Minimum x-value for rectangular bounding box to be copied from the source bitmap
210-
//| :param int y1: Minimum y-value for rectangular bounding box to be copied from the source bitmap
211-
//| :param int x2: Maximum x-value (exclusive) for rectangular bounding box to be copied from the source bitmap
212-
//| :param int y2: Maximum y-value (exclusive) for rectangular bounding box to be copied from the source bitmap
213-
//| :param int skip_index: bitmap palette index in the source that will not be copied,
214-
//| set to None to copy all pixels"""
215-
//| ...
216-
STATIC mp_obj_t displayio_bitmap_obj_blit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
217-
enum {ARG_x, ARG_y, ARG_source, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_skip_index};
218-
static const mp_arg_t allowed_args[] = {
219-
{MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} },
220-
{MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} },
221-
{MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
222-
{MP_QSTR_x1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
223-
{MP_QSTR_y1, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
224-
{MP_QSTR_x2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->width
225-
{MP_QSTR_y2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->height
226-
{MP_QSTR_skip_index, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
227-
};
228-
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
229-
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
230-
231-
displayio_bitmap_t *self = MP_OBJ_TO_PTR(pos_args[0]);
232-
check_for_deinit(self);
233-
234-
// Check x,y are within self (target) bitmap boundary
235-
int16_t x = mp_arg_validate_int_range(args[ARG_x].u_int, 0, MAX(0, self->width - 1), MP_QSTR_x);
236-
int16_t y = mp_arg_validate_int_range(args[ARG_y].u_int, 0, MAX(0, self->height - 1), MP_QSTR_y);
237-
238-
displayio_bitmap_t *source = mp_arg_validate_type(args[ARG_source].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap);
239-
240-
241-
// ensure that the target bitmap (self) has at least as many `bits_per_value` as the source
242-
if (self->bits_per_value < source->bits_per_value) {
243-
mp_raise_ValueError(translate("source palette too large"));
244-
}
245-
246-
// Check x1,y1,x2,y2 are within source bitmap boundary
247-
int16_t x1 = mp_arg_validate_int_range(args[ARG_x1].u_int, 0, MAX(0, source->width - 1), MP_QSTR_x1);
248-
int16_t y1 = mp_arg_validate_int_range(args[ARG_y1].u_int, 0, MAX(0, source->height - 1), MP_QSTR_y1);
249-
int16_t x2, y2;
250-
// if x2 or y2 is None, then set as the maximum size of the source bitmap
251-
if (args[ARG_x2].u_obj == mp_const_none) {
252-
x2 = source->width;
253-
} else {
254-
x2 = mp_arg_validate_int_range(mp_obj_get_int(args[ARG_x2].u_obj), 0, source->width, MP_QSTR_x2);
255-
}
256-
// int16_t y2;
257-
if (args[ARG_y2].u_obj == mp_const_none) {
258-
y2 = source->height;
259-
} else {
260-
y2 = mp_arg_validate_int_range(mp_obj_get_int(args[ARG_y2].u_obj), 0, source->height, MP_QSTR_y2);
261-
}
262-
263-
// Ensure x1 < x2 and y1 < y2
264-
if (x1 > x2) {
265-
int16_t temp = x2;
266-
x2 = x1;
267-
x1 = temp;
268-
}
269-
if (y1 > y2) {
270-
int16_t temp = y2;
271-
y2 = y1;
272-
y1 = temp;
273-
}
274-
275-
uint32_t skip_index;
276-
bool skip_index_none; // flag whether skip_value was None
277-
278-
if (args[ARG_skip_index].u_obj == mp_const_none) {
279-
skip_index = 0;
280-
skip_index_none = true;
281-
} else {
282-
skip_index = mp_obj_get_int(args[ARG_skip_index].u_obj);
283-
skip_index_none = false;
284-
}
285-
286-
common_hal_displayio_bitmap_blit(self, x, y, source, x1, y1, x2, y2, skip_index, skip_index_none);
287-
288-
return mp_const_none;
289-
}
290-
MP_DEFINE_CONST_FUN_OBJ_KW(displayio_bitmap_blit_obj, 1, displayio_bitmap_obj_blit);
291-
292189
//| def fill(self, value: int) -> None:
293190
//| """Fills the bitmap with the supplied palette index value."""
294191
//| ...
@@ -363,7 +260,6 @@ MP_DEFINE_CONST_FUN_OBJ_1(displayio_bitmap_deinit_obj, displayio_bitmap_obj_dein
363260
STATIC const mp_rom_map_elem_t displayio_bitmap_locals_dict_table[] = {
364261
{ MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_bitmap_height_obj) },
365262
{ MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_bitmap_width_obj) },
366-
{ MP_ROM_QSTR(MP_QSTR_blit), MP_ROM_PTR(&displayio_bitmap_blit_obj) },
367263
{ MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&displayio_bitmap_fill_obj) },
368264
{ MP_ROM_QSTR(MP_QSTR_dirty), MP_ROM_PTR(&displayio_bitmap_dirty_obj) },
369265
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&displayio_bitmap_deinit_obj) },

shared-bindings/displayio/Bitmap.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,6 @@ uint16_t common_hal_displayio_bitmap_get_height(displayio_bitmap_t *self);
4242
uint16_t common_hal_displayio_bitmap_get_width(displayio_bitmap_t *self);
4343
uint32_t common_hal_displayio_bitmap_get_bits_per_value(displayio_bitmap_t *self);
4444
void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *bitmap, int16_t x, int16_t y, uint32_t value);
45-
void common_hal_displayio_bitmap_blit(displayio_bitmap_t *self, int16_t x, int16_t y, displayio_bitmap_t *source,
46-
int16_t x1, int16_t y1, int16_t x2, int16_t y2,
47-
uint32_t skip_index, bool skip_index_none);
4845
uint32_t common_hal_displayio_bitmap_get_pixel(displayio_bitmap_t *bitmap, int16_t x, int16_t y);
4946
void common_hal_displayio_bitmap_fill(displayio_bitmap_t *bitmap, uint32_t value);
5047
int common_hal_displayio_bitmap_get_buffer(displayio_bitmap_t *self, mp_buffer_info_t *bufinfo, mp_uint_t flags);

shared-module/bitmaptools/__init__.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,3 +982,71 @@ void common_hal_bitmaptools_draw_circle(displayio_bitmap_t *destination,
982982

983983
draw_circle(destination, x, y, radius, value);
984984
}
985+
986+
void common_hal_bitmaptools_blit(displayio_bitmap_t *destination, displayio_bitmap_t *source, int16_t x, int16_t y,
987+
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,
988+
bool skip_dest_index_none) {
989+
990+
if (destination->read_only) {
991+
mp_raise_RuntimeError(translate("Read-only"));
992+
}
993+
// Copy region of "source" bitmap into "destination" bitmap at location x,y in the "destination"
994+
// If skip_value is encountered in the source bitmap, it will not be copied.
995+
// If skip_value is `None`, then all pixels are copied.
996+
// This function assumes input checks were performed for pixel index entries.
997+
998+
// Update the dirty area
999+
int16_t dirty_x_max = (x + (x2 - x1));
1000+
if (dirty_x_max > destination->width) {
1001+
dirty_x_max = destination->width;
1002+
}
1003+
int16_t dirty_y_max = y + (y2 - y1);
1004+
if (dirty_y_max > destination->height) {
1005+
dirty_y_max = destination->height;
1006+
}
1007+
1008+
displayio_area_t a = { x, y, dirty_x_max, dirty_y_max, NULL};
1009+
displayio_bitmap_set_dirty_area(destination, &a);
1010+
1011+
bool x_reverse = false;
1012+
bool y_reverse = false;
1013+
1014+
// Add reverse direction option to protect blitting of destination bitmap back into destination bitmap
1015+
if (x > x1) {
1016+
x_reverse = true;
1017+
}
1018+
if (y > y1) {
1019+
y_reverse = true;
1020+
}
1021+
1022+
// simplest version - use internal functions for get/set pixels
1023+
for (int16_t i = 0; i < (x2 - x1); i++) {
1024+
1025+
const int xs_index = x_reverse ? ((x2) - i - 1) : x1 + i; // x-index into the source bitmap
1026+
const int xd_index = x_reverse ? ((x + (x2 - x1)) - i - 1) : x + i; // x-index into the destination bitmap
1027+
1028+
if ((xd_index >= 0) && (xd_index < destination->width)) {
1029+
for (int16_t j = 0; j < (y2 - y1); j++) {
1030+
1031+
const int ys_index = y_reverse ? ((y2) - j - 1) : y1 + j; // y-index into the source bitmap
1032+
const int yd_index = y_reverse ? ((y + (y2 - y1)) - j - 1) : y + j; // y-index into the destination bitmap
1033+
1034+
if ((yd_index >= 0) && (yd_index < destination->height)) {
1035+
uint32_t value = common_hal_displayio_bitmap_get_pixel(source, xs_index, ys_index);
1036+
if (skip_dest_index_none) { // if skip_dest_index is none, then only check source skip
1037+
if ((skip_source_index_none) || (value != skip_source_index)) { // write if skip_value_none is True
1038+
displayio_bitmap_write_pixel(destination, xd_index, yd_index, value);
1039+
}
1040+
} else { // check dest_value index against skip_dest_index and skip if they match
1041+
uint32_t dest_value = common_hal_displayio_bitmap_get_pixel(destination, xd_index, yd_index);
1042+
if (dest_value != skip_dest_index) {
1043+
if ((skip_source_index_none) || (value != skip_source_index)) { // write if skip_value_none is True
1044+
displayio_bitmap_write_pixel(destination, xd_index, yd_index, value);
1045+
}
1046+
}
1047+
}
1048+
}
1049+
}
1050+
}
1051+
}
1052+
}

0 commit comments

Comments
 (0)