]> git.cworth.org Git - apitrace/blob - image.cpp
Use the process ID as process name when /proc/self/exe can't be read.
[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 <zlib.h>
28 #include <png.h>
29
30 #include <math.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33
34 #include <fstream>
35
36 #include "image.hpp"
37
38
39 namespace Image {
40
41
42 #pragma pack(push,2)
43 struct FileHeader {
44     uint16_t bfType;
45     uint32_t bfSize;
46     uint16_t bfReserved1;
47     uint16_t bfReserved2;
48     uint32_t bfOffBits;
49 };
50 #pragma pack(pop)
51
52 struct InfoHeader {
53     uint32_t biSize;
54     int32_t biWidth;
55     int32_t biHeight;
56     uint16_t biPlanes;
57     uint16_t biBitCount;
58     uint32_t biCompression;
59     uint32_t biSizeImage;
60     int32_t biXPelsPerMeter;
61     int32_t biYPelsPerMeter;
62     uint32_t biClrUsed;
63     uint32_t biClrImportant;
64 };
65
66 struct Pixel {
67     uint8_t rgbBlue;
68     uint8_t rgbGreen;
69     uint8_t rgbRed;
70     uint8_t rgbAlpha;
71 };
72
73
74 bool
75 Image::writeBMP(const char *filename) const {
76     struct FileHeader bmfh;
77     struct InfoHeader bmih;
78     unsigned x, y;
79
80     bmfh.bfType = 0x4d42;
81     bmfh.bfSize = 14 + 40 + height*width*4;
82     bmfh.bfReserved1 = 0;
83     bmfh.bfReserved2 = 0;
84     bmfh.bfOffBits = 14 + 40;
85
86     bmih.biSize = 40;
87     bmih.biWidth = width;
88     bmih.biHeight = height;
89     bmih.biPlanes = 1;
90     bmih.biBitCount = 32;
91     bmih.biCompression = 0;
92     bmih.biSizeImage = height*width*4;
93     bmih.biXPelsPerMeter = 0;
94     bmih.biYPelsPerMeter = 0;
95     bmih.biClrUsed = 0;
96     bmih.biClrImportant = 0;
97
98     std::ofstream stream(filename, std::ofstream::binary);
99
100     if (!stream)
101         return false;
102
103     stream.write((const char *)&bmfh, 14);
104     stream.write((const char *)&bmih, 40);
105
106     unsigned stride = width*4;
107
108     if (flipped) {
109         for (y = 0; y < height; ++y) {
110             const unsigned char *ptr = pixels + y * stride;
111             for (x = 0; x < width; ++x) {
112                 struct Pixel pixel;
113                 pixel.rgbRed   = ptr[x*4 + 0];
114                 pixel.rgbGreen = ptr[x*4 + 1];
115                 pixel.rgbBlue  = ptr[x*4 + 2];
116                 pixel.rgbAlpha = ptr[x*4 + 3];
117                 stream.write((const char *)&pixel, 4);
118             }
119         }
120     } else {
121         y = height;
122         while (y--) {
123             const unsigned char *ptr = pixels + y * stride;
124             for (x = 0; x < width; ++x) {
125                 struct Pixel pixel;
126                 pixel.rgbRed   = ptr[x*4 + 0];
127                 pixel.rgbGreen = ptr[x*4 + 1];
128                 pixel.rgbBlue  = ptr[x*4 + 2];
129                 pixel.rgbAlpha = ptr[x*4 + 3];
130                 stream.write((const char *)&pixel, 4);
131             }
132         }
133     }
134
135     stream.close();
136
137     return true;
138 }
139
140 bool
141 Image::writePNG(const char *filename) const {
142     FILE *fp;
143     png_structp png_ptr;
144     png_infop info_ptr;
145
146     fp = fopen(filename, "wb");
147     if (!fp)
148         goto no_fp;
149
150     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
151     if (!png_ptr)
152         goto no_png;
153
154     info_ptr = png_create_info_struct(png_ptr);
155     if (!info_ptr) {
156         png_destroy_write_struct(&png_ptr,  NULL);
157         goto no_png;
158     }
159
160     if (setjmp(png_jmpbuf(png_ptr))) {
161         png_destroy_write_struct(&png_ptr, &info_ptr);
162         goto no_png;
163     }
164
165     png_init_io(png_ptr, fp);
166
167     png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA,
168         PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
169
170     png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
171
172     png_write_info(png_ptr, info_ptr);
173
174     if (!flipped) {
175         for (unsigned y = 0; y < height; ++y) {
176             png_bytep row = (png_bytep)(pixels + y*width*4);
177             png_write_rows(png_ptr, &row, 1);
178         }
179     } else {
180         unsigned y = height;
181         while (y--) {
182             png_bytep row = (png_bytep)(pixels + y*width*4);
183             png_write_rows(png_ptr, &row, 1);
184         }
185     }
186
187     png_write_end(png_ptr, info_ptr);
188     png_destroy_write_struct(&png_ptr, &info_ptr);
189
190     fclose(fp);
191     return true;
192
193 no_png:
194     fclose(fp);
195 no_fp:
196     return false;
197 }
198
199
200 Image *
201 readPNG(const char *filename)
202 {
203     FILE *fp;
204     png_structp png_ptr;
205     png_infop info_ptr;
206     png_infop end_info;
207     Image *image;
208
209     fp = fopen(filename, "rb");
210     if (!fp)
211         goto no_fp;
212
213     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
214     if (!png_ptr)
215         goto no_png;
216
217     info_ptr = png_create_info_struct(png_ptr);
218     if (!info_ptr) {
219         png_destroy_read_struct(&png_ptr, NULL, NULL);
220         goto no_png;
221     }
222
223     end_info = png_create_info_struct(png_ptr);
224     if (!end_info) {
225         png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
226         goto no_png;
227     }
228
229     if (setjmp(png_jmpbuf(png_ptr))) {
230         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
231         goto no_png;
232     }
233
234     png_init_io(png_ptr, fp);
235
236     png_read_info(png_ptr, info_ptr);
237
238     png_uint_32 width, height;
239     int bit_depth, color_type, interlace_type, compression_type, filter_method;
240
241     png_get_IHDR(png_ptr, info_ptr,
242                  &width, &height,
243                  &bit_depth, &color_type, &interlace_type,
244                  &compression_type, &filter_method);
245
246     image = new Image(width, height);
247     if (!image)
248         goto no_image;
249
250     /* Convert to RGBA8 */
251     if (color_type == PNG_COLOR_TYPE_PALETTE)
252         png_set_palette_to_rgb(png_ptr);
253     if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
254         png_set_expand_gray_1_2_4_to_8(png_ptr);
255     if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
256         png_set_tRNS_to_alpha(png_ptr);
257     if (bit_depth == 16)
258         png_set_strip_16(png_ptr);
259
260     for (unsigned y = 0; y < height; ++y) {
261         png_bytep row = (png_bytep)(image->pixels + y*width*4);
262         png_read_row(png_ptr, row, NULL);
263     }
264
265     png_read_end(png_ptr, info_ptr);
266     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
267     fclose(fp);
268     return image;
269
270 no_image:
271     png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
272 no_png:
273     fclose(fp);
274 no_fp:
275     return NULL;
276 }
277
278
279 double Image::compare(Image &ref)
280 {
281     if (width != ref.width ||
282         height != ref.height) {
283         return 0.0;
284     }
285
286     const unsigned char *pSrc = start();
287     const unsigned char *pRef = ref.start();
288
289     unsigned long long error = 0;
290     for (unsigned y = 0; y < height; ++y) {
291         for (unsigned  x = 0; x < width; ++x) {
292             // FIXME: Ignore alpha channel until we are able to pick a visual
293             // that matches the traces
294             for (unsigned  c = 0; c < 3; ++c) {
295                 int delta = pSrc[x*4 + c] - pRef[x*4 + c];
296                 error += delta*delta;
297             }
298         }
299
300         pSrc += stride();
301         pRef += ref.stride();
302     }
303
304     double numerator = error*2 + 1;
305     double denominator = height*width*3ULL*255ULL*255ULL*2;
306     double quotient = numerator/denominator;
307
308     // Precision in bits
309     double precision = -log(quotient)/log(2.0);
310
311     return precision;
312 }
313
314 struct png_tmp_buffer
315 {
316     char *buffer;
317     size_t size;
318 };
319
320 static void
321 pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length)
322 {
323     struct png_tmp_buffer *buf = (struct png_tmp_buffer*) png_get_io_ptr(png_ptr);
324     size_t nsize = buf->size + length;
325
326     /* allocate or grow buffer */
327     if (buf->buffer)
328         buf->buffer = (char*)realloc(buf->buffer, nsize);
329     else
330         buf->buffer = (char*)malloc(nsize);
331
332     if (!buf->buffer)
333         png_error(png_ptr, "Buffer allocation error");
334
335     memcpy(buf->buffer + buf->size, data, length);
336     buf->size += length;
337 }
338
339 bool writePixelsToBuffer(unsigned char *pixels,
340                          unsigned width, unsigned height, unsigned numChannels,
341                          bool flipped,
342                          char **buffer,
343                          int *size)
344 {
345     struct png_tmp_buffer png_mem;
346     png_structp png_ptr;
347     png_infop info_ptr;
348     int type;
349
350     png_mem.buffer = NULL;
351     png_mem.size = 0;
352
353     switch (numChannels) {
354     case 4:
355         type = PNG_COLOR_TYPE_RGB_ALPHA;
356         break;
357     case 3:
358         type = PNG_COLOR_TYPE_RGB;
359         break;
360     case 2:
361         type = PNG_COLOR_TYPE_GRAY_ALPHA;
362         break;
363     case 1:
364         type = PNG_COLOR_TYPE_GRAY;
365         break;
366     default:
367         goto no_png;
368     }
369
370     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
371     if (!png_ptr)
372         goto no_png;
373
374     info_ptr = png_create_info_struct(png_ptr);
375     if (!info_ptr) {
376         png_destroy_write_struct(&png_ptr,  NULL);
377         goto no_png;
378     }
379
380     if (setjmp(png_jmpbuf(png_ptr))) {
381         png_destroy_write_struct(&png_ptr, &info_ptr);
382         goto no_png;
383     }
384
385     png_set_write_fn(png_ptr, &png_mem, pngWriteCallback, NULL);
386
387     png_set_IHDR(png_ptr, info_ptr, width, height, 8,
388                  type, PNG_INTERLACE_NONE,
389                  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
390
391     png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
392
393     png_write_info(png_ptr, info_ptr);
394
395     if (!flipped) {
396         for (unsigned y = 0; y < height; ++y) {
397             png_bytep row = (png_bytep)(pixels + y*width*numChannels);
398             png_write_rows(png_ptr, &row, 1);
399         }
400     } else {
401         unsigned y = height;
402         while (y--) {
403             png_bytep row = (png_bytep)(pixels + y*width*numChannels);
404             png_write_rows(png_ptr, &row, 1);
405         }
406     }
407
408     png_write_end(png_ptr, info_ptr);
409     png_destroy_write_struct(&png_ptr, &info_ptr);
410
411     *buffer = png_mem.buffer;
412     *size = png_mem.size;
413
414     return true;
415
416 no_png:
417     *buffer = NULL;
418     *size = 0;
419
420     if (png_mem.buffer)
421         free(png_mem.buffer);
422     return false;
423 }
424
425 } /* namespace Image */