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