all repos — mgba @ 2b3631dc91ec424429d4dc3259c8b8f81575bf09

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 PNGReadPixels(png_structp png, png_infop info, void* pixels, unsigned width, unsigned height, unsigned stride) {
139	if (setjmp(png_jmpbuf(png))) {
140		return false;
141	}
142
143	uint8_t* pixelData = pixels;
144	unsigned pngHeight = png_get_image_height(png, info);
145	if (height > pngHeight) {
146		height = pngHeight;
147	}
148
149	unsigned pngWidth = png_get_image_width(png, info);
150	if (width > pngWidth) {
151		width = pngWidth;
152	}
153
154	unsigned i;
155	png_bytep row = malloc(png_get_rowbytes(png, info));
156	for (i = 0; i < height; ++i) {
157		png_read_row(png, row, 0);
158		unsigned x;
159		for (x = 0; x < width; ++x) {
160			pixelData[stride * i * 4 + x * 4] = row[x * 3];
161			pixelData[stride * i * 4 + x * 4 + 1] = row[x * 3 + 1];
162			pixelData[stride * i * 4 + x * 4 + 2] = row[x * 3 + 2];
163		}
164	}
165	free(row);
166	return true;
167}
168
169bool PNGReadFooter(png_structp png, png_infop end) {
170	if (setjmp(png_jmpbuf(png))) {
171		return false;
172	}
173	png_read_end(png, end);
174	return true;
175}
176
177void PNGReadClose(png_structp png, png_infop info, png_infop end) {
178	png_destroy_read_struct(&png, &info, &end);
179}