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
generated by LDoc 1.4.6 Last updated 2023-04-13 13:58:34