all repos — mgba @ a872bd36421a63b70f6d428dc1886b73ceb607ec

mGBA Game Boy Advance Emulator

src/util/png-io.c (view raw)

  1#include "util/png-io.h"
  2
  3#include "vfs.h"
  4
  5static void _pngWrite(png_structp png, png_bytep buffer, png_size_t size) {
  6	struct VFile* vf = png_get_io_ptr(png);
  7	size_t written = vf->write(vf, buffer, size);
  8	if (written != size) {
  9		png_error(png, "Could not write PNG");
 10	}
 11}
 12
 13static void _pngRead(png_structp png, png_bytep buffer, png_size_t size) {
 14	struct VFile* vf = png_get_io_ptr(png);
 15	size_t read = vf->read(vf, buffer, size);
 16	if (read != size) {
 17		png_error(png, "Could not read PNG");
 18	}
 19}
 20
 21png_structp PNGWriteOpen(struct VFile* source) {
 22	png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
 23	if (!png) {
 24		return 0;
 25	}
 26	if (setjmp(png_jmpbuf(png))) {
 27		png_destroy_write_struct(&png, 0);
 28		return 0;
 29	}
 30	png_set_write_fn(png, source, _pngWrite, 0);
 31	return png;
 32}
 33
 34png_infop PNGWriteHeader(png_structp png, unsigned width, unsigned height) {
 35	png_infop info = png_create_info_struct(png);
 36	if (!info) {
 37		return 0;
 38	}
 39	png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
 40	png_write_info(png, info);
 41	return info;
 42}
 43
 44bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned stride, void* pixels) {
 45	png_bytep row = malloc(sizeof(png_bytep) * width * 3);
 46	if (!row) {
 47		return false;
 48	}
 49	png_bytep pixelData = pixels;
 50	if (setjmp(png_jmpbuf(png))) {
 51		free(row);
 52		return false;
 53	}
 54	unsigned i;
 55	for (i = 0; i < height; ++i) {
 56		unsigned x;
 57		for (x = 0; x < width; ++x) {
 58			row[x * 3] = pixelData[stride * i * 4 + x * 4];
 59			row[x * 3 + 1] = pixelData[stride * i * 4 + x * 4 + 1];
 60			row[x * 3 + 2] = pixelData[stride * i * 4 + x * 4 + 2];
 61		}
 62		png_write_row(png, row);
 63	}
 64	free(row);
 65	return true;
 66}
 67
 68bool PNGWriteCustomChunk(png_structp png, const char* name, size_t size, void* data) {
 69	char realName[5];
 70	strncpy(realName, name, 4);
 71	realName[0] = tolower(realName[0]);
 72	realName[1] = tolower(realName[1]);
 73	realName[4] = '\0';
 74	if (setjmp(png_jmpbuf(png))) {
 75		return false;
 76	}
 77	png_write_chunk(png, (png_const_bytep) realName, data, size);
 78	return true;
 79}
 80
 81void PNGWriteClose(png_structp png, png_infop info) {
 82	if (!setjmp(png_jmpbuf(png))) {
 83		png_write_end(png, info);
 84	}
 85	png_destroy_write_struct(&png, &info);
 86}
 87
 88bool isPNG(struct VFile* source) {
 89	png_byte header[PNG_HEADER_BYTES];
 90	source->read(source, header, PNG_HEADER_BYTES);
 91	return !png_sig_cmp(header, 0, PNG_HEADER_BYTES);
 92}
 93
 94png_structp PNGReadOpen(struct VFile* source, unsigned offset) {
 95	png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
 96	if (!png) {
 97		return 0;
 98	}
 99	if (setjmp(png_jmpbuf(png))) {
100		png_destroy_read_struct(&png, 0, 0);
101		return 0;
102	}
103	png_set_read_fn(png, source, _pngRead);
104	png_set_sig_bytes(png, offset);
105	return png;
106}
107
108bool PNGInstallChunkHandler(png_structp png, void* context, ChunkHandler handler, const char* chunkName) {
109	if (setjmp(png_jmpbuf(png))) {
110		return false;
111	}
112	png_set_read_user_chunk_fn(png, context, handler);
113	png_set_keep_unknown_chunks(png, PNG_HANDLE_CHUNK_ALWAYS, (png_const_bytep) chunkName, 1);
114	return true;
115}
116
117bool PNGReadHeader(png_structp png, png_infop info) {
118	if (setjmp(png_jmpbuf(png))) {
119		return false;
120	}
121	png_read_info(png, info);
122	return true;
123}
124
125bool PNGIgnorePixels(png_structp png, png_infop info) {
126	if (setjmp(png_jmpbuf(png))) {
127		return false;
128	}
129
130	unsigned height = png_get_image_height(png, info);
131	unsigned i;
132	for (i = 0; i < height; ++i) {
133		png_read_row(png, 0, 0);
134	}
135	return true;
136}
137
138bool PNGReadFooter(png_structp png, png_infop end) {
139	if (setjmp(png_jmpbuf(png))) {
140		return false;
141	}
142	png_read_end(png, end);
143	return true;
144}
145
146void PNGReadClose(png_structp png, png_infop info, png_infop end) {
147	png_destroy_read_struct(&png, &info, &end);
148}