Skip to content

Commit bb71f8c

Browse files
authored
Merge pull request micropython#5544 from jepler/alphablend
bitmaptools: add alphablend
2 parents e5c7ff7 + 6790f95 commit bb71f8c

File tree

8 files changed

+166
-5
lines changed

8 files changed

+166
-5
lines changed

locale/circuitpython.pot

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,10 @@ msgstr ""
552552
msgid "Bit depth must be multiple of 8."
553553
msgstr ""
554554

555+
#: shared-bindings/bitmaptools/__init__.c
556+
msgid "Bitmap size and bits per value must match"
557+
msgstr ""
558+
555559
#: supervisor/shared/safe_mode.c
556560
msgid "Boot device must be first device (interface #0)."
557561
msgstr ""
@@ -1071,6 +1075,14 @@ msgstr ""
10711075
msgid "Firmware image is invalid"
10721076
msgstr ""
10731077

1078+
#: shared-bindings/bitmaptools/__init__.c
1079+
msgid "For L8 colorspace, input bitmap must have 8 bits per pixel"
1080+
msgstr ""
1081+
1082+
#: shared-bindings/bitmaptools/__init__.c
1083+
msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel"
1084+
msgstr ""
1085+
10741086
#: ports/cxd56/common-hal/camera/Camera.c
10751087
msgid "Format not supported"
10761088
msgstr ""
@@ -2390,6 +2402,10 @@ msgstr ""
23902402
msgid "Unsupported baudrate"
23912403
msgstr ""
23922404

2405+
#: shared-bindings/bitmaptools/__init__.c
2406+
msgid "Unsupported colorspace"
2407+
msgstr ""
2408+
23932409
#: shared-module/displayio/display_core.c
23942410
msgid "Unsupported display bus type"
23952411
msgstr ""

ports/atmel-samd/boards/pybadge/mpconfigboard.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ EXTERNAL_FLASH_DEVICES = GD25Q16C
1111
LONGINT_IMPL = MPZ
1212

1313
CIRCUITPY_AESIO = 0
14+
CIRCUITPY_FRAMEBUFFERIO = 0
1415
CIRCUITPY_GAMEPADSHIFT = 1
1516
CIRCUITPY_GIFIO = 0
1617
CIRCUITPY_STAGE = 1

ports/atmel-samd/boards/pygamer/mpconfigboard.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ EXTERNAL_FLASH_DEVICES = GD25Q64C
1111
LONGINT_IMPL = MPZ
1212

1313
CIRCUITPY_AESIO = 0
14+
CIRCUITPY_FRAMEBUFFERIO = 0
1415
CIRCUITPY_GAMEPADSHIFT = 1
1516
CIRCUITPY_GIFIO = 0
1617
CIRCUITPY_STAGE = 1

ports/atmel-samd/mpconfigport.mk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ CIRCUITPY_TOUCHIO_USE_NATIVE = 0
103103
CIRCUITPY_ALARM ?= 0
104104
CIRCUITPY_PS2IO ?= 1
105105
CIRCUITPY_SAMD ?= 1
106-
CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_FULL_BUILD)
107106
CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_FULL_BUILD)
107+
CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_FRAMEBUFFERIO)
108108
CIRCUITPY_WATCHDOG ?= 1
109109

110110
endif # samd51
@@ -122,8 +122,8 @@ CIRCUITPY_TOUCHIO_USE_NATIVE = 0
122122

123123
CIRCUITPY_PS2IO ?= 1
124124
CIRCUITPY_SAMD ?= 1
125-
CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_FULL_BUILD)
126125
CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_FULL_BUILD)
126+
CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_FRAMEBUFFERIO)
127127

128128
endif # same51
129129
######################################################################

ports/stm/boards/thunderpack_v11/mpconfigboard.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ LD_COMMON = boards/common_nvm.ld
1717
LD_FILE = boards/STM32F411_nvm.ld
1818

