]> git.cworth.org Git - apitrace/blob - image/image_pnm.cpp
Use skiplist-based FastCallSet within trace::CallSet
[apitrace] / image / image_pnm.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 <assert.h>
29 #include <string.h>
30 #include <stdint.h>
31 #include <stdio.h>
32
33 #include "image.hpp"
34
35
36 namespace image {
37
38 /**
39  * http://en.wikipedia.org/wiki/Netpbm_format
40  * http://netpbm.sourceforge.net/doc/ppm.html
41  */
42 void
43 Image::writePNM(std::ostream &os, const char *comment) const {
44     assert(channels == 1 || channels >= 3);
45
46     os << (channels == 1 ? "P5" : "P6") << "\n";
47     if (comment) {
48         os << "#" << comment << "\n";
49     }
50     os << width << " " << height << "\n";
51     os << "255" << "\n";
52
53     const unsigned char *row;
54
55     if (channels == 1 || channels == 3) {
56         for (row = start(); row != end(); row += stride()) {
57             os.write((const char *)row, width*channels);
58         }
59     } else {
60         unsigned char *tmp = new unsigned char[width*3];
61         if (channels == 4) {
62             for (row = start(); row != end(); row += stride()) {
63                 const uint32_t *src = (const uint32_t *)row;
64                 uint32_t *dst = (uint32_t *)tmp;
65                 unsigned x;
66                 for (x = 0; x + 4 <= width; x += 4) {
67                     /*
68                      * It's much faster to access dwords than bytes.
69                      *
70                      * FIXME: Big-endian version.
71                      */
72
73                     uint32_t rgba0 = *src++ & 0xffffff;
74                     uint32_t rgba1 = *src++ & 0xffffff;
75                     uint32_t rgba2 = *src++ & 0xffffff;
76                     uint32_t rgba3 = *src++ & 0xffffff;
77                     uint32_t rgb0 = rgba0
78                                   | (rgba1 << 24);
79                     uint32_t rgb1 = (rgba1 >> 8)
80                                   | (rgba2 << 16);
81                     uint32_t rgb2 = (rgba2 >> 16)
82                                   | (rgba3 << 8);
83                     *dst++ = rgb0;
84                     *dst++ = rgb1;
85                     *dst++ = rgb2;
86                 }
87                 for (; x < width; ++x) {
88                     tmp[x*3 + 0] = row[x*4 + 0];
89                     tmp[x*3 + 1] = row[x*4 + 1];
90                     tmp[x*3 + 2] = row[x*4 + 2];
91                 }
92                 os.write((const char *)tmp, width*3);
93             }
94         } else if (channels == 2) {
95             for (row = start(); row != end(); row += stride()) {
96                 const unsigned char *src = row;
97                 unsigned char *dst = tmp;
98                 for (unsigned x = 0; x < width; ++x) {
99                     *dst++ = *src++;
100                     *dst++ = *src++;
101                     *dst++ = 0;
102                 }
103                 os.write((const char *)tmp, width*3);
104             }
105         } else {
106             assert(0);
107         }
108         delete [] tmp;
109     }
110 }
111
112 const char *
113 readPNMHeader(const char *buffer, size_t bufferSize, unsigned *channels, unsigned *width, unsigned *height)
114 {
115     *channels = 0;
116     *width = 0;
117     *height = 0;
118
119     const char *currentBuffer = buffer;
120     const char *nextBuffer;
121
122     // parse number of channels
123     int scannedChannels = sscanf(currentBuffer, "P%d\n", channels);
124     if (scannedChannels != 1) { // validate scanning of channels
125         // invalid channel line
126         return buffer;
127     }
128     // convert channel token to number of channels
129     *channels = (*channels == 5) ? 1 : 3;
130
131     // advance past channel line
132     nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1;
133     bufferSize -= nextBuffer - currentBuffer;
134     currentBuffer = nextBuffer;
135
136     // skip over optional comment
137     if (*currentBuffer == '#') {
138         // advance past comment line
139         nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1;
140         bufferSize -= nextBuffer - currentBuffer;
141         currentBuffer = nextBuffer;
142     }
143
144     // parse dimensions of image
145     int scannedDimensions = sscanf(currentBuffer, "%d %d\n", width, height);
146     if (scannedDimensions != 2) { // validate scanning of dimensions
147         // invalid dimension line
148         return buffer;
149     }
150
151     // advance past dimension line
152     nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1;
153     bufferSize -= nextBuffer - currentBuffer;
154     currentBuffer = nextBuffer;
155
156     // skip over "255\n" at end of header
157     nextBuffer = (const char *) memchr((const void *) currentBuffer, '\n', bufferSize) + 1;
158
159     // return start of image data
160     return nextBuffer;
161 }
162
163 } /* namespace image */