summaryrefslogtreecommitdiff
path: root/shared-bindings
diff options
context:
space:
mode:
authorJeff Epler <jeff@adafruit.com>2021-03-17 07:57:31 -0500
committerGitHub <noreply@github.com>2021-03-17 07:57:31 -0500
commitbfc8c89536e12dba0cc9adc0065819d730bb0983 (patch)
tree32b383f83e9e67455e4354737e979e07b708b756 /shared-bindings
parent75ba26ee7c74cded73985212075c6eb4d8071af4 (diff)
parent074ba1daff2c188d1aef278833982016da49f403 (diff)
Merge pull request #4403 from jepler/bitmap-read-2
bitmaptools: Add readinto, arrayblit
Diffstat (limited to 'shared-bindings')
-rw-r--r--shared-bindings/bitmaptools/__init__.c156
-rw-r--r--shared-bindings/bitmaptools/__init__.h5
2 files changed, 161 insertions, 0 deletions
diff --git a/shared-bindings/bitmaptools/__init__.c b/shared-bindings/bitmaptools/__init__.c
index cb30a46f8..bdd4d3e67 100644
--- a/shared-bindings/bitmaptools/__init__.c
+++ b/shared-bindings/bitmaptools/__init__.c
@@ -29,6 +29,7 @@
#include <stdint.h>
+#include "py/binary.h"
#include "py/obj.h"
#include "py/runtime.h"
@@ -357,8 +358,163 @@ STATIC mp_obj_t bitmaptools_obj_draw_line(size_t n_args, const mp_obj_t *pos_arg
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_draw_line_obj, 0, bitmaptools_obj_draw_line);
// requires all 6 arguments
+//| def arrayblit(bitmap: displayio.Bitmap, data: ReadableBuffer, x1: int=0, y1: int=0, x2: Optional[int]=None, y2: Optional[int]=None, skip_index:Optional[int]=None) -> None:
+//| """Inserts pixels from ``data`` into the rectangle of width×height pixels with the upper left corner at ``(x,y)``
+//|
+//| The values from ``data`` are taken modulo the number of color values
+//| avalable in the destination bitmap.
+//|
+//| If x1 or y1 are not specified, they are taken as 0. If x2 or y2
+//| are not specified, or are given as -1, they are taken as the width
+//| and height of the image.
+//|
+//| The coordinates affected by the blit are ``x1 <= x < x2`` and ``y1 <= y < y2``.
+//|
+//| ``data`` must contain at least as many elements as required. If it
+//| contains excess elements, they are ignored.
+//|
+//| The blit takes place by rows, so the first elements of ``data`` go
+//| to the first row, the next elements to the next row, and so on.
+//|
+//| :param displayio.Bitmap bitmap: A writable bitmap
+//| :param ReadableBuffer data: Buffer containing the source pixel values
+//| :param int x1: The left corner of the area to blit into (inclusive)
+//| :param int y1: The top corner of the area to blit into (inclusive)
+//| :param int x2: The right of the area to blit into (exclusive)
+//| :param int y2: The bottom corner of the area to blit into (exclusive)
+//| :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_arrayblit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_bitmap, ARG_data, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_skip_index };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_x1, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_y1, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_x2, MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_y2, MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_skip_index, MP_ARG_OBJ, {.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);
+
+ if (!MP_OBJ_IS_TYPE(args[ARG_bitmap].u_obj, &displayio_bitmap_type)) {
+ mp_raise_TypeError(NULL);
+ }
+ displayio_bitmap_t *bitmap = MP_OBJ_TO_PTR(args[ARG_bitmap].u_obj);
+
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ);
+
+ int x1 = args[ARG_x1].u_int;
+ int y1 = args[ARG_y1].u_int;
+ int x2 = args[ARG_x2].u_int == -1 ? bitmap->width : args[ARG_x2].u_int;
+ int y2 = args[ARG_y2].u_int == -1 ? bitmap->height : args[ARG_y2].u_int;
+
+ if ((x1 < 0) || (y1 < 0) || (x1 > x2) || (y1 > y2) || (x2 > bitmap->width) || (y2 > bitmap->height)) {
+ mp_raise_IndexError(translate("pixel coordinates out of bounds"));
+ }
+
+ size_t output_element_count = (x2 - x1) * (y2 - y1);
+ size_t element_size = mp_binary_get_size('@', bufinfo.typecode, NULL);
+ size_t input_element_count = bufinfo.len / element_size;
+
+ bool skip_specified = args[ARG_skip_index].u_obj != mp_const_none;
+ uint32_t skip_index = skip_specified ? mp_obj_get_int(args[ARG_skip_index].u_obj) : 0;
+ if (input_element_count < output_element_count) {
+ mp_raise_IndexError(translate("index out of range"));
+ }
+
+ common_hal_bitmaptools_arrayblit(bitmap, bufinfo.buf, element_size, x1, y1, x2, y2, skip_specified, skip_index);
+
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_arrayblit_obj, 0, bitmaptools_arrayblit);
+
+
+//| def readinto(bitmap: displayio.Bitmap, file: typing.BinaryIO, bits_per_pixel: int, element_size: int = 1, reverse_pixels_in_element: bool = False, swap_bytes_in_element: bool = False) -> None:
+//| """Read from a binary file into a bitmap
+//| The file must be positioned so that it consists of ``bitmap.height`` rows of pixel data, where each row is the smallest multiple of ``element_size`` bytes that can hold ``bitmap.width`` pixels.
+//|
+//| The bytes in an element can be optionally swapped, and the pixels in an element can be reversed.
+//|
+//| This function doesn't parse image headers, but is useful to speed up loading of uncompressed image formats such as PCF glyph data.
+//|
+//| :param displayio.Bitmap bitmap: A writable bitmap
+//| :param typing.BinaryIO file: A file opened in binary mode
+//| :param int bits_per_pixel: Number of bits per pixel. Values 1, 2, 4, 8, 16, 24, and 32 are supported;
+//| :param int element_size: Number of bytes per element. Values of 1, 2, and 4 are supported, except that 24 ``bits_per_pixel`` requires 1 byte per element.
+//| :param bool reverse_pixels_in_element: If set, the first pixel in a word is taken from the Most Signficant Bits; otherwise, it is taken from the Least Significant Bits.
+//| :param bool swap_bytes_in_element: If the ``element_size`` is not 1, then reverse the byte order of each element read.
+//| """
+//| ...
+//|
+
+STATIC mp_obj_t bitmaptools_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_bitmap, ARG_file, ARG_bits_per_pixel, ARG_element_size, ARG_reverse_pixels_in_element, ARG_swap_bytes_in_element };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_file, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_bits_per_pixel, MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_element_size, MP_ARG_INT, { .u_int = 1 } },
+ { MP_QSTR_reverse_pixels_in_element, MP_ARG_BOOL, { .u_bool = false } },
+ { MP_QSTR_swap_bytes_in_element, MP_ARG_BOOL, { .u_bool = false } },
+ };
+
+ 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);
+
+ if (!MP_OBJ_IS_TYPE(args[ARG_bitmap].u_obj, &displayio_bitmap_type)) {
+ mp_raise_TypeError(NULL);
+ }
+ displayio_bitmap_t *bitmap = MP_OBJ_TO_PTR(args[ARG_bitmap].u_obj);
+
+ if (!MP_OBJ_IS_TYPE(args[ARG_file].u_obj, &mp_type_fileio)) {
+ mp_raise_TypeError(NULL);
+ }
+ pyb_file_obj_t *file = MP_OBJ_TO_PTR(args[ARG_file].u_obj);
+
+ int element_size = args[ARG_element_size].u_int;
+ if (element_size != 1 && element_size != 2 && element_size != 4) {
+ mp_raise_ValueError_varg(translate("invalid element_size %d, must be, 1, 2, or 4"), element_size);
+ }
+
+ int bits_per_pixel = args[ARG_bits_per_pixel].u_int;
+ switch (bits_per_pixel) {
+ case 24:
+ if (element_size != 1) {
+ mp_raise_ValueError_varg(translate("invalid element size %d for bits_per_pixel %d\n"), element_size, bits_per_pixel);
+ }
+ break;
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ break;
+ default:
+ mp_raise_ValueError_varg(translate("invalid bits_per_pixel %d, must be, 1, 4, 8, 16, 24, or 32"), bits_per_pixel);
+ }
+
+ bool reverse_pixels_in_element = args[ARG_reverse_pixels_in_element].u_bool;
+ bool swap_bytes_in_element = args[ARG_swap_bytes_in_element].u_bool;
+
+ common_hal_bitmaptools_readinto(bitmap, file, element_size, bits_per_pixel, reverse_pixels_in_element, swap_bytes_in_element);
+
+ return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_readinto_obj, 0, bitmaptools_readinto);
+
STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&bitmaptools_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_rotozoom), MP_ROM_PTR(&bitmaptools_rotozoom_obj) },
+ { MP_ROM_QSTR(MP_QSTR_arrayblit), MP_ROM_PTR(&bitmaptools_arrayblit_obj) },
{ MP_ROM_QSTR(MP_QSTR_fill_region), MP_ROM_PTR(&bitmaptools_fill_region_obj) },
{ MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) },
};
diff --git a/shared-bindings/bitmaptools/__init__.h b/shared-bindings/bitmaptools/__init__.h
index 42f111b02..6b80f98f5 100644
--- a/shared-bindings/bitmaptools/__init__.h
+++ b/shared-bindings/bitmaptools/__init__.h
@@ -27,7 +27,9 @@
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H
#define MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H
+#include "shared-module/displayio/Bitmap.h"
#include "py/obj.h"
+#include "extmod/vfs_fat.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,
@@ -49,4 +51,7 @@ void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination,
int16_t x1, int16_t y1,
uint32_t value);
+void common_hal_bitmaptools_readinto(displayio_bitmap_t *self, pyb_file_obj_t *file, int element_size, int bits_per_pixel, bool reverse_pixels_in_word, bool swap_bytes);
+void common_hal_bitmaptools_arrayblit(displayio_bitmap_t *self, void *data, int element_size, int x1, int y1, int x2, int y2, bool skip_specified, uint32_t skip_index);
+
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H