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}