all repos — mgba @ c035d97286707f6f5de10789e1dd8a7ca3e5f8e5

mGBA Game Boy Advance Emulator

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

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