From 403ea89d5799a37d4cda08071d5bf2e5bc86a383 Mon Sep 17 00:00:00 2001 From: gamblor21 Date: Tue, 18 Apr 2023 19:44:03 -0500 Subject: [PATCH] Initial paletts for OnDiskGif --- shared-bindings/gifio/OnDiskGif.c | 28 ++++++- shared-bindings/gifio/OnDiskGif.h | 3 +- shared-module/gifio/OnDiskGif.c | 121 +++++++++++++++++++++--------- shared-module/gifio/OnDiskGif.h | 8 +- 4 files changed, 118 insertions(+), 42 deletions(-) diff --git a/shared-bindings/gifio/OnDiskGif.c b/shared-bindings/gifio/OnDiskGif.c index f6acccfabf..cfed55d0c8 100644 --- a/shared-bindings/gifio/OnDiskGif.c +++ b/shared-bindings/gifio/OnDiskGif.c @@ -117,9 +117,16 @@ //| """ //| ... STATIC mp_obj_t gifio_ondiskgif_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - mp_arg_check_num(n_args, n_kw, 1, 1, false); - mp_obj_t arg = all_args[0]; + enum { ARG_filename, ARG_use_palette, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_filename, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_use_palette, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + MP_STATIC_ASSERT(MP_ARRAY_SIZE(allowed_args) == NUM_ARGS); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_obj_t arg = all_args[0]; if (mp_obj_is_str(arg)) { arg = mp_call_function_2(MP_OBJ_FROM_PTR(&mp_builtin_open_obj), arg, MP_ROM_QSTR(MP_QSTR_rb)); } @@ -130,7 +137,7 @@ STATIC mp_obj_t gifio_ondiskgif_make_new(const mp_obj_type_t *type, size_t n_arg gifio_ondiskgif_t *self = m_new_obj(gifio_ondiskgif_t); self->base.type = &gifio_ondiskgif_type; - common_hal_gifio_ondiskgif_construct(self, MP_OBJ_TO_PTR(arg)); + common_hal_gifio_ondiskgif_construct(self, MP_OBJ_TO_PTR(arg), args[ARG_use_palette].u_bool); return MP_OBJ_FROM_PTR(self); } @@ -199,6 +206,20 @@ MP_DEFINE_CONST_FUN_OBJ_1(gifio_ondiskgif_get_bitmap_obj, gifio_ondiskgif_obj_ge MP_PROPERTY_GETTER(gifio_ondiskgif_bitmap_obj, (mp_obj_t)&gifio_ondiskgif_get_bitmap_obj); +//| palette: displayio.Palette +//| """The palette for the current frame.""" +STATIC mp_obj_t gifio_ondiskgif_obj_get_palette(mp_obj_t self_in) { + gifio_ondiskgif_t *self = MP_OBJ_TO_PTR(self_in); + + check_for_deinit(self); + return common_hal_gifio_ondiskgif_get_palette(self); +} + +MP_DEFINE_CONST_FUN_OBJ_1(gifio_ondiskgif_get_palette_obj, gifio_ondiskgif_obj_get_palette); + +MP_PROPERTY_GETTER(gifio_ondiskgif_palette_obj, + (mp_obj_t)&gifio_ondiskgif_get_palette_obj); + //| def next_frame(self) -> float: //| """Loads the next frame. Returns expected delay before the next frame in seconds.""" STATIC mp_obj_t gifio_ondiskgif_obj_next_frame(mp_obj_t self_in) { @@ -285,6 +306,7 @@ STATIC const mp_rom_map_elem_t gifio_ondiskgif_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&gifio_ondiskgif___exit___obj) }, { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&gifio_ondiskgif_height_obj) }, { MP_ROM_QSTR(MP_QSTR_bitmap), MP_ROM_PTR(&gifio_ondiskgif_bitmap_obj) }, + { MP_ROM_QSTR(MP_QSTR_palette), MP_ROM_PTR(&gifio_ondiskgif_palette_obj) }, { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&gifio_ondiskgif_width_obj) }, { MP_ROM_QSTR(MP_QSTR_next_frame), MP_ROM_PTR(&gifio_ondiskgif_next_frame_obj) }, { MP_ROM_QSTR(MP_QSTR_duration), MP_ROM_PTR(&gifio_ondiskgif_duration_obj) }, diff --git a/shared-bindings/gifio/OnDiskGif.h b/shared-bindings/gifio/OnDiskGif.h index 6776466e8d..deaa639685 100644 --- a/shared-bindings/gifio/OnDiskGif.h +++ b/shared-bindings/gifio/OnDiskGif.h @@ -32,13 +32,14 @@ extern const mp_obj_type_t gifio_ondiskgif_type; -void common_hal_gifio_ondiskgif_construct(gifio_ondiskgif_t *self, pyb_file_obj_t *file); +void common_hal_gifio_ondiskgif_construct(gifio_ondiskgif_t *self, pyb_file_obj_t *file, bool use_palette); uint32_t common_hal_gifio_ondiskgif_get_pixel(gifio_ondiskgif_t *bitmap, int16_t x, int16_t y); uint16_t common_hal_gifio_ondiskgif_get_height(gifio_ondiskgif_t *self); mp_obj_t common_hal_gifio_ondiskgif_get_bitmap(gifio_ondiskgif_t *self); +mp_obj_t common_hal_gifio_ondiskgif_get_palette(gifio_ondiskgif_t *self); uint16_t common_hal_gifio_ondiskgif_get_width(gifio_ondiskgif_t *self); uint32_t common_hal_gifio_ondiskgif_next_frame(gifio_ondiskgif_t *self, bool setDirty); int32_t common_hal_gifio_ondiskgif_get_duration(gifio_ondiskgif_t *self); diff --git a/shared-module/gifio/OnDiskGif.c b/shared-module/gifio/OnDiskGif.c index aeb4f7bb74..f6adfa0775 100644 --- a/shared-module/gifio/OnDiskGif.c +++ b/shared-module/gifio/OnDiskGif.c @@ -26,6 +26,7 @@ #include "shared-bindings/gifio/OnDiskGif.h" #include "shared-bindings/displayio/Bitmap.h" +#include "shared-bindings/displayio/Palette.h" #include @@ -34,7 +35,6 @@ static int32_t GIFReadFile(GIFFILE *pFile, uint8_t *pBuf, int32_t iLen) { - // mp_printf(&mp_plat_print, "GifReadFile len %d ", iLen); uint32_t iBytesRead; iBytesRead = iLen; pyb_file_obj_t *f = pFile->fHandle; @@ -50,18 +50,15 @@ static int32_t GIFReadFile(GIFFILE *pFile, uint8_t *pBuf, int32_t iLen) { mp_raise_OSError(MP_EIO); } pFile->iPos = f->fp.fptr; - // mp_printf(&mp_plat_print, " now at %d\n", pFile->iPos); return bytes_read; } /* GIFReadFile() */ static int32_t GIFSeekFile(GIFFILE *pFile, int32_t iPosition) { - // mp_printf(&mp_plat_print, "GifSeekFile %d ", iPosition); pyb_file_obj_t *f = pFile->fHandle; f_lseek(&f->fp, iPosition); pFile->iPos = f->fp.fptr; - // mp_printf(&mp_plat_print, " now at %d\n", pFile->iPos); return pFile->iPos; } /* GIFSeekFile() */ @@ -71,10 +68,25 @@ static void GIFDraw(GIFDRAW *pDraw) { // The palette is either RGB565 or the original 24-bit RGB values // depending on the pixel type selected with gif.begin() - displayio_bitmap_t *bitmap = (displayio_bitmap_t *)pDraw->pUser; + gifio_ondiskgif_displayio_objs_t *displayio_objs = (gifio_ondiskgif_displayio_objs_t *)pDraw->pUser; + displayio_bitmap_t *bitmap = displayio_objs->bitmap; + displayio_palette_t *palette = displayio_objs->palette; - uint8_t *s; - uint16_t *d; + // Update the palette if we have one in RGB888 + if (palette != NULL) { + uint8_t *pPal = pDraw->pPalette24; + for (int p = 0; p < 256; p++) { + uint8_t r = *pPal++; + uint8_t g = *pPal++; + uint8_t b = *pPal++; + uint32_t color = (r << 16) + (g << 8) + b; + common_hal_displayio_palette_set_color(palette, p, color); + common_hal_displayio_palette_make_opaque(palette, p); // Transparency can change frame to frame + } + if (pDraw->ucHasTransparency) { + common_hal_displayio_palette_make_transparent(palette, pDraw->ucTransparent); + } + } int iWidth = pDraw->iWidth; if (iWidth + pDraw->iX > bitmap->width) { @@ -87,11 +99,6 @@ static void GIFDraw(GIFDRAW *pDraw) { int32_t row_start = (pDraw->y + pDraw->iY) * bitmap->stride; uint32_t *row = bitmap->data + row_start; - s = pDraw->pPixels; - d = (uint16_t *)row; - - uint16_t *pPal; - pPal = (uint16_t *)pDraw->pPalette; if (pDraw->ucDisposalMethod == 2) { // restore to background color // Not supported currently. Need to reset the area the previous frame occupied @@ -101,31 +108,53 @@ static void GIFDraw(GIFDRAW *pDraw) { // To workaround clear the gif.bitmap object yourself as required. } - uint8_t c, ucTransparent = pDraw->ucTransparent; - d += pDraw->iX; - if (pDraw->ucHasTransparency == 1) { + if (palette != NULL) { + uint8_t *s = pDraw->pPixels; + uint8_t *d = (uint8_t *)row; + + d += pDraw->iX; for (int x = 0; x < iWidth; x++) { - c = *s++; - if (c != ucTransparent) { - *d = pPal[c]; - } - d++; + *d++ = *s++; } } else { - for (int x = 0; x < iWidth; x++) - { - c = *s++; - *d++ = pPal[c]; + // No palette writing RGB565_SWAPPED right to bitmap buffer + uint8_t *s = pDraw->pPixels; + ; + uint16_t *d = (uint16_t *)row; + + uint16_t *pPal; + pPal = (uint16_t *)pDraw->pPalette; + + uint8_t c, ucTransparent = pDraw->ucTransparent; + d += pDraw->iX; + if (pDraw->ucHasTransparency == 1) { + for (int x = 0; x < iWidth; x++) + { + c = *s++; + if (c != ucTransparent) { + *d = pPal[c]; + } + d++; + } + } else { + for (int x = 0; x < iWidth; x++) + { + c = *s++; + *d++ = pPal[c]; + } } } } -void common_hal_gifio_ondiskgif_construct(gifio_ondiskgif_t *self, pyb_file_obj_t *file) { - // mp_printf(&mp_plat_print, "Begin OnDiskGif\n"); +void common_hal_gifio_ondiskgif_construct(gifio_ondiskgif_t *self, pyb_file_obj_t *file, bool use_palette) { self->file = file; - GIF_begin(&self->gif, GIF_PALETTE_RGB565_BE); + if (use_palette == true) { + GIF_begin(&self->gif, GIF_PALETTE_RGB888); + } else { + GIF_begin(&self->gif, GIF_PALETTE_RGB565_BE); + } self->gif.iError = GIF_SUCCESS; self->gif.pfnRead = GIFReadFile; @@ -143,10 +172,22 @@ void common_hal_gifio_ondiskgif_construct(gifio_ondiskgif_t *self, pyb_file_obj_ mp_arg_error_invalid(MP_QSTR_file); } + int bpp = 16; + if (use_palette == true) { + mp_printf(&mp_plat_print, "Using palette\n"); + displayio_palette_t *palette = m_new_obj(displayio_palette_t); + palette->base.type = &displayio_palette_type; + common_hal_displayio_palette_construct(palette, 256, false); + self->displayio_objs.palette = palette; + bpp = 8; + } else { + self->displayio_objs.palette = NULL; + } + displayio_bitmap_t *bitmap = m_new_obj(displayio_bitmap_t); bitmap->base.type = &displayio_bitmap_type; - common_hal_displayio_bitmap_construct(bitmap, self->gif.iCanvasWidth, self->gif.iCanvasHeight, 16); - self->bitmap = bitmap; + common_hal_displayio_bitmap_construct(bitmap, self->gif.iCanvasWidth, self->gif.iCanvasHeight, bpp); + self->displayio_objs.bitmap = bitmap; GIFINFO info; GIF_getInfo(&self->gif, &info); @@ -158,12 +199,13 @@ void common_hal_gifio_ondiskgif_construct(gifio_ondiskgif_t *self, pyb_file_obj_ void common_hal_gifio_ondiskgif_deinit(gifio_ondiskgif_t *self) { self->file = NULL; - common_hal_displayio_bitmap_deinit(self->bitmap); - self->bitmap = NULL; + common_hal_displayio_bitmap_deinit(self->displayio_objs.bitmap); + self->displayio_objs.bitmap = NULL; + self->displayio_objs.palette = NULL; } bool common_hal_gifio_ondiskgif_deinited(gifio_ondiskgif_t *self) { - return self->bitmap == NULL; + return self->displayio_objs.bitmap == NULL; } uint16_t common_hal_gifio_ondiskgif_get_height(gifio_ondiskgif_t *self) { @@ -175,7 +217,11 @@ uint16_t common_hal_gifio_ondiskgif_get_width(gifio_ondiskgif_t *self) { } mp_obj_t common_hal_gifio_ondiskgif_get_bitmap(gifio_ondiskgif_t *self) { - return MP_OBJ_FROM_PTR(self->bitmap); + return MP_OBJ_FROM_PTR(self->displayio_objs.bitmap); +} + +mp_obj_t common_hal_gifio_ondiskgif_get_palette(gifio_ondiskgif_t *self) { + return MP_OBJ_FROM_PTR(self->displayio_objs.palette); } int32_t common_hal_gifio_ondiskgif_get_duration(gifio_ondiskgif_t *self) { @@ -196,17 +242,18 @@ int32_t common_hal_gifio_ondiskgif_get_max_delay(gifio_ondiskgif_t *self) { uint32_t common_hal_gifio_ondiskgif_next_frame(gifio_ondiskgif_t *self, bool setDirty) { int nextDelay = 0; - int result = GIF_playFrame(&self->gif, &nextDelay, self->bitmap); + int result = 0; + result = GIF_playFrame(&self->gif, &nextDelay, &self->displayio_objs); if ((result >= 0) && (setDirty)) { displayio_area_t dirty_area = { .x1 = 0, .y1 = 0, - .x2 = self->bitmap->width, - .y2 = self->bitmap->height, + .x2 = self->displayio_objs.bitmap->width, + .y2 = self->displayio_objs.bitmap->height, }; - displayio_bitmap_set_dirty_area(self->bitmap, &dirty_area); + displayio_bitmap_set_dirty_area(self->displayio_objs.bitmap, &dirty_area); } return nextDelay; diff --git a/shared-module/gifio/OnDiskGif.h b/shared-module/gifio/OnDiskGif.h index c40781ef1f..70479ac8d9 100644 --- a/shared-module/gifio/OnDiskGif.h +++ b/shared-module/gifio/OnDiskGif.h @@ -34,14 +34,20 @@ #include "lib/AnimatedGIF/AnimatedGIF_circuitpy.h" #include "shared-module/displayio/Bitmap.h" +#include "shared-module/displayio/Palette.h" #include "extmod/vfs_fat.h" +typedef struct { + displayio_bitmap_t *bitmap; + displayio_palette_t *palette; +} gifio_ondiskgif_displayio_objs_t; + typedef struct { mp_obj_base_t base; GIFIMAGE gif; pyb_file_obj_t *file; - displayio_bitmap_t *bitmap; + gifio_ondiskgif_displayio_objs_t displayio_objs; int32_t duration; int32_t frame_count; int32_t min_delay;