png.c
#ifdef LIL_USE_PNG #include <png.h> #include <math.h> #include "inc.h" struct PngFakeFile{ const char* buf; unsigned size; unsigned cur; }; static void pngFakeRead(png_structp png, png_bytep data, size_t n){ struct PngFakeFile* file = png_get_io_ptr(png); if(n > file->cur - file->size) n = file->cur - file->size; memcpy(data, file->buf+file->cur, n); file->cur += n; } LUAFUNC(importPng){ size_t len; const uint8_t* data = (const uint8_t*)lua_tolstring(L, 1, &len); png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png) return 0; png_infop info = png_create_info_struct(png); if(!info){ png_destroy_info_struct(png, &info); png_destroy_read_struct(&png, NULL, NULL); return 0; } if(setjmp(png_jmpbuf(png))){ png_destroy_info_struct(png, &info); png_destroy_read_struct(&png, &info, NULL); return 0; } png_set_read_fn(png, NULL, pngFakeRead); struct PngFakeFile ff = {.buf = (char*)data, .size = len, .cur = 0}; png_init_io(png, (FILE*)&ff); png_read_info(png, info); uint32_t w, h; int bitDepth, colourType; png_get_IHDR(png, info, &w, &h, &bitDepth, &colourType, NULL, NULL, NULL); const lil_Image* img = lil_newImage(L, w, h); if(!img){ png_destroy_info_struct(png, &info); png_destroy_read_struct(&png, &info, NULL); return 0; } png_set_expand(png); png_set_strip_16(png); png_set_gray_to_rgb(png); png_set_add_alpha(png, 0xff, PNG_FILLER_AFTER); png_read_update_info(png, info); unsigned char** rows = malloc(sizeof(unsigned char*) * h); for(int y = 0; y < h; y++) rows[y] = (unsigned char*)(&img->d[y * w]); png_read_image(png, rows); free(rows); png_destroy_info_struct(png, &info); png_destroy_read_struct(&png, &info, NULL); lil_pushImage(L, img); return 1; } static void pngFakeFlush(){} static void pngFakeWrite(png_structp png, png_bytep data, size_t len){ luaL_addlstring(png_get_io_ptr(png), (char*)data, len); } LUAFUNC(exportPng){ const lil_Image* img = lil_getImage(L, 1); png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png) return 0; png_infop info = png_create_info_struct(png); if(!info){ png_destroy_info_struct(png, &info); png_destroy_write_struct(&png, NULL); return 0; } if(setjmp(png_jmpbuf(png))){ png_destroy_info_struct(png, &info); png_destroy_write_struct(&png, NULL); return 0; } png_set_write_fn(png, NULL, pngFakeWrite, pngFakeFlush); luaL_Buffer b; luaL_buffinit(L, &b); png_init_io(png, (FILE*)&b); lil_Number speed; lil_getExportOpts(L, 2, NULL, &speed); png_set_compression_level(png, round(speed * 9)); png_set_IHDR(png, info, img->w, img->h, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png, info); unsigned char** rows = malloc(sizeof(unsigned char*) * img->h); for(int y = 0; y < img->h; y++) rows[y] = (unsigned char*)(&img->d[y * img->w]); png_write_image(png, rows); png_write_end(png, NULL); free(rows); png_destroy_info_struct(png, &info); png_destroy_write_struct(&png, &info); luaL_pushresult(&b); return 1; } #endif