Add bitmaptools module
This commit is contained in:
parent
e41137c745
commit
b720028642
|
@ -1852,7 +1852,7 @@ msgstr ""
|
|||
msgid "Read-only filesystem"
|
||||
msgstr ""
|
||||
|
||||
#: shared-module/displayio/Bitmap.c
|
||||
#: shared-module/bitmaptools/__init__.c shared-module/displayio/Bitmap.c
|
||||
msgid "Read-only object"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2683,6 +2683,10 @@ msgstr ""
|
|||
msgid "circle can only be registered in one parent"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/bitmaptools/__init__.c
|
||||
msgid "clip point must be (x,y) tuple"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/msgpack/ExtType.c
|
||||
msgid "code outside range 0~127"
|
||||
msgstr ""
|
||||
|
@ -3682,6 +3686,7 @@ msgstr ""
|
|||
#: ports/esp32s2/boards/targett_module_clip_wrover/mpconfigboard.h
|
||||
#: ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.h
|
||||
#: ports/esp32s2/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h
|
||||
#: ports/esp32s2/boards/unexpectedmaker_tinys2/mpconfigboard.h
|
||||
msgid "pressing boot button at start up.\n"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3830,7 +3835,7 @@ msgstr ""
|
|||
msgid "sosfilt requires iterable arguments"
|
||||
msgstr ""
|
||||
|
||||
#: shared-bindings/displayio/Bitmap.c
|
||||
#: shared-bindings/bitmaptools/__init__.c shared-bindings/displayio/Bitmap.c
|
||||
msgid "source palette too large"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -139,6 +139,9 @@ endif
|
|||
ifeq ($(CIRCUITPY_BITBANG_APA102),1)
|
||||
SRC_PATTERNS += bitbangio/SPI%
|
||||
endif
|
||||
ifeq ($(CIRCUITPY_BITMAPTOOLS),1)
|
||||
SRC_PATTERNS += bitmaptools/%
|
||||
endif
|
||||
ifeq ($(CIRCUITPY_BITOPS),1)
|
||||
SRC_PATTERNS += bitops/%
|
||||
endif
|
||||
|
@ -472,6 +475,7 @@ SRC_SHARED_MODULE_ALL = \
|
|||
bitbangio/OneWire.c \
|
||||
bitbangio/SPI.c \
|
||||
bitbangio/__init__.c \
|
||||
bitmaptools/__init__.c \
|
||||
bitops/__init__.c \
|
||||
board/__init__.c \
|
||||
adafruit_bus_device/__init__.c \
|
||||
|
|
|
@ -306,6 +306,13 @@ extern const struct _mp_obj_module_t bitbangio_module;
|
|||
#define BITBANGIO_MODULE
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_BITMAPTOOLS
|
||||
#define BITMAPTOOLS_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_bitmaptools), (mp_obj_t)&bitmaptools_module },
|
||||
extern const struct _mp_obj_module_t bitmaptools_module;
|
||||
#else
|
||||
#define BITMAPTOOLS_MODULE
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_BITOPS
|
||||
extern const struct _mp_obj_module_t bitops_module;
|
||||
#define BITOPS_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_bitops),(mp_obj_t)&bitops_module },
|
||||
|
@ -313,7 +320,6 @@ extern const struct _mp_obj_module_t bitops_module;
|
|||
#define BITOPS_MODULE
|
||||
#endif
|
||||
|
||||
|
||||
#if CIRCUITPY_BLEIO
|
||||
#define BLEIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__bleio), (mp_obj_t)&bleio_module },
|
||||
extern const struct _mp_obj_module_t bleio_module;
|
||||
|
@ -835,6 +841,7 @@ extern const struct _mp_obj_module_t msgpack_module;
|
|||
AUDIOPWMIO_MODULE \
|
||||
BINASCII_MODULE \
|
||||
BITBANGIO_MODULE \
|
||||
BITMAPTOOLS_MODULE \
|
||||
BITOPS_MODULE \
|
||||
BLEIO_MODULE \
|
||||
BOARD_MODULE \
|
||||
|
|
|
@ -95,6 +95,9 @@ CFLAGS += -DCIRCUITPY_BITBANG_APA102=$(CIRCUITPY_BITBANG_APA102)
|
|||
CIRCUITPY_BITBANGIO ?= $(CIRCUITPY_FULL_BUILD)
|
||||
CFLAGS += -DCIRCUITPY_BITBANGIO=$(CIRCUITPY_BITBANGIO)
|
||||
|
||||
CIRCUITPY_BITMAPTOOLS ?= $(CIRCUITPY_FULL_BUILD)
|
||||
CFLAGS += -DCIRCUITPY_BITMAPTOOLS=$(CIRCUITPY_BITMAPTOOLS)
|
||||
|
||||
CIRCUITPY_BITOPS ?= 0
|
||||
CFLAGS += -DCIRCUITPY_BITOPS=$(CIRCUITPY_BITOPS)
|
||||
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Kevin Matocha
|
||||
*
|
||||
* 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 "shared-bindings/displayio/Bitmap.h"
|
||||
#include "shared-bindings/bitmaptools/__init__.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
STATIC int16_t validate_point(mp_obj_t point, int16_t default_value) {
|
||||
// Checks if point is None and returns default_value, otherwise decodes integer value
|
||||
if ( point == mp_const_none ) {
|
||||
return default_value;
|
||||
}
|
||||
return mp_obj_get_int(point);
|
||||
}
|
||||
|
||||
STATIC void extract_tuple(mp_obj_t xy_tuple, int16_t *x, int16_t *y, int16_t x_default, int16_t y_default) {
|
||||
// Helper function for rotozoom
|
||||
// Extract x,y values from a tuple or default if None
|
||||
if ( xy_tuple == mp_const_none ) {
|
||||
*x = x_default;
|
||||
*y = y_default;
|
||||
} else if ( !MP_OBJ_IS_OBJ(xy_tuple) ) {
|
||||
mp_raise_ValueError(translate("clip point must be (x,y) tuple"));
|
||||
} else {
|
||||
mp_obj_t* items;
|
||||
mp_obj_get_array_fixed_n(xy_tuple, 2, &items);
|
||||
*x = mp_obj_get_int(items[0]);
|
||||
*y = mp_obj_get_int(items[1]);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void validate_clip_region(displayio_bitmap_t *bitmap, mp_obj_t clip0_tuple, int16_t *clip0_x, int16_t *clip0_y,
|
||||
mp_obj_t clip1_tuple, int16_t *clip1_x, int16_t *clip1_y) {
|
||||
// Helper function for rotozoom
|
||||
// 1. Extract the clip x,y points from the two clip tuples
|
||||
// 2. Rearrange values such that clip0_ < clip1_
|
||||
// 3. Constrain the clip points to within the bitmap
|
||||
|
||||
extract_tuple(clip0_tuple, clip0_x, clip0_y, 0, 0);
|
||||
extract_tuple(clip1_tuple, clip1_x, clip1_y, bitmap->width, bitmap->height);
|
||||
|
||||
// Ensure the value for clip0 is less than clip1 (for both x and y)
|
||||
if ( *clip0_x > *clip1_x ) {
|
||||
int16_t temp_value = *clip0_x; // swap values
|
||||
*clip0_x = *clip1_x;
|
||||
*clip1_x = temp_value;
|
||||
}
|
||||
if ( *clip0_y > *clip1_y ) {
|
||||
int16_t temp_value = *clip0_y; // swap values
|
||||
*clip0_y = *clip1_y;
|
||||
*clip1_y = temp_value;
|
||||
}
|
||||
|
||||
// Constrain the clip window to within the bitmap boundaries
|
||||
if (*clip0_x < 0) {
|
||||
*clip0_x = 0;
|
||||
}
|
||||
if (*clip0_y < 0) {
|
||||
*clip0_y = 0;
|
||||
}
|
||||
if (*clip0_x > bitmap->width) {
|
||||
*clip0_x = bitmap->width;
|
||||
}
|
||||
if (*clip0_y > bitmap->height) {
|
||||
*clip0_y = bitmap->height;
|
||||
}
|
||||
if (*clip1_x < 0) {
|
||||
*clip1_x = 0;
|
||||
}
|
||||
if (*clip1_y < 0) {
|
||||
*clip1_y = 0;
|
||||
}
|
||||
if (*clip1_x > bitmap->width) {
|
||||
*clip1_x = bitmap->width;
|
||||
}
|
||||
if (*clip1_y > bitmap->height) {
|
||||
*clip1_y = bitmap->height;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//|
|
||||
//| def rotozoom(dest_bitmap: Bitmap, ox: int, oy: int,
|
||||
//| dest_clip0: Tuple[int, int],
|
||||
//| dest_clip1: Tuple[int, int],
|
||||
//| source_bitmap: Bitmap,
|
||||
//| px: int, py: int,
|
||||
//| source_clip0: Tuple[int, int],
|
||||
//| source_clip1: Tuple[int, int],
|
||||
//| angle: float,
|
||||
//| scale: float,
|
||||
//| skip_index: int) -> None:
|
||||
//| """Inserts the source bitmap region into the destination bitmap with rotation (angle), scale
|
||||
//| and clipping (both on source and destination bitmaps).
|
||||
//|
|
||||
//| :param bitmap dest_bitmap: The bitmap that will be copied into
|
||||
//| :param int ox: Horizontal pixel location in destination bitmap where source bitmap
|
||||
//| point (px,py) is placed
|
||||
//| :param int oy: Vertical pixel location in destination bitmap where source bitmap
|
||||
//| point (px,py) is placed
|
||||
//| :param dest_clip0: First corner of rectangular destination clipping
|
||||
//| region that constrains region of writing into destination bitmap
|
||||
//| :type dest_clip0: Tuple[int,int]
|
||||
//| :param dest_clip1: second corner of rectangular destination clipping
|
||||
//| region that constrains region of writing into destination bitmap
|
||||
//| :type dest_clip1: Tuple[int,int]
|
||||
//| :param bitmap source_bitmap: Source bitmap that contains the graphical region to be copied
|
||||
//| :param int px: Horizontal pixel location in source bitmap that is placed into the
|
||||
//| destination bitmap at (ox,oy)
|
||||
//| :param int py: Vertical pixel location in source bitmap that is placed into the
|
||||
//| destination bitmap at (ox,oy)
|
||||
//| :param source_clip0: First corner of rectangular destination clipping
|
||||
//| region that constrains region of writing into destination bitmap
|
||||
//| :type source_clip0: Tuple[int,int]
|
||||
//| :param source_clip1: second corner of rectangular destination clipping
|
||||
//| region that constrains region of writing into destination bitmap
|
||||
//| :type source_clip1: Tuple[int,int]
|
||||
//| :param float angle: angle of rotation, in radians (positive is clockwise direction)
|
||||
//| :param float scale: scaling factor
|
||||
//| :param int skip_index: bitmap palette index in the source that will not be copied,
|
||||
//| set to None to copy all pixels"""
|
||||
//| ...
|
||||
//|
|
||||
STATIC mp_obj_t bitmaptools_obj_rotozoom(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args){
|
||||
enum {ARG_dest_bitmap, ARG_ox, ARG_oy, ARG_dest_clip0, ARG_dest_clip1,
|
||||
ARG_source_bitmap, ARG_px, ARG_py,
|
||||
ARG_source_clip0, ARG_source_clip1,
|
||||
ARG_angle, ARG_scale, ARG_skip_index};
|
||||
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ},
|
||||
{MP_QSTR_ox, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to destination->width / 2
|
||||
{MP_QSTR_oy, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to destination->height / 2
|
||||
{MP_QSTR_dest_clip0, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{MP_QSTR_dest_clip1, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
|
||||
{MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ},
|
||||
{MP_QSTR_px, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->width / 2
|
||||
{MP_QSTR_py, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->height / 2
|
||||
{MP_QSTR_source_clip0, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
{MP_QSTR_source_clip1, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||
|
||||
{MP_QSTR_angle, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to 0.0
|
||||
{MP_QSTR_scale, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to 1.0
|
||||
{MP_QSTR_skip_index, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj=mp_const_none} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap
|
||||
|
||||
displayio_bitmap_t *source = MP_OBJ_TO_PTR(args[ARG_source_bitmap].u_obj); // the source bitmap
|
||||
|
||||
// ensure that the destination bitmap has at least as many `bits_per_value` as the source
|
||||
if (destination->bits_per_value < source->bits_per_value) {
|
||||
mp_raise_ValueError(translate("source palette too large"));
|
||||
}
|
||||
|
||||
// Confirm the destination location target (ox,oy); if None, default to bitmap midpoint
|
||||
int16_t ox, oy;
|
||||
ox = validate_point(args[ARG_ox].u_obj, destination->width / 2);
|
||||
oy = validate_point(args[ARG_oy].u_obj, destination->height / 2);
|
||||
|
||||
// Confirm the source location target (px,py); if None, default to bitmap midpoint
|
||||
int16_t px, py;
|
||||
px = validate_point(args[ARG_px].u_obj, source->width / 2);
|
||||
py = validate_point(args[ARG_py].u_obj, source->height / 2);
|
||||
|
||||
// Validate the clipping regions for the destination bitmap
|
||||
int16_t dest_clip0_x, dest_clip0_y, dest_clip1_x, dest_clip1_y;
|
||||
|
||||
validate_clip_region(destination, args[ARG_dest_clip0].u_obj, &dest_clip0_x, &dest_clip0_y,
|
||||
args[ARG_dest_clip1].u_obj, &dest_clip1_x, &dest_clip1_y);
|
||||
|
||||
// Validate the clipping regions for the source bitmap
|
||||
int16_t source_clip0_x, source_clip0_y, source_clip1_x, source_clip1_y;
|
||||
|
||||
validate_clip_region(source, args[ARG_source_clip0].u_obj, &source_clip0_x, &source_clip0_y,
|
||||
args[ARG_source_clip1].u_obj, &source_clip1_x, &source_clip1_y);
|
||||
|
||||
// Confirm the angle value
|
||||
float angle=0.0;
|
||||
if ( args[ARG_angle].u_obj != mp_const_none ) {
|
||||
angle = mp_obj_get_float(args[ARG_angle].u_obj);
|
||||
}
|
||||
|
||||
// Confirm the scale value
|
||||
float scale=1.0;
|
||||
if ( args[ARG_scale].u_obj != mp_const_none ) {
|
||||
scale = mp_obj_get_float(args[ARG_scale].u_obj);
|
||||
}
|
||||
if (scale < 0) { // ensure scale >= 0
|
||||
scale = 1.0;
|
||||
}
|
||||
|
||||
uint32_t skip_index;
|
||||
bool skip_index_none; // Flag whether input skip_value was None
|
||||
if (args[ARG_skip_index].u_obj == mp_const_none ) {
|
||||
skip_index = 0;
|
||||
skip_index_none = true;
|
||||
} else {
|
||||
skip_index = mp_obj_get_int(args[ARG_skip_index].u_obj);
|
||||
skip_index_none = false;
|
||||
}
|
||||
|
||||
common_hal_bitmaptools_rotozoom(destination, ox, oy,
|
||||
dest_clip0_x, dest_clip0_y,
|
||||
dest_clip1_x, dest_clip1_y,
|
||||
source, px, py,
|
||||
source_clip0_x, source_clip0_y,
|
||||
source_clip1_x, source_clip1_y,
|
||||
angle,
|
||||
scale,
|
||||
skip_index, skip_index_none);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_rotozoom_obj, 0, bitmaptools_obj_rotozoom);
|
||||
// requires at least 2 arguments (destination bitmap and source bitmap)
|
||||
|
||||
|
||||
STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR_rotozoom), MP_ROM_PTR(&bitmaptools_rotozoom_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(bitmaptools_module_globals, bitmaptools_module_globals_table);
|
||||
|
||||
|
||||
const mp_obj_module_t bitmaptools_module = {
|
||||
.base = {&mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&bitmaptools_module_globals,
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Kevin Matocha
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H
|
||||
#define MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
void common_hal_bitmaptools_rotozoom(displayio_bitmap_t *self, int16_t ox, int16_t oy,
|
||||
int16_t dest_clip0_x, int16_t dest_clip0_y,
|
||||
int16_t dest_clip1_x, int16_t dest_clip1_y,
|
||||
displayio_bitmap_t *source, int16_t px, int16_t py,
|
||||
int16_t source_clip0_x, int16_t source_clip0_y,
|
||||
int16_t source_clip1_x, int16_t source_clip1_y,
|
||||
float angle,
|
||||
float scale,
|
||||
uint32_t skip_index, bool skip_index_none);
|
||||
|
||||
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Kevin Matocha
|
||||
*
|
||||
* 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 "shared-bindings/displayio/Bitmap.h"
|
||||
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "math.h"
|
||||
|
||||
void common_hal_bitmaptools_rotozoom(displayio_bitmap_t *self, int16_t ox, int16_t oy,
|
||||
int16_t dest_clip0_x, int16_t dest_clip0_y,
|
||||
int16_t dest_clip1_x, int16_t dest_clip1_y,
|
||||
displayio_bitmap_t *source, int16_t px, int16_t py,
|
||||
int16_t source_clip0_x, int16_t source_clip0_y,
|
||||
int16_t source_clip1_x, int16_t source_clip1_y,
|
||||
float angle,
|
||||
float scale,
|
||||
uint32_t skip_index, bool skip_index_none) {
|
||||
|
||||
// Copies region from source to the destination bitmap, including rotation,
|
||||
// scaling and clipping of either the source or destination regions
|
||||
//
|
||||
// *self: destination bitmap
|
||||
// ox: the (ox, oy) destination point where the source (px,py) point is placed
|
||||
// oy:
|
||||
// dest_clip0: (x,y) is the corner of the clip window on the destination bitmap
|
||||
// dest_clip1: (x,y) is the other corner of the clip window of the destination bitmap
|
||||
// *source: the source bitmap
|
||||
// px: the (px, py) point of rotation of the source bitmap
|
||||
// py:
|
||||
// source_clip0: (x,y) is the corner of the clip window on the source bitmap
|
||||
// source_clip1: (x,y) is the other of the clip window on the source bitmap
|
||||
// angle: angle of rotation in radians, positive is clockwise
|
||||
// scale: scale factor
|
||||
// skip_index: color index that should be ignored (and not copied over)
|
||||
// skip_index_none: if skip_index_none is True, then all color indexes should be copied
|
||||
// (that is, no color indexes should be skipped)
|
||||
|
||||
|
||||
// Copy complete "source" bitmap into "self" bitmap at location x,y in the "self"
|
||||
// Add a boolean to determine if all values are copied, or only if non-zero
|
||||
// If skip_value is encountered in the source bitmap, it will not be copied.
|
||||
// If skip_value is `None`, then all pixels are copied.
|
||||
|
||||
|
||||
// # Credit from https://github.com/wernsey/bitmap
|
||||
// # MIT License from
|
||||
// # * Copyright (c) 2017 Werner Stoop <wstoop@gmail.com>
|
||||
// #
|
||||
// # *
|
||||
// # * #### `void bm_rotate_blit(Bitmap *dst, int ox, int oy, Bitmap *src, int px, int py, double angle, double scale);`
|
||||
// # *
|
||||
// # * Rotates a source bitmap `src` around a pivot point `px,py` and blits it onto a destination bitmap `dst`.
|
||||
// # *
|
||||
// # * The bitmap is positioned such that the point `px,py` on the source is at the offset `ox,oy` on the destination.
|
||||
// # *
|
||||
// # * The `angle` is clockwise, in radians. The bitmap is also scaled by the factor `scale`.
|
||||
// #
|
||||
// # void bm_rotate_blit(Bitmap *dst, int ox, int oy, Bitmap *src, int px, int py, double angle, double scale);
|
||||
|
||||
|
||||
// # /*
|
||||
// # Reference:
|
||||
// # "Fast Bitmap Rotation and Scaling" By Steven Mortimer, Dr Dobbs' Journal, July 01, 2001
|
||||
// # http://www.drdobbs.com/architecture-and-design/fast-bitmap-rotation-and-scaling/184416337
|
||||
// # See also http://www.efg2.com/Lab/ImageProcessing/RotateScanline.htm
|
||||
// # */
|
||||
|
||||
|
||||
if (self->read_only) {
|
||||
mp_raise_RuntimeError(translate("Read-only object"));
|
||||
}
|
||||
|
||||
int16_t x,y;
|
||||
|
||||
int16_t minx = dest_clip1_x;
|
||||
int16_t miny = dest_clip1_y;
|
||||
int16_t maxx = dest_clip0_x;
|
||||
int16_t maxy = dest_clip0_y;
|
||||
|
||||
float sinAngle = sinf(angle);
|
||||
float cosAngle = cosf(angle);
|
||||
|
||||
float dx, dy;
|
||||
|
||||
/* Compute the position of where each corner on the source bitmap
|
||||
will be on the destination to get a bounding box for scanning */
|
||||
dx = -cosAngle * px * scale + sinAngle * py * scale + ox;
|
||||
dy = -sinAngle * px * scale - cosAngle * py * scale + oy;
|
||||
if(dx < minx) minx = (int16_t)dx;
|
||||
if(dx > maxx) maxx = (int16_t)dx;
|
||||
if(dy < miny) miny = (int16_t)dy;
|
||||
if(dy > maxy) maxy = (int16_t)dy;
|
||||
|
||||
dx = cosAngle * (source->width - px) * scale + sinAngle * py * scale + ox;
|
||||
dy = sinAngle * (source->width - px) * scale - cosAngle * py * scale + oy;
|
||||
if(dx < minx) minx = (int16_t)dx;
|
||||
if(dx > maxx) maxx = (int16_t)dx;
|
||||
if(dy < miny) miny = (int16_t)dy;
|
||||
if(dy > maxy) maxy = (int16_t)dy;
|
||||
|
||||
dx = cosAngle * (source->width - px) * scale - sinAngle * (source->height - py) * scale + ox;
|
||||
dy = sinAngle * (source->width - px) * scale + cosAngle * (source->height - py) * scale + oy;
|
||||
if(dx < minx) minx = (int16_t)dx;
|
||||
if(dx > maxx) maxx = (int16_t)dx;
|
||||
if(dy < miny) miny = (int16_t)dy;
|
||||
if(dy > maxy) maxy = (int16_t)dy;
|
||||
|
||||
dx = -cosAngle * px * scale - sinAngle * (source->height - py) * scale + ox;
|
||||
dy = -sinAngle * px * scale + cosAngle * (source->height - py) * scale + oy;
|
||||
if(dx < minx) minx = (int16_t)dx;
|
||||
if(dx > maxx) maxx = (int16_t)dx;
|
||||
if(dy < miny) miny = (int16_t)dy;
|
||||
if(dy > maxy) maxy = (int16_t)dy;
|
||||
|
||||
/* Clipping */
|
||||
if(minx < dest_clip0_x) minx = dest_clip0_x;
|
||||
if(maxx > dest_clip1_x - 1) maxx = dest_clip1_x - 1;
|
||||
if(miny < dest_clip0_y) miny = dest_clip0_y;
|
||||
if(maxy > dest_clip1_y - 1) maxy = dest_clip1_y - 1;
|
||||
|
||||
float dvCol = cosAngle / scale;
|
||||
float duCol = sinAngle / scale;
|
||||
|
||||
float duRow = dvCol;
|
||||
float dvRow = -duCol;
|
||||
|
||||
float startu = px - (ox * dvCol + oy * duCol);
|
||||
float startv = py - (ox * dvRow + oy * duRow);
|
||||
|
||||
float rowu = startu + miny * duCol;
|
||||
float rowv = startv + miny * dvCol;
|
||||
|
||||
for(y = miny; y <= maxy; y++) {
|
||||
float u = rowu + minx * duRow;
|
||||
float v = rowv + minx * dvRow;
|
||||
for(x = minx; x <= maxx; x++) {
|
||||
if(u >= source_clip0_x && u < source_clip1_x && v >= source_clip0_y && v < source_clip1_y) {
|
||||
uint32_t c = common_hal_displayio_bitmap_get_pixel(source, u, v);
|
||||
if( (skip_index_none) || (c != skip_index) ) {
|
||||
common_hal_displayio_bitmap_set_pixel(self, x, y, c);
|
||||
}
|
||||
}
|
||||
u += duRow;
|
||||
v += dvRow;
|
||||
}
|
||||
rowu += duCol;
|
||||
rowv += dvCol;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue