all repos — mgba @ c14da05d8dca225010677643c32fea5c0ac8517a

mGBA Game Boy Advance Emulator

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

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