diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 6599f49ae1a63..801c8f5709495 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -216,7 +216,8 @@ msgstr "" msgid "%q must be of type %q, %q, or %q, not %q" msgstr "" -#: py/argcheck.c shared-module/synthio/__init__.c +#: py/argcheck.c shared-bindings/bitmapfilter/__init__.c +#: shared-module/synthio/__init__.c msgid "%q must be of type %q, not %q" msgstr "" @@ -896,10 +897,6 @@ msgstr "" msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Destination bitmap too small to contain image" -msgstr "" - #: shared-bindings/audiobusio/PDMIn.c msgid "Destination capacity is smaller than destination_length." msgstr "" @@ -2539,6 +2536,10 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "bitmap sizes must match" msgstr "" @@ -3879,10 +3880,6 @@ msgstr "" msgid "parameters must be registers in sequence r0 to r3" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "pixel coordinates out of bounds" -msgstr "" - #: extmod/vfs_posix_file.c msgid "poll on file not available on win32" msgstr "" @@ -4277,6 +4274,10 @@ msgstr "" msgid "unsupported Xtensa instruction '%s' with %d arguments" msgstr "" +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" +msgstr "" + #: shared-module/gifio/GifWriter.c msgid "unsupported colorspace for GifWriter" msgstr "" @@ -4323,6 +4324,16 @@ msgstr "" msgid "wbits" msgstr "" +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" +msgstr "" + +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " +msgstr "" + #: shared-bindings/is31fl3741/FrameBuffer.c msgid "width must be greater than zero" msgstr "" diff --git a/ports/espressif/boards/deneyap_kart_1a_v2/mpconfigboard.mk b/ports/espressif/boards/deneyap_kart_1a_v2/mpconfigboard.mk index fb36bbf0db6d5..1200547f93932 100644 --- a/ports/espressif/boards/deneyap_kart_1a_v2/mpconfigboard.mk +++ b/ports/espressif/boards/deneyap_kart_1a_v2/mpconfigboard.mk @@ -15,5 +15,6 @@ CIRCUITPY_ESP_PSRAM_MODE = opi CIRCUITPY_ESP_PSRAM_FREQ = 80m CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_BITMAPFILTER = 0 OPTIMIZATION_FLAGS = -Os diff --git a/ports/espressif/boards/lolin_s3_mini/mpconfigboard.mk b/ports/espressif/boards/lolin_s3_mini/mpconfigboard.mk index 2bd303adb31b1..9b1a18a2844f5 100644 --- a/ports/espressif/boards/lolin_s3_mini/mpconfigboard.mk +++ b/ports/espressif/boards/lolin_s3_mini/mpconfigboard.mk @@ -15,6 +15,7 @@ CIRCUITPY_ESP_PSRAM_FREQ = 40m OPTIMIZATION_FLAGS = -Os CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_BITMAPFILTER = 0 # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel diff --git a/ports/espressif/boards/waveshare_esp32_s3_zero/mpconfigboard.mk b/ports/espressif/boards/waveshare_esp32_s3_zero/mpconfigboard.mk index 649a30f94dc57..cf7a2f43d6972 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_zero/mpconfigboard.mk +++ b/ports/espressif/boards/waveshare_esp32_s3_zero/mpconfigboard.mk @@ -15,6 +15,7 @@ CIRCUITPY_ESP_PSRAM_FREQ = 40m OPTIMIZATION_FLAGS = -Os CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_BITMAPFILTER = 0 # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index be1a38949d7c2..e935f3057dcf4 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -114,6 +114,7 @@ CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 0 else ifeq ($(IDF_TARGET),esp32s3) # Modules +CIRCUITPY_BITMAPFILTER ?= $(CIRCUITPY_ESPCAMERA) CIRCUITPY_PARALLELDISPLAY = 0 CIRCUITPY_RGBMATRIX_USES_SUPERVISOR_ALLOCATION = 0 diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index eeeb0cf2e354f..f116d8f5885fe 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -336,8 +336,8 @@ void port_free(void *ptr) { heap_caps_free(ptr); } -void port_realloc(void *ptr, size_t size) { - heap_caps_realloc(ptr, size, MALLOC_CAP_8BIT); +void *port_realloc(void *ptr, size_t size) { + return heap_caps_realloc(ptr, size, MALLOC_CAP_8BIT); } size_t port_heap_get_largest_free_size(void) { diff --git a/ports/unix/displayio_min.c b/ports/unix/displayio_min.c index 45cfc1b73cfb1..3dfcdb41416c0 100644 --- a/ports/unix/displayio_min.c +++ b/ports/unix/displayio_min.c @@ -30,6 +30,8 @@ #include "shared-bindings/displayio/__init__.h" #include "shared-bindings/displayio/Bitmap.h" +#include "shared-bindings/displayio/ColorConverter.h" +#include "shared-bindings/displayio/Palette.h" MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, RGB888, DISPLAYIO_COLORSPACE_RGB888); MAKE_ENUM_VALUE(displayio_colorspace_type, displayio_colorspace, RGB565, DISPLAYIO_COLORSPACE_RGB565); @@ -81,6 +83,8 @@ STATIC const mp_rom_map_elem_t displayio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_displayio) }, { MP_ROM_QSTR(MP_QSTR_Bitmap), MP_ROM_PTR(&displayio_bitmap_type) }, { MP_ROM_QSTR(MP_QSTR_Colorspace), MP_ROM_PTR(&displayio_colorspace_type) }, + { MP_ROM_QSTR(MP_QSTR_ColorConverter), MP_ROM_PTR(&displayio_colorconverter_type) }, + { MP_ROM_QSTR(MP_QSTR_Palette), MP_ROM_PTR(&displayio_palette_type) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_module_globals, displayio_module_globals_table); diff --git a/ports/unix/variants/coverage/mpconfigvariant.mk b/ports/unix/variants/coverage/mpconfigvariant.mk index d61cc64bf564c..ee8a395e87ac9 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.mk +++ b/ports/unix/variants/coverage/mpconfigvariant.mk @@ -34,9 +34,12 @@ SRC_BITMAP := \ shared-bindings/audiomixer/__init__.c \ shared-bindings/audiomixer/Mixer.c \ shared-bindings/audiomixer/MixerVoice.c \ + shared-bindings/bitmapfilter/__init__.c \ shared-bindings/bitmaptools/__init__.c \ shared-bindings/codeop/__init__.c \ shared-bindings/displayio/Bitmap.c \ + shared-bindings/displayio/ColorConverter.c \ + shared-bindings/displayio/Palette.c \ shared-bindings/jpegio/__init__.c \ shared-bindings/jpegio/JpegDecoder.c \ shared-bindings/locale/__init__.c \ @@ -60,11 +63,12 @@ SRC_BITMAP := \ shared-module/audiomixer/__init__.c \ shared-module/audiomixer/Mixer.c \ shared-module/audiomixer/MixerVoice.c \ + shared-module/bitmapfilter/__init__.c \ shared-module/bitmaptools/__init__.c \ shared-module/displayio/area.c \ shared-module/displayio/Bitmap.c \ shared-module/displayio/ColorConverter.c \ - shared-module/displayio/ColorConverter.c \ + shared-module/displayio/Palette.c \ shared-module/jpegio/__init__.c \ shared-module/jpegio/JpegDecoder.c \ shared-module/os/getenv.c \ diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 6b008b4ebfd29..b611d111c0f2f 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -144,6 +144,9 @@ endif ifeq ($(CIRCUITPY_BITMAPTOOLS),1) SRC_PATTERNS += bitmaptools/% endif +ifeq ($(CIRCUITPY_BITMAPFILTER),1) +SRC_PATTERNS += bitmapfilter/% +endif ifeq ($(CIRCUITPY_BITOPS),1) SRC_PATTERNS += bitops/% endif @@ -609,6 +612,7 @@ SRC_SHARED_MODULE_ALL = \ bitbangio/SPI.c \ bitbangio/__init__.c \ bitmaptools/__init__.c \ + bitmapfilter/__init__.c \ bitops/__init__.c \ board/__init__.c \ adafruit_bus_device/__init__.c \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 109cab85725cf..06095d47cb3e8 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -147,6 +147,10 @@ CFLAGS += -DCIRCUITPY_BITBANG_APA102=$(CIRCUITPY_BITBANG_APA102) CIRCUITPY_BITBANGIO ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_BITBANGIO=$(CIRCUITPY_BITBANGIO) +# bitmapfilter also depends on displayio, but is disabled by default +CIRCUITPY_BITMAPFILTER ?= 0 +CFLAGS += -DCIRCUITPY_BITMAPFILTER=$(CIRCUITPY_BITMAPFILTER) + CIRCUITPY_BITOPS ?= 0 CFLAGS += -DCIRCUITPY_BITOPS=$(CIRCUITPY_BITOPS) @@ -236,7 +240,7 @@ CFLAGS += -DCIRCUITPY_DOTCLOCKFRAMEBUFFER=$(CIRCUITPY_DOTCLOCKFRAMEBUFFER) CIRCUITPY_DOTCLOCKFRAMEBUFFER_USES_SUPERVISOR_ALLOCATION ?= 1 CFLAGS += -DCIRCUITPY_DOTCLOCKFRAMEBUFFER_USES_SUPERVISOR_ALLOCATION=$(CIRCUITPY_DOTCLOCKFRAMEBUFFER_USES_SUPERVISOR_ALLOCATION) -# bitmaptools and framebufferio rely on displayio +# bitmaptools and framebufferio rely on displayio and are not on small boards CIRCUITPY_BITMAPTOOLS ?= $(call enable-if-all,$(CIRCUITPY_FULL_BUILD) $(CIRCUITPY_DISPLAYIO)) CIRCUITPY_FRAMEBUFFERIO ?= $(call enable-if-all,$(CIRCUITPY_FULL_BUILD) $(CIRCUITPY_DISPLAYIO)) CIRCUITPY_VECTORIO ?= $(CIRCUITPY_DISPLAYIO) diff --git a/shared-bindings/bitmapfilter/__init__.c b/shared-bindings/bitmapfilter/__init__.c new file mode 100644 index 0000000000000..1f3f242b1a3c0 --- /dev/null +++ b/shared-bindings/bitmapfilter/__init__.c @@ -0,0 +1,632 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "py/objnamedtuple.h" +#include "shared-bindings/displayio/Bitmap.h" +#include "shared-bindings/displayio/Palette.h" +#include "shared-bindings/bitmapfilter/__init__.h" + +//| +//| def morph( +//| bitmap: displayio.Bitmap, +//| weights: Sequence[int], +//| mul: float | None = None, +//| add: float = 0, +//| mask: displayio.Bitmap | None = None, +//| threshold=False, +//| offset: int = 0, +//| invert: bool = False, +//| ) -> displayio.Bitmap: +//| """Convolve an image with a kernel +//| +//| The name of the function comes from +//| `OpenMV `_. +//| ImageMagick calls this "-morphology" ("-morph" is an unrelated image blending +//| algorithm). PIL calls this "kernel". +//| +//| For background on how this kind of image processing, including some +//| useful ``weights`` values, see `wikipedia's article on the +//| subject `_. +//| +//| The ``bitmap``, which must be in RGB565_SWAPPED format, is modified +//| according to the ``weights``. Then a scaling factor ``mul`` and an +//| offset factor ``add`` are applied. +//| +//| The ``weights`` must be a sequence of integers. The length of the tuple +//| must be the square of an odd number, usually 9 and sometimes 25. +//| Specific weights create different effects. For instance, these +//| weights represent a 3x3 gaussian blur: ``[1, 2, 1, 2, 4, 2, 1, 2, 1]`` +//| +//| ``mul`` is number to multiply the convolution pixel results by. +//| If `None` (the default) is passed, the value of ``1/sum(weights)`` +//| is used (or ``1`` if ``sum(weights)`` is ``0``). For most weights, his +//| default value will preserve the overall image brightness. +//| +//| ``add`` is a value to add to each convolution pixel result. +//| +//| ``mul`` basically allows you to do a global contrast adjustment and +//| add allows you to do a global brightness adjustment. Pixels that go +//| outside of the image mins and maxes for color channels will be +//| clipped. +//| +//| If you’d like to adaptive threshold the image on the output of the +//| filter you can pass ``threshold=True`` which will enable adaptive +//| thresholding of the image which sets pixels to one or zero based on a +//| pixel’s brightness in relation to the brightness of the kernel of pixels +//| around them. A negative ``offset`` value sets more pixels to 1 as you make +//| it more negative while a positive value only sets the sharpest contrast +//| changes to 1. Set ``invert`` to invert the binary image resulting output. +//| +//| ``mask`` is another image to use as a pixel level mask for the operation. +//| The mask should be an image the same size as the image being operated on. +//| Only pixels set to a non-zero value in the mask are modified. +//| +//| .. code-block:: python +//| +//| kernel_gauss_3 = [ +//| 1, 2, 1, +//| 2, 4, 2, +//| 1, 2, 1] +//| +//| def blur(bitmap): +//| \"""Blur the bitmap with a 3x3 gaussian kernel\""" +//| bitmapfilter.morph(bitmap, kernel_gauss_3, 1/sum(kernel_gauss_3)) +//| """ +//| + + +STATIC mp_float_t get_m(mp_obj_t mul_obj, int sum) { + return mul_obj != mp_const_none ? mp_obj_get_float(mul_obj) : sum ? 1 / (mp_float_t)sum : 1; +} + +STATIC mp_obj_t bitmapfilter_morph(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_bitmap, ARG_weights, ARG_mul, ARG_add, ARG_threshold, ARG_offset, ARG_invert, ARG_mask }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_weights, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_mul, MP_ARG_OBJ, { .u_obj = MP_ROM_NONE } }, + { MP_QSTR_add, MP_ARG_OBJ, { .u_obj = MP_ROM_INT(0) } }, + { MP_QSTR_threshold, MP_ARG_BOOL, { .u_bool = false } }, + { MP_QSTR_offset, MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_invert, MP_ARG_BOOL, { .u_bool = false } }, + { MP_QSTR_mask, 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); + + mp_arg_validate_type(args[ARG_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_bitmap); + displayio_bitmap_t *bitmap = args[ARG_bitmap].u_obj; + + displayio_bitmap_t *mask = NULL; // the mask bitmap + if (args[ARG_mask].u_obj != mp_const_none) { + mp_arg_validate_type(args[ARG_mask].u_obj, &displayio_bitmap_type, MP_QSTR_mask); + mask = MP_OBJ_TO_PTR(args[ARG_mask].u_obj); + } + + mp_float_t b = mp_obj_get_float(args[ARG_add].u_obj); + + mp_obj_t weights = args[ARG_weights].u_obj; + mp_obj_t obj_len = mp_obj_len(weights); + if (obj_len == MP_OBJ_NULL || !mp_obj_is_small_int(obj_len)) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be of type %q, not %q"), MP_QSTR_weights, MP_QSTR_Sequence, mp_obj_get_type(weights)->name); + } + + size_t n_weights = MP_OBJ_SMALL_INT_VALUE(obj_len); + + size_t sq_n_weights = (int)MICROPY_FLOAT_C_FUN(sqrt)(n_weights); + if (sq_n_weights % 2 == 0 || sq_n_weights * sq_n_weights != n_weights) { + mp_raise_ValueError(MP_ERROR_TEXT("weights must be a sequence with an odd square number of elements (usually 9 or 25)")); + } + + int iweights[n_weights]; + int weight_sum = 0; + for (size_t i = 0; i < n_weights; i++) { + mp_int_t j = mp_obj_get_int(mp_obj_subscr(weights, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL)); + iweights[i] = j; + weight_sum += j; + } + + mp_float_t m = get_m(args[ARG_mul].u_obj, weight_sum); + + shared_module_bitmapfilter_morph(bitmap, mask, sq_n_weights / 2, iweights, m, b, + args[ARG_threshold].u_bool, args[ARG_offset].u_bool, args[ARG_invert].u_bool); + return args[ARG_bitmap].u_obj; +} +MP_DEFINE_CONST_FUN_OBJ_KW(bitmapfilter_morph_obj, 0, bitmapfilter_morph); +static mp_obj_t subscr(mp_obj_t o, int i) { + return mp_obj_subscr(o, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL); +} + +static mp_float_t float_subscr(mp_obj_t o, int i) { + return mp_obj_get_float(subscr(o, i)); +} + +//| class ChannelScale: +//| """A weight object to use with mix() that scales each channel independently +//| +//| This is useful for global contrast and brightness adjustment on a +//| per-component basis. For instance, to cut red contrast in half (while keeping the minimum value +//| as black or 0.0), +//| +//| .. code-block:: python +//| +//| reduce_red_contrast = bitmapfilter.ChannelScale(0.5, 1, 1) +//| """ +//| +//| def __init__(self, r: float, g: float, b: float) -> None: +//| """Construct a ChannelScale object +//| +//| The ``r`` parameter gives the scale factor for the red channel of +//| pixels, and so forth.""" +//| +static const mp_obj_namedtuple_type_t bitmapfilter_channel_scale_type = { + NAMEDTUPLE_TYPE_BASE_AND_SLOTS(MP_QSTR_ChannelScale), + .n_fields = 3, + .fields = { + MP_QSTR_r, + MP_QSTR_g, + MP_QSTR_b, + }, +}; +//| class ChannelScaleOffset: +//| """A weight object to use with mix() that scales and offsets each channel independently +//| +//| The ``r``, ``g``, and ``b`` parameters give a scale factor for each color +//| component, while the ``r_add`, ``g_add`` and ``b_add`` give offset values +//| added to each component. +//| +//| This is useful for global contrast and brightness adjustment on a +//| per-component basis. For instance, to cut red contrast in half while adjusting the +//| brightness so that the middle value is still 0.5: +//| +//| .. code-block:: python +//| +//| reduce_red_contrast = bitmapfilter.ChannelScaleOffset( +//| 0.5, 0.25, +//| 1, 0, +//| 1, 0) +//| """ +//| +//| def __init__( +//| self, r: float, r_add: float, g: float, g_add: float, b: float, b_add: float +//| ) -> None: +//| """Construct a ChannelScaleOffset object""" +//| +static const mp_obj_namedtuple_type_t bitmapfilter_channel_scale_offset_type = { + NAMEDTUPLE_TYPE_BASE_AND_SLOTS(MP_QSTR_ChannelScaleOffset), + .n_fields = 6, + .fields = { + MP_QSTR_r, + MP_QSTR_g, + MP_QSTR_b, + MP_QSTR_r_add, + MP_QSTR_g_add, + MP_QSTR_b_add, + }, +}; + +//| class ChannelMixer: +//| """A weight object to use with mix() that mixes different channels together +//| +//| The parameters with names like ``rb`` give the fraction of +//| each channel to mix into every other channel. For instance, +//| ``rb`` gives the fraction of blue to mix into red, and ``gg`` +//| gives the fraction of green to mix into green. +//| +//| Conversion to sepia is an example where a ChannelMixer is appropriate, +//| because the sepia conversion is defined as mixing a certain fraction of R, +//| G, and B input values into each output value: +//| +//| .. code-block:: python +//| +//| sepia_weights = bitmapfilter.ChannelMixer( +//| .393, .769, .189, +//| .349, .686, .168, +//| .272, .534, .131) +//| +//| def sepia(bitmap): +//| \"""Convert the bitmap to sepia\""" +//| bitmapfilter.mix(bitmap, sepia_weights) +//| mix_into_red = ChannelMixer( +//| 0.5, 0.25, 0.25, +//| 0, 1, 0, +//| 0, 1, 0) +//| """ +//| +//| def __init__( +//| self, +//| rr: float, +//| rg: float, +//| rb: float, +//| gr: float, +//| gg: float, +//| gb: float, +//| br: float, +//| bg: float, +//| bb: float, +//| ) -> None: +//| """Construct a ChannelMixer object""" +//| +static const mp_obj_namedtuple_type_t bitmapfilter_channel_mixer_type = { + NAMEDTUPLE_TYPE_BASE_AND_SLOTS(MP_QSTR_ChannelMixer), + .n_fields = 9, + .fields = { + MP_QSTR_rr, + MP_QSTR_rg, + MP_QSTR_rb, + MP_QSTR_gr, + MP_QSTR_gg, + MP_QSTR_gb, + MP_QSTR_br, + MP_QSTR_bg, + MP_QSTR_bb, + }, +}; + +//| class ChannelMixerOffset: +//| """A weight object to use with mix() that mixes different channels together, plus an offset value +//| +//| The parameters with names like ``rb`` give the fraction of +//| each channel to mix into every other channel. For instance, +//| ``rb`` gives the fraction of blue to mix into red, and ``gg`` +//| gives the fraction of green to mix into green. The ``r_add``, ``g_add`` +//| and ``b_add`` parameters give offsets applied to each component. +//| +//| For instance, to perform sepia conversion but also increase the overall brightness by 10%: +//| +//| .. code-block:: python +//| +//| sepia_weights_brighten = bitmapfilter.ChannelMixerOffset( +//| .393, .769, .189, .1 +//| .349, .686, .168, .1 +//| .272, .534, .131, .1) +//| """ +//| +//| def __init__( +//| self, +//| rr: float, +//| rg: float, +//| rb: float, +//| r_add: float, +//| gr: float, +//| gg: float, +//| gb: float, +//| g_add: float, +//| br: float, +//| bg: float, +//| bb: float, +//| b_add: float, +//| ) -> None: +//| """Construct a ChannelMixerOffset object""" +//| +static const mp_obj_namedtuple_type_t bitmapfilter_channel_mixer_offset_type = { + NAMEDTUPLE_TYPE_BASE_AND_SLOTS(MP_QSTR_ChannelMixerOffset), + .n_fields = 12, + .fields = { + MP_QSTR_rr, + MP_QSTR_rg, + MP_QSTR_rb, + MP_QSTR_r_add, + MP_QSTR_gr, + MP_QSTR_gg, + MP_QSTR_gb, + MP_QSTR_g_add, + MP_QSTR_br, + MP_QSTR_bg, + MP_QSTR_bb, + MP_QSTR_b_add, + }, +}; + +//| def mix( +//| bitmap: displayio.Bitmap, +//| weights: ChannelScale | ChannelScaleOffset | ChannelMixer | ChannelMixerOffset, +//| mask: displayio.Bitmap | None = None, +//| ) -> displayio.Bitmap: +//| """Perform a channel mixing operation on the bitmap +//| +//| This is similar to the "channel mixer" tool in popular photo editing software. +//| Imagemagick calls this "-color-matrix". In PIL, this is accomplished with the +//| ``convert`` method's ``matrix`` argument. +//| +//| The ``bitmap``, which must be in RGB565_SWAPPED format, is modified +//| according to the ``weights``. +//| +//| The ``weights`` must be one of the above types: `ChannelScale`, +//| `ChannelScaleOffset`, `ChannelMixer`, or `ChannelMixerOffset`. For the +//| effect of each different kind of weights object, see the type +//| documentation. +//| +//| After computation, any out of range values are clamped to the greatest or +//| smallest valid value. +//| +//| ``mask`` is another image to use as a pixel level mask for the operation. +//| The mask should be an image the same size as the image being operated on. +//| Only pixels set to a non-zero value in the mask are modified. +//| """ +//| +STATIC mp_obj_t bitmapfilter_mix(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_bitmap, ARG_weights, ARG_mask }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_weights, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_mask, 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); + + mp_arg_validate_type(args[ARG_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_bitmap); + displayio_bitmap_t *bitmap = MP_OBJ_TO_PTR(args[ARG_bitmap].u_obj); + + mp_float_t weights[12]; + memset(weights, 0, sizeof(weights)); + + mp_obj_t weights_obj = args[ARG_weights].u_obj; + if (mp_obj_is_type(weights_obj, (const mp_obj_type_t *)&bitmapfilter_channel_scale_type)) { + for (int i = 0; i < 3; i++) { + weights[5 * i] = float_subscr(weights_obj, i); + } + } else if (mp_obj_is_type(weights_obj, (const mp_obj_type_t *)&bitmapfilter_channel_scale_offset_type)) { + for (int i = 0; i < 3; i++) { + weights[5 * i] = float_subscr(weights_obj, i * 2); + weights[4 * i + 3] = float_subscr(weights_obj, i * 2 + 1); + } + } else if (mp_obj_is_type(weights_obj, (const mp_obj_type_t *)&bitmapfilter_channel_mixer_type)) { + for (int i = 0; i < 9; i++) { + weights[i + i / 3] = float_subscr(weights_obj, i); + } + } else if (mp_obj_is_type(weights_obj, (const mp_obj_type_t *)&bitmapfilter_channel_mixer_offset_type)) { + for (int i = 0; i < 12; i++) { + weights[i] = float_subscr(weights_obj, i); + } + } else { + mp_raise_ValueError_varg( + MP_ERROR_TEXT("weights must be an object of type %q, %q, %q, or %q, not %q "), + MP_QSTR_ScaleMixer, MP_QSTR_ScaleMixerOffset, + MP_QSTR_ChannelMixer, MP_QSTR_ChannelMixerOffset, + mp_obj_get_type_qstr(weights_obj) + ); + } + + + displayio_bitmap_t *mask = NULL; + if (args[ARG_mask].u_obj != mp_const_none) { + mp_arg_validate_type(args[ARG_mask].u_obj, &displayio_bitmap_type, MP_QSTR_mask); + mask = MP_OBJ_TO_PTR(args[ARG_mask].u_obj); + } + + shared_module_bitmapfilter_mix(bitmap, mask, weights); + return args[ARG_bitmap].u_obj; +} +MP_DEFINE_CONST_FUN_OBJ_KW(bitmapfilter_mix_obj, 0, bitmapfilter_mix); + +//| def solarize(bitmap, threshold: float = 0.5, mask: displayio.Bitmap | None = None): +//| """Create a "solarization" effect on an image +//| +//| This filter inverts pixels with brightness values above ``threshold``, while leaving +//| lower brightness pixels alone. +//| +//| This effect is similar to `an effect observed in real life film +//| `_ which can also be +//| `produced during the printmaking process +//| `_ +//| +//| PIL and ImageMagic both call this "solarize". +//| """ +//| +STATIC mp_obj_t bitmapfilter_solarize(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_bitmap, ARG_threshold, ARG_mask }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_threshold, MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_mask, 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); + + mp_float_t threshold = (args[ARG_threshold].u_obj == NULL) ? MICROPY_FLOAT_CONST(0.5) : mp_obj_get_float(args[ARG_threshold].u_obj); + mp_arg_validate_type(args[ARG_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_bitmap); + displayio_bitmap_t *bitmap = MP_OBJ_TO_PTR(args[ARG_bitmap].u_obj); + + + displayio_bitmap_t *mask = NULL; + if (args[ARG_mask].u_obj != mp_const_none) { + mp_arg_validate_type(args[ARG_mask].u_obj, &displayio_bitmap_type, MP_QSTR_mask); + mask = MP_OBJ_TO_PTR(args[ARG_mask].u_obj); + } + + shared_module_bitmapfilter_solarize(bitmap, mask, threshold); + return args[ARG_bitmap].u_obj; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(bitmapfilter_solarize_obj, 0, bitmapfilter_solarize); + + +//| LookupFunction = Callable[[float], float] +//| """Any function which takes a number and returns a number. The input +//| and output values should be in the range from 0 to 1 inclusive.""" +//| ThreeLookupFunctions = Tuple[LookupFunction, LookupFunction, LookupFunction] +//| """Any sequenceof three `LookupFunction` objects""" +//| +//| def lookup( +//| bitmap: displayio.Bitmap, +//| lookup: LookupFunction | ThreeLookupFunctions, +//| mask: displayio.Bitmap | None, +//| ) -> displayio.Bitmap: +//| """Modify the channels of a bitmap according to a look-up table +//| +//| This can be used to implement non-linear transformations of color values, +//| such as gamma curves. +//| +//| This is similar to, but more limiting than, PIL's "LUT3D" facility. It is not +//| directly available in OpenMV or ImageMagic. +//| +//| The ``bitmap``, which must be in RGB565_SWAPPED format, is modified +//| according to the values of the ``lookup`` function or functions. +//| +//| If one ``lookup`` function is supplied, the same function is used for all 3 +//| image channels. Otherwise, it must be a tuple of 3 functions. The first +//| function is used for R, the second function for G, and the third for B. +//| +//| Each lookup function is called for each possible channel value from 0 to 1 +//| inclusive (64 times for green, 32 times for red or blue), and the return +//| value (also from 0 to 1) is used whenever that color value is returned. +//| +//| ``mask`` is another image to use as a pixel level mask for the operation. +//| The mask should be an image the same size as the image being operated on. +//| Only pixels set to a non-zero value in the mask are modified. +//| """ +//| + +STATIC int scaled_lut(int maxval, mp_obj_t func, int i) { + mp_obj_t obj = mp_call_function_1(func, mp_obj_new_float(i / (mp_float_t)maxval)); + mp_float_t val = mp_obj_get_float(obj); + return (int)MICROPY_FLOAT_C_FUN(round)(val * maxval); +} + +STATIC mp_obj_t bitmapfilter_lookup(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_bitmap, ARG_lookup, ARG_mask }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_lookup, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_mask, 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); + + mp_arg_validate_type(args[ARG_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_bitmap); + displayio_bitmap_t *bitmap = MP_OBJ_TO_PTR(args[ARG_bitmap].u_obj); + + mp_obj_t lookup_r, lookup_g, lookup_b; + + if (mp_obj_is_tuple_compatible(args[ARG_lookup].u_obj)) { + mp_obj_tuple_t *lookup_tuple = MP_OBJ_TO_PTR(args[ARG_lookup].u_obj); + mp_arg_validate_length(lookup_tuple->len, 3, MP_QSTR_lookup); + lookup_r = lookup_tuple->items[0]; + lookup_g = lookup_tuple->items[1]; + lookup_b = lookup_tuple->items[2]; + } else { + lookup_r = lookup_g = lookup_b = args[ARG_lookup].u_obj; + } + + bitmapfilter_lookup_table_t table; + + for (int i = 0; i < 32; i++) { + table.r[i] = scaled_lut(31, lookup_r, i); + table.b[i] = lookup_r == lookup_b ? table.r[i] : scaled_lut(31, lookup_b, i); + } + for (int i = 0; i < 64; i++) { + table.g[i] = scaled_lut(63, lookup_g, i); + } + + displayio_bitmap_t *mask = NULL; + if (args[ARG_mask].u_obj != mp_const_none) { + mp_arg_validate_type(args[ARG_mask].u_obj, &displayio_bitmap_type, MP_QSTR_mask); + mask = MP_OBJ_TO_PTR(args[ARG_mask].u_obj); + } + + shared_module_bitmapfilter_lookup(bitmap, mask, &table); + return args[ARG_bitmap].u_obj; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(bitmapfilter_lookup_obj, 0, bitmapfilter_lookup); + +//| def false_color( +//| bitmap: displayio.Bitmap, +//| palette: displayio.Palette, +//| mask: displayio.Bitmap | None, +//| ) -> displayio.Bitmap: +//| """Convert the image to false color using the given palette +//| +//| In OpenMV this is accomplished via the ``ironbow`` function, which uses a default +//| palette known as "ironbow". Imagemagic produces a similar effect with ``-clut``. +//| PIL can accomplish this by converting an image to "L" format, then applying a +//| palette to convert it into "P" mode. +//| +//| The ``bitmap``, which must be in RGB565_SWAPPED format, is converted into false color. +//| +//| The ``palette``, which must be of length 256, is used as a look-up table. +//| +//| Each pixel is converted to a luminance (brightness/greyscale) value +//| in the range 0..255, then the corresponding palette entry is looked up and +//| stored in the bitmap. +//| +//| ``mask`` is another image to use as a pixel level mask for the operation. +//| The mask should be an image the same size as the image being operated on. +//| Only pixels set to a non-zero value in the mask are modified. +//| """ +//| +STATIC mp_obj_t bitmapfilter_false_color(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_bitmap, ARG_palette, ARG_mask }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_palette, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_mask, 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); + + mp_arg_validate_type(args[ARG_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_bitmap); + displayio_bitmap_t *bitmap = MP_OBJ_TO_PTR(args[ARG_bitmap].u_obj); + + mp_arg_validate_type(args[ARG_palette].u_obj, &displayio_palette_type, MP_QSTR_palette); + displayio_palette_t *palette = MP_OBJ_TO_PTR(args[ARG_palette].u_obj); + mp_arg_validate_length(palette->color_count, 256, MP_QSTR_palette); + + displayio_bitmap_t *mask = NULL; + if (args[ARG_mask].u_obj != mp_const_none) { + mp_arg_validate_type(args[ARG_mask].u_obj, &displayio_bitmap_type, MP_QSTR_mask); + mask = MP_OBJ_TO_PTR(args[ARG_mask].u_obj); + } + + shared_module_bitmapfilter_false_color(bitmap, mask, palette->colors); + return args[ARG_bitmap].u_obj; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(bitmapfilter_false_color_obj, 0, bitmapfilter_false_color); +STATIC const mp_rom_map_elem_t bitmapfilter_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bitmapfilter) }, + { MP_ROM_QSTR(MP_QSTR_morph), MP_ROM_PTR(&bitmapfilter_morph_obj) }, + { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&bitmapfilter_mix_obj) }, + { MP_ROM_QSTR(MP_QSTR_solarize), MP_ROM_PTR(&bitmapfilter_solarize_obj) }, + { MP_ROM_QSTR(MP_QSTR_false_color), MP_ROM_PTR(&bitmapfilter_false_color_obj) }, + { MP_ROM_QSTR(MP_QSTR_lookup), MP_ROM_PTR(&bitmapfilter_lookup_obj) }, + { MP_ROM_QSTR(MP_QSTR_ChannelScale), MP_ROM_PTR(&bitmapfilter_channel_scale_type) }, + { MP_ROM_QSTR(MP_QSTR_ChannelScaleOffset), MP_ROM_PTR(&bitmapfilter_channel_scale_offset_type) }, + { MP_ROM_QSTR(MP_QSTR_ChannelMixer), MP_ROM_PTR(&bitmapfilter_channel_mixer_type) }, + { MP_ROM_QSTR(MP_QSTR_ChannelMixerOffset), MP_ROM_PTR(&bitmapfilter_channel_mixer_offset_type) }, +}; +STATIC MP_DEFINE_CONST_DICT(bitmapfilter_module_globals, bitmapfilter_module_globals_table); + +const mp_obj_module_t bitmapfilter_module = { + .base = {&mp_type_module }, + .globals = (mp_obj_dict_t *)&bitmapfilter_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_bitmapfilter, bitmapfilter_module); diff --git a/shared-bindings/bitmapfilter/__init__.h b/shared-bindings/bitmapfilter/__init__.h new file mode 100644 index 0000000000000..f90035d1c2125 --- /dev/null +++ b/shared-bindings/bitmapfilter/__init__.h @@ -0,0 +1,75 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Jeff Epler for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include "shared-module/displayio/Bitmap.h" + +void shared_module_bitmapfilter_morph( + displayio_bitmap_t *bitmap, + displayio_bitmap_t *mask, + const int ksize, + const int *krn, + const mp_float_t m, + const mp_float_t b, + bool threshold, + int offset, + bool invert); + +void shared_module_bitmapfilter_morph9( + displayio_bitmap_t *bitmap, + displayio_bitmap_t *mask, + const int ksize, + int krn[9 * (2 * ksize + 1) * (2 * ksize + 1)], // Note: modifies krn[] + const mp_float_t m[3], + const mp_float_t b[3], + bool threshold, + int offset, + bool invert); + +void shared_module_bitmapfilter_mix( + displayio_bitmap_t *bitmap, + displayio_bitmap_t *mask, + const mp_float_t weights[12]); + +void shared_module_bitmapfilter_solarize( + displayio_bitmap_t *bitmap, + displayio_bitmap_t *mask, + const mp_float_t threshold); + +typedef struct { + uint8_t r[32], g[64], b[32]; +} bitmapfilter_lookup_table_t; + +void shared_module_bitmapfilter_lookup( + displayio_bitmap_t *bitmap, + displayio_bitmap_t *mask, + const bitmapfilter_lookup_table_t *table); + +void shared_module_bitmapfilter_false_color( + displayio_bitmap_t *bitmap, + displayio_bitmap_t *mask, + _displayio_color_t palette[256]); diff --git a/shared-bindings/displayio/Palette.c b/shared-bindings/displayio/Palette.c index 7beaa2ae32d08..2b2fa237f00b5 100644 --- a/shared-bindings/displayio/Palette.c +++ b/shared-bindings/displayio/Palette.c @@ -32,7 +32,6 @@ #include "py/binary.h" #include "py/objproperty.h" #include "py/runtime.h" -#include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/util.h" //| class Palette: @@ -52,7 +51,7 @@ STATIC mp_obj_t displayio_palette_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { enum { ARG_color_count, ARG_dither }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_color_count, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_color_count, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0 } }, { MP_QSTR_dither, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; diff --git a/shared-module/bitmapfilter/__init__.c b/shared-module/bitmapfilter/__init__.c new file mode 100644 index 0000000000000..72f38eceb1794 --- /dev/null +++ b/shared-module/bitmapfilter/__init__.c @@ -0,0 +1,458 @@ +/* + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * Copyright (c) 2024 Jeff Epler for Adafruit Industries + * + * This work is licensed under the MIT license, see the file LICENSE for details. + * Adapted from https://github.com/openmv/openmv/blob/master/bitmap/omv/imlib/filter.c#L2083 + */ + +#include +#include + +#include "py/runtime.h" + +#include "shared-bindings/displayio/Bitmap.h" +#include "shared-bindings/displayio/Palette.h" +#include "shared-bindings/bitmapfilter/__init__.h" +#include "shared-module/bitmapfilter/__init__.h" + +#if defined(UNIX) +#include +#define port_free free +#define port_malloc(sz, hint) (malloc(sz)) +#define port_realloc realloc +#else +#include "supervisor/port_heap.h" +#endif + +// Triggered by use of IM_MIN(IM_MAX(...)); this is a spurious diagnostic. +#pragma GCC diagnostic ignored "-Wshadow" + +static void check_matching_details(displayio_bitmap_t *b1, displayio_bitmap_t *b2) { + if (b1->width != b2->width || b1->height != b2->height) { + mp_raise_ValueError(MP_ERROR_TEXT("bitmap size and depth must match")); + } +} + +size_t scratchpad_size = 0; +static void *scratchpad = NULL; + +static void *scratchpad_alloc(size_t sz) { + if (sz == 0) { + if (scratchpad) { + port_free(scratchpad); + } + scratchpad_size = sz; + scratchpad = NULL; + } else { + if (scratchpad) { + if (sz > scratchpad_size) { + void *tmp = port_realloc(scratchpad, sz); + if (!tmp) { + port_free(scratchpad); + scratchpad = NULL; + } else { + scratchpad = tmp; + scratchpad_size = sz; + } + } + } else { + scratchpad = port_malloc(sz, false); + scratchpad_size = sz; + } + if (!scratchpad) { + m_malloc_fail(sz); + } + } + return scratchpad; +} + +static void scratch_bitmap16(displayio_bitmap_t *buf, int rows, int cols) { + int stride = (cols + 1) / 2; + size_t sz = rows * stride * sizeof(uint32_t); + void *data = scratchpad_alloc(sz); + // memset(data, 0, sz); + buf->width = cols; + buf->height = rows; + buf->stride = stride; + buf->data = data; +} + +#define IM_MAX(a, b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a > _b ? _a : _b; }) +#define IM_MIN(a, b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; }) +#define IM_DIV(a, b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _b ? (_a / _b) : 0; }) +#define IM_MOD(a, b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _b ? (_a % _b) : 0; }) + +#define IMAGE_RGB565_LINE_LEN_BYTES(bitmap) \ + ((bitmap)->width * 2) + +#define IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, y) \ + (uint16_t *)(&(bitmap)->data[(bitmap)->stride * (y)]) +#define IMAGE_GET_RGB565_PIXEL_FAST(rowptr, x) \ + __builtin_bswap16((rowptr)[(x)]) +#define IMAGE_PUT_RGB565_PIXEL_FAST(rowptr, x, val) \ + ((rowptr)[(x)] = __builtin_bswap16((val))) +#define COLOR_R5_G6_B5_TO_RGB565(r, g, b) \ + (((r) << 11) | ((g) << 5) | (b)) +#define COLOR_R8_G8_B8_TO_RGB565(r8, g8, b8) ((((r8) & 0xF8) << 8) | (((g8) & 0xFC) << 3) | ((b8) >> 3)) + +#define COLOR_RGB565_TO_R5(pixel) (((pixel) >> 11) & 0x1F) +#define COLOR_RGB565_TO_R8(pixel) \ + ({ \ + __typeof__ (pixel) __pixel = (pixel); \ + __pixel = (__pixel >> 8) & 0xF8; \ + __pixel | (__pixel >> 5); \ + }) + +#define COLOR_RGB565_TO_G6(pixel) (((pixel) >> 5) & 0x3F) +#define COLOR_RGB565_TO_G8(pixel) \ + ({ \ + __typeof__ (pixel) __pixel = (pixel); \ + __pixel = (__pixel >> 3) & 0xFC; \ + __pixel | (__pixel >> 6); \ + }) + +#define COLOR_RGB565_TO_B5(pixel) ((pixel) & 0x1F) +#define COLOR_RGB565_TO_B8(pixel) \ + ({ \ + __typeof__ (pixel) __pixel = (pixel); \ + __pixel = (__pixel << 3) & 0xF8; \ + __pixel | (__pixel >> 5); \ + }) +#define COLOR_R5_MAX (0x1F) +#define COLOR_G6_MAX (0x3F) +#define COLOR_B5_MAX (0x1F) +#define COLOR_R8_MIN 0 +#define COLOR_R8_MAX 255 +#define COLOR_G8_MIN 0 +#define COLOR_G8_MAX 255 +#define COLOR_B8_MIN 0 +#define COLOR_B8_MAX 255 + +#define COLOR_RGB565_BINARY_MAX (0xffff) +#define COLOR_RGB565_BINARY_MIN (0x0000) + +#define COLOR_RGB888_TO_Y(r8, g8, b8) ((((r8) * 38) + ((g8) * 75) + ((b8) * 15)) >> 7) // 0.299R + 0.587G + 0.114B +#define COLOR_RGB565_TO_Y(rgb565) \ + ({ \ + __typeof__ (rgb565) __rgb565 = (rgb565); \ + int r = COLOR_RGB565_TO_R8(__rgb565); \ + int g = COLOR_RGB565_TO_G8(__rgb565); \ + int b = COLOR_RGB565_TO_B8(__rgb565); \ + COLOR_RGB888_TO_Y(r, g, b); \ + }) + +#define COLOR_RGB888_TO_U(r8, g8, b8) ((((r8) * -21) - ((g8) * 43) + ((b8) * 64)) >> 7) // -0.168736R - 0.331264G + 0.5B +#define COLOR_RGB565_TO_U(rgb565) \ + ({ \ + __typeof__ (rgb565) __rgb565 = (rgb565); \ + int r = COLOR_RGB565_TO_R8(__rgb565); \ + int g = COLOR_RGB565_TO_G8(__rgb565); \ + int b = COLOR_RGB565_TO_B8(__rgb565); \ + COLOR_RGB888_TO_U(r, g, b); \ + }) + +#define COLOR_RGB888_TO_V(r8, g8, b8) ((((r8) * 64) - ((g8) * 54) - ((b8) * 10)) >> 7) // 0.5R - 0.418688G - 0.081312B +#define COLOR_RGB565_TO_V(rgb565) \ + ({ \ + __typeof__ (rgb565) __rgb565 = (rgb565); \ + int r = COLOR_RGB565_TO_R8(__rgb565); \ + int g = COLOR_RGB565_TO_G8(__rgb565); \ + int b = COLOR_RGB565_TO_B8(__rgb565); \ + COLOR_RGB888_TO_V(r, g, b); \ + }) + +// https://en.wikipedia.org/wiki/YCbCr -> JPEG Conversion +STATIC uint16_t imlib_yuv_to_rgb(uint8_t y, int8_t u, int8_t v) { + uint32_t r = IM_MAX(IM_MIN(y + ((91881 * v) >> 16), COLOR_R8_MAX), COLOR_R8_MIN); + uint32_t g = IM_MAX(IM_MIN(y - (((22554 * u) + (46802 * v)) >> 16), COLOR_G8_MAX), COLOR_G8_MIN); + uint32_t b = IM_MAX(IM_MIN(y + ((116130 * u) >> 16), COLOR_B8_MAX), COLOR_B8_MIN); + + return COLOR_R8_G8_B8_TO_RGB565(r, g, b); +} + +// CIRCUITPY-CHANGE (vs openmv): an offset is removed so that the Y value is the +// same as from COLOR_RGB565_TO_Y. +#define COLOR_YUV_TO_RGB565(y, u, v) imlib_yuv_to_rgb((y), u, v) + + +void shared_module_bitmapfilter_morph( + displayio_bitmap_t *bitmap, + displayio_bitmap_t *mask, + const int ksize, + const int *krn, + const mp_float_t m, + const mp_float_t b, + bool threshold, + int offset, + bool invert) { + + int brows = ksize + 1; + + const int32_t m_int = (int32_t)MICROPY_FLOAT_C_FUN(round)(65536 * m); + const int32_t b_int = (int32_t)MICROPY_FLOAT_C_FUN(round)(65536 * COLOR_G6_MAX * b); + + check_matching_details(bitmap, bitmap); + + switch (bitmap->bits_per_value) { + default: + mp_raise_ValueError(MP_ERROR_TEXT("unsupported bitmap depth")); + case 16: { + displayio_bitmap_t buf; + scratch_bitmap16(&buf, brows, bitmap->width); + + for (int y = 0, yy = bitmap->height; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, y); + uint16_t *buf_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)); + + for (int x = 0, xx = bitmap->width; x < xx; x++) { + if (mask && common_hal_displayio_bitmap_get_pixel(mask, x, y)) { + IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)); + continue; // Short circuit. + + } + int32_t r_acc = 0, g_acc = 0, b_acc = 0, ptr = 0; + + if (x >= ksize && x < bitmap->width - ksize && y >= ksize && y < bitmap->height - ksize) { + for (int j = -ksize; j <= ksize; j++) { + uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, y + j); + for (int k = -ksize; k <= ksize; k++) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr, x + k); + r_acc += krn[ptr] * COLOR_RGB565_TO_R5(pixel); + g_acc += krn[ptr] * COLOR_RGB565_TO_G6(pixel); + b_acc += krn[ptr++] * COLOR_RGB565_TO_B5(pixel); + } + } + } else { + for (int j = -ksize; j <= ksize; j++) { + uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, + IM_MIN(IM_MAX(y + j, 0), (bitmap->height - 1))); + for (int k = -ksize; k <= ksize; k++) { + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr, + IM_MIN(IM_MAX(x + k, 0), (bitmap->width - 1))); + r_acc += krn[ptr] * COLOR_RGB565_TO_R5(pixel); + g_acc += krn[ptr] * COLOR_RGB565_TO_G6(pixel); + b_acc += krn[ptr++] * COLOR_RGB565_TO_B5(pixel); + } + } + } + r_acc = (r_acc * m_int + b_int) >> 16; + if (r_acc > COLOR_R5_MAX) { + r_acc = COLOR_R5_MAX; + } else if (r_acc < 0) { + r_acc = 0; + } + g_acc = (g_acc * m_int + b_int * 2) >> 16; + if (g_acc > COLOR_G6_MAX) { + g_acc = COLOR_G6_MAX; + } else if (g_acc < 0) { + g_acc = 0; + } + b_acc = (b_acc * m_int + b_int) >> 16; + if (b_acc > COLOR_B5_MAX) { + b_acc = COLOR_B5_MAX; + } else if (b_acc < 0) { + b_acc = 0; + } + + int pixel = COLOR_R5_G6_B5_TO_RGB565(r_acc, g_acc, b_acc); + + if (threshold) { + if (((COLOR_RGB565_TO_Y(pixel) - offset) < COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x))) ^ invert) { + pixel = COLOR_RGB565_BINARY_MAX; + } else { + pixel = COLOR_RGB565_BINARY_MIN; + } + } + + IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, pixel); + } + + if (y >= ksize) { // Transfer buffer lines... + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, (y - ksize)), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(bitmap)); + } + } + + // Copy any remaining lines from the buffer image... + for (int y = IM_MAX(bitmap->height - ksize, 0), yy = bitmap->height; y < yy; y++) { + memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, y), + IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)), + IMAGE_RGB565_LINE_LEN_BYTES(bitmap)); + } + + break; + } + } +} + +void shared_module_bitmapfilter_mix( + displayio_bitmap_t *bitmap, + displayio_bitmap_t *mask, + const mp_float_t weights[12]) { + + int wt[12]; + for (int i = 0; i < 12; i++) { + // The different scale factors correct for G having 6 bits while R, G have 5 + // by doubling the scale for R/B->G and halving the scale for G->R/B. + // As well, the final value in each row has to be scaled up by the + // component's maxval. + int scale = + (i == 1 || i == 9) ? 32768 : // Mixing G into R/B + (i == 4 || i == 6) ? 131072 : // Mixing R/B into G + (i == 3 || i == 11) ? 65535 * COLOR_B5_MAX : // Offset for R/B + (i == 7) ? 65535 * COLOR_G6_MAX : // Offset for G + 65536; + wt[i] = (int32_t)MICROPY_FLOAT_C_FUN(round)(scale * weights[i]); + } + + check_matching_details(bitmap, bitmap); + + switch (bitmap->bits_per_value) { + default: + mp_raise_ValueError(MP_ERROR_TEXT("unsupported bitmap depth")); + case 16: { + for (int y = 0, yy = bitmap->height; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, y); + for (int x = 0, xx = bitmap->width; x < xx; x++) { + if (mask && common_hal_displayio_bitmap_get_pixel(mask, x, y)) { + continue; // Short circuit. + } + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x); + int32_t r_acc = 0, g_acc = 0, b_acc = 0; + int r = COLOR_RGB565_TO_R5(pixel); + int g = COLOR_RGB565_TO_G6(pixel); + int b = COLOR_RGB565_TO_B5(pixel); + r_acc = r * wt[0] + g * wt[1] + b * wt[2] + wt[3]; + r_acc >>= 16; + if (r_acc < 0) { + r_acc = 0; + } else if (r_acc > COLOR_R5_MAX) { + r_acc = COLOR_R5_MAX; + } + + g_acc = r * wt[4] + g * wt[5] + b * wt[6] + wt[7]; + g_acc >>= 16; + if (g_acc < 0) { + g_acc = 0; + } else if (g_acc > COLOR_G6_MAX) { + g_acc = COLOR_G6_MAX; + } + + b_acc = r * wt[8] + g * wt[9] + b * wt[10] + wt[11]; + b_acc >>= 16; + if (b_acc < 0) { + b_acc = 0; + } else if (b_acc > COLOR_B5_MAX) { + b_acc = COLOR_B5_MAX; + } + + pixel = COLOR_R5_G6_B5_TO_RGB565(r_acc, g_acc, b_acc); + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, pixel); + } + } + break; + } + } +} + +void shared_module_bitmapfilter_solarize( + displayio_bitmap_t *bitmap, + displayio_bitmap_t *mask, + const mp_float_t threshold) { + + int threshold_i = (int32_t)MICROPY_FLOAT_C_FUN(round)(256 * threshold); + switch (bitmap->bits_per_value) { + default: + mp_raise_ValueError(MP_ERROR_TEXT("unsupported bitmap depth")); + case 16: { + for (int y = 0, yy = bitmap->height; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, y); + for (int x = 0, xx = bitmap->width; x < xx; x++) { + if (mask && common_hal_displayio_bitmap_get_pixel(mask, x, y)) { + continue; // Short circuit. + } + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x); + int y = COLOR_RGB565_TO_Y(pixel); + if (y > threshold_i) { + y = MIN(255, MAX(0, 2 * threshold_i - y)); + int u = COLOR_RGB565_TO_U(pixel); + int v = COLOR_RGB565_TO_V(pixel); + pixel = COLOR_YUV_TO_RGB565(y, u, v); + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, pixel); + } + } + } + break; + } + } +} + +void shared_module_bitmapfilter_lookup( + displayio_bitmap_t *bitmap, + displayio_bitmap_t *mask, + const bitmapfilter_lookup_table_t *table) { + + switch (bitmap->bits_per_value) { + default: + mp_raise_ValueError(MP_ERROR_TEXT("unsupported bitmap depth")); + case 16: { + for (int y = 0, yy = bitmap->height; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, y); + for (int x = 0, xx = bitmap->width; x < xx; x++) { + if (mask && common_hal_displayio_bitmap_get_pixel(mask, x, y)) { + continue; // Short circuit. + } + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x); + int r = COLOR_RGB565_TO_R5(pixel); + int g = COLOR_RGB565_TO_G6(pixel); + int b = COLOR_RGB565_TO_B5(pixel); + + r = table->r[r]; + g = table->g[g]; + b = table->b[b]; + + pixel = COLOR_R5_G6_B5_TO_RGB565(r, g, b); + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, pixel); + } + } + break; + } + } +} + +void shared_module_bitmapfilter_false_color( + displayio_bitmap_t *bitmap, + displayio_bitmap_t *mask, + _displayio_color_t palette[256]) { + + uint16_t table[256]; + for (int i = 0; i < 256; i++) { + uint32_t rgb888 = palette[i].rgb888; + int r = rgb888 >> 16; + int g = (rgb888 >> 8) & 0xff; + int b = rgb888 & 0xff; + table[i] = COLOR_R8_G8_B8_TO_RGB565(r, g, b); + } + + switch (bitmap->bits_per_value) { + default: + mp_raise_ValueError(MP_ERROR_TEXT("unsupported bitmap depth")); + case 16: { + for (int y = 0, yy = bitmap->height; y < yy; y++) { + uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(bitmap, y); + for (int x = 0, xx = bitmap->width; x < xx; x++) { + if (mask && common_hal_displayio_bitmap_get_pixel(mask, x, y)) { + continue; // Short circuit. + } + int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x); + int y = COLOR_RGB565_TO_Y(pixel); + pixel = table[y]; + IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, pixel); + } + } + } + } +} diff --git a/shared-module/bitmapfilter/__init__.h b/shared-module/bitmapfilter/__init__.h new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/supervisor/port_heap.h b/supervisor/port_heap.h index 101f78ed690c5..54a7cc80b3aea 100644 --- a/supervisor/port_heap.h +++ b/supervisor/port_heap.h @@ -44,6 +44,6 @@ void *port_malloc(size_t size, bool dma_capable); void port_free(void *ptr); -void port_realloc(void *ptr, size_t size); +void *port_realloc(void *ptr, size_t size); size_t port_heap_get_largest_free_size(void); diff --git a/supervisor/shared/port.c b/supervisor/shared/port.c index 052611d446ae5..0ea521b940389 100644 --- a/supervisor/shared/port.c +++ b/supervisor/shared/port.c @@ -62,8 +62,8 @@ MP_WEAK void port_free(void *ptr) { tlsf_free(heap, ptr); } -MP_WEAK void port_realloc(void *ptr, size_t size) { - tlsf_realloc(heap, ptr, size); +MP_WEAK void *port_realloc(void *ptr, size_t size) { + return tlsf_realloc(heap, ptr, size); } static void max_size_walker(void *ptr, size_t size, int used, void *user) { diff --git a/tests/circuitpython/bitmapfilter_ironbow.py b/tests/circuitpython/bitmapfilter_ironbow.py new file mode 100644 index 0000000000000..fdb282ba14f30 --- /dev/null +++ b/tests/circuitpython/bitmapfilter_ironbow.py @@ -0,0 +1,29 @@ +from displayio import Bitmap +import bitmapfilter +import ulab +from dump_bitmap import dump_bitmap_rgb_swapped +from blinka_image import decode_resource +from ironbow import ironbow_palette + + +def test_pattern(): + return decode_resource("testpattern", 2) + + +def make_quadrant_bitmap(): + b = Bitmap(17, 17, 1) + for i in range(b.height): + for j in range(b.width): + b[i, j] = (i < 8) ^ (j < 8) + return b + + +q = make_quadrant_bitmap() +b = test_pattern() +dump_bitmap_rgb_swapped(b) + +sepia_weights = [0.393, 0.769, 0.189, 0.349, 0.686, 0.168, 0.272, 0.534, 0.131] + +print("ironbow (masked)") +bitmapfilter.false_color(b, ironbow_palette, mask=q) +dump_bitmap_rgb_swapped(b) diff --git a/tests/circuitpython/bitmapfilter_ironbow.py.exp b/tests/circuitpython/bitmapfilter_ironbow.py.exp new file mode 100644 index 0000000000000..f072301a6ded1 --- /dev/null +++ b/tests/circuitpython/bitmapfilter_ironbow.py.exp @@ -0,0 +1,67 @@ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████▓▓▓▓▓▓▓▓████████████ ████████████████████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▓▓▓▓▒▒▒▒████████████▓▓▓▓ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +········████████████············ ········████············████████ ················████████████···· +········████████████············ ········████············████████ ················████████████···· +········████████████············ ········████············████████ ················████████████···· +········████████████············ ········████············████████ ················████████████···· + +ironbow (masked) +········█████████··············· ········█████████··············· ········█████████··············· +········█████████··············· ········█████████··············· ········█████████··············· +········█████████··············· ········█████████··············· ········█████████··············· +░░░░░░░░█████████···░░░░········ ········█████████··············· ░░░░░░░░█████████···░░░░········ +░░░░░░░░█████████░░░░░░░········ ········████▓▓▓▓▓··············· ░░░░░░░░█████████░░░░░░░········ +░░░░░░░░█████████░░░░░░░········ ░░░░░░░░████▓▓▓▓▓···░░░░········ ░░░░░░░░▓▓▓▓▓▓▓▓█░░░░░░░········ +▒▒▒▒▒▒▒▒█████████░░░░░░░····░░░░ ░░░░░░░░████▓▓▓▓▓···░░░░········ ▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓█░░░░░░░····░░░░ +▒▒▒▒▒▒▒▒█████████░░░▒▒▒▒····░░░░ ░░░░░░░░████▓▓▓▓▓···░░░░········ ▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓█░░░▒▒▒▒····░░░░ +▓▓▓▓▓▓▓▓····░░░░░░░░▒▒▒▒░░░░░░░░ ▓▓▓▓▓▓▓▓····░░░░░░░░░░░░········ ▓▓▓▓▓▓▓▓····░░░░░░░░▒▒▒▒░░░░░░░░ +▓▓▓▓▓▓▓▓····▒▒▒▒░░░░▒▒▒▒░░░░░░░░ ▓▓▓▓▓▓▓▓····░░░░░░░░▒▒▒▒········ ▓▓▓▓▓▓▓▓····▒▒▒▒░░░░▒▒▒▒░░░░░░░░ +▓▓▓▓▓▓▓▓····▒▒▒▒░░░░▒▒▒▒░░░░░░░░ ▓▓▓▓▓▓▓▓····░░░░░░░░▒▒▒▒····░░░░ ▓▓▓▓▓▓▓▓····▒▒▒▒░░░░▒▒▒▒░░░░░░░░ +▓▓▓▓▓▓▓▓····▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░ ▓▓▓▓▓▓▓▓····░░░░░░░░▒▒▒▒····░░░░ ▓▓▓▓▓▓▓▓····▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░ +▒▒▒▒▒▒▒▒····▒▒▒▒▒▒▒▒▓▓▓▓░░░░░░░░ ▒▒▒▒▒▒▒▒····▒▒▒▒░░░░▓▓▓▓····░░░░ ▒▒▒▒▒▒▒▒····▒▒▒▒▒▒▒▒▓▓▓▓░░░░░░░░ +▒▒▒▒▒▒▒▒····▒▒▒▒▒▒▒▒▓▓▓▓░░░░░░░░ ▒▒▒▒▒▒▒▒····▒▒▒▒░░░░▓▓▓▓····░░░░ ▒▒▒▒▒▒▒▒····▒▒▒▒▒▒▒▒▓▓▓▓░░░░░░░░ +▒▒▒▒▒▒▒▒····▒▒▒▒▒▒▒▒▓▓▓▓░░░░░░░░ ▒▒▒▒▒▒▒▒····▒▒▒▒▒▒▒▒▓▓▓▓░░░░░░░░ ▒▒▒▒▒▒▒▒····▒▒▒▒▒▒▒▒▓▓▓▓░░░░░░░░ +▒▒▒▒▒▒▒▒····▓▓▓▓▒▒▒▒▓▓▓▓░░░░▒▒▒▒ ▒▒▒▒▒▒▒▒····▓▓▓▓▒▒▒▒▓▓▓▓░░░░░░░░ ▒▒▒▒▒▒▒▒····▓▓▓▓▒▒▒▒▓▓▓▓░░░░▒▒▒▒ +▒▒▒▒▒▒▒▒░░░░▓▓▓▓▒▒▒▒████░░░░▒▒▒▒ ▒▒▒▒▒▒▒▒····▓▓▓▓▒▒▒▒████░░░░░░░░ ▒▒▒▒▒▒▒▒░░░░▓▓▓▓▒▒▒▒████░░░░▒▒▒▒ +████████░░░░▓▓▓▓▓▓▓▓████░░░░▒▒▒▒ ████████····▓▓▓▓▓▓▓▓████░░░░░░░░ ▓▓▓▓▓▓▓▓░░░░▓▓▓▓▓▓▓▓████░░░░▒▒▒▒ +▓▓▓▓▓▓▓▓░░░░▓▓▓▓▓▓▓▓████░░░░▒▒▒▒ ████████····▓▓▓▓▓▓▓▓████░░░░░░░░ ▒▒▒▒▒▒▒▒░░░░▓▓▓▓▓▓▓▓████░░░░▒▒▒▒ +▓▓▓▓▓▓▓▓░░░░▓▓▓▓▓▓▓▓████░░░░▒▒▒▒ ████████····▓▓▓▓▓▓▓▓████░░░░▒▒▒▒ ▒▒▒▒▒▒▒▒░░░░▓▓▓▓▓▓▓▓▓▓▓▓░░░░▒▒▒▒ +▒▒▒▒▒▒▒▒░░░░████▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒ ████████····████▓▓▓▓████░░░░▒▒▒▒ ▒▒▒▒▒▒▒▒░░░░████▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒ +░░░░░░░░░░░░████▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒ ████████····████▓▓▓▓████░░░░▒▒▒▒ ▒▒▒▒▒▒▒▒░░░░████▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒ +░░░░░░░░░░░░████▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒ ████████····████▓▓▓▓████░░░░▒▒▒▒ ▒▒▒▒▒▒▒▒░░░░████▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒ +░░░░░░░░░░░░████▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒ ▓▓▓▓▓▓▓▓····████▓▓▓▓████░░░░▒▒▒▒ ▓▓▓▓▓▓▓▓░░░░▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒ +········░░░░████████░░░░▒▒▒▒▓▓▓▓ ▓▓▓▓▓▓▓▓····████████████░░░░▓▓▓▓ ▓▓▓▓▓▓▓▓░░░░▓▓▓▓████▒▒▒▒▒▒▒▒▓▓▓▓ +········░░░░▓▓▓▓████░░░░▒▒▒▒▓▓▓▓ ▒▒▒▒▒▒▒▒····████████████░░░░▓▓▓▓ ████████░░░░▒▒▒▒████▒▒▒▒▒▒▒▒▓▓▓▓ +········░░░░▓▓▓▓████░░░░▒▒▒▒▓▓▓▓ ░░░░░░░░····████████▓▓▓▓░░░░▓▓▓▓ ████████░░░░▒▒▒▒████▓▓▓▓▒▒▒▒▓▓▓▓ +········░░░░▒▒▒▒████····▒▒▒▒▓▓▓▓ ░░░░░░░░····████████▓▓▓▓▒▒▒▒▓▓▓▓ ████████░░░░▒▒▒▒████▓▓▓▓▒▒▒▒▓▓▓▓ +········░░░░▒▒▒▒████····▒▒▒▒▓▓▓▓ ············████████▓▓▓▓▒▒▒▒▓▓▓▓ ████████░░░░▒▒▒▒▓▓▓▓████▒▒▒▒▓▓▓▓ +········░░░░▒▒▒▒████····▒▒▒▒▓▓▓▓ ············████████▒▒▒▒▒▒▒▒▓▓▓▓ ▓▓▓▓▓▓▓▓░░░░▒▒▒▒▒▒▒▒████▒▒▒▒▓▓▓▓ +········░░░░░░░░▓▓▓▓····▒▒▒▒▓▓▓▓ ············████████░░░░▒▒▒▒▓▓▓▓ ▒▒▒▒▒▒▒▒░░░░▒▒▒▒▒▒▒▒████▒▒▒▒▓▓▓▓ +········░░░░░░░░▓▓▓▓····▒▒▒▒▓▓▓▓ ············████████░░░░▒▒▒▒▓▓▓▓ ████████░░░░▒▒▒▒▒▒▒▒████▒▒▒▒▓▓▓▓ + diff --git a/tests/circuitpython/bitmapfilter_lookup.py b/tests/circuitpython/bitmapfilter_lookup.py new file mode 100644 index 0000000000000..76b49e5ed8cbb --- /dev/null +++ b/tests/circuitpython/bitmapfilter_lookup.py @@ -0,0 +1,26 @@ +from math import sin, cos, pi +from displayio import Bitmap +import bitmapfilter +import ulab +from dump_bitmap import dump_bitmap_rgb_swapped +from blinka_image import decode_resource + + +def func1(x): + return sin(x * pi) + + +def func2(x): + return cos(x * pi / 2) + + +def test_pattern(): + return decode_resource("testpattern", 2) + + +b = test_pattern() +dump_bitmap_rgb_swapped(b) + +print("lookup3") +bitmapfilter.lookup(b, (func1, func2, func2)) +dump_bitmap_rgb_swapped(b) diff --git a/tests/circuitpython/bitmapfilter_lookup.py.exp b/tests/circuitpython/bitmapfilter_lookup.py.exp new file mode 100644 index 0000000000000..68499b3064a04 --- /dev/null +++ b/tests/circuitpython/bitmapfilter_lookup.py.exp @@ -0,0 +1,67 @@ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████▓▓▓▓▓▓▓▓████████████ ████████████████████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▓▓▓▓▒▒▒▒████████████▓▓▓▓ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +········████████████············ ········████············████████ ················████████████···· +········████████████············ ········████············████████ ················████████████···· +········████████████············ ········████············████████ ················████████████···· +········████████████············ ········████············████████ ················████████████···· + +lookup3 +████████████████████████████████ ································ ································ +████████████████████████████████ ································ ································ +████████████████████████████████ ································ ································ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ································ ································ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ································ ································ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ································ ································ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ································ ································ +░░░░░░░░████████████░░░░▒▒▒▒▒▒▒▒ ································ ································ +░░░░░░░░████████████░░░░░░░░░░░░ ································ ································ +░░░░░░░░████████████░░░░░░░░░░░░ ································ ································ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░····░░░░░░░░░░░░········ ░░░░░░░░░░░░░░░░············░░░░ +········████████████····░░░░···· ░░░░░░░░····░░░░░░░░░░░░········ ░░░░░░░░░░░░░░░░············░░░░ +········████████████············ ░░░░░░░░····░░░░░░░░░░░░········ ░░░░░░░░░░░░░░░░············░░░░ +········████████████············ ░░░░░░░░····░░░░░░░░░░░░········ ░░░░░░░░░░░░░░░░············░░░░ +········████████████············ ░░░░░░░░····░░░░░░░░░░░░········ ░░░░░░░░░░░░░░░░············░░░░ +········████████████············ ░░░░░░░░····░░░░░░░░░░░░········ ░░░░░░░░░░░░░░░░············░░░░ +········████████████············ ░░░░░░░░····░░░░░░░░░░░░········ ░░░░░░░░░░░░░░░░············░░░░ +········████████████············ ░░░░░░░░····░░░░░░░░░░░░········ ░░░░░░░░░░░░░░░░············░░░░ +········████████████············ ▒▒▒▒▒▒▒▒····▒▒▒▒▒▒▒▒▒▒▒▒········ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒············▒▒▒▒ +········████████████············ ▒▒▒▒▒▒▒▒····▒▒▒▒▒▒▒▒▒▒▒▒········ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒············▒▒▒▒ +········████████████············ ▒▒▒▒▒▒▒▒····▒▒▒▒▒▒▒▒▒▒▒▒········ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒············▒▒▒▒ +░░░░░░░░████████████░░░░░░░░░░░░ ▒▒▒▒▒▒▒▒····▒▒▒▒▒▒▒▒▒▒▒▒········ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒············▒▒▒▒ +░░░░░░░░████████████░░░░░░░░░░░░ ▒▒▒▒▒▒▒▒····▒▒▒▒▒▒▒▒▒▒▒▒········ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒············▒▒▒▒ +░░░░░░░░████████████░░░░░░░░░░░░ ▒▒▒▒▒▒▒▒····▒▒▒▒▒▒▒▒▒▒▒▒········ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒············▒▒▒▒ +░░░░░░░░████████████░░░░░░░░░░░░ ▓▓▓▓▓▓▓▓····▓▓▓▓▓▓▓▓▓▓▓▓········ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓············▓▓▓▓ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▓▓▓▓▓▓▓▓····▓▓▓▓▓▓▓▓▓▓▓▓········ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓············▓▓▓▓ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▓▓▓▓▓▓▓▓····▓▓▓▓▓▓▓▓▓▓▓▓········ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓············▓▓▓▓ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▓▓▓▓▓▓▓▓····▓▓▓▓▓▓▓▓▓▓▓▓········ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓············▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓····▓▓▓▓▓▓▓▓▓▓▓▓········ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓············▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ████████····████████████········ ████████████████············████ +████████████████████████████████ ████████····████████████········ ████████████████············████ +████████████████████████████████ ████████····████████████········ ████████████████············████ + diff --git a/tests/circuitpython/bitmapfilter_mix.py b/tests/circuitpython/bitmapfilter_mix.py new file mode 100644 index 0000000000000..5e94afbeb7a37 --- /dev/null +++ b/tests/circuitpython/bitmapfilter_mix.py @@ -0,0 +1,54 @@ +from displayio import Bitmap +import bitmapfilter +import ulab +from dump_bitmap import dump_bitmap_rgb_swapped +from blinka_image import decode_resource + + +def test_pattern(): + return decode_resource("testpattern", 2) + + +def make_quadrant_bitmap(): + b = Bitmap(17, 17, 1) + for i in range(b.height): + for j in range(b.width): + b[i, j] = (i < 8) ^ (j < 8) + return b + + +q = make_quadrant_bitmap() +b = test_pattern() +dump_bitmap_rgb_swapped(b) + +sepia_weights = bitmapfilter.ChannelMixer( + 0.393, 0.769, 0.189, 0.349, 0.686, 0.168, 0.272, 0.534, 0.131 +) + +print("sepia") +bitmapfilter.mix(b, sepia_weights) +dump_bitmap_rgb_swapped(b) + +# Red channel only +print("red channel only (note: masked)") +b = test_pattern() +bitmapfilter.mix(b, bitmapfilter.ChannelScale(1, 0, 0), mask=q) +dump_bitmap_rgb_swapped(b) + +# Scale green channel +print("scale green channel (note: masked)") +b = test_pattern() +bitmapfilter.mix(b, bitmapfilter.ChannelScale(1, 2, 0), mask=q) +dump_bitmap_rgb_swapped(b) + +# Swap R & G channels +print("swap R&G") +b = test_pattern() +bitmapfilter.mix(b, bitmapfilter.ChannelMixerOffset(0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0)) +dump_bitmap_rgb_swapped(b) + +# invert B +print("invert B") +b = test_pattern() +bitmapfilter.mix(b, bitmapfilter.ChannelScaleOffset(1, 0, 1, 0, -1, 1)) +dump_bitmap_rgb_swapped(b) diff --git a/tests/circuitpython/bitmapfilter_mix.py.exp b/tests/circuitpython/bitmapfilter_mix.py.exp new file mode 100644 index 0000000000000..45ee444204ee9 --- /dev/null +++ b/tests/circuitpython/bitmapfilter_mix.py.exp @@ -0,0 +1,203 @@ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████▓▓▓▓▓▓▓▓████████████ ████████████████████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▓▓▓▓▒▒▒▒████████████▓▓▓▓ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +········████████████············ ········████············████████ ················████████████···· +········████████████············ ········████············████████ ················████████████···· +········████████████············ ········████············████████ ················████████████···· +········████████████············ ········████············████████ ················████████████···· + +sepia +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +▓▓▓▓▓▓▓▓████████████████████████ ████████████████████████████████ ████████████████████████████████ +▓▓▓▓▓▓▓▓████▓▓▓▓████▓▓▓▓████████ ▓▓▓▓▓▓▓▓████▓▓▓▓████▓▓▓▓████████ ▓▓▓▓▓▓▓▓████████████████████████ +▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓████████████▓▓▓▓████████ +▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓████▓▓▓▓████▓▓▓▓████████ +▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ +▒▒▒▒▒▒▒▒████▓▓▓▓▓▓▓▓▓▓▓▓████▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ +▒▒▒▒▒▒▒▒████▓▓▓▓▓▓▓▓▓▓▓▓████▓▓▓▓ ▒▒▒▒▒▒▒▒████▓▓▓▓▓▓▓▓▓▓▓▓████▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████▓▓▓▓ +▒▒▒▒▒▒▒▒████▓▓▓▓▓▓▓▓▒▒▒▒████▓▓▓▓ ▒▒▒▒▒▒▒▒████▓▓▓▓▓▓▓▓▓▓▓▓████▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████▓▓▓▓ +▒▒▒▒▒▒▒▒████▓▓▓▓▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▓▓▓▓▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████▓▓▓▓ +▒▒▒▒▒▒▒▒████▒▒▒▒▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▓▓▓▓▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▓▓▓▓▓▓▓▓▓▓▓▓████▓▓▓▓ +▒▒▒▒▒▒▒▒████▒▒▒▒▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▓▓▓▓▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▓▓▓▓▓▓▓▓▓▓▓▓████▓▓▓▓ +░░░░░░░░████▒▒▒▒▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▒▒▒▒▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▓▓▓▓▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ +░░░░░░░░████▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▒▒▒▒▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▓▓▓▓▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ +░░░░░░░░████▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓ ░░░░░░░░████▒▒▒▒▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▓▓▓▓▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ +░░░░░░░░████▒▒▒▒▒▒▒▒░░░░▓▓▓▓▓▓▓▓ ░░░░░░░░████▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▒▒▒▒▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ +░░░░░░░░████▒▒▒▒▒▒▒▒░░░░▓▓▓▓▓▓▓▓ ░░░░░░░░████▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▒▒▒▒▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ +░░░░░░░░████▒▒▒▒▒▒▒▒░░░░▓▓▓▓▓▓▓▓ ░░░░░░░░████▒▒▒▒▒▒▒▒░░░░▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▒▒▒▒▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ +········████░░░░▒▒▒▒░░░░▓▓▓▓▒▒▒▒ ░░░░░░░░████▒▒▒▒▒▒▒▒░░░░▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▒▒▒▒▓▓▓▓▒▒▒▒▓▓▓▓▓▓▓▓ +········▓▓▓▓░░░░▒▒▒▒░░░░▓▓▓▓▒▒▒▒ ░░░░░░░░████▒▒▒▒▒▒▒▒░░░░▓▓▓▓▓▓▓▓ ░░░░░░░░████▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓ +········▓▓▓▓░░░░▒▒▒▒░░░░▓▓▓▓▒▒▒▒ ········████▒▒▒▒▒▒▒▒░░░░▓▓▓▓▓▓▓▓ ░░░░░░░░████▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓ +········▓▓▓▓░░░░▒▒▒▒····▓▓▓▓▒▒▒▒ ········▓▓▓▓░░░░▒▒▒▒░░░░▓▓▓▓▒▒▒▒ ░░░░░░░░████▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▓▓ +········▓▓▓▓░░░░▒▒▒▒····▓▓▓▓▒▒▒▒ ········▓▓▓▓░░░░▒▒▒▒░░░░▓▓▓▓▒▒▒▒ ░░░░░░░░████▒▒▒▒▒▒▒▒░░░░▓▓▓▓▓▓▓▓ +········▓▓▓▓░░░░░░░░····▓▓▓▓▒▒▒▒ ········▓▓▓▓░░░░▒▒▒▒░░░░▓▓▓▓▒▒▒▒ ░░░░░░░░████▒▒▒▒▒▒▒▒░░░░▓▓▓▓▓▓▓▓ +········▓▓▓▓░░░░░░░░····▓▓▓▓▒▒▒▒ ········▓▓▓▓░░░░▒▒▒▒····▓▓▓▓▒▒▒▒ ░░░░░░░░████▒▒▒▒▒▒▒▒░░░░▓▓▓▓▓▓▓▓ +········▓▓▓▓░░░░░░░░····▓▓▓▓▒▒▒▒ ········▓▓▓▓░░░░▒▒▒▒····▓▓▓▓▒▒▒▒ ░░░░░░░░████▒▒▒▒▒▒▒▒░░░░▓▓▓▓▓▓▓▓ +········▓▓▓▓····░░░░····▓▓▓▓▒▒▒▒ ········▓▓▓▓░░░░░░░░····▓▓▓▓▒▒▒▒ ░░░░░░░░████▒▒▒▒▒▒▒▒░░░░▓▓▓▓▓▓▓▓ +········▓▓▓▓····░░░░····▓▓▓▓▒▒▒▒ ········▓▓▓▓░░░░░░░░····▓▓▓▓▒▒▒▒ ········████░░░░▒▒▒▒░░░░▓▓▓▓▒▒▒▒ +········▓▓▓▓····░░░░····▒▒▒▒▒▒▒▒ ········▓▓▓▓░░░░░░░░····▓▓▓▓▒▒▒▒ ········▓▓▓▓░░░░▒▒▒▒░░░░▓▓▓▓▒▒▒▒ + +red channel only (note: masked) +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████▓▓▓▓▓███████████████ ████████████████████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ████████████▓▓▓▓▓███████████████ ████████▓▓▓▓▓▓▓▓████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ████████████▓▓▓▓▓███████████████ ████████▓▓▓▓▓▓▓▓████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ████████████▓▓▓▓▓███████████████ ████████▓▓▓▓▓▓▓▓████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████████████████████████ ▓▓▓▓▓▓▓▓████████████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████████████████████████ ▓▓▓▓▓▓▓▓████████████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████████████████████████ ▓▓▓▓▓▓▓▓████████████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████████████████████████ ▓▓▓▓▓▓▓▓████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████████████████████████ ▒▒▒▒▒▒▒▒████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████████████████████████ ▒▒▒▒▒▒▒▒████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████████████████████████ ▒▒▒▒▒▒▒▒████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████████████████████████ ▒▒▒▒▒▒▒▒████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████████████████████████ ▒▒▒▒▒▒▒▒████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ████████████████████████████████ ████████████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ████████████████████████████████ ████████████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ████████████████████████████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ████████████████████████████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ████████████████████████████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ████████████████████████████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ████████████████████████████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ████████████████████████████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ████████████████████████████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ████████████████████████████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ████████████████████████████████ ████████████████████████████████ +········████████████············ ████████████████████████████████ ████████████████████████████████ +········████████████············ ████████████████████████████████ ████████████████████████████████ +········████████████············ ████████████████████████████████ ████████████████████████████████ +········████████████············ ████████████████████████████████ ████████████████████████████████ + +scale green channel (note: masked) +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ▓▓▓▓▓▓▓▓█████████▓▓▓▓▓▓▓████████ ████████████████████████████████ +████████████████████████████████ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ████████████████████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ████████▓▓▓▓▓▓▓▓████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▓▓▓▓▓▒▒▒▒▒▒▒████████ ████████▓▓▓▓▓▓▓▓████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▒▒▒▒▒▒▒▒████▓▓▓▓▓▒▒▒▒▒▒▒████████ ████████▓▓▓▓▓▓▓▓████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▓▓▓▓▓▓▓▓████████████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▓▓▓▓▓▓▓▓████████████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████░░░░░░░░░░░░████████ ▓▓▓▓▓▓▓▓████████████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████░░░░░░░░░░░░████████ ▓▓▓▓▓▓▓▓████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████░░░░░░░░░░░░████████ ▒▒▒▒▒▒▒▒████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████░░░░░░░░░░░░████████ ▒▒▒▒▒▒▒▒████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████············████████ ▒▒▒▒▒▒▒▒████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████············████████ ▒▒▒▒▒▒▒▒████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████············████████ ▒▒▒▒▒▒▒▒████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ········████············████████ ████████████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ········████············████████ ████████████████████████████████ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ········████············████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ········████············████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ········████············████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ········████············████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ········████············████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ········████············████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ········████············████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ········████············████████ ████████████████████████████████ +░░░░░░░░████████████░░░░░░░░░░░░ ········████············████████ ████████████████████████████████ +········████████████············ ········████············████████ ████████████████████████████████ +········████████████············ ········████············████████ ████████████████████████████████ +········████████████············ ········████············████████ ████████████████████████████████ +········████████████············ ········████············████████ ████████████████████████████████ + +swap R&G +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████▓▓▓▓▓▓▓▓████████████ ████████████████████████████████ ████████████████████████████████ +▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▓▓▓▓▒▒▒▒████████████▓▓▓▓ +▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░████████████░░░░ +········████············████████ ········████████████············ ················████████████···· +········████············████████ ········████████████············ ················████████████···· +········████············████████ ········████████████············ ················████████████···· +········████············████████ ········████████████············ ················████████████···· + +invert B +████████████████████████████████ ████████████████████████████████ ································ +████████████████████████████████ ████████████████████████████████ ································ +████████████████████████████████ ████████████████████████████████ ································ +████████████████████████████████ ████████████████████████████████ ································ +████████████████████████████████ ████████████▓▓▓▓▓▓▓▓████████████ ░░░░░░░░░░░░░░░░············░░░░ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ░░░░░░░░░░░░░░░░············░░░░ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ░░░░░░░░░░░░░░░░············░░░░ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ░░░░░░░░░░░░░░░░············░░░░ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ░░░░░░░░░░░░░░░░············░░░░ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ░░░░░░░░░░░░░░░░············░░░░ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ░░░░░░░░░░░░░░░░············░░░░ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▒▒▒▒▒▒▒▒░░░░░░░░············▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒············▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒············▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒············▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒············▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒············▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒············▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒············▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓············▓▓▓▓ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓············▓▓▓▓ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓············▓▓▓▓ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓············▓▓▓▓ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓············▓▓▓▓ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓············▓▓▓▓ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓············▓▓▓▓ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓············▓▓▓▓ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ████████████████············████ +········████████████············ ········████············████████ ████████████████············████ +········████████████············ ········████············████████ ████████████████············████ +········████████████············ ········████············████████ ████████████████············████ +········████████████············ ········████············████████ ████████████████············████ + diff --git a/tests/circuitpython/bitmapfilter_morph.py b/tests/circuitpython/bitmapfilter_morph.py new file mode 100644 index 0000000000000..6d6f7cf6fc3c8 --- /dev/null +++ b/tests/circuitpython/bitmapfilter_morph.py @@ -0,0 +1,41 @@ +from displayio import Bitmap +import bitmapfilter +from dump_bitmap import dump_bitmap + + +def make_circle_bitmap(): + b = Bitmap(17, 17, 65535) + for i in range(b.height): + y = i - 8 + for j in range(b.width): + x = j - 8 + c = (x * x + y * y) > 64 + b[i, j] = 0xFFFF if c else 0 + return b + + +def make_quadrant_bitmap(): + b = Bitmap(17, 17, 1) + for i in range(b.height): + for j in range(b.width): + b[i, j] = (i < 8) ^ (j < 8) + return b + + +blur = (1, 2, 1, 2, 4, 2, 1, 2, 1) +sharpen = [-1, -2, -1, -2, 4, -2, -1, -2, -1] +b = make_circle_bitmap() +dump_bitmap(b) +bitmapfilter.morph(b, weights=blur) +dump_bitmap(b) + +b = make_circle_bitmap() +q = make_quadrant_bitmap() +dump_bitmap(q) +bitmapfilter.morph(b, mask=q, weights=blur, add=1 / 4) +dump_bitmap(b) + +# This is a kind of edge filter +b = make_circle_bitmap() +bitmapfilter.morph(b, weights=sharpen, threshold=True, add=0.125, invert=True) +dump_bitmap(b) diff --git a/tests/circuitpython/bitmapfilter_morph.py.exp b/tests/circuitpython/bitmapfilter_morph.py.exp new file mode 100644 index 0000000000000..4d0f81785e338 --- /dev/null +++ b/tests/circuitpython/bitmapfilter_morph.py.exp @@ -0,0 +1,90 @@ +········█········ +·····███████····· +···███████████··· +··█████████████·· +··█████████████·· +·███████████████· +·███████████████· +·███████████████· +█████████████████ +·███████████████· +·███████████████· +·███████████████· +··█████████████·· +··█████████████·· +···███████████··· +·····███████····· +········█········ + +·····░░▒▓▒░░····· +···░▒▓▓▓█▓▓▓▒░··· +··░▓▓███████▓▓░·· +·░▓███████████▓░· +·▒▓███████████▓▒· +░▓█████████████▓░ +░▓█████████████▓░ +▒▓█████████████▓▒ +▓███████████████▓ +▒▓█████████████▓▒ +░▓█████████████▓░ +░▓█████████████▓░ +·▒▓███████████▓▒· +·░▓███████████▓░· +··░▓▓███████▓▓░·· +···░▒▓▓▓█▓▓▓▒░··· +·····░░▒▓▒░░····· + +████████▓▓▓▓▓▓▓▓▓ +████████▓▓▓▓▓▓▓▓▓ +████████▓▓▓▓▓▓▓▓▓ +████████▓▓▓▓▓▓▓▓▓ +████████▓▓▓▓▓▓▓▓▓ +████████▓▓▓▓▓▓▓▓▓ +████████▓▓▓▓▓▓▓▓▓ +████████▓▓▓▓▓▓▓▓▓ +▓▓▓▓▓▓▓▓█████████ +▓▓▓▓▓▓▓▓█████████ +▓▓▓▓▓▓▓▓█████████ +▓▓▓▓▓▓▓▓█████████ +▓▓▓▓▓▓▓▓█████████ +▓▓▓▓▓▓▓▓█████████ +▓▓▓▓▓▓▓▓█████████ +▓▓▓▓▓▓▓▓█████████ +▓▓▓▓▓▓▓▓█████████ + +········█········ +·····░░░████····· +···░░▒▒▒██████··· +··░▒▒▒▒▒███████·· +··░▒▒▒▒▒███████·· +·░▒▒▒▒▒▒████████· +·░▒▒▒▒▒▒████████· +·░▒▒▒▒▒▒████████· +████████▒▒▒▒▒▒▒▒░ +·███████▒▒▒▒▒▒▒░· +·███████▒▒▒▒▒▒▒░· +·███████▒▒▒▒▒▒▒░· +··██████▒▒▒▒▒▒░·· +··██████▒▒▒▒▒▒░·· +···█████▒▒▒▒░░··· +·····███▒░░░····· +········░········ + +·····███·███····· +···██·······██··· +··█···········█·· +·█·············█· +·█·············█· +█···············█ +█···············█ +█···············█ +················· +█···············█ +█···············█ +█···············█ +·█·············█· +·█·············█· +··█···········█·· +···██·······██··· +·····███·███····· + diff --git a/tests/circuitpython/bitmapfilter_solar.py b/tests/circuitpython/bitmapfilter_solar.py new file mode 100644 index 0000000000000..07dfd44eb9a29 --- /dev/null +++ b/tests/circuitpython/bitmapfilter_solar.py @@ -0,0 +1,26 @@ +from displayio import Bitmap +import bitmapfilter +import ulab +from dump_bitmap import dump_bitmap_rgb_swapped +from blinka_image import decode_resource + + +def test_pattern(): + return decode_resource("testpattern", 2) + + +def make_quadrant_bitmap(): + b = Bitmap(17, 17, 1) + for i in range(b.height): + for j in range(b.width): + b[i, j] = (i < 8) ^ (j < 8) + return b + + +q = make_quadrant_bitmap() +b = test_pattern() +dump_bitmap_rgb_swapped(b) + +print("solarize (masked)") +bitmapfilter.solarize(b, mask=q) +dump_bitmap_rgb_swapped(b) diff --git a/tests/circuitpython/bitmapfilter_solar.py.exp b/tests/circuitpython/bitmapfilter_solar.py.exp new file mode 100644 index 0000000000000..9ddb5945e8787 --- /dev/null +++ b/tests/circuitpython/bitmapfilter_solar.py.exp @@ -0,0 +1,67 @@ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████▓▓▓▓▓▓▓▓████████████ ████████████████████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▓▓▓▓▒▒▒▒████████████▓▓▓▓ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +░░░░░░░░████████████░░░░░░░░░░░░ ░░░░░░░░████░░░░░░░░░░░░████████ ░░░░░░░░░░░░░░░░████████████░░░░ +········████████████············ ········████············████████ ················████████████···· +········████████████············ ········████············████████ ················████████████···· +········████████████············ ········████············████████ ················████████████···· +········████████████············ ········████············████████ ················████████████···· + +solarize (masked) +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████████████████████████ ████████████████████████████████ +████████████████████████████████ ████████████▓▓▓▓▓▓▓▓████████████ ████████████████████████████████ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▓▓▓▓▓▓▓▓████████████▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓████▓▓▓▓▓▓▓▓▓▓▓▓████████ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓████████████▓▓▓▓ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▓▓▓▓▒▒▒▒████████████▓▓▓▓ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▒▒▒▒▒▒▒▒████████████▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒████▒▒▒▒▒▒▒▒▒▒▒▒████████ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████▒▒▒▒ +▓▓▓▓▓▓▓▓████████████▒▒▒▒░░░░░░░░ ▓▓▓▓▓▓▓▓████░░░░░░░░▒▒▒▒████████ ▓▓▓▓▓▓▓▓░░░░░░░░████████████░░░░ +▓▓▓▓▓▓▓▓████████████▒▒▒▒░░░░░░░░ ▓▓▓▓▓▓▓▓████░░░░░░░░▒▒▒▒████████ ▓▓▓▓▓▓▓▓░░░░░░░░████████████░░░░ +▓▓▓▓▓▓▓▓████████████▒▒▒▒░░░░░░░░ ▓▓▓▓▓▓▓▓████░░░░░░░░▒▒▒▒████████ ▓▓▓▓▓▓▓▓░░░░░░░░████████████░░░░ +▓▓▓▓▓▓▓▓████████████▒▒▒▒░░░░░░░░ ▓▓▓▓▓▓▓▓████░░░░░░░░▒▒▒▒████████ ▓▓▓▓▓▓▓▓░░░░░░░░████████████░░░░ +▓▓▓▓▓▓▓▓████████████▒▒▒▒░░░░░░░░ ▓▓▓▓▓▓▓▓████░░░░░░░░▒▒▒▒████████ ▓▓▓▓▓▓▓▓░░░░░░░░████████████░░░░ +▓▓▓▓▓▓▓▓████████████▓▓▓▓░░░░░░░░ ▓▓▓▓▓▓▓▓████░░░░░░░░▒▒▒▒████████ ▓▓▓▓▓▓▓▓░░░░░░░░████████████░░░░ +▓▓▓▓▓▓▓▓████████████▓▓▓▓░░░░░░░░ ▓▓▓▓▓▓▓▓████░░░░░░░░▓▓▓▓████████ ▓▓▓▓▓▓▓▓░░░░░░░░████████████░░░░ +▓▓▓▓▓▓▓▓████████████▓▓▓▓░░░░░░░░ ▓▓▓▓▓▓▓▓████░░░░░░░░▓▓▓▓████████ ▓▓▓▓▓▓▓▓░░░░░░░░████████████░░░░ +████████████████████▓▓▓▓········ ████████████░░░░░░░░▓▓▓▓████████ ████████····▒▒▒▒████████████···· +████████████████████▓▓▓▓········ ████████████░░░░░░░░▓▓▓▓████████ ████████····▒▒▒▒████████████···· +████████████████████▓▓▓▓········ ████████████▒▒▒▒░░░░▓▓▓▓████████ ████████····▒▒▒▒████████████···· +████████████████████▓▓▓▓········ ████████████▒▒▒▒░░░░▓▓▓▓████████ ████████····▒▒▒▒████████████···· + diff --git a/tests/testlib/blinka_image.py b/tests/testlib/blinka_image.py new file mode 100644 index 0000000000000..404425d0ae380 --- /dev/null +++ b/tests/testlib/blinka_image.py @@ -0,0 +1,69 @@ +import binascii +from displayio import Bitmap +import jpegio + +content = binascii.a2b_base64( + b""" +/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDACEXGR0ZFSEdGx0lIyEoMlM2Mi4uMmZJTTxTeWp/fXdq +dHKFlr+ihY21kHJ0puOotcbM1tjWgaDr/OnQ+r/S1s7/2wBDASMlJTIsMmI2NmLOiXSJzs7Ozs7O +zs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7/wAARCADwAPADASIA +AhEBAxEB/8QAGgABAAMBAQEAAAAAAAAAAAAAAAIDBAEFBv/EACsQAAICAQMDAwMEAwAAAAAAAAAB +AgMREiExBEFREyJhMkJSBTNxgRRikf/EABgBAQEBAQEAAAAAAAAAAAAAAAACAQME/8QAIxEBAQAC +AgICAgMBAAAAAAAAAAECEQMSITFBURMiMmFxof/aAAwDAQACEQMRAD8A8oAAAAAAAAAAAAAB2MXJ +7FsafLNktbpSC/0oh0rsb0pqqATlU1xuQJs0wAAAAAAAAAAAAAAAAAAAAAAAAAAADDfY6oSfYDh2 +MXJ4RONLfOxbGKitipjflshFKKwW1U23vFUHL57EY1+rZCHlnrz6qrooKuCSx3LtvqGWXV58+g6q +EdTgmvgzJ7tNYa5TPo6+ohKmM3JPPg839Y6eMdN8FjLw/kmZX5Jk88hOCkvkmDpZtbI1h4YLbo/c +VHGzVRQAGMAAAAAAAAAAAAAAAAAAAC5AA0rSltgOcU8ZK61GSw+STqWcnWW68LWAAtqdE9F0ZeGV +9e5O7PZ8HQ9+dybNoyx3ZVXT2ThNNuWnwbuo66V9Cq9NYXdmYGdfGm9JvaEYNfcTAKk0pGxZgzMa +pfSzKc805AAISAAAAAAAAAAAAAAAAAAAAABZCU2ttytLLwXWPRFQj/Zs8KxnzXVOX4ndUvxM+X5Z +JWSXcqZG161PnY6lgpVsu5ZCxS/kqZStlTABbQAARseIMzF9zxAoOWftGQACGAAAAAAAAAAAAAAA +AAAAAACyiOZanwiE3qk2S9RqGldyAVbNSQAASHYvDTOCKy0BrXAC4B3dAAGim97pFRKx5myJwyu6 +igAMYAAAAAAAAAAAAAAAAAAAAAAAAAAAWUxzLPgrNtENMF5ZuPt048O9RBKfJE7NymroIzeItkim +6XCMyuomqgAcUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC3p4KdizwjelAz9PDTDPdljeEdMfD1Y8Ws +d70XqOVjkqAOjhJqBlm9Umy+2WImc5Z34ZkAAhIAAAAAAAAAAAAAAAAAAAAAAAAAABZRW7LEvBWb +OmjohnuzZ7Xhhcr4XaWuxG2LUcktT8lc7HLbsdZp25byTUutIAHG8LJrkpulmWPBWG8tsHG3dc6A +AwAdUW+w0S8DQ4BjAAAAAAAAAAAAAAAAAAAAAAtyz09McyNk2I1R1zSN6WFgp6SKjFya5NOYeCsZ +4enitwn8ark8RKjRZKGjHcznSTSMuS53zNBXc8Rx5LCmfvsS7GZekVUEm+EaFXFdiSSXCI6M6qY1 +N87Fsa4rsSBcxkboACWTWoygpLdFFkHB78HowUfTxjcz9UloRGchMe0yt8aZAd0vwcObmAAAAAAA +AAAAAAABOENX8CTY7RhXRzwW9R7rFFdyEqsLMeUT6eLstcpPgvVnhcmM9r4rTFI6S0Pyjqrb7lar +13n45PbPJ5Zw7JYk0cKea3fkI0VuyUpITeIMt6RqNL3WTL7Rlv4QaaZOEHOWOCeU+6Oxa1LdDbvl +xaxt2rnW4yxycUGWzktT3RB2QX3Iy5Kw48esuVW4j6fBBJIrfUwUGllsqd05fTHAuW0cdw49/wCt +OuME3J4MspO6f+qCrcnmbyTSSWw1b7Rllcrb9ukZQUlwSJ11ufBWtptkm6xSi4vDOF/VQ0teSg42 +aqbNUABjAAAAAAAAA21U5gsGI9DpZ6obdkXh7VP43XtTb7E0yXTRxXnyc6rheWyyCxBI23deniws +y8pHJScVszpGxPHBs9unLrrdq3uAC3kV3P2nFVtyxd2Rak8Ea3Wa3VfpP8mPSf5MvhXKfBBpp4N6 +w8W6V+l5bCqiWYJyqko5HWF1PapQiuxI7h+CdVep+41t/WbVhLLwiyVeJNJ7HYxUXkbXjx5ZTcQd +clyi2paWSsfBltu+2HPky3VMcZ+LeXuo3P1b8dkcdUTsI6V8kzJj9uevtnnU47rdEDWZ7YaXlcMn +LHXmMsQABCQAAAAll4Asqrzu+CaU65aq3/RNLSkjp1mM0vU0qlZKc4qSxubVJY+kxz/ciajJ4rtx +4TPdyT1R/E5OxaMY5IkLOxUreXhx67QABTirt+qP8mpcIy3cJhTtx5Od9unHnMLdttbxkg92Z1fb +H7UPXs/EbbjnhM7l9tBOTehGT15/iHfa1jSJTPPDK436aCUPqRk9S5/BzFr5lgTas+WZY2RpnOKb +y0VS6iK+lZZX6S7tskopcI3VqPy5a1HJTsue+yOxgokgbI5SAAKaHLIZplLwdFvtpfyTl6Otynhk +ABxcwAACVbxZF/JEkoSxqEGyxNvJDDZOqanBeS6vCT2O0u3fkw649sWK3ZxfybIxzFNNFF1eYto7 +RLVWvgnxtWGOcy1vS/Q/KDrTjuyAecM2WLz4+TLHXZS+QAW86NizBnKnmOPBMp/bs+GTfF2yrgOQ +U0Aaa5QAAJN8IAACTrko6sbBlsiIO4fgnXD3e7gxVl1vSslBZks8Fs4RUtkcMt06cfH3x3U5qKw0 +jF1U8tRXY0dRaoQS7mBtt5ZGdcplMePpAAEOYAAB3U33OACUJuDyjXV1MM+7YxA2XSu111b3ODz7 +kUVSULnHOzM4G3S81uv6elhnCqjqm0oz5L9fwi5qu2PJnlNyf9VOuTeUiBpVj8FEovLZe443HPdt +nhEjKKksMkAlXCfpvTNbeTTXpypLcpaTWGV4lU8xlt4J8xUykmrPDbalJor0IqXVZfvRZG2EuJGd +tuvDMOki6rCTWCtxTfBODWHuiOTbfBhhj3yrmleC1vNZXleTrsiq95ISt5ccf1/1w6uUUy6iC43K +pdTL7VgncVny4ya212NJ7vBms6hLaH/SiU5TeZPJEy5beb8tmMxjrbk8t5OAEuQAAAAAAAAAAAAA +E4XThw9iADZbPTTHqvKJf5EPkyA3ddZzZxqd1bIO6PZMoBvapvJasdrfGxW23ywDLbXPYADB1Sa4 +bGuXlnADbup+WcAAAAAAAAAAAAD/2Q==""" +) + +decoder = jpegio.JpegDecoder() + + +def decode_common(content, scale): + w, h = decoder.open(content) + bitmap = Bitmap(w >> scale, h >> scale, 65535) + decoder.decode(bitmap, scale=scale) + return bitmap + + +def decode_blinka(scale): + return decode_common(content, scale) + + +def decode_resource(rsrc, scale): + rsrc = __file__.rsplit("/", 1)[0] + "/" + rsrc + ".jpg" + with open(rsrc, "rb") as f: + return decode_common(f, scale) diff --git a/tests/testlib/blue.jpg b/tests/testlib/blue.jpg new file mode 100644 index 0000000000000..64bbf0e42dee4 Binary files /dev/null and b/tests/testlib/blue.jpg differ diff --git a/tests/testlib/dump_bitmap.py b/tests/testlib/dump_bitmap.py new file mode 100644 index 0000000000000..65ed03ec6221f --- /dev/null +++ b/tests/testlib/dump_bitmap.py @@ -0,0 +1,17 @@ +palette = list("█▓▓▒▒░░·") + + +def dump_bitmap(b, shifts=(0,)): + for i in range(b.height): + for shift in shifts: + for j in range(b.width): + # Bit order is gggBBBBBRRRRRGGG" so shift of 0 takes high order bits of G + p = (b[j, i] >> shift) & 7 + print(end=palette[p]) + print(end=" ") + print() + print() + + +def dump_bitmap_rgb_swapped(b): + dump_bitmap(b, (5, 0, 10)) diff --git a/tests/testlib/green.jpg b/tests/testlib/green.jpg new file mode 100644 index 0000000000000..992ad648af67d Binary files /dev/null and b/tests/testlib/green.jpg differ diff --git a/tests/testlib/ironbow.py b/tests/testlib/ironbow.py new file mode 100644 index 0000000000000..2f9b31322fb6f --- /dev/null +++ b/tests/testlib/ironbow.py @@ -0,0 +1,45 @@ +import displayio + +ironbow_palette = displayio.Palette(256) + +# fmt: off +for i, pi in enumerate( + [ + 0xFFFFFF, 0xFFFFFF, 0xFFFEFF, 0xF7FEF7, 0xF7FDF7, 0xF7FDF7, 0xF7FCF7, 0xEFFCEF, + 0xEFFFEF, 0xEFFFEF, 0xEFFAEF, 0xE7FAE7, 0xE7FDE7, 0xE7FDE7, 0xE7F8E7, 0xDEF8DE, + 0xDEFFDE, 0xDEFFDE, 0xDEFEDE, 0xD6FED6, 0xD6F5D6, 0xD6F5D6, 0xD6F4D6, 0xCEF4CE, + 0xCEFFCE, 0xCEFFCE, 0xCEFACE, 0xC6FAC6, 0xC6F5C6, 0xC6F5C6, 0xC6F0C6, 0xBDF0BD, + 0xBDBFBD, 0xBDBFBD, 0xBDBEBD, 0xB5BEB5, 0xB5BDB5, 0xB5BDB5, 0xB5BCB5, 0xB5BCB5, + 0xADAFAD, 0xADAFAD, 0xADAAAD, 0xADAAAD, 0xA5ADA5, 0xA5ADA5, 0xA5A8A5, 0xA5A8A5, + 0x9CBF9C, 0x9CBF9C, 0x9CBE9C, 0x9CBE9C, 0x94B594, 0x94B594, 0x94B494, 0x94B494, + 0x8CAF8C, 0x8CAF8C, 0x8CAA8C, 0x8CAA8C, 0x84A584, 0x84A584, 0x84A084, 0x84A084, + 0x7B7F7B, 0x7B7F7B, 0x7B7E7B, 0x7B7E7B, 0x737D73, 0x737D73, 0x737C73, 0x737C73, + 0x6B7F6B, 0x6B7F6B, 0x6B7A6B, 0x6B7A6B, 0x637D63, 0x637D63, 0x637863, 0x637863, + 0x5A5F5A, 0x5A5F5A, 0x5A5E5A, 0x5A5E5A, 0x525552, 0x525552, 0x525452, 0x525452, + 0x4A5F4A, 0x4A5F4A, 0x4A5A4A, 0x4A5A4A, 0x4A554A, 0x425542, 0x425042, 0x425042, + 0x423F42, 0x393F39, 0x393E39, 0x393E39, 0x393D39, 0x313D31, 0x313C31, 0x313C31, + 0x312F31, 0x292F29, 0x292A29, 0x292A29, 0x292D29, 0x212D21, 0x212821, 0x212821, + 0x211F21, 0x181F18, 0x181E18, 0x181E18, 0x181518, 0x101510, 0x101410, 0x101410, + 0x100F10, 0x080F08, 0x080A08, 0x080A08, 0x080508, 0x000500, 0x000000, 0x000000, + 0x000008, 0x000010, 0x000018, 0x080021, 0x080029, 0x080029, 0x080031, 0x100039, + 0x100042, 0x10004A, 0x180052, 0x18005A, 0x180063, 0x18006B, 0x21006B, 0x210073, + 0x21007B, 0x29007B, 0x31007B, 0x31007B, 0x39007B, 0x39007B, 0x42007B, 0x4A007B, + 0x4A0084, 0x520084, 0x520084, 0x5A0084, 0x630084, 0x630084, 0x6B0084, 0x6B0084, + 0x73008C, 0x7B008C, 0x7B008C, 0x84008C, 0x84058C, 0x8C058C, 0x94058C, 0x94058C, + 0x9C058C, 0x9C058C, 0xA5058C, 0xA5058C, 0xAD058C, 0xB5058C, 0xB50A8C, 0xBD0A8C, + 0xBD0A8C, 0xBD0F84, 0xC6147B, 0xC6157B, 0xC61573, 0xC61E6B, 0xCE1F6B, 0xCE2863, + 0xCE2863, 0xCE2D5A, 0xD62A52, 0xD62F52, 0xD62F4A, 0xDE3C42, 0xDE3D42, 0xDE3E39, + 0xDE3E31, 0xDE3F31, 0xDE5029, 0xE75529, 0xE75A29, 0xE75A21, 0xE75F21, 0xE75421, + 0xE75521, 0xE75E18, 0xE75F18, 0xE75F18, 0xEF7810, 0xEF7D10, 0xEF7A10, 0xEF7F08, + 0xEF7C08, 0xEF7D08, 0xEF7D08, 0xEF7E08, 0xEF7F08, 0xEFA008, 0xEFA508, 0xF7AA08, + 0xF7AF10, 0xF7B410, 0xF7B510, 0xF7BE10, 0xF7BF10, 0xF7A810, 0xF7A810, 0xF7AD10, + 0xF7AA10, 0xF7AF10, 0xF7BC10, 0xF7BD10, 0xF7BE10, 0xF7BF10, 0xF7BF10, 0xFFF018, + 0xFFF518, 0xFFFA18, 0xFFFF18, 0xFFF418, 0xFFF518, 0xFFFE18, 0xFFFE21, 0xFFFF21, + 0xFFF829, 0xFFFD31, 0xFFFD42, 0xFFFA52, 0xFFFA63, 0xFFFA6B, 0xFFFF7B, 0xFFFF8C, + 0xFFFC94, 0xFFFCA5, 0xFFFDB5, 0xFFFDBD, 0xFFFECE, 0xFFFEDE, 0xFFFFEF, 0xFFFF18, + ] +): + ironbow_palette[i] = pi +del i +del pi +del displayio diff --git a/tests/testlib/make_testpattern.py b/tests/testlib/make_testpattern.py new file mode 100644 index 0000000000000..30b0f34e254b8 --- /dev/null +++ b/tests/testlib/make_testpattern.py @@ -0,0 +1,29 @@ +import PIL.Image + +i = PIL.Image.new("RGB", (32, 32)) + +for y in range(32): + z = y * 255 // 31 + p = (z, z, z) + for x in range(0, 8): + i.putpixel((x, y), p) + p = (0, 0, z) + for x in range(8, 12): + i.putpixel((x, y), p) + p = (0, z, z) + for x in range(12, 16): + i.putpixel((x, y), p) + p = (0, z, 0) + for x in range(16, 20): + i.putpixel((x, y), p) + p = (z, z, 0) + for x in range(20, 24): + i.putpixel((x, y), p) + p = (z, 0, 0) + for x in range(24, 28): + i.putpixel((x, y), p) + p = (z, 0, z) + for x in range(28, 32): + i.putpixel((x, y), p) +i = i.resize((128, 128), PIL.Image.NEAREST) +i.save("testpattern.jpg", "JPEG", quality=90) diff --git a/tests/testlib/red.jpg b/tests/testlib/red.jpg new file mode 100644 index 0000000000000..9a0de0af656dd Binary files /dev/null and b/tests/testlib/red.jpg differ diff --git a/tests/testlib/testpattern.jpg b/tests/testlib/testpattern.jpg new file mode 100644 index 0000000000000..9eecd1fdb2a3e Binary files /dev/null and b/tests/testlib/testpattern.jpg differ diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 6ec3adcf08d24..46fd6ddcf2c42 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -52,9 +52,9 @@ port builtins micropython __future__ _asyncio _thread aesio array audiocore -audiomixer binascii bitmaptools cexample -cmath codeop collections cppexample -displayio errno example_package +audiomixer binascii bitmapfilter bitmaptools +cexample cmath codeop collections +cppexample displayio errno example_package gc hashlib heapq io jpegio json locale math os platform qrio rainbowio