diff --git a/3rd/cute_png/src/cute_png.c b/3rd/cute_png/src/cute_png.c index ac992af1..d111f505 100644 --- a/3rd/cute_png/src/cute_png.c +++ b/3rd/cute_png/src/cute_png.c @@ -1,4 +1,5 @@ #include "pocketpy.h" +#include #define CUTE_PNG_IMPLEMENTATION #include "cute_png.h" @@ -147,26 +148,6 @@ static bool cute_png_Image__clear(int argc, py_Ref argv) { return true; } -static bool cute_png_Image__to_rgb565_bytes(int argc, py_Ref argv) { - PY_CHECK_ARGC(1); - cp_image_t* image = py_touserdata(argv); - unsigned char* data = py_newbytes(py_retval(), image->w * image->h * 2); - for(int y = 0; y < image->h; y++) { - for(int x = 0; x < image->w; x++) { - size_t idx = y * image->w + x; - cp_pixel_t pixel = image->pix[idx]; - uint16_t r = (pixel.r >> 3) & 0x1F; - uint16_t g = (pixel.g >> 2) & 0x3F; - uint16_t b = (pixel.b >> 3) & 0x1F; - uint16_t rgb565 = (r << 11) | (g << 5) | b; - // use little-endian - data[idx * 2 + 0] = rgb565 & 0xFF; - data[idx * 2 + 1] = (rgb565 >> 8) & 0xFF; - } - } - return true; -} - static bool cute_png_Image__to_png_bytes(int argc, py_Ref argv) { PY_CHECK_ARGC(1); cp_image_t* image = py_touserdata(argv); @@ -178,6 +159,54 @@ static bool cute_png_Image__to_png_bytes(int argc, py_Ref argv) { return true; } +static bool cute_png_Image__to_png_file(int argc, py_Ref argv) { + PY_CHECK_ARGC(2); + cp_image_t* image = py_touserdata(argv); + size_t size = 0; + + py_Type tp_FileIO = py_gettype("io", py_name("FileIO")); + if(tp_FileIO != tp_nil) { + PY_CHECK_ARG_TYPE(1, tp_FileIO); + FILE** ud = py_touserdata(py_arg(1)); + FILE* fp = *ud; + + cp_saved_png_t saved_image = cp_save_png_to_memory(image); + assert(saved_image.data != NULL); + size = fwrite(saved_image.data, saved_image.size, 1, fp); + CUTE_PNG_FREE(saved_image.data); + } + py_newint(py_retval(), size); + return true; +} + +static bool cute_png_Image__to_rgb565_file(int argc, py_Ref argv) { + PY_CHECK_ARGC(2); + cp_image_t* image = py_touserdata(argv); + size_t size = 0; + + py_Type tp_FileIO = py_gettype("io", py_name("FileIO")); + if(tp_FileIO != tp_nil) { + PY_CHECK_ARG_TYPE(1, tp_FileIO); + FILE** ud = py_touserdata(py_arg(1)); + FILE* fp = *ud; + + for(int y = 0; y < image->h; y++) { + for(int x = 0; x < image->w; x++) { + size_t idx = y * image->w + x; + cp_pixel_t pixel = image->pix[idx]; + uint16_t r = (pixel.r >> 3) & 0x1F; + uint16_t g = (pixel.g >> 2) & 0x3F; + uint16_t b = (pixel.b >> 3) & 0x1F; + uint16_t rgb565 = (r << 11) | (g << 5) | b; + // use little-endian + size += fwrite(&rgb565, 1, 2, fp); + } + } + } + py_newint(py_retval(), size); + return true; +} + void pk__add_module_cute_png() { py_GlobalRef mod = py_newmodule("cute_png"); py_Type tp_image = py_newtype("Image", tp_object, mod, cute_png_Image__dtor); @@ -196,6 +225,7 @@ void pk__add_module_cute_png() { py_bindmethod(tp_image, "getpixel", cute_png_Image__getpixel); py_bindmethod(tp_image, "clear", cute_png_Image__clear); - py_bindmethod(tp_image, "to_rgb565_bytes", cute_png_Image__to_rgb565_bytes); py_bindmethod(tp_image, "to_png_bytes", cute_png_Image__to_png_bytes); + py_bindmethod(tp_image, "to_png_file", cute_png_Image__to_png_file); + py_bindmethod(tp_image, "to_rgb565_file", cute_png_Image__to_rgb565_file); } \ No newline at end of file diff --git a/include/pocketpy/interpreter/types.h b/include/pocketpy/interpreter/types.h index 56535e7a..a9acafb9 100644 --- a/include/pocketpy/interpreter/types.h +++ b/include/pocketpy/interpreter/types.h @@ -2,6 +2,7 @@ #include "pocketpy/common/vector.h" #include "pocketpy/objects/base.h" +#include typedef struct { uint64_t hash; @@ -22,3 +23,9 @@ typedef c11_vector List; void c11_chunked_array2d__mark(void* ud, c11_vector* p_stack); void function__gc_mark(void* ud, c11_vector* p_stack); + +typedef struct { + FILE* file; // cute_png will cast the whole userdata to FILE** + const char* path; + const char* mode; +} io_FileIO; diff --git a/include/typings/cute_png.pyi b/include/typings/cute_png.pyi index 8f8b4ce1..6aca4708 100644 --- a/include/typings/cute_png.pyi +++ b/include/typings/cute_png.pyi @@ -1,5 +1,6 @@ from array2d import array2d from vmath import color32 +from io import FileIO class Image: @property @@ -16,8 +17,10 @@ class Image: def getpixel(self, x: int, y: int) -> color32: ... def clear(self, color: color32) -> None: ... - def to_rgb565_bytes(self) -> bytes: ... def to_png_bytes(self) -> bytes: ... + def to_png_file(self, file: FileIO) -> int: ... + def to_rgb565_file(self, file: FileIO) -> int: ... + def loads(data: bytes) -> array2d[color32]: ... def dumps(image: array2d[color32]) -> bytes: ... diff --git a/src/modules/os.c b/src/modules/os.c index cceb1718..37a7d9c5 100644 --- a/src/modules/os.c +++ b/src/modules/os.c @@ -1,5 +1,6 @@ #include "pocketpy/objects/base.h" #include "pocketpy/pocketpy.h" +#include "pocketpy/interpreter/types.h" #include "pocketpy/interpreter/vm.h" #if PK_ENABLE_OS @@ -101,12 +102,6 @@ void pk__add_module_os() { py_newdict(py_emplacedict(mod, py_name("environ"))); } -typedef struct { - const char* path; - const char* mode; - FILE* file; -} io_FileIO; - static bool io_FileIO__new__(int argc, py_Ref argv) { // __new__(cls, file, mode) PY_CHECK_ARGC(3); @@ -213,6 +208,14 @@ static bool io_FileIO_write(int argc, py_Ref argv) { return true; } +static bool io_FileIO_flush(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + io_FileIO* ud = py_touserdata(py_arg(0)); + fflush(ud->file); + py_newnone(py_retval()); + return true; +} + void pk__add_module_io() { py_Ref mod = py_newmodule("io"); @@ -226,6 +229,7 @@ void pk__add_module_io() { py_bindmethod(FileIO, "close", io_FileIO_close); py_bindmethod(FileIO, "tell", io_FileIO_tell); py_bindmethod(FileIO, "seek", io_FileIO_seek); + py_bindmethod(FileIO, "flush", io_FileIO_flush); py_newint(py_emplacedict(mod, py_name("SEEK_SET")), SEEK_SET); py_newint(py_emplacedict(mod, py_name("SEEK_CUR")), SEEK_CUR);