Skip to content

Commit 542fb58

Browse files
committed
add arrayblit
1 parent b33d77b commit 542fb58

File tree

3 files changed

+113
-1
lines changed

3 files changed

+113
-1
lines changed

shared-bindings/bitmaptools/__init__.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include <stdint.h>
3131

32+
#include "py/binary.h"
3233
#include "py/obj.h"
3334
#include "py/runtime.h"
3435

@@ -357,6 +358,85 @@ STATIC mp_obj_t bitmaptools_obj_draw_line(size_t n_args, const mp_obj_t *pos_arg
357358
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_draw_line_obj, 0, bitmaptools_obj_draw_line);
358359
// requires all 6 arguments
359360

361+
//| def arrayblit(bitmap: display.Bitmap, data: ReadableBuffer, x1: int=0, y1: int=0, x2: Optional[int]=None, y2: Optional[int]=None, skip_index:Optional[int]=None) -> None:
362+
//| """Inserts pixels from ``data`` into the rectangle of width×height pixels with the upper left corner at ``(x,y)``
363+
//|
364+
//| The values from ``data`` are taken modulo the number of color values
365+
//| avalable in the destintaion bitmap.
366+
//|
367+
//| If x1 or y1 are not specified, they are taken as 0. If x2 or y2
368+
//| are not specified, or are given as -1, they are taken as the width
369+
//| and height of the image.
370+
//|
371+
//| The coordinates affected by the blit are ``x1 <= x < x2`` and ``y1 <
372+
//| y < y2``.
373+
//|
374+
//| ``data`` must contain at least as many elements as required. If it
375+
//| contains excess elements, they are ignored.
376+
//|
377+
//| The blit takes place by rows, so the first elements of ``data`` go
378+
//| to the first row, the next elements to the next row, and so on.
379+
//|
380+
//| :param displayio.Bitmap bitmap: A writable bitmap
381+
//| :param ReadableBuffer data: Buffer containing the source pixel values
382+
//| :param int x1: The left corner of the area to blit into (inclusive)
383+
//| :param int y1: The top corner of the area to blit into (inclusive)
384+
//| :param int x2: The right of the area to blit into (exclusive)
385+
//| :param int y2: The bottom corner of the area to blit into (exclusive)
386+
//| :param int skip_index: Bitmap palette index in the source that will not be copied,
387+
//| set to None to copy all pixels"""
388+
//| """
389+
//| ...
390+
//|
391+
STATIC mp_obj_t bitmaptools_arrayblit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
392+
enum { ARG_bitmap, ARG_data, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_skip_index };
393+
static const mp_arg_t allowed_args[] = {
394+
{ MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ },
395+
{ MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ },
396+
{ MP_QSTR_x1, MP_ARG_INT, {.u_int = 0} },
397+
{ MP_QSTR_y1, MP_ARG_INT, {.u_int = 0} },
398+
{ MP_QSTR_x2, MP_ARG_INT, {.u_int = -1} },
399+
{ MP_QSTR_y2, MP_ARG_INT, {.u_int = -1} },
400+
{ MP_QSTR_skip_index, MP_ARG_OBJ, {.u_obj = mp_const_none } },
401+
}
402+
;
403+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
404+
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
405+
406+
if (!MP_OBJ_IS_TYPE(args[ARG_bitmap].u_obj, &displayio_bitmap_type)) {
407+
mp_raise_TypeError(NULL);
408+
}
409+
displayio_bitmap_t *bitmap = MP_OBJ_TO_PTR(args[ARG_bitmap].u_obj);
410+
411+
mp_buffer_info_t bufinfo;
412+
mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ);
413+
414+
int x1 = args[ARG_x1].u_int;
415+
int y1 = args[ARG_y1].u_int;
416+
int x2 = args[ARG_x2].u_int == -1 ? bitmap->width : args[ARG_x2].u_int;
417+
int y2 = args[ARG_y2].u_int == -1 ? bitmap->height : args[ARG_y2].u_int;
418+
419+
if ((x1 < 0) || (y1 < 0) || (x1 > x2) || (y1 > y2) || (x2 > bitmap->width) || (y2 > bitmap->height)) {
420+
mp_raise_IndexError(translate("pixel coordinates out of bounds"));
421+
}
422+
423+
size_t output_element_count = (x2-x1) * (y2-y1);
424+
size_t element_size = mp_binary_get_size('@', bufinfo.typecode, NULL);
425+
size_t input_element_count = bufinfo.len / element_size;
426+
427+
bool skip_specified = args[ARG_skip_index].u_obj != mp_const_none;
428+
uint32_t skip_index = skip_specified ? mp_obj_get_int(args[ARG_skip_index].u_obj) : 0;
429+
if (input_element_count < output_element_count) {
430+
mp_raise_IndexError(translate("index out of range"));
431+
}
432+
433+
common_hal_bitmaptools_arrayblit(bitmap, bufinfo.buf, element_size, x1, y1, x2, y2, skip_specified, skip_index);
434+
435+
return mp_const_none;
436+
}
437+
MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_arrayblit_obj, 0, bitmaptools_arrayblit);
438+
439+
360440
//| 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:
361441
//| """Read from a binary file into a bitmap
362442
//| 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.
@@ -435,6 +515,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_readinto_obj, 0, bitmaptools_readinto);
435515
STATIC const mp_rom_map_elem_t bitmaptools_module_globals_table[] = {
436516
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&bitmaptools_readinto_obj) },
437517
{ MP_ROM_QSTR(MP_QSTR_rotozoom), MP_ROM_PTR(&bitmaptools_rotozoom_obj) },
518+
{ MP_ROM_QSTR(MP_QSTR_arrayblit), MP_ROM_PTR(&bitmaptools_arrayblit_obj) },
438519
{ MP_ROM_QSTR(MP_QSTR_fill_region), MP_ROM_PTR(&bitmaptools_fill_region_obj) },
439520
{ MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) },
440521
};

shared-bindings/bitmaptools/__init__.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,6 @@ void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination,
5252
uint32_t value);
5353

5454
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);
55+
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);
5556

5657
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BITMAPTOOLS__INIT__H

shared-module/bitmaptools/__init__.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,37 @@ void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination,
339339
}
340340
}
341341

342+
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_value) {
343+
uint32_t mask = (1 << common_hal_displayio_bitmap_get_bits_per_value(self)) - 1;
344+
345+
for (int y=y1; y<y2; y++) {
346+
for (int x=x1; x<x2; x++) {
347+
uint32_t value;
348+
switch(element_size) {
349+
default:
350+
case 1:
351+
value = *(uint8_t*) data;
352+
data = (void*)((uint8_t*)data + 1);
353+
break;
354+
case 2:
355+
value = *(uint16_t*) data;
356+
data = (void*)((uint16_t*)data + 1);
357+
break;
358+
case 4:
359+
value = *(uint32_t*) data;
360+
data = (void*)((uint32_t*)data + 1);
361+
break;
362+
}
363+
if (!skip_specified || value != skip_value) {
364+
displayio_bitmap_write_pixel(self, x, y, value & mask);
365+
}
366+
}
367+
}
368+
}
369+
342370
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_element, bool swap_bytes) {
371+
uint32_t mask = (1 << common_hal_displayio_bitmap_get_bits_per_value(self)) - 1;
372+
343373
if (self->read_only) {
344374
mp_raise_RuntimeError(translate("Read-only object"));
345375
}
@@ -418,7 +448,7 @@ void common_hal_bitmaptools_readinto(displayio_bitmap_t *self, pyb_file_obj_t* f
418448
break;
419449
}
420450

421-
displayio_bitmap_write_pixel(self, x, y, value);
451+
displayio_bitmap_write_pixel(self, x, y, value & mask);
422452
}
423453
}
424454

0 commit comments

Comments
 (0)