bitmaptools: add alphablend
This blends two "565"-format bitmaps, including byteswapped ones. All the bitmaps have to have the same memory format. The routine takes about 63ms on a Kaluga when operating on 320x240 bitmaps. Of course, displaying the bitmap also takes time. There's untested code for the L8 (8-bit greyscale) case. This can be enabled once gifio is merged.
This commit is contained in:
parent
102af55e0a
commit
2ec2761ce0
|
@ -552,6 +552,10 @@ msgstr ""
|
||||||
msgid "Bit depth must be multiple of 8."
|
msgid "Bit depth must be multiple of 8."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: shared-bindings/bitmaptools/__init__.c
|
||||||
|
msgid "Bitmap size and bits per value must match"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: supervisor/shared/safe_mode.c
|
#: supervisor/shared/safe_mode.c
|
||||||
msgid "Boot device must be first device (interface #0)."
|
msgid "Boot device must be first device (interface #0)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1071,6 +1075,14 @@ msgstr ""
|
||||||
msgid "Firmware image is invalid"
|
msgid "Firmware image is invalid"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: shared-bindings/bitmaptools/__init__.c
|
||||||
|
msgid "For L8 colorspace, input bitmap must have 8 bits per pixel"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: shared-bindings/bitmaptools/__init__.c
|
||||||
|
msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: ports/cxd56/common-hal/camera/Camera.c
|
#: ports/cxd56/common-hal/camera/Camera.c
|
||||||
msgid "Format not supported"
|
msgid "Format not supported"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2390,6 +2402,10 @@ msgstr ""
|
||||||
msgid "Unsupported baudrate"
|
msgid "Unsupported baudrate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: shared-bindings/bitmaptools/__init__.c
|
||||||
|
msgid "Unsupported colorspace"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: shared-module/displayio/display_core.c
|
#: shared-module/displayio/display_core.c
|
||||||
msgid "Unsupported display bus type"
|
msgid "Unsupported display bus type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -244,6 +244,85 @@ STATIC mp_obj_t bitmaptools_obj_rotozoom(size_t n_args, const mp_obj_t *pos_args
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_rotozoom_obj, 0, bitmaptools_obj_rotozoom);
|
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_rotozoom_obj, 0, bitmaptools_obj_rotozoom);
|
||||||
// requires at least 2 arguments (destination bitmap and source bitmap)
|
// requires at least 2 arguments (destination bitmap and source bitmap)
|
||||||
|
|
||||||
|
//|
|
||||||
|
//| def alphablend(dest_bitmap, source_bitmap_1, source_bitmap_2, colorspace: displayio.Colorspace, factor1: float=.5, factor2: float=None):
|
||||||
|
//| """Alpha blend the two source bitmaps into the destination.
|
||||||
|
//|
|
||||||
|
//| It is permitted for the destination bitmap to be one of the two
|
||||||
|
//| source bitmaps.
|
||||||
|
//|
|
||||||
|
//| :param bitmap dest_bitmap: Destination bitmap that will be written into
|
||||||
|
//| :param bitmap source_bitmap_1: The first source bitmap
|
||||||
|
//| :param bitmap source_bitmap_2: The second source bitmap
|
||||||
|
//| :param float factor1: The proportion of bitmap 1 to mix in
|
||||||
|
//| :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.
|
||||||
|
//| :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``.
|
||||||
|
//|
|
||||||
|
//| For the L8 colorspace, the bitmaps must have a bits-per-value of 8.
|
||||||
|
//| For the RGB colorspaces, they must have a bits-per-value of 16."""
|
||||||
|
//|
|
||||||
|
|
||||||
|
STATIC mp_obj_t bitmaptools_alphablend(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
|
enum {ARG_dest_bitmap, ARG_source_bitmap_1, ARG_source_bitmap_2, ARG_colorspace, ARG_factor_1, ARG_factor_2};
|
||||||
|
|
||||||
|
static const mp_arg_t allowed_args[] = {
|
||||||
|
{MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ},
|
||||||
|
{MP_QSTR_source_bitmap_1, MP_ARG_REQUIRED | MP_ARG_OBJ},
|
||||||
|
{MP_QSTR_source_bitmap_2, MP_ARG_REQUIRED | MP_ARG_OBJ},
|
||||||
|
{MP_QSTR_colorspace, MP_ARG_REQUIRED | MP_ARG_OBJ},
|
||||||
|
{MP_QSTR_factor_1, MP_ARG_OBJ, {.u_obj = MP_ROM_NONE}},
|
||||||
|
{MP_QSTR_factor_2, MP_ARG_OBJ, {.u_obj = MP_ROM_NONE}},
|
||||||
|
};
|
||||||
|
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
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
float factor1 = (args[ARG_factor_1].u_obj == mp_const_none) ? .5f : mp_obj_float_get(args[ARG_factor_1].u_obj);
|
||||||
|
float factor2 = (args[ARG_factor_2].u_obj == mp_const_none) ? 1 - factor1 : mp_obj_float_get(args[ARG_factor_2].u_obj);
|
||||||
|
|
||||||
|
displayio_colorspace_t colorspace = (displayio_colorspace_t)cp_enum_value(&displayio_colorspace_type, args[ARG_colorspace].u_obj);
|
||||||
|
|
||||||
|
if (destination->width != source1->width
|
||||||
|
|| destination->height != source1->height
|
||||||
|
|| destination->bits_per_value != source1->bits_per_value
|
||||||
|
|| destination->width != source2->width
|
||||||
|
|| destination->height != source2->height
|
||||||
|
|| destination->bits_per_value != source2->bits_per_value
|
||||||
|
) {
|
||||||
|
mp_raise_ValueError(translate("Bitmap size and bits per value must match"));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (colorspace) {
|
||||||
|
#if 0
|
||||||
|
case DISPLAYIO_COLORSPACE_L8:
|
||||||
|
if (destination->bits_per_value != 8) {
|
||||||
|
mp_raise_ValueError(translate("For L8 colorspace, input bitmap must have 8 bits per pixel"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case DISPLAYIO_COLORSPACE_RGB565:
|
||||||
|
case DISPLAYIO_COLORSPACE_RGB565_SWAPPED:
|
||||||
|
case DISPLAYIO_COLORSPACE_BGR565:
|
||||||
|
case DISPLAYIO_COLORSPACE_BGR565_SWAPPED:
|
||||||
|
if (destination->bits_per_value != 16) {
|
||||||
|
mp_raise_ValueError(translate("For RGB colorspaces, input bitmap must have 16 bits per pixel"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
mp_raise_ValueError(translate("Unsupported colorspace"));
|
||||||
|
}
|
||||||
|
|
||||||
|
common_hal_bitmaptools_alphablend(destination, source1, source2, colorspace, factor1, factor2);
|
||||||
|
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_alphablend_obj, 0, bitmaptools_alphablend);
|
||||||
|
|
||||||
//|
|
//|
|
||||||
//| def fill_region(
|
//| def fill_region(
|
||||||
//| dest_bitmap: displayio.Bitmap,
|
//| dest_bitmap: displayio.Bitmap,
|
||||||
|
@ -276,7 +355,7 @@ STATIC mp_obj_t bitmaptools_obj_fill_region(size_t n_args, const mp_obj_t *pos_a
|
||||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
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);
|
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(args[ARG_dest_bitmap].u_obj); // the destination bitmap
|
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
|
||||||
|
|
||||||
uint32_t value, color_depth;
|
uint32_t value, color_depth;
|
||||||
value = args[ARG_value].u_int;
|
value = args[ARG_value].u_int;
|
||||||
|
@ -327,7 +406,7 @@ STATIC mp_obj_t bitmaptools_obj_boundary_fill(size_t n_args, const mp_obj_t *pos
|
||||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
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);
|
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
|
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;
|
uint32_t fill_color_value, color_depth;
|
||||||
fill_color_value = args[ARG_fill_color_value].u_int;
|
fill_color_value = args[ARG_fill_color_value].u_int;
|
||||||
|
@ -391,7 +470,7 @@ STATIC mp_obj_t bitmaptools_obj_draw_line(size_t n_args, const mp_obj_t *pos_arg
|
||||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
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);
|
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(args[ARG_dest_bitmap].u_obj); // the destination bitmap
|
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
|
||||||
|
|
||||||
uint32_t value, color_depth;
|
uint32_t value, color_depth;
|
||||||
value = args[ARG_value].u_int;
|
value = args[ARG_value].u_int;
|
||||||
|
@ -573,6 +652,7 @@ STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&bitmaptools_readinto_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&bitmaptools_readinto_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_rotozoom), MP_ROM_PTR(&bitmaptools_rotozoom_obj) },
|
{ 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_arrayblit), MP_ROM_PTR(&bitmaptools_arrayblit_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_alphablend), MP_ROM_PTR(&bitmaptools_alphablend_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_fill_region), MP_ROM_PTR(&bitmaptools_fill_region_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_boundary_fill), MP_ROM_PTR(&bitmaptools_boundary_fill_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) },
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#define MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H
|
#define MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H
|
||||||
|
|
||||||
#include "shared-module/displayio/Bitmap.h"
|
#include "shared-module/displayio/Bitmap.h"
|
||||||
|
#include "shared-bindings/displayio/__init__.h"
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include "extmod/vfs_fat.h"
|
#include "extmod/vfs_fat.h"
|
||||||
|
|
||||||
|
@ -58,4 +59,6 @@ void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination,
|
||||||
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);
|
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);
|
||||||
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);
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H
|
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H
|
||||||
|
|
|
@ -602,3 +602,67 @@ void common_hal_bitmaptools_readinto(displayio_bitmap_t *self, pyb_file_obj_t *f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
displayio_area_t a = {0, 0, dest->width, dest->height};
|
||||||
|
displayio_bitmap_set_dirty_area(dest, &a);
|
||||||
|
|
||||||
|
int ifactor1 = (int)(factor1 * 256);
|
||||||
|
int ifactor2 = (int)(factor2 * 256);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (colorspace == DISPLAYIO_COLORSPACE_L8) {
|
||||||
|
for (int y = 0; y < dest->height; y++) {
|
||||||
|
uint8_t *dptr = (uint8_t *)(dest->data + y * dest->stride);
|
||||||
|
uint8_t *sptr1 = (uint8_t *)(source1->data + y * source1->stride);
|
||||||
|
uint8_t *sptr2 = (uint8_t *)(source2->data + y * source2->stride);
|
||||||
|
for (int x = 0; x < dest->width; x++) {
|
||||||
|
// This is round(l1*f1 + l2*f2) & clip to range in fixed-point
|
||||||
|
int pixel = (*sptr1++ *ifactor1 + *sptr2++ *ifactor2 + 128) / 256;
|
||||||
|
*dptr++ = MIN(255, MAX(0, pixel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
bool swap = (colorspace == DISPLAYIO_COLORSPACE_RGB565_SWAPPED) || (colorspace == DISPLAYIO_COLORSPACE_BGR565_SWAPPED);
|
||||||
|
for (int y = 0; y < dest->height; y++) {
|
||||||
|
uint16_t *dptr = (uint16_t *)(dest->data + y * dest->stride);
|
||||||
|
uint16_t *sptr1 = (uint16_t *)(source1->data + y * source1->stride);
|
||||||
|
uint16_t *sptr2 = (uint16_t *)(source2->data + y * source2->stride);
|
||||||
|
for (int x = 0; x < dest->width; x++) {
|
||||||
|
int spix1 = *sptr1++;
|
||||||
|
int spix2 = *sptr2++;
|
||||||
|
|
||||||
|
if (swap) {
|
||||||
|
spix1 = __builtin_bswap16(spix1);
|
||||||
|
spix2 = __builtin_bswap16(spix2);
|
||||||
|
}
|
||||||
|
const int r_mask = 0xf800; // (or b mask, if BGR)
|
||||||
|
const int g_mask = 0x07e0;
|
||||||
|
const int b_mask = 0x001f; // (or r mask, if BGR)
|
||||||
|
|
||||||
|
// This is round(r1*f1 + r2*f2) & clip to range in fixed-point
|
||||||
|
// but avoiding shifting it down to start at bit 0
|
||||||
|
int r = ((spix1 & r_mask) * ifactor1
|
||||||
|
+ (spix2 & r_mask) * ifactor2 + r_mask / 2) / 256;
|
||||||
|
r = MIN(r_mask, MAX(0, r)) & r_mask;
|
||||||
|
|
||||||
|
// ditto
|
||||||
|
int g = ((spix1 & g_mask) * ifactor1
|
||||||
|
+ (spix2 & g_mask) * ifactor2 + g_mask / 2) / 256;
|
||||||
|
g = MIN(g_mask, MAX(0, g)) & g_mask;
|
||||||
|
|
||||||
|
int b = ((spix1 & b_mask) * ifactor1
|
||||||
|
+ (spix2 & b_mask) * ifactor2 + b_mask / 2) / 256;
|
||||||
|
b = MIN(b_mask, MAX(0, b)) & b_mask;
|
||||||
|
|
||||||
|
uint16_t pixel = r | g | b;
|
||||||
|
if (swap) {
|
||||||
|
pixel = __builtin_bswap16(pixel);
|
||||||
|
}
|
||||||
|
*dptr++ = pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue