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