modules/py_gif: Refactor arg parsing.

This commit is contained in:
iabdalkader 2023-11-12 14:41:56 +01:00
parent d15fc6b8d9
commit 555e67ecd6

View File

@ -8,6 +8,9 @@
* *
* GIF Python module. * GIF Python module.
*/ */
#include "imlib_config.h"
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
#include "py/mphal.h" #include "py/mphal.h"
#include "py/runtime.h" #include "py/runtime.h"
@ -18,114 +21,126 @@
#include "py_helper.h" #include "py_helper.h"
#include "py_image.h" #include "py_image.h"
static const mp_obj_type_t py_gif_type; // forward declare static const mp_obj_type_t py_gif_type;
// Gif class
// Gif object
typedef struct py_gif_obj { typedef struct py_gif_obj {
mp_obj_base_t base; mp_obj_base_t base;
int width; uint32_t width;
int height; uint32_t height;
bool color; bool color;
bool loop; bool loop;
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
FIL fp; FIL fp;
#endif
} py_gif_obj_t; } py_gif_obj_t;
static mp_obj_t py_gif_open(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
py_gif_obj_t *gif = m_new_obj(py_gif_obj_t);
gif->width = py_helper_keyword_int(n_args, args, 1, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_width), framebuffer_get_width());
gif->height = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_height), framebuffer_get_height());
gif->color = py_helper_keyword_int(n_args, args, 3, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_color), framebuffer_get_depth() >= 2);
gif->loop = py_helper_keyword_int(n_args, args, 4, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_loop), true);
gif->base.type = &py_gif_type;
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
file_open(&gif->fp, mp_obj_str_get_str(args[0]), false, FA_WRITE | FA_CREATE_ALWAYS);
gif_open(&gif->fp, gif->width, gif->height, gif->color, gif->loop);
#else
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Image I/O is not supported"));
#endif
return gif;
}
static mp_obj_t py_gif_width(mp_obj_t gif_obj) {
py_gif_obj_t *arg_gif = gif_obj;
return mp_obj_new_int(arg_gif->width);
}
static mp_obj_t py_gif_height(mp_obj_t gif_obj) {
py_gif_obj_t *arg_gif = gif_obj;
return mp_obj_new_int(arg_gif->height);
}
static mp_obj_t py_gif_format(mp_obj_t gif_obj) {
py_gif_obj_t *arg_gif = gif_obj;
return mp_obj_new_int(arg_gif->color ? PIXFORMAT_RGB565 : PIXFORMAT_GRAYSCALE);
}
static mp_obj_t py_gif_size(mp_obj_t gif_obj) {
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
py_gif_obj_t *arg_gif = gif_obj;
return mp_obj_new_int(file_size(&arg_gif->fp));
#else
return mp_obj_new_int(0);
#endif
}
static mp_obj_t py_gif_loop(mp_obj_t gif_obj) {
py_gif_obj_t *arg_gif = gif_obj;
return mp_obj_new_int(arg_gif->loop);
}
static mp_obj_t py_gif_add_frame(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
py_gif_obj_t *arg_gif = args[0];
image_t *arg_img = py_image_cobj(args[1]);
PY_ASSERT_FALSE_MSG(IM_IS_JPEG(arg_img), "Operation not supported on JPEG images.");
PY_ASSERT_FALSE_MSG(IM_IS_BINARY(arg_img), "Operation not supported on binary images.");
PY_ASSERT_FALSE_MSG((arg_gif->width != arg_img->w) ||
(arg_gif->height != arg_img->h), "Unexpected image geometry!");
int delay = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_delay), 10);
gif_add_frame(&arg_gif->fp, arg_img, delay);
#else
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Image I/O is not supported"));
#endif
return mp_const_none;
}
static mp_obj_t py_gif_close(mp_obj_t gif_obj) {
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
py_gif_obj_t *arg_gif = gif_obj;
gif_close(&arg_gif->fp);
#endif
return mp_const_none;
}
static void py_gif_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { static void py_gif_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
py_gif_obj_t *self = self_in; py_gif_obj_t *self = self_in;
mp_printf(print, "<gif width:%d height:%d color:%d loop:%d>", self->width, self->height, self->color, self->loop); mp_printf(print, "<gif width:%d height:%d color:%d loop:%d>", self->width, self->height, self->color, self->loop);
} }
static mp_obj_t py_gif_width(mp_obj_t self_in) {
py_gif_obj_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_int(self->width);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_width_obj, py_gif_width); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_width_obj, py_gif_width);
static mp_obj_t py_gif_height(mp_obj_t self_in) {
py_gif_obj_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_int(self->height);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_height_obj, py_gif_height); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_height_obj, py_gif_height);
static mp_obj_t py_gif_format(mp_obj_t self_in) {
py_gif_obj_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_int(self->color ? PIXFORMAT_RGB565 : PIXFORMAT_GRAYSCALE);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_format_obj, py_gif_format); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_format_obj, py_gif_format);
static mp_obj_t py_gif_size(mp_obj_t self_in) {
py_gif_obj_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_int(file_size(&self->fp));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_size_obj, py_gif_size); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_size_obj, py_gif_size);
static mp_obj_t py_gif_loop(mp_obj_t self_in) {
py_gif_obj_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_int(self->loop);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_loop_obj, py_gif_loop); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_loop_obj, py_gif_loop);
static mp_obj_t py_gif_add_frame(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_delay };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_delay, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 10 } },
};
// Parse args.
py_gif_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
image_t *image = py_helper_arg_to_image(pos_args[1], ARG_IMAGE_MUTABLE);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// Sanity checks
if (self->width != image->w || self->height != image->h) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Unexpected image geometry"));
}
if (image->pixfmt == PIXFORMAT_JPEG || image->pixfmt == PIXFORMAT_BINARY) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Image format is not supported"));
}
gif_add_frame(&self->fp, image, args[ARG_delay].u_int);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_gif_add_frame_obj, 2, py_gif_add_frame); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_gif_add_frame_obj, 2, py_gif_add_frame);
STATIC mp_obj_t py_gif_close(mp_obj_t self_in) {
py_gif_obj_t *self = MP_OBJ_TO_PTR(self_in);
gif_close(&self->fp);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_close_obj, py_gif_close); STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_gif_close_obj, py_gif_close);
static const mp_map_elem_t locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_width), (mp_obj_t) &py_gif_width_obj }, static mp_obj_t py_gif_open(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
{ MP_OBJ_NEW_QSTR(MP_QSTR_height), (mp_obj_t) &py_gif_height_obj }, enum { ARG_width, ARG_height, ARG_color, ARG_loop };
{ MP_OBJ_NEW_QSTR(MP_QSTR_format), (mp_obj_t) &py_gif_format_obj }, static const mp_arg_t allowed_args[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_size), (mp_obj_t) &py_gif_size_obj }, { MP_QSTR_width, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = -1 } },
{ MP_OBJ_NEW_QSTR(MP_QSTR_loop), (mp_obj_t) &py_gif_loop_obj }, { MP_QSTR_height, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = -1 } },
{ MP_OBJ_NEW_QSTR(MP_QSTR_add_frame), (mp_obj_t) &py_gif_add_frame_obj }, { MP_QSTR_color, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = -1 } },
{ MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t) &py_gif_close_obj }, { MP_QSTR_loop, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_bool = true } },
};
// Parse args.
const char *path = mp_obj_str_get_str(pos_args[0]);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
py_gif_obj_t *gif = m_new_obj_with_finaliser(py_gif_obj_t);
gif->base.type = &py_gif_type;
gif->width = (args[ARG_width].u_int == -1) ? framebuffer_get_width() : args[ARG_width].u_int;
gif->height = (args[ARG_height].u_int == -1) ? framebuffer_get_height() : args[ARG_height].u_int;
gif->color = (args[ARG_color].u_int == -1) ? (framebuffer_get_depth() >= 2) : args[ARG_color].u_bool;
gif->loop = args[ARG_loop].u_bool;
file_open(&gif->fp, path, false, FA_WRITE | FA_CREATE_ALWAYS);
gif_open(&gif->fp, gif->width, gif->height, gif->color, gif->loop);
return gif;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_gif_open_obj, 1, py_gif_open);
STATIC const mp_rom_map_elem_t py_gif_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_gif) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&py_gif_close_obj) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_width), MP_ROM_PTR(&py_gif_width_obj) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_height), MP_ROM_PTR(&py_gif_height_obj) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_format), MP_ROM_PTR(&py_gif_format_obj) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_size), MP_ROM_PTR(&py_gif_size_obj) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_loop), MP_ROM_PTR(&py_gif_loop_obj) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_add_frame), MP_ROM_PTR(&py_gif_add_frame_obj) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_close), MP_ROM_PTR(&py_gif_close_obj) },
{ NULL, NULL }, { NULL, NULL },
}; };
STATIC MP_DEFINE_CONST_DICT(py_gif_locals_dict, locals_dict_table); STATIC MP_DEFINE_CONST_DICT(py_gif_locals_dict, py_gif_locals_dict_table);
STATIC MP_DEFINE_CONST_OBJ_TYPE( STATIC MP_DEFINE_CONST_OBJ_TYPE(
py_gif_type, py_gif_type,
@ -135,10 +150,9 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE(
locals_dict, &py_gif_locals_dict locals_dict, &py_gif_locals_dict
); );
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_gif_open_obj, 1, py_gif_open); STATIC const mp_rom_map_elem_t globals_dict_table[] = {
static const mp_map_elem_t globals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_gif) }, { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_gif) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_Gif), (mp_obj_t) &py_gif_open_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_Gif), MP_ROM_PTR(&py_gif_open_obj) },
{ NULL, NULL }, { NULL, NULL },
}; };
STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table); STATIC MP_DEFINE_CONST_DICT(globals_dict, globals_dict_table);
@ -149,3 +163,4 @@ const mp_obj_module_t gif_module = {
}; };
MP_REGISTER_MODULE(MP_QSTR_gif, gif_module); MP_REGISTER_MODULE(MP_QSTR_gif, gif_module);
#endif // IMLIB_ENABLE_IMAGE_FILE_IO