1919
CIRCUITPY_AESIO = 0
20+
CIRCUITPY_BITMAPTOOLS = 0
2021
CIRCUITPY_BLEIO_HCI = 0
2122
CIRCUITPY_VECTORIO = 0
2223
CIRCUITPY_ULAB = 0

shared-bindings/bitmaptools/__init__.c

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,83 @@ STATIC mp_obj_t bitmaptools_obj_rotozoom(size_t n_args, const mp_obj_t *pos_args
244244
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_rotozoom_obj, 0, bitmaptools_obj_rotozoom);
245245
// requires at least 2 arguments (destination bitmap and source bitmap)
246246

247+
//|
248+
//| def alphablend(dest_bitmap, source_bitmap_1, source_bitmap_2, colorspace: displayio.Colorspace, factor1: float=.5, factor2: float=None):
249+
//| """Alpha blend the two source bitmaps into the destination.
250+
//|
251+
//| It is permitted for the destination bitmap to be one of the two
252+
//| source bitmaps.
253+
//|
254+
//| :param bitmap dest_bitmap: Destination bitmap that will be written into
255+
//| :param bitmap source_bitmap_1: The first source bitmap
256+
//| :param bitmap source_bitmap_2: The second source bitmap
257+
//| :param float factor1: The proportion of bitmap 1 to mix in
258+
//| :param float factor2: The proportion of bitmap 2 to mix in. If specified as `None`, ``1-factor1`` is used. Usually the proportions should sum to 1.
259+
//| :param displayio.Colorspace colorspace: The colorspace of the bitmaps. They must all have the same colorspace. Only the following colorspaces are permitted: ``L8``, ``RGB565``, ``RGB565_SWAPPED``, ``BGR565`` and ``BGR565_SWAPPED``.
260+
//|
261+
//| For the L8 colorspace, the bitmaps must have a bits-per-value of 8.
262+
//| For the RGB colorspaces, they must have a bits-per-value of 16."""
263+
//|
264+
265+
STATIC mp_obj_t bitmaptools_alphablend(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
266+
enum {ARG_dest_bitmap, ARG_source_bitmap_1, ARG_source_bitmap_2, ARG_colorspace, ARG_factor_1, ARG_factor_2};
267+
268+
static const mp_arg_t allowed_args[] = {
269+
{MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ},
270+
{MP_QSTR_source_bitmap_1, MP_ARG_REQUIRED | MP_ARG_OBJ},
271+
{MP_QSTR_source_bitmap_2, MP_ARG_REQUIRED | MP_ARG_OBJ},
272+
{MP_QSTR_colorspace, MP_ARG_REQUIRED | MP_ARG_OBJ},
273+
{MP_QSTR_factor_1, MP_ARG_OBJ, {.u_obj = MP_ROM_NONE}},
274+
{MP_QSTR_factor_2, MP_ARG_OBJ, {.u_obj = MP_ROM_NONE}},
275+
};
276+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
277+
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
278+
279+
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
280+
displayio_bitmap_t *source1 = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_source_bitmap_1].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap_1)); // the first source bitmap
281+
displayio_bitmap_t *source2 = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_source_bitmap_2].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap_2)); // the second source bitmap
282+
283+
float factor1 = (args[ARG_factor_1].u_obj == mp_const_none) ? .5f : mp_obj_float_get(args[ARG_factor_1].u_obj);
284+
float factor2 = (args[ARG_factor_2].u_obj == mp_const_none) ? 1 - factor1 : mp_obj_float_get(args[ARG_factor_2].u_obj);
285+
286+
displayio_colorspace_t colorspace = (displayio_colorspace_t)cp_enum_value(&displayio_colorspace_type, args[ARG_colorspace].u_obj);
287+
288+
if (destination->width != source1->width
289+
|| destination->height != source1->height
290+
|| destination->bits_per_value != source1->bits_per_value
291+
|| destination->width != source2->width
292+
|| destination->height != source2->height
293+
|| destination->bits_per_value != source2->bits_per_value
294+
) {
295+
mp_raise_ValueError(translate("Bitmap size and bits per value must match"));
296+
}
297+
298+
switch (colorspace) {
299+
case DISPLAYIO_COLORSPACE_L8:
300+
if (destination->bits_per_value != 8) {
301+
mp_raise_ValueError(translate("For L8 colorspace, input bitmap must have 8 bits per pixel"));
302+
}
303+
break;
304+
305+
case DISPLAYIO_COLORSPACE_RGB565:
306+
case DISPLAYIO_COLORSPACE_RGB565_SWAPPED:
307+
case DISPLAYIO_COLORSPACE_BGR565:
308+
case DISPLAYIO_COLORSPACE_BGR565_SWAPPED:
309+
if (destination->bits_per_value != 16) {
310+
mp_raise_ValueError(translate("For RGB colorspaces, input bitmap must have 16 bits per pixel"));
311+
}
312+
break;
313+
314+
default:
315+
mp_raise_ValueError(translate("Unsupported colorspace"));
316+
}
317+
318+
common_hal_bitmaptools_alphablend(destination, source1, source2, colorspace, factor1, factor2);
319+
320+
return mp_const_none;
321+
}
322+
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_alphablend_obj, 0, bitmaptools_alphablend);
323+
247324
//|
248325
//| def fill_region(
249326
//| dest_bitmap: displayio.Bitmap,
@@ -276,7 +353,7 @@ STATIC mp_obj_t bitmaptools_obj_fill_region(size_t n_args, const mp_obj_t *pos_a
276353
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
277354
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
278355

279-
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
356+
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
280357

281358
uint32_t value, color_depth;
282359
value = args[ARG_value].u_int;
@@ -327,7 +404,7 @@ STATIC mp_obj_t bitmaptools_obj_boundary_fill(size_t n_args, const mp_obj_t *pos
327404
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
328405
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
329406

330-
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
407+
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
331408

332409
uint32_t fill_color_value, color_depth;
333410
fill_color_value = args[ARG_fill_color_value].u_int;
@@ -391,7 +468,7 @@ STATIC mp_obj_t bitmaptools_obj_draw_line(size_t n_args, const mp_obj_t *pos_arg
391468
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
392469
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
393470

394-
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
471+
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
395472

396473
uint32_t value, color_depth;
397474
value = args[ARG_value].u_int;
@@ -573,6 +650,7 @@ STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = {
573650
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&bitmaptools_readinto_obj) },
574651
{ MP_ROM_QSTR(MP_QSTR_rotozoom), MP_ROM_PTR(&bitmaptools_rotozoom_obj) },
575652
{ MP_ROM_QSTR(MP_QSTR_arrayblit), MP_ROM_PTR(&bitmaptools_arrayblit_obj) },
653+
{ MP_ROM_QSTR(MP_QSTR_alphablend), MP_ROM_PTR(&bitmaptools_alphablend_obj) },
576654
{ MP_ROM_QSTR(MP_QSTR_fill_region), MP_ROM_PTR(&bitmaptools_fill_region_obj) },
577655
{ MP_ROM_QSTR(MP_QSTR_boundary_fill), MP_ROM_PTR(&bitmaptools_boundary_fill_obj) },
578656
{ MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) },

shared-bindings/bitmaptools/__init__.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#define MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H
2929

3030
#include "shared-module/displayio/Bitmap.h"
31+
#include "shared-bindings/displayio/__init__.h"
3132
#include "py/obj.h"
3233
#include "extmod/vfs_fat.h"
3334

@@ -58,4 +59,6 @@ void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination,
5859
void common_hal_bitmaptools_readinto(displayio_bitmap_t *self, pyb_file_obj_t *file, int element_size, int bits_per_pixel, bool reverse_pixels_in_word, bool swap_bytes, bool reverse_rows);
5960
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);
6061

62+
void common_hal_bitmaptools_alphablend(displayio_bitmap_t *destination, displayio_bitmap_t *source1, displayio_bitmap_t *source2, displayio_colorspace_t colorspace, float factor1, float factor2);
63+
6164
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H

shared-module/bitmaptools/__init__.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,3 +602,64 @@ void common_hal_bitmaptools_readinto(displayio_bitmap_t *self, pyb_file_obj_t *f
602602
}
603603
}
604604
}
605+
606+
void common_hal_bitmaptools_alphablend(displayio_bitmap_t *dest, displayio_bitmap_t *source1, displayio_bitmap_t *source2, displayio_colorspace_t colorspace, float factor1, float factor2) {
607+
displayio_area_t a = {0, 0, dest->width, dest->height};
608+
displayio_bitmap_set_dirty_area(dest, &a);
609+
610+
int ifactor1 = (int)(factor1 * 256);
611+
int ifactor2 = (int)(factor2 * 256);
612+
613+
if (colorspace == DISPLAYIO_COLORSPACE_L8) {
614+
for (int y = 0; y < dest->height; y++) {
615+
uint8_t *dptr = (uint8_t *)(dest->data + y * dest->stride);
616+
uint8_t *sptr1 = (uint8_t *)(source1->data + y * source1->stride);
617+
uint8_t *sptr2 = (uint8_t *)(source2->data + y * source2->stride);
618+
for (int x = 0; x < dest->width; x++) {
619+
// This is round(l1*f1 + l2*f2) & clip to range in fixed-point
620+
int pixel = (*sptr1++ *ifactor1 + *sptr2++ *ifactor2 + 128) / 256;
621+
*dptr++ = MIN(255, MAX(0, pixel));
622+
}
623+
}
624+
} else {
625+
bool swap = (colorspace == DISPLAYIO_COLORSPACE_RGB565_SWAPPED) || (colorspace == DISPLAYIO_COLORSPACE_BGR565_SWAPPED);
626+
for (int y = 0; y < dest->height; y++) {
627+
uint16_t *dptr = (uint16_t *)(dest->data + y * dest->stride);
628+
uint16_t *sptr1 = (uint16_t *)(source1->data + y * source1->stride);
629+
uint16_t *sptr2 = (uint16_t *)(source2->data + y * source2->stride);
630+
for (int x = 0; x < dest->width; x++) {
631+
int spix1 = *sptr1++;
632+
int spix2 = *sptr2++;
633+
634+
if (swap) {
635+
spix1 = __builtin_bswap16(spix1);
636+
spix2 = __builtin_bswap16(spix2);
637+
}
638+
const int r_mask = 0xf800; // (or b mask, if BGR)
639+
const int g_mask = 0x07e0;
640+
const int b_mask = 0x001f; // (or r mask, if BGR)
641+
642+
// This is round(r1*f1 + r2*f2) & clip to range in fixed-point
643+
// but avoiding shifting it down to start at bit 0
644+
int r = ((spix1 & r_mask) * ifactor1
645+
+ (spix2 & r_mask) * ifactor2 + r_mask / 2) / 256;
646+
r = MIN(r_mask, MAX(0, r)) & r_mask;
647+
648+
// ditto
649+
int g = ((spix1 & g_mask) * ifactor1
650+
+ (spix2 & g_mask) * ifactor2 + g_mask / 2) / 256;
651+
g = MIN(g_mask, MAX(0, g)) & g_mask;
652+
653+
int b = ((spix1 & b_mask) * ifactor1
654+
+ (spix2 & b_mask) * ifactor2 + b_mask / 2) / 256;
655+
b = MIN(b_mask, MAX(0, b)) & b_mask;
656+
657+
uint16_t pixel = r | g | b;
658+
if (swap) {
659+
pixel = __builtin_bswap16(pixel);
660+
}
661+
*dptr++ = pixel;
662+
}
663+
}
664+
}
665+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy