PNGDEC: Clean up API, add get_palette and index copy.

pull/802/head
Phil Howard 2023-07-21 13:23:08 +01:00
rodzic 6db7a9a0a6
commit 5ec6903f7f
3 zmienionych plików z 85 dodań i 34 usunięć

Wyświetl plik

@ -6,6 +6,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(PNG_openFILE_obj, _PNG_openFILE);
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(PNG_decode_obj, 1, _PNG_decode);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(PNG_getWidth_obj, _PNG_getWidth);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(PNG_getHeight_obj, _PNG_getHeight);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(PNG_getPalette_obj, _PNG_getPalette);
// class
STATIC const mp_rom_map_elem_t PNG_locals_dict_table[] = {
@ -15,7 +16,7 @@ STATIC const mp_rom_map_elem_t PNG_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_decode), MP_ROM_PTR(&PNG_decode_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_width), MP_ROM_PTR(&PNG_getWidth_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&PNG_getHeight_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_height), MP_ROM_PTR(&PNG_getHeight_obj) },
{ MP_ROM_QSTR(MP_QSTR_get_palette), MP_ROM_PTR(&PNG_getPalette_obj) },
};
STATIC MP_DEFINE_CONST_DICT(PNG_locals_dict, PNG_locals_dict_table);
@ -44,10 +45,10 @@ STATIC const mp_map_elem_t PNG_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pngdec) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_PNG), (mp_obj_t)&PNG_type },
{ MP_ROM_QSTR(MP_QSTR_PNG_SCALE_FULL), MP_ROM_INT(0) },
{ MP_ROM_QSTR(MP_QSTR_PNG_SCALE_HALF), MP_ROM_INT(2) },
{ MP_ROM_QSTR(MP_QSTR_PNG_SCALE_QUARTER), MP_ROM_INT(4) },
{ MP_ROM_QSTR(MP_QSTR_PNG_SCALE_EIGHTH), MP_ROM_INT(8) },
{ MP_ROM_QSTR(MP_QSTR_PNG_NORMAL), MP_ROM_INT(0) },
{ MP_ROM_QSTR(MP_QSTR_PNG_POSTERISE), MP_ROM_INT(0) },
{ MP_ROM_QSTR(MP_QSTR_PNG_DITHER), MP_ROM_INT(1) },
{ MP_ROM_QSTR(MP_QSTR_PNG_COPY), MP_ROM_INT(2) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_PNG_globals, PNG_globals_table);

Wyświetl plik

@ -20,7 +20,7 @@ typedef struct _ModPicoGraphics_obj_t {
typedef struct _PNG_decode_target {
void *target;
uint8_t flags = 0;
uint8_t mode = 0;
Point position = {0, 0};
Rect source = {0, 0, 0, 0};
Point scale = {1, 1};
@ -39,8 +39,10 @@ typedef struct _PNG_obj_t {
int height;
} _PNG_obj_t;
enum FLAGS : uint8_t {
FLAG_NO_DITHER = 1u
enum DECODE_MODE : uint8_t {
MODE_POSTERIZE = 0u,
MODE_DITHER = 1u,
MODE_COPY = 2u,
};
void *pngdec_open_callback(const char *filename, int32_t *size) {
@ -121,7 +123,7 @@ MICROPY_EVENT_POLL_HOOK
_PNG_decode_target *target = (_PNG_decode_target*)pDraw->pUser;
PicoGraphics *current_graphics = (PicoGraphics *)target->target;
Point current_position = target->position;
uint8_t current_flags = target->flags;
uint8_t current_mode = target->mode;
Point scale = target->scale;
// "pixel" is slow and clipped,
// guaranteeing we wont draw png data out of the framebuffer..
@ -175,7 +177,7 @@ MICROPY_EVENT_POLL_HOOK
uint8_t a = pDraw->iHasAlpha ? pDraw->pPalette[768 + i] : 1;
if (a) {
if (current_graphics->pen_type == PicoGraphics::PEN_RGB332) {
if (current_flags & FLAG_NO_DITHER) {
if (current_mode == MODE_POSTERIZE || current_mode == MODE_COPY) {
// Posterized output to RGB332
current_graphics->set_pen(RGB(r, g, b).to_rgb332());
current_graphics->rectangle({current_position.x, current_position.y, scale.x, scale.y});
@ -192,7 +194,12 @@ MICROPY_EVENT_POLL_HOOK
|| current_graphics->pen_type == PicoGraphics::PEN_3BIT
|| current_graphics->pen_type == PicoGraphics::PEN_INKY7) {
if(current_flags & FLAG_NO_DITHER) {
// Copy raw palette indexes over
if(current_mode == MODE_COPY) {
current_graphics->set_pen(i);
current_graphics->rectangle({current_position.x, current_position.y, scale.x, scale.y});
// Posterized output to the available palete
} else if(current_mode == MODE_POSTERIZE) {
int closest = RGB(r, g, b).closest(current_graphics->get_palette(), current_graphics->get_palette_size());
if (closest == -1) {
closest = 0;
@ -285,21 +292,14 @@ mp_obj_t _PNG_openRAM(mp_obj_t self_in, mp_obj_t buffer) {
// decode
mp_obj_t _PNG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_x, ARG_y, ARG_scale, ARG_dither,
ARG_source_x, ARG_source_y, ARG_source_w, ARG_source_h,
ARG_scale_x, ARG_scale_y };
enum { ARG_self, ARG_x, ARG_y, ARG_scale, ARG_mode, ARG_source };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_x, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_y, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_scale, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_dither, MP_ARG_OBJ, {.u_obj = mp_const_true} },
{ MP_QSTR_source_x, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_source_y, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_source_w, MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_source_h, MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_scale_x, MP_ARG_INT, {.u_int = 1} },
{ MP_QSTR_scale_y, MP_ARG_INT, {.u_int = 1} },
{ MP_QSTR_scale, MP_ARG_OBJ, {.u_obj = nullptr} },
{ MP_QSTR_mode, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_source, MP_ARG_OBJ, {.u_obj = nullptr} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@ -307,10 +307,43 @@ mp_obj_t _PNG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
_PNG_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _PNG_obj_t);
// TODO: Implement integer 1x/2x/3x scaling by repeating pixels?
//int f = args[ARG_scale].u_int;
if(mp_obj_is_type(args[ARG_source].u_obj, &mp_type_tuple)){
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(args[ARG_source].u_obj, mp_obj_tuple_t);
self->decode_target->flags = args[ARG_dither].u_obj == mp_const_false ? FLAG_NO_DITHER : 0;
if(tuple->len != 4) mp_raise_ValueError("decode(): source tuple must contain (x, y, w, h)");
self->decode_target->source = {
mp_obj_get_int(tuple->items[0]),
mp_obj_get_int(tuple->items[1]),
mp_obj_get_int(tuple->items[2]),
mp_obj_get_int(tuple->items[3])
};
} else {
self->decode_target->source = {0, 0, self->width, self->height};
}
// Scale is a single int, corresponds to both width/height
if (mp_obj_is_int(args[ARG_scale].u_obj)) {
self->decode_target->scale = {
mp_obj_get_int(args[ARG_scale].u_obj),
mp_obj_get_int(args[ARG_scale].u_obj)
};
// Scale is a tuple, separate scales for width/height
} else if(mp_obj_is_type(args[ARG_scale].u_obj, &mp_type_tuple)){
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR2(args[ARG_scale].u_obj, mp_obj_tuple_t);
if(tuple->len != 2) mp_raise_ValueError("decode(): scale tuple must contain (scale_x, scale_y)");
self->decode_target->scale = {
mp_obj_get_int(tuple->items[0]),
mp_obj_get_int(tuple->items[1])
};
// Something else, just roll with the default
} else {
self->decode_target->scale = {1, 1};
}
self->decode_target->mode = args[ARG_mode].u_int;
self->decode_target->position = {args[ARG_x].u_int, args[ARG_y].u_int};
@ -321,15 +354,6 @@ mp_obj_t _PNG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
pngdec_open_helper(self);
int source_x = args[ARG_source_x].u_int;
int source_y = args[ARG_source_y].u_int;
int source_w = args[ARG_source_w].u_int == -1 ? self->width : args[ARG_source_w].u_int;
int source_h = args[ARG_source_h].u_int == -1 ? self->height : args[ARG_source_h].u_int;
self->decode_target->source = {source_x, source_y, source_w, source_h};
self->decode_target->scale = {args[ARG_scale_x].u_int, args[ARG_scale_y].u_int};
result = self->png->decode(self->decode_target, 0);
// Close the file since we've opened it on-demand
@ -350,4 +374,29 @@ mp_obj_t _PNG_getHeight(mp_obj_t self_in) {
return mp_obj_new_int(self->height);
}
// get_height
mp_obj_t _PNG_getPalette(mp_obj_t self_in) {
_PNG_obj_t *self = MP_OBJ_TO_PTR2(self_in, _PNG_obj_t);
pngdec_open_helper(self);
self->png->decode(nullptr, 0);
uint8_t *palette = self->png->getPalette();
mp_obj_t palette_out[256];
for(auto i = 0u; i < 256; i++) {
mp_obj_t entry[3] = {
mp_obj_new_int(*palette++),
mp_obj_new_int(*palette++),
mp_obj_new_int(*palette++)
};
palette_out[i] = mp_obj_new_tuple(3, entry);
}
self->png->close();
return mp_obj_new_list(256, palette_out);
}
}

Wyświetl plik

@ -10,5 +10,6 @@ extern mp_obj_t _PNG_openFILE(mp_obj_t self_in, mp_obj_t filename);
extern mp_obj_t _PNG_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
extern mp_obj_t _PNG_getWidth(mp_obj_t self_in);
extern mp_obj_t _PNG_getHeight(mp_obj_t self_in);
extern mp_obj_t _PNG_getPalette(mp_obj_t self_in);
extern void *pngdec_open_callback(const char *filename, int32_t *size);