]> git.cworth.org Git - apitrace/blob - image/image_png.cpp
image: Move helpers to respective modules.
[apitrace] / image / 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 static void
47 pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length)
48 {
49     std::ostream *os = (std::ostream *) png_get_io_ptr(png_ptr);
50     os->write((const char *)data, length);
51 }
52
53 bool
54 Image::writePNG(std::ostream &os) const
55 {
56     png_structp png_ptr;
57     png_infop info_ptr;
58     int color_type;
59
60     switch (channels) {
61     case 4:
62         color_type = PNG_COLOR_TYPE_RGB_ALPHA;
63         break;
64     case 3:
65         color_type = PNG_COLOR_TYPE_RGB;
66         break;
67     case 2:
68         color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
69         break;
70     case 1:
71         color_type = PNG_COLOR_TYPE_GRAY;
72         break;
73     default:
74         assert(0);
75         goto no_png;
76     }
77
78     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
79     if (!png_ptr)
80         goto no_png;
81
82     info_ptr = png_create_info_struct(png_ptr);
83     if (!info_ptr) {
84         png_destroy_write_struct(&png_ptr,  NULL);
85         goto no_png;
86     }
87
88     if (setjmp(png_jmpbuf(png_ptr))) {
89         png_destroy_write_struct(&png_ptr, &info_ptr);
90         goto no_png;
91     }
92
93     png_set_write_fn(png_ptr, &os, pngWriteCallback, NULL);
94
95     png_set_IHDR(png_ptr, info_ptr, width, height, 8,
96                  color_type, PNG_INTERLACE_NONE,
97                  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
98
99     png_set_compression_level(png_ptr, png_compression_level);
100
101     png_write_info(png_ptr, info_ptr);
102
103     if (!flipped) {
104         for (unsigned y = 0; y < height; ++y) {
105             png_bytep row = (png_bytep)(pixels + y*width*channels);
106             png_write_rows(png_ptr, &row, 1);
107         }
108     } else {
109         unsigned y = height;
110         while (y--) {
111             png_bytep row = (png_bytep)(pixels + y*width*channels);
112             png_write_rows(png_ptr, &row, 1);
113         }
114     }
115
116     png_write_end(png_ptr, info_ptr);
117     png_destroy_write_struct(&png_ptr, &info_ptr);
118
119     return true;
120
121 no_png:
122     return false;
123 }
124
125
126 bool
127 Image::writePNG(const char *filename) const
128 {
129     std::ofstream os(filename, std::ofstream::binary);
130     if (!os) {
131         return false;
132     }
133     return writePNG(os);
134 }
135
136
137 Image *
138 readPNG(const char *filename)
139 {
140     FILE *fp;
141     png_structp png_ptr;
142     png_infop info_ptr;
143     png_infop end_info;
144     unsigned channels;
145     Image *image;
146
147     fp = fopen(filename, "rb");
148     if (!fp)
149         goto no_fp;
150
151     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
152     if (!png_ptr)
153         goto no_png;
154
155     info_ptr = png_create_info_struct(png_ptr);
156     if (!info_ptr) {
157         png_destroy_read_struct(&png_ptr, NULL, NULL);
158         goto no_png;
159     }
160
161     end_info = png_create_info_struct(png_ptr);
162     if (!end_info) {
163         png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
164         goto no_png;
165     }
166
167     if (setjmp(png_jmpbuf(png_ptr))) {
168         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
169         goto no_png;
170     }
171
172     png_init_io(png_ptr, fp);
173
174     png_read_info(png_ptr, info_ptr);
175
176     png_uint_32 width, height;
177     int bit_depth, color_type, interlace_type, compression_type, filter_method;
178
179     png_get_IHDR(png_ptr, info_ptr,
180                  &width, &height,
181                  &bit_depth, &color_type, &interlace_type,
182                  &compression_type, &filter_method);
183
184     /* Convert to RGBA8 */
185     if (color_type == PNG_COLOR_TYPE_PALETTE)
186         png_set_palette_to_rgb(png_ptr);
187     if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
188         png_set_expand_gray_1_2_4_to_8(png_ptr);
189     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
190         png_set_tRNS_to_alpha(png_ptr);
191     if (bit_depth == 16)
192         png_set_strip_16(png_ptr);
193
194     channels = png_get_channels(png_ptr, info_ptr);
195     image = new Image(width, height, channels);
196     if (!image)
197         goto no_image;
198
199     assert(png_get_rowbytes(png_ptr, info_ptr) == width*channels);
200     for (unsigned y = 0; y < height; ++y) {
201         png_bytep row = (png_bytep)(image->pixels + y*width*channels);
202         png_read_row(png_ptr, row, NULL);
203     }
204
205     png_read_end(png_ptr, info_ptr);
206     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
207     fclose(fp);
208     return image;
209
210 no_image:
211     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
212 no_png:
213     fclose(fp);
214 no_fp:
215     return NULL;
216 }
217
218
219
220 } /* namespace image */