]> git.cworth.org Git - apitrace/blob - common/image_png.cpp
glstate: Use stringstream for holding the temporary PNG images.
[apitrace] / common / 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 static const int png_compression_level = Z_BEST_SPEED;
44
45
46 bool
47 Image::writePNG(const char *filename) const {
48     FILE *fp;
49     png_structp png_ptr;
50     png_infop info_ptr;
51
52     fp = fopen(filename, "wb");
53     if (!fp)
54         goto no_fp;
55
56     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
57     if (!png_ptr)
58         goto no_png;
59
60     info_ptr = png_create_info_struct(png_ptr);
61     if (!info_ptr) {
62         png_destroy_write_struct(&png_ptr,  NULL);
63         goto no_png;
64     }
65
66     if (setjmp(png_jmpbuf(png_ptr))) {
67         png_destroy_write_struct(&png_ptr, &info_ptr);
68         goto no_png;
69     }
70
71     png_init_io(png_ptr, fp);
72
73     int color_type;
74     switch (channels) {
75     case 4:
76         color_type = PNG_COLOR_TYPE_RGB_ALPHA;
77         break;
78     case 3:
79         color_type = PNG_COLOR_TYPE_RGB;
80         break;
81     case 2:
82         color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
83         break;
84     case 1:
85         color_type = PNG_COLOR_TYPE_GRAY;
86         break;
87     default:
88         assert(0);
89         return false;
90     }
91
92     png_set_IHDR(png_ptr, info_ptr, width, height, 8, color_type,
93         PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
94
95     png_set_compression_level(png_ptr, png_compression_level);
96
97     png_write_info(png_ptr, info_ptr);
98
99     if (!flipped) {
100         for (unsigned y = 0; y < height; ++y) {
101             png_bytep row = (png_bytep)(pixels + y*width*channels);
102             png_write_rows(png_ptr, &row, 1);
103         }
104     } else {
105         unsigned y = height;
106         while (y--) {
107             png_bytep row = (png_bytep)(pixels + y*width*channels);
108             png_write_rows(png_ptr, &row, 1);
109         }
110     }
111
112     png_write_end(png_ptr, info_ptr);
113     png_destroy_write_struct(&png_ptr, &info_ptr);
114
115     fclose(fp);
116     return true;
117
118 no_png:
119     fclose(fp);
120 no_fp:
121     return false;
122 }
123
124
125 Image *
126 readPNG(const char *filename)
127 {
128     FILE *fp;
129     png_structp png_ptr;
130     png_infop info_ptr;
131     png_infop end_info;
132     Image *image;
133
134     fp = fopen(filename, "rb");
135     if (!fp)
136         goto no_fp;
137
138     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
139     if (!png_ptr)
140         goto no_png;
141
142     info_ptr = png_create_info_struct(png_ptr);
143     if (!info_ptr) {
144         png_destroy_read_struct(&png_ptr, NULL, NULL);
145         goto no_png;
146     }
147
148     end_info = png_create_info_struct(png_ptr);
149     if (!end_info) {
150         png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
151         goto no_png;
152     }
153
154     if (setjmp(png_jmpbuf(png_ptr))) {
155         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
156         goto no_png;
157     }
158
159     png_init_io(png_ptr, fp);
160
161     png_read_info(png_ptr, info_ptr);
162
163     png_uint_32 width, height;
164     int bit_depth, color_type, interlace_type, compression_type, filter_method;
165
166     png_get_IHDR(png_ptr, info_ptr,
167                  &width, &height,
168                  &bit_depth, &color_type, &interlace_type,
169                  &compression_type, &filter_method);
170
171     image = new Image(width, height);
172     if (!image)
173         goto no_image;
174
175     /* Convert to RGBA8 */
176     if (color_type == PNG_COLOR_TYPE_PALETTE)
177         png_set_palette_to_rgb(png_ptr);
178     if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
179         png_set_expand_gray_1_2_4_to_8(png_ptr);
180     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
181         png_set_tRNS_to_alpha(png_ptr);
182     if (bit_depth == 16)
183         png_set_strip_16(png_ptr);
184
185     for (unsigned y = 0; y < height; ++y) {
186         png_bytep row = (png_bytep)(image->pixels + y*width*4);
187         png_read_row(png_ptr, row, NULL);
188     }
189
190     png_read_end(png_ptr, info_ptr);
191     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
192     fclose(fp);
193     return image;
194
195 no_image:
196     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
197 no_png:
198     fclose(fp);
199 no_fp:
200     return NULL;
201 }
202
203
204 static void
205 pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length)
206 {
207     std::ostream *os = (std::ostream *) png_get_io_ptr(png_ptr);
208     os->write((const char *)data, length);
209 }
210
211 bool
212 writePixelsToBuffer(std::ostream &os,
213                     unsigned char *pixels,
214                     unsigned width, unsigned height, unsigned numChannels,
215                     bool flipped)
216 {
217     png_structp png_ptr;
218     png_infop info_ptr;
219     int type;
220
221     switch (numChannels) {
222     case 4:
223         type = PNG_COLOR_TYPE_RGB_ALPHA;
224         break;
225     case 3:
226         type = PNG_COLOR_TYPE_RGB;
227         break;
228     case 2:
229         type = PNG_COLOR_TYPE_GRAY_ALPHA;
230         break;
231     case 1:
232         type = PNG_COLOR_TYPE_GRAY;
233         break;
234     default:
235         goto no_png;
236     }
237
238     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
239     if (!png_ptr)
240         goto no_png;
241
242     info_ptr = png_create_info_struct(png_ptr);
243     if (!info_ptr) {
244         png_destroy_write_struct(&png_ptr,  NULL);
245         goto no_png;
246     }
247
248     if (setjmp(png_jmpbuf(png_ptr))) {
249         png_destroy_write_struct(&png_ptr, &info_ptr);
250         goto no_png;
251     }
252
253     png_set_write_fn(png_ptr, &os, pngWriteCallback, NULL);
254
255     png_set_IHDR(png_ptr, info_ptr, width, height, 8,
256                  type, PNG_INTERLACE_NONE,
257                  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
258
259     png_set_compression_level(png_ptr, png_compression_level);
260
261     png_write_info(png_ptr, info_ptr);
262
263     if (!flipped) {
264         for (unsigned y = 0; y < height; ++y) {
265             png_bytep row = (png_bytep)(pixels + y*width*numChannels);
266             png_write_rows(png_ptr, &row, 1);
267         }
268     } else {
269         unsigned y = height;
270         while (y--) {
271             png_bytep row = (png_bytep)(pixels + y*width*numChannels);
272             png_write_rows(png_ptr, &row, 1);
273         }
274     }
275
276     png_write_end(png_ptr, info_ptr);
277     png_destroy_write_struct(&png_ptr, &info_ptr);
278
279     return true;
280
281 no_png:
282     return false;
283 }
284
285 } /* namespace image */