blob: 4f0a917373cbd7773838afaf7bded33dff2ec45e [file] [log] [blame]
Zack Rusin952e9d42011-04-09 23:37:21 -04001#include "apisurface.h"
José Fonseca3f456402012-03-25 20:59:24 +01002#include "thumbnail.h"
Zack Rusin952e9d42011-04-09 23:37:21 -04003
José Fonseca52398312013-09-11 18:42:07 +01004#include <sstream>
5
Zack Rusin952e9d42011-04-09 23:37:21 -04006#include <QDebug>
7#include <QSysInfo>
8
José Fonseca52398312013-09-11 18:42:07 +01009#include "image/image.hpp"
10
11
Zack Rusin952e9d42011-04-09 23:37:21 -040012ApiSurface::ApiSurface()
13{
14}
15
16QSize ApiSurface::size() const
17{
18 return m_size;
19}
20
21void ApiSurface::setSize(const QSize &size)
22{
23 m_size = size;
24}
25
José Fonseca52398312013-09-11 18:42:07 +010026struct ByteArrayBuf : public std::streambuf
27{
Jose Fonsecac296a3e2015-05-01 17:43:54 +010028 ByteArrayBuf(const QByteArray & a)
José Fonseca52398312013-09-11 18:42:07 +010029 {
Jose Fonsecac296a3e2015-05-01 17:43:54 +010030 setg((char *)a.data(), (char *)a.data(), (char *)a.data() + a.size());
José Fonseca52398312013-09-11 18:42:07 +010031 }
32};
33
Jose Fonseca93a7c0c2015-05-27 20:52:51 +010034void ApiSurface::setData(const QByteArray &data)
Zack Rusin952e9d42011-04-09 23:37:21 -040035{
Jose Fonseca93a7c0c2015-05-27 20:52:51 +010036 m_data = data;
José Fonseca994535d2013-09-12 17:26:34 +010037
José Fonseca52398312013-09-11 18:42:07 +010038 /*
Zack Rusina69f0de2013-09-12 17:21:51 -040039 * We need to do the conversion to create the thumbnail
José Fonseca52398312013-09-11 18:42:07 +010040 */
Jose Fonseca93a7c0c2015-05-27 20:52:51 +010041 image::Image *image = imageFromData(data);
José Fonseca52398312013-09-11 18:42:07 +010042 Q_ASSERT(image);
Zack Rusina69f0de2013-09-12 17:21:51 -040043 QImage img = qimageFromRawImage(image);
44 m_thumb = thumbnail(img);
José Fonseca52398312013-09-11 18:42:07 +010045 delete image;
Zack Rusin952e9d42011-04-09 23:37:21 -040046}
47
Jose Fonseca93a7c0c2015-05-27 20:52:51 +010048QByteArray ApiSurface::data() const
Zack Rusin952e9d42011-04-09 23:37:21 -040049{
Jose Fonseca93a7c0c2015-05-27 20:52:51 +010050 return m_data;
Zack Rusin952e9d42011-04-09 23:37:21 -040051}
52
53QImage ApiSurface::thumb() const
54{
55 return m_thumb;
56}
57
Zack Rusinb25c4b92011-11-16 22:43:34 -050058int ApiSurface::depth() const
59{
60 return m_depth;
61}
62
63void ApiSurface::setDepth(int depth)
64{
65 m_depth = depth;
66}
67
Zack Rusine181b992011-11-17 16:00:41 -050068QString ApiSurface::formatName() const
69{
70 return m_formatName;
71}
72
73void ApiSurface::setFormatName(const QString &str)
74{
75 m_formatName = str;
76}
77
78
Zack Rusin952e9d42011-04-09 23:37:21 -040079ApiTexture::ApiTexture()
José Fonseca18081d52011-05-07 00:10:25 +010080 : ApiSurface()
Zack Rusin952e9d42011-04-09 23:37:21 -040081{
82}
83
José Fonseca18081d52011-05-07 00:10:25 +010084QString ApiTexture::label() const
Zack Rusin952e9d42011-04-09 23:37:21 -040085{
José Fonseca18081d52011-05-07 00:10:25 +010086 return m_label;
Zack Rusin952e9d42011-04-09 23:37:21 -040087}
88
José Fonseca18081d52011-05-07 00:10:25 +010089void ApiTexture::setLabel(const QString &str)
Zack Rusin952e9d42011-04-09 23:37:21 -040090{
José Fonseca18081d52011-05-07 00:10:25 +010091 m_label = str;
Zack Rusin952e9d42011-04-09 23:37:21 -040092}
Zack Rusina6846412011-04-10 19:51:44 -040093
94ApiFramebuffer::ApiFramebuffer()
95 : ApiSurface()
96{
97}
98
99QString ApiFramebuffer::type() const
100{
101 return m_type;
102}
103
104void ApiFramebuffer::setType(const QString &str)
105{
106 m_type = str;
107}
Zack Rusinb25c4b92011-11-16 22:43:34 -0500108
Zack Rusina69f0de2013-09-12 17:21:51 -0400109image::Image *
Jose Fonseca93a7c0c2015-05-27 20:52:51 +0100110ApiSurface::imageFromData(const QByteArray &dataArray)
Zack Rusina69f0de2013-09-12 17:21:51 -0400111{
Zack Rusina69f0de2013-09-12 17:21:51 -0400112 image::Image *image;
113
114 /*
115 * Detect the PNG vs PFM images.
116 */
117 const char pngSignature[] = {(char)0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0};
118 if (dataArray.startsWith(pngSignature)) {
119 ByteArrayBuf buf(dataArray);
120 std::istream istr(&buf);
121 image = image::readPNG(istr);
122 } else {
123 image = image::readPNM(dataArray.data(), dataArray.size());
124 }
125
126 return image;
127}
128
129
José Fonseca36509be2013-09-17 15:22:50 +0100130static inline unsigned char clamp(int x)
131{
132 if (x <= 0) {
133 return 0;
134 }
135 if (x > 255) {
136 return 255;
137 }
138 return (unsigned char) x;
139}
140
141static inline unsigned char clamp(float x)
142{
143 if (x <= 0.0f) {
144 return 0;
145 }
146 if (x > 255.0f) {
147 return 255;
148 }
149 return (unsigned char) (x + 0.5f);
150}
151
152
Zack Rusina69f0de2013-09-12 17:21:51 -0400153QImage
José Fonseca36509be2013-09-17 15:22:50 +0100154ApiSurface::qimageFromRawImage(const image::Image *image,
155 float lowerValue,
156 float upperValue,
157 bool opaque,
158 bool alpha)
Zack Rusina69f0de2013-09-12 17:21:51 -0400159{
160 QImage img;
161 int width = image->width;
162 int height = image->height;
163
164 img = QImage(width, height, QImage::Format_ARGB32);
165
José Fonseca36509be2013-09-17 15:22:50 +0100166 int offset = - lowerValue * 255;
167 int scale = 256 / (upperValue - lowerValue);
168
169 float offset_f = - lowerValue;
170 float scale_f = 255.0f / (upperValue - lowerValue);
171
172 int aMask = (opaque || alpha) ? 0xff : 0;
173
Zack Rusina69f0de2013-09-12 17:21:51 -0400174 const unsigned char *srcRow = image->start();
175 for (int y = 0; y < height; ++y) {
176 QRgb *dst = (QRgb *)img.scanLine(y);
177
178 if (image->channelType == image::TYPE_UNORM8) {
179 const unsigned char *src = srcRow;
180 for (int x = 0; x < width; ++x) {
Zack Rusind36c6ee2013-09-12 17:41:57 -0400181 unsigned char rgba[4] = {0, 0, 0, 0xff};
Zack Rusina69f0de2013-09-12 17:21:51 -0400182 for (int c = 0; c < image->channels; ++c) {
José Fonseca36509be2013-09-17 15:22:50 +0100183 rgba[c] = clamp(((*src++ + offset) * scale) >> 8);
Zack Rusina69f0de2013-09-12 17:21:51 -0400184 }
185 if (image->channels == 1) {
186 // Use gray-scale instead of red
187 rgba[1] = rgba[0];
188 rgba[2] = rgba[0];
189 }
José Fonseca36509be2013-09-17 15:22:50 +0100190 if (alpha) {
191 rgba[2] = rgba[1] = rgba[0] = rgba[3];
192 }
193 rgba[3] |= aMask;
Zack Rusina69f0de2013-09-12 17:21:51 -0400194 dst[x] = qRgba(rgba[0], rgba[1], rgba[2], rgba[3]);
195 }
196 } else {
197 const float *src = (const float *)srcRow;
198 for (int x = 0; x < width; ++x) {
199 unsigned char rgba[4] = {0, 0, 0, 0xff};
200 for (int c = 0; c < image->channels; ++c) {
José Fonseca36509be2013-09-17 15:22:50 +0100201 rgba[c] = clamp((*src++ + offset_f)*scale_f);
Zack Rusina69f0de2013-09-12 17:21:51 -0400202 }
203 if (image->channels == 1) {
204 // Use gray-scale instead of red
205 rgba[1] = rgba[0];
206 rgba[2] = rgba[0];
207 }
José Fonseca36509be2013-09-17 15:22:50 +0100208 if (alpha) {
209 rgba[2] = rgba[1] = rgba[0] = rgba[3];
210 }
211 rgba[3] |= aMask;
Zack Rusina69f0de2013-09-12 17:21:51 -0400212 dst[x] = qRgba(rgba[0], rgba[1], rgba[2], rgba[3]);
213 }
214 }
215
216 srcRow += image->stride();
217 }
218
219 return img;
220}