void a_png_readFile(const char* path, Pixel** pixels, int* width, int* height) { File* const f = a_file_open(path, "r"); png_structp png = NULL; png_infop info = NULL; if(!f) { goto cleanUp; } #define PNG_SIG 8 png_byte sig[PNG_SIG]; a_file_read(f, sig, PNG_SIG); if(png_sig_cmp(sig, 0, PNG_SIG) != 0) { a_error("%s is not a PNG", path); goto cleanUp; } png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png) { goto cleanUp; } info = png_create_info_struct(png); if(!info) { goto cleanUp; } if(setjmp(png_jmpbuf(png))) { goto cleanUp; } png_init_io(png, a_file_handle(f)); png_set_sig_bytes(png, PNG_SIG); png_read_png(png, info, PNG_TRANSFORM_IDENTITY, NULL); const int type = png_get_color_type(png, info); if(type != PNG_COLOR_TYPE_RGB && type != PNG_COLOR_TYPE_RGBA) { a_error("%s not 8-bit RGBA PNG", path); goto cleanUp; } pngToPixels(png, info, pixels, width, height); cleanUp: if(png) { png_destroy_read_struct(&png, info ? &info : NULL, NULL); } if(f) { a_file_close(f); } }
void a_png_write(const char* path, const Pixel* data, int width, int height) { File* f = a_file_open(path, "w"); png_structp png = NULL; png_infop info = NULL; png_bytepp rows = NULL; if(!f) { goto cleanUp; } rows = malloc(height * sizeof(png_bytep)); memset(rows, 0, height * sizeof(png_bytep)); png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png) { goto cleanUp; } info = png_create_info_struct(png); if(!info) { goto cleanUp; } if(setjmp(png_jmpbuf(png))) { goto cleanUp; } png_set_compression_level(png, Z_BEST_COMPRESSION); png_set_IHDR( png, info, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); for(int i = 0; i < height; i++) { rows[i] = malloc(width * 3 * sizeof(png_byte)); for(int j = 0; j < width; j++) { const Pixel p = *(data + i * width + j); rows[i][j * 3 + 0] = a_pixel_red(p); rows[i][j * 3 + 1] = a_pixel_green(p); rows[i][j * 3 + 2] = a_pixel_blue(p); } } png_init_io(png, a_file_handle(f)); png_set_rows(png, info, rows); png_write_png(png, info, PNG_TRANSFORM_IDENTITY, NULL); png_write_end(png, NULL); cleanUp: if(png) { png_destroy_write_struct(&png, info ? &info : NULL); } if(rows) { for(int i = 0; i < height; i++) { free(rows[i]); } free(rows); } if(f) { a_file_close(f); } }
void a_png_write(const char* Path, const APixel* Data, int Width, int Height, char* Title, char* Description) { AFile* f = a_file_open(Path, "wb"); png_structp png = NULL; png_infop info = NULL; png_bytepp rows = NULL; png_text text[2]; int numText = 0; if(!f) { goto cleanUp; } rows = a_mem_malloc(Height * sizeof(png_bytep)); memset(rows, 0, Height * sizeof(png_bytep)); png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!png) { goto cleanUp; } info = png_create_info_struct(png); if(!info) { goto cleanUp; } if(setjmp(png_jmpbuf(png))) { goto cleanUp; } png_set_compression_level(png, Z_BEST_COMPRESSION); png_set_IHDR( png, info, Width, Height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); for(int i = 0; i < Height; i++) { rows[i] = a_mem_malloc(Width * 3 * sizeof(png_byte)); for(int j = 0; j < Width; j++) { const APixel p = *(Data + i * Width + j); rows[i][j * 3 + 0] = a_pixel_red(p); rows[i][j * 3 + 1] = a_pixel_green(p); rows[i][j * 3 + 2] = a_pixel_blue(p); } } if(Title != NULL) { text[numText].compression = PNG_TEXT_COMPRESSION_NONE; text[numText].key = "Title"; text[numText].text = Title; numText++; } if(Description != NULL) { text[numText].compression = PNG_TEXT_COMPRESSION_NONE; text[numText].key = "Description"; text[numText].text = Description; numText++; } png_init_io(png, a_file_handle(f)); png_set_rows(png, info, rows); png_set_text(png, info, text, numText); png_write_png(png, info, PNG_TRANSFORM_IDENTITY, NULL); png_write_end(png, NULL); cleanUp: if(png) { png_destroy_write_struct(&png, info ? &info : NULL); } if(rows) { for(int i = 0; i < Height; i++) { free(rows[i]); } free(rows); } if(f) { a_file_close(f); } }