]> git.cworth.org Git - apitrace/blob - image_png.cpp
Add glXDestroyContext because the warnings were getting irritating.
[apitrace] / image_png.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
4  * Copyright 2008-2010 VMware, Inc.
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  *
25  **************************************************************************/
26
27
28 #include <zlib.h>
29 #include <png.h>
30
31 #include <assert.h>
32 #include <stdint.h>
33 #include <stdlib.h>
34
35 #include <fstream>
36
37 #include "image.hpp"
38
39
40 namespace Image {
41
42
43 bool
44 Image::writePNG(const char *filename) const {
45     FILE *fp;
46     png_structp png_ptr;
47     png_infop info_ptr;
48
49     fp = fopen(filename, "wb");
50     if (!fp)
51         goto no_fp;
52
53     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
54     if (!png_ptr)
55         goto no_png;
56
57     info_ptr = png_create_info_struct(png_ptr);
58     if (!info_ptr) {
59         png_destroy_write_struct(&png_ptr,  NULL);
60         goto no_png;
61     }
62
63     if (setjmp(png_jmpbuf(png_ptr))) {
64         png_destroy_write_struct(&png_ptr, &info_ptr);
65         goto no_png;
66     }
67
68     png_init_io(png_ptr, fp);
69
70     int color_type;
71     switch (channels) {
72     case 4:
73         color_type = PNG_COLOR_TYPE_RGB_ALPHA;
74         break;
75     case 3:
76         color_type = PNG_COLOR_TYPE_RGB;
77         break;
78     case 2:
79         color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
80         break;
81     case 1:
82         color_type = PNG_COLOR_TYPE_GRAY;
83         break;
84     default:
85         assert(0);
86         return false;
87     }
88
89     png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type,
90         PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
91
92     png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
93
94     png_write_info(png_ptr, info_ptr);
95
96     if (!flipped) {
97         for (unsigned y = 0; y < height; ++y) {
98             png_bytep row = (png_bytep)(pixels + y*width*channels);
99             png_write_rows(png_ptr, &row, 1);
100         }
101     } else {
102         unsigned y = height;
103         while (y--) {
104             png_bytep row = (png_bytep)(pixels + y*width*channels);
105             png_write_rows(png_ptr, &row, 1);
106         }
107     }
108
109     png_write_end(png_ptr, info_ptr);
110     png_destroy_write_struct(&png_ptr, &info_ptr);
111
112     fclose(fp);
113     return true;
114
115 no_png:
116     fclose(fp);
117 no_fp:
118     return false;
119 }
120
121
122 Image *
123 readPNG(const char *filename)
124 {
125     FILE *fp;
126     png_structp png_ptr;
127     png_infop info_ptr;
128     png_infop end_info;
129     Image *image;
130
131     fp = fopen(filename, "rb");
132     if (!fp)
133         goto no_fp;
134
135     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
136     if (!png_ptr)
137         goto no_png;
138
139     info_ptr = png_create_info_struct(png_ptr);
140     if (!info_ptr) {
141         png_destroy_read_struct(&png_ptr, NULL, NULL);
142         goto no_png;
143     }
144
145     end_info = png_create_info_struct(png_ptr);
146     if (!end_info) {
147         png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
148         goto no_png;
149     }
150
151     if (setjmp(png_jmpbuf(png_ptr))) {
152         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
153         goto no_png;
154     }
155
156     png_init_io(png_ptr, fp);
157
158     png_read_info(png_ptr, info_ptr);
159
160     png_uint_32 width, height;
161     int bit_depth, color_type, interlace_type, compression_type, filter_method;
162
163     png_get_IHDR(png_ptr, info_ptr,
164                  &width, &height,
165                  &bit_depth, &color_type, &interlace_type,
166                  &compression_type, &filter_method);
167
168     image = new Image(width, height);
169     if (!image)
170         goto no_image;
171
172     /* Convert to RGBA8 */
173     if (color_type == PNG_COLOR_TYPE_PALETTE)
174         png_set_palette_to_rgb(png_ptr);
175     if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
176         png_set_expand_gray_1_2_4_to_8(png_ptr);
177     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
178         png_set_tRNS_to_alpha(png_ptr);
179     if (bit_depth == 16)
180         png_set_strip_16(png_ptr);
181
182     for (unsigned y = 0; y < height; ++y) {
183         png_bytep row = (png_bytep)(image->pixels + y*width*4);
184         png_read_row(png_ptr, row, NULL);
185     }
186
187     png_read_end(png_ptr, info_ptr);
188     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
189     fclose(fp);
190     return image;
191
192 no_image:
193     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
194 no_png:
195     fclose(fp);
196 no_fp:
197     return NULL;
198 }
199
200
201 struct png_tmp_buffer
202 {
203     char *buffer;
204     size_t size;
205 };
206
207 static void
208 pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length)
209 {
210     struct png_tmp_buffer *buf = (struct png_tmp_buffer*) png_get_io_ptr(png_ptr);
211     size_t nsize = buf->size + length;
212
213     /* allocate or grow buffer */
214     if (buf->buffer)
215         buf->buffer = (char*)realloc(buf->buffer, nsize);
216     else
217         buf->buffer = (char*)malloc(nsize);
218
219     if (!buf->buffer)
220         png_error(png_ptr, "Buffer allocation error");
221
222     memcpy(buf->buffer + buf->size, data, length);
223     buf->size += length;
224 }
225
226 bool writePixelsToBuffer(unsigned char *pixels,
227                          unsigned width, unsigned height, unsigned numChannels,
228                          bool flipped,
229                          char **buffer,
230                          int *size)
231 {
232     struct png_tmp_buffer png_mem;
233     png_structp png_ptr;
234     png_infop info_ptr;
235     int type;
236
237     png_mem.buffer = NULL;
238     png_mem.size = 0;
239
240     switch (numChannels) {
241     case 4:
242         type = PNG_COLOR_TYPE_RGB_ALPHA;
243         break;
244     case 3:
245         type = PNG_COLOR_TYPE_RGB;
246         break;
247     case 2:
248         type = PNG_COLOR_TYPE_GRAY_ALPHA;
249         break;
250     case 1:
251         type = PNG_COLOR_TYPE_GRAY;
252         break;
253     default:
254         goto no_png;
255     }
256
257     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
258     if (!png_ptr)
259         goto no_png;
260
261     info_ptr = png_create_info_struct(png_ptr);
262     if (!info_ptr) {
263         png_destroy_write_struct(&png_ptr,  NULL);
264         goto no_png;
265     }
266
267     if (setjmp(png_jmpbuf(png_ptr))) {
268         png_destroy_write_struct(&png_ptr, &info_ptr);
269         goto no_png;
270     }
271
272     png_set_write_fn(png_ptr, &png_mem, pngWriteCallback, NULL);
273
274     png_set_IHDR(png_ptr, info_ptr, width, height, 8,
275                  type, PNG_INTERLACE_NONE,
276                  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
277
278     png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
279
280     png_write_info(png_ptr, info_ptr);
281
282     if (!flipped) {
283         for (unsigned y = 0; y < height; ++y) {
284             png_bytep row = (png_bytep)(pixels + y*width*numChannels);
285             png_write_rows(png_ptr, &row, 1);
286         }
287     } else {
288         unsigned y = height;
289         while (y--) {
290             png_bytep row = (png_bytep)(pixels + y*width*numChannels);
291             png_write_rows(png_ptr, &row, 1);
292         }
293     }
294
295     png_write_end(png_ptr, info_ptr);
296     png_destroy_write_struct(&png_ptr, &info_ptr);
297
298     *buffer = png_mem.buffer;
299     *size = png_mem.size;
300
301     return true;
302
303 no_png:
304     *buffer = NULL;
305     *size = 0;
306
307     if (png_mem.buffer)
308         free(png_mem.buffer);
309     return false;
310 }
311
312 } /* namespace Image */