diff options
| author | Jeff Epler <jepler@unpythonic.net> | 2021-03-14 13:27:28 -0500 |
|---|---|---|
| committer | Jeff Epler <jepler@unpythonic.net> | 2021-03-14 13:57:46 -0500 |
| commit | 9133b23a37649cc53568f8208c2493348441d700 (patch) | |
| tree | d6f3fb7fb3c79d0929e1e777a344911bf009ca53 /shared-module | |
| parent | d2563c57dedfa3a8acaf19bfd2f5b98caad41fe9 (diff) | |
bitmaptools: Add readinto
When reading uncompressed bitmap data directly, readinto can work
much more quickly than a Python-coded loop.
On a Raspberry Pi Pico, I benchmarked a modified version of
adafruit_bitmap_font's pcf reader which uses readinto instead of
the existing code. My test font was a 72-point file created from Arial.
This decreased the time to load all the ASCII glyphs from 4.9 seconds to
just 0.44 seconds.
While this attempts to support many pixel configurations (1/2/4/8/16/24/32
bpp; swapped words and pixels) only the single combination used by
PCF fonts was tested.
Diffstat (limited to 'shared-module')
| -rw-r--r-- | shared-module/bitmaptools/__init__.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/shared-module/bitmaptools/__init__.c b/shared-module/bitmaptools/__init__.c index 6f168b555..a41b5007c 100644 --- a/shared-module/bitmaptools/__init__.c +++ b/shared-module/bitmaptools/__init__.c @@ -25,10 +25,12 @@ */ +#include "shared-bindings/bitmaptools/__init__.h" #include "shared-bindings/displayio/Bitmap.h" #include "shared-module/displayio/Bitmap.h" #include "py/runtime.h" +#include "py/mperrno.h" #include "math.h" #include "stdlib.h" @@ -336,3 +338,91 @@ void common_hal_bitmaptools_draw_line(displayio_bitmap_t *destination, } } } + +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) { + if (self->read_only) { + mp_raise_RuntimeError(translate("Read-only object")); + } + + size_t elements_per_row = (self->width * bits_per_pixel + element_size * 8 - 1) / (element_size * 8); + size_t rowsize = element_size * elements_per_row; + size_t rowsize_in_u32 = (rowsize + sizeof(uint32_t) - 1) / sizeof(uint32_t); + size_t rowsize_in_u16 = (rowsize + sizeof(uint16_t) - 1) / sizeof(uint16_t); + for(int y=0; y<self->height; y++) { + uint32_t rowdata32[rowsize_in_u32]; + uint16_t *rowdata16 = (uint16_t*)rowdata32; + uint8_t *rowdata8 = (uint8_t*)rowdata32; + + UINT bytes_read = 0; + if (f_read(&file->fp, rowdata32, rowsize, &bytes_read) != FR_OK || bytes_read != rowsize) { + mp_raise_OSError(MP_EIO); + } + + if (swap_bytes) { + switch(element_size) { + case 2: + { + for(int i=0; i< rowsize_in_u16; i++) { + rowdata16[i] = __builtin_bswap16(rowdata16[i]); + } + } + break; + case 4: + for(int i=0; i< rowsize_in_u32; i++) { + rowdata32[i] = __builtin_bswap32(rowdata32[i]); + } + default: + break; + } + } + + for(int x=0; x<self->width; x++) { + int value = 0; + switch(bits_per_pixel) { + case 1: + { + int byte_offset = x / 8; + int bit_offset = reverse_pixels_in_element ? (7 - x % 8) : x % 8; + + value = (rowdata8[byte_offset] >> bit_offset) & 1; + break; + } + case 2: + { + int byte_offset = x / 4; + int bit_offset = 2 * (reverse_pixels_in_element ? (3 - x % 4) : x % 4); + + value = (rowdata8[byte_offset] >> bit_offset) & 3; + break; + } + case 4: + { + int byte_offset = x / 2; + int bit_offset = 4 * (reverse_pixels_in_element ? (1 - x % 2) : x % 2); + + value = (rowdata8[byte_offset] >> bit_offset) & 7; + break; + } + case 8: + value = rowdata8[x]; + break; + + case 16: + value = rowdata16[x]; + break; + + case 24: + value = (rowdata8[x * 3] << 16) | (rowdata8[x * 3 + 1] << 8) | (rowdata8[x * 3 + 2] << 8); + break; + + case 32: + value = rowdata32[x]; + break; + } + + displayio_bitmap_write_pixel(self, x, y, value); + } + } + + displayio_bitmap_set_dirty_area(self, 0, 0, self->width, self->height); +} |
