2525 */
2626
2727#include "shared-bindings/displayio/Bitmap.h"
28+ #include "shared-bindings/displayio/Palette.h"
29+ #include "shared-bindings/displayio/ColorConverter.h"
2830#include "shared-bindings/bitmaptools/__init__.h"
2931
3032#include <stdint.h>
3133
3234#include "py/binary.h"
35+ #include "py/enum.h"
3336#include "py/obj.h"
3437#include "py/runtime.h"
3538
@@ -642,9 +645,92 @@ STATIC mp_obj_t bitmaptools_readinto(size_t n_args, const mp_obj_t *pos_args, mp
642645
643646 return mp_const_none ;
644647}
645-
646648MP_DEFINE_CONST_FUN_OBJ_KW (bitmaptools_readinto_obj , 0 , bitmaptools_readinto );
647649
650+ //| class DitherAlgorithm:
651+ //| """Identifies the algorith for dither to use"""
652+ //|
653+ //| Atkinson: "DitherAlgorithm"
654+ //| """The classic Atkinson dither, often associated with the Hypercard esthetic"""
655+ //|
656+ //| FloydStenberg: "DitherAlgorithm"
657+ //| """The Floyd-Stenberg dither"""
658+ //|
659+ MAKE_ENUM_VALUE (bitmaptools_dither_algorithm_type , dither_algorithm , Atkinson , DITHER_ALGORITHM_ATKINSON );
660+ MAKE_ENUM_VALUE (bitmaptools_dither_algorithm_type , dither_algorithm , FloydStenberg , DITHER_ALGORITHM_ATKINSON );
661+
662+ MAKE_ENUM_MAP (bitmaptools_dither_algorithm ) {
663+ MAKE_ENUM_MAP_ENTRY (dither_algorithm , Atkinson ),
664+ MAKE_ENUM_MAP_ENTRY (dither_algorithm , FloydStenberg ),
665+ };
666+ STATIC MP_DEFINE_CONST_DICT (bitmaptools_dither_algorithm_locals_dict , bitmaptools_dither_algorithm_locals_table );
667+
668+ MAKE_PRINTER (bitmaptools , bitmaptools_dither_algorithm );
669+
670+ MAKE_ENUM_TYPE (bitmaptools , DitherAlgorithm , bitmaptools_dither_algorithm );
671+
672+ //| def dither(dest_bitmap: displayio.Bitmap, source_bitmapp: displayio.Bitmap, source_colorspace: displayio.Colorspace, algorithm: DitherAlgorithm=DitherAlgorithm.Atkinson) -> None:
673+ //| """Convert the input image into a 2-level output image using the given dither algorithm.
674+ //|
675+ //| :param bitmap dest_bitmap: Destination bitmap. It must have a value_count of 2 or 65536. The stored values are 0 and the maximum pixel value.
676+ //| :param bitmap source_bitmap: Source bitmap that contains the graphical region to be dithered. It must have a value_count of 65536.
677+ //| :param colorspace: The colorspace of the image. The supported colorspaces are ``RGB565``, ``BGR565``, ``RGB565_SWAPPED``, and ``BGR565_SWAPPED``
678+ //| :param algorithm: The dither algorithm to use, one of the `DitherAlgorithm` values.
679+ //| """
680+ //| ...
681+ //|
682+ STATIC mp_obj_t bitmaptools_dither (size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
683+ enum { ARG_dest_bitmap , ARG_source_bitmap , ARG_source_colorspace , ARG_algorithm };
684+ static const mp_arg_t allowed_args [] = {
685+ { MP_QSTR_dest_bitmap , MP_ARG_REQUIRED | MP_ARG_OBJ },
686+ { MP_QSTR_source_bitmap , MP_ARG_REQUIRED | MP_ARG_OBJ },
687+ { MP_QSTR_source_colorspace , MP_ARG_REQUIRED | MP_ARG_OBJ },
688+ { MP_QSTR_algorithm , MP_ARG_OBJ , { .u_obj = MP_ROM_PTR ((void * )& dither_algorithm_Atkinson_obj ) } },
689+ };
690+ mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
691+ mp_arg_parse_all (n_args , pos_args , kw_args , MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
692+ displayio_bitmap_t * source_bitmap = mp_arg_validate_type (args [ARG_source_bitmap ].u_obj , & displayio_bitmap_type , MP_QSTR_source_bitmap );
693+ displayio_bitmap_t * dest_bitmap = mp_arg_validate_type (args [ARG_dest_bitmap ].u_obj , & displayio_bitmap_type , MP_QSTR_dest_bitmap );
694+ bitmaptools_dither_algorithm_t algorithm = cp_enum_value (& bitmaptools_dither_algorithm_type , args [ARG_algorithm ].u_obj );
695+ displayio_colorspace_t colorspace = cp_enum_value (& displayio_colorspace_type , args [ARG_source_colorspace ].u_obj );
696+
697+ if (source_bitmap -> width != dest_bitmap -> width || source_bitmap -> height != dest_bitmap -> height ) {
698+ mp_raise_TypeError (translate ("bitmap sizes must match" ));
699+ }
700+
701+ if (dest_bitmap -> bits_per_value != 16 && dest_bitmap -> bits_per_value != 1 ) {
702+ mp_raise_TypeError (translate ("source_bitmap must have value_count of 2 or 65536" ));
703+ }
704+
705+
706+ switch (colorspace ) {
707+ case DISPLAYIO_COLORSPACE_RGB565 :
708+ case DISPLAYIO_COLORSPACE_RGB565_SWAPPED :
709+ case DISPLAYIO_COLORSPACE_BGR565 :
710+ case DISPLAYIO_COLORSPACE_BGR565_SWAPPED :
711+ if (source_bitmap -> bits_per_value != 16 ) {
712+ mp_raise_TypeError (translate ("source_bitmap must have value_count of 65536" ));
713+ }
714+ break ;
715+
716+ case DISPLAYIO_COLORSPACE_L8 :
717+ if (source_bitmap -> bits_per_value != 8 ) {
718+ mp_raise_TypeError (translate ("source_bitmap must have value_count of 8" ));
719+ }
720+ break ;
721+
722+ default :
723+ mp_raise_TypeError (translate ("unsupported colorspace for dither" ));
724+ }
725+
726+
727+ common_hal_bitmaptools_dither (dest_bitmap , source_bitmap , colorspace , algorithm );
728+
729+ return mp_const_none ;
730+ }
731+ MP_DEFINE_CONST_FUN_OBJ_KW (bitmaptools_dither_obj , 0 , bitmaptools_dither );
732+
733+
648734STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table [] = {
649735 { MP_ROM_QSTR (MP_QSTR___name__ ), MP_ROM_QSTR (MP_QSTR_bitmaptools ) },
650736 { MP_ROM_QSTR (MP_QSTR_readinto ), MP_ROM_PTR (& bitmaptools_readinto_obj ) },
@@ -654,6 +740,8 @@ STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = {
654740 { MP_ROM_QSTR (MP_QSTR_fill_region ), MP_ROM_PTR (& bitmaptools_fill_region_obj ) },
655741 { MP_ROM_QSTR (MP_QSTR_boundary_fill ), MP_ROM_PTR (& bitmaptools_boundary_fill_obj ) },
656742 { MP_ROM_QSTR (MP_QSTR_draw_line ), MP_ROM_PTR (& bitmaptools_draw_line_obj ) },
743+ { MP_ROM_QSTR (MP_QSTR_dither ), MP_ROM_PTR (& bitmaptools_dither_obj ) },
744+ { MP_ROM_QSTR (MP_QSTR_DitherAlgorithm ), MP_ROM_PTR (& bitmaptools_dither_algorithm_type ) },
657745};
658746STATIC MP_DEFINE_CONST_DICT (bitmaptools_module_globals , bitmaptools_module_globals_table );
659747
0 commit comments