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