]> git.cworth.org Git - apitrace/blob - gui/apisurface.cpp
Rescale the image pixels using the full precision.
[apitrace] / gui / apisurface.cpp
1 #include "apisurface.h"
2 #include "thumbnail.h"
3
4 #include <sstream>
5
6 #include <QDebug>
7 #include <QSysInfo>
8
9 #include "image/image.hpp"
10
11
12 ApiSurface::ApiSurface()
13 {
14 }
15
16 QSize ApiSurface::size() const
17 {
18     return m_size;
19 }
20
21 void ApiSurface::setSize(const QSize &size)
22 {
23     m_size = size;
24 }
25
26 struct ByteArrayBuf : public std::streambuf
27 {
28     ByteArrayBuf(QByteArray & a)
29     {
30         setg(a.data(), a.data(), a.data() + a.size());
31     }
32 };
33
34 void ApiSurface::contentsFromBase64(const QByteArray &base64)
35 {
36     m_base64Data = base64;
37
38     /*
39      * We need to do the conversion to create the thumbnail
40      */
41     image::Image *image = imageFromBase64(base64);
42     Q_ASSERT(image);
43     QImage img = qimageFromRawImage(image);
44     m_thumb = thumbnail(img);
45     delete image;
46 }
47
48 QByteArray ApiSurface::base64Data() const
49 {
50     return m_base64Data;
51 }
52
53 QImage ApiSurface::thumb() const
54 {
55     return m_thumb;
56 }
57
58 int ApiSurface::depth() const
59 {
60     return m_depth;
61 }
62
63 void ApiSurface::setDepth(int depth)
64 {
65     m_depth = depth;
66 }
67
68 QString ApiSurface::formatName() const
69 {
70     return m_formatName;
71 }
72
73 void ApiSurface::setFormatName(const QString &str)
74 {
75     m_formatName = str;
76 }
77
78
79 ApiTexture::ApiTexture()
80     : ApiSurface()
81 {
82 }
83
84 QString ApiTexture::label() const
85 {
86     return m_label;
87 }
88
89 void ApiTexture::setLabel(const QString &str)
90 {
91     m_label = str;
92 }
93
94 ApiFramebuffer::ApiFramebuffer()
95     : ApiSurface()
96 {
97 }
98
99 QString ApiFramebuffer::type() const
100 {
101     return m_type;
102 }
103
104 void ApiFramebuffer::setType(const QString &str)
105 {
106     m_type = str;
107 }
108
109 image::Image *
110 ApiSurface::imageFromBase64(const QByteArray &base64)
111 {
112     QByteArray dataArray = QByteArray::fromBase64(base64);
113     image::Image *image;
114
115     /*
116      * Detect the PNG vs PFM images.
117      */
118     const char pngSignature[] = {(char)0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0};
119     if (dataArray.startsWith(pngSignature)) {
120         ByteArrayBuf buf(dataArray);
121         std::istream istr(&buf);
122         image = image::readPNG(istr);
123     } else {
124         image = image::readPNM(dataArray.data(), dataArray.size());
125     }
126
127     return image;
128 }
129
130
131 static inline unsigned char clamp(int x)
132 {
133     if (x <= 0) {
134         return 0;
135     }
136     if (x > 255) {
137         return 255;
138     }
139     return (unsigned char) x;
140 }
141
142 static inline unsigned char clamp(float x)
143 {
144     if (x <= 0.0f) {
145         return 0;
146     }
147     if (x > 255.0f) {
148         return 255;
149     }
150     return (unsigned char) (x + 0.5f);
151 }
152
153
154 QImage
155 ApiSurface::qimageFromRawImage(const image::Image *image,
156                                float lowerValue,
157                                float upperValue,
158                                bool opaque,
159                                bool alpha)
160 {
161     QImage img;
162     int width = image->width;
163     int height = image->height;
164
165     img = QImage(width, height, QImage::Format_ARGB32);
166
167     int offset = - lowerValue * 255;
168     int scale = 256 / (upperValue - lowerValue);
169
170     float offset_f = - lowerValue;
171     float scale_f = 255.0f / (upperValue - lowerValue);
172
173     int aMask = (opaque || alpha) ? 0xff : 0;
174
175     const unsigned char *srcRow = image->start();
176     for (int y = 0; y < height; ++y) {
177         QRgb *dst = (QRgb *)img.scanLine(y);
178
179         if (image->channelType == image::TYPE_UNORM8) {
180             const unsigned char *src = srcRow;
181             for (int x = 0; x < width; ++x) {
182                 unsigned char rgba[4] = {0, 0, 0, 0xff};
183                 for (int c = 0; c < image->channels; ++c) {
184                     rgba[c] = clamp(((*src++ + offset) * scale) >> 8);
185                 }
186                 if (image->channels == 1) {
187                     // Use gray-scale instead of red
188                     rgba[1] = rgba[0];
189                     rgba[2] = rgba[0];
190                 }
191                 if (alpha) {
192                     rgba[2] = rgba[1] = rgba[0] = rgba[3];
193                 }
194                 rgba[3] |= aMask;
195                 dst[x] = qRgba(rgba[0], rgba[1], rgba[2], rgba[3]);
196             }
197         } else {
198             const float *src = (const float *)srcRow;
199             for (int x = 0; x < width; ++x) {
200                 unsigned char rgba[4] = {0, 0, 0, 0xff};
201                 for (int c = 0; c < image->channels; ++c) {
202                     rgba[c] = clamp((*src++ + offset_f)*scale_f);
203                 }
204                 if (image->channels == 1) {
205                     // Use gray-scale instead of red
206                     rgba[1] = rgba[0];
207                     rgba[2] = rgba[0];
208                 }
209                 if (alpha) {
210                     rgba[2] = rgba[1] = rgba[0] = rgba[3];
211                 }
212                 rgba[3] |= aMask;
213                 dst[x] = qRgba(rgba[0], rgba[1], rgba[2], rgba[3]);
214             }
215         }
216
217         srcRow += image->stride();
218     }
219
220     return img;
221 }