blob: d8aaeaf6164d96270173dc5f54057bd722a372e7 [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>
Martin Schulzeb44232b2016-04-16 19:06:16 +02005#include <memory>
José Fonseca52398312013-09-11 18:42:07 +01006
Zack Rusin952e9d42011-04-09 23:37:21 -04007#include <QDebug>
8#include <QSysInfo>
9
Jose Fonsecabceafec2016-05-05 11:09:52 +010010#include "image.hpp"
José Fonseca52398312013-09-11 18:42:07 +010011
12
Zack Rusin952e9d42011-04-09 23:37:21 -040013ApiSurface::ApiSurface()
14{
15}
16
17QSize ApiSurface::size() const
18{
19 return m_size;
20}
21
22void ApiSurface::setSize(const QSize &size)
23{
24 m_size = size;
25}
26
José Fonseca52398312013-09-11 18:42:07 +010027struct ByteArrayBuf : public std::streambuf
28{
Jose Fonsecac296a3e2015-05-01 17:43:54 +010029 ByteArrayBuf(const QByteArray & a)
José Fonseca52398312013-09-11 18:42:07 +010030 {
Jose Fonsecac296a3e2015-05-01 17:43:54 +010031 setg((char *)a.data(), (char *)a.data(), (char *)a.data() + a.size());
José Fonseca52398312013-09-11 18:42:07 +010032 }
33};
34
Martin Schulzeb44232b2016-04-16 19:06:16 +020035QImage ApiSurface::calculateThumbnail(bool opaque, bool alpha) const
Zack Rusin952e9d42011-04-09 23:37:21 -040036{
Martin Schulzeb44232b2016-04-16 19:06:16 +020037 return m_data.isEmpty() ? QImage{} : calculateThumbnail(m_data, opaque, alpha);
38}
José Fonseca994535d2013-09-12 17:26:34 +010039
Martin Schulzeb44232b2016-04-16 19:06:16 +020040QImage ApiSurface::calculateThumbnail(const QByteArray &data, bool opaque,
41 bool alpha) const
42{
José Fonseca52398312013-09-11 18:42:07 +010043 /*
Zack Rusina69f0de2013-09-12 17:21:51 -040044 * We need to do the conversion to create the thumbnail
José Fonseca52398312013-09-11 18:42:07 +010045 */
Martin Schulzeb44232b2016-04-16 19:06:16 +020046 std::unique_ptr<image::Image> image{imageFromData(data)};
José Fonseca52398312013-09-11 18:42:07 +010047 Q_ASSERT(image);
Martin Schulzeb44232b2016-04-16 19:06:16 +020048 QImage img = qimageFromRawImage(image.get(), 0.0f, 1.0f, opaque, alpha);
49 return thumbnail(img);
50}
51
52void ApiSurface::setData(const QByteArray &data)
53{
54 m_data = data;
Zack Rusin952e9d42011-04-09 23:37:21 -040055}
56
Jose Fonseca93a7c0c2015-05-27 20:52:51 +010057QByteArray ApiSurface::data() const
Zack Rusin952e9d42011-04-09 23:37:21 -040058{
Jose Fonseca93a7c0c2015-05-27 20:52:51 +010059 return m_data;
Zack Rusin952e9d42011-04-09 23:37:21 -040060}
61
Zack Rusinb25c4b92011-11-16 22:43:34 -050062int ApiSurface::depth() const
63{
64 return m_depth;
65}
66
67void ApiSurface::setDepth(int depth)
68{
69 m_depth = depth;
70}
71
Zack Rusine181b992011-11-17 16:00:41 -050072QString ApiSurface::formatName() const
73{
74 return m_formatName;
75}
76
77void ApiSurface::setFormatName(const QString &str)
78{
79 m_formatName = str;
80}
81
82
Zack Rusin952e9d42011-04-09 23:37:21 -040083ApiTexture::ApiTexture()
José Fonseca18081d52011-05-07 00:10:25 +010084 : ApiSurface()
Zack Rusin952e9d42011-04-09 23:37:21 -040085{
86}
87
José Fonseca18081d52011-05-07 00:10:25 +010088QString ApiTexture::label() const
Zack Rusin952e9d42011-04-09 23:37:21 -040089{
José Fonseca18081d52011-05-07 00:10:25 +010090 return m_label;
Zack Rusin952e9d42011-04-09 23:37:21 -040091}
92
José Fonseca18081d52011-05-07 00:10:25 +010093void ApiTexture::setLabel(const QString &str)
Zack Rusin952e9d42011-04-09 23:37:21 -040094{
José Fonseca18081d52011-05-07 00:10:25 +010095 m_label = str;
Zack Rusin952e9d42011-04-09 23:37:21 -040096}
Zack Rusina6846412011-04-10 19:51:44 -040097
98ApiFramebuffer::ApiFramebuffer()
99 : ApiSurface()
100{
101}
102
103QString ApiFramebuffer::type() const
104{
105 return m_type;
106}
107
108void ApiFramebuffer::setType(const QString &str)
109{
110 m_type = str;
111}
Zack Rusinb25c4b92011-11-16 22:43:34 -0500112
Zack Rusina69f0de2013-09-12 17:21:51 -0400113image::Image *
Jose Fonseca93a7c0c2015-05-27 20:52:51 +0100114ApiSurface::imageFromData(const QByteArray &dataArray)
Zack Rusina69f0de2013-09-12 17:21:51 -0400115{
Zack Rusina69f0de2013-09-12 17:21:51 -0400116 image::Image *image;
117
118 /*
119 * Detect the PNG vs PFM images.
120 */
121 const char pngSignature[] = {(char)0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0};
122 if (dataArray.startsWith(pngSignature)) {
123 ByteArrayBuf buf(dataArray);
124 std::istream istr(&buf);
125 image = image::readPNG(istr);
126 } else {
127 image = image::readPNM(dataArray.data(), dataArray.size());
128 }
129
130 return image;
131}
132
133
José Fonseca36509be2013-09-17 15:22:50 +0100134static inline unsigned char clamp(int x)
135{
136 if (x <= 0) {
137 return 0;
138 }
139 if (x > 255) {
140 return 255;
141 }
142 return (unsigned char) x;
143}
144
145static inline unsigned char clamp(float x)
146{
147 if (x <= 0.0f) {
148 return 0;
149 }
150 if (x > 255.0f) {
151 return 255;
152 }
153 return (unsigned char) (x + 0.5f);
154}
155
156
Zack Rusina69f0de2013-09-12 17:21:51 -0400157QImage
José Fonseca36509be2013-09-17 15:22:50 +0100158ApiSurface::qimageFromRawImage(const image::Image *image,
159 float lowerValue,
160 float upperValue,
161 bool opaque,
162 bool alpha)
Zack Rusina69f0de2013-09-12 17:21:51 -0400163{
164 QImage img;
165 int width = image->width;
166 int height = image->height;
167
168 img = QImage(width, height, QImage::Format_ARGB32);
169
José Fonseca36509be2013-09-17 15:22:50 +0100170 int offset = - lowerValue * 255;
171 int scale = 256 / (upperValue - lowerValue);
172
173 float offset_f = - lowerValue;
174 float scale_f = 255.0f / (upperValue - lowerValue);
175
176 int aMask = (opaque || alpha) ? 0xff : 0;
177
Zack Rusina69f0de2013-09-12 17:21:51 -0400178 const unsigned char *srcRow = image->start();
179 for (int y = 0; y < height; ++y) {
180 QRgb *dst = (QRgb *)img.scanLine(y);
181
182 if (image->channelType == image::TYPE_UNORM8) {
183 const unsigned char *src = srcRow;
184 for (int x = 0; x < width; ++x) {
Zack Rusind36c6ee2013-09-12 17:41:57 -0400185 unsigned char rgba[4] = {0, 0, 0, 0xff};
Zack Rusina69f0de2013-09-12 17:21:51 -0400186 for (int c = 0; c < image->channels; ++c) {
José Fonseca36509be2013-09-17 15:22:50 +0100187 rgba[c] = clamp(((*src++ + offset) * scale) >> 8);
Zack Rusina69f0de2013-09-12 17:21:51 -0400188 }
189 if (image->channels == 1) {
190 // Use gray-scale instead of red
191 rgba[1] = rgba[0];
192 rgba[2] = rgba[0];
193 }
José Fonseca36509be2013-09-17 15:22:50 +0100194 if (alpha) {
195 rgba[2] = rgba[1] = rgba[0] = rgba[3];
196 }
197 rgba[3] |= aMask;
Zack Rusina69f0de2013-09-12 17:21:51 -0400198 dst[x] = qRgba(rgba[0], rgba[1], rgba[2], rgba[3]);
199 }
200 } else {
201 const float *src = (const float *)srcRow;
202 for (int x = 0; x < width; ++x) {
203 unsigned char rgba[4] = {0, 0, 0, 0xff};
204 for (int c = 0; c < image->channels; ++c) {
José Fonseca36509be2013-09-17 15:22:50 +0100205 rgba[c] = clamp((*src++ + offset_f)*scale_f);
Zack Rusina69f0de2013-09-12 17:21:51 -0400206 }
207 if (image->channels == 1) {
208 // Use gray-scale instead of red
209 rgba[1] = rgba[0];
210 rgba[2] = rgba[0];
211 }
José Fonseca36509be2013-09-17 15:22:50 +0100212 if (alpha) {
213 rgba[2] = rgba[1] = rgba[0] = rgba[3];
214 }
215 rgba[3] |= aMask;
Zack Rusina69f0de2013-09-12 17:21:51 -0400216 dst[x] = qRgba(rgba[0], rgba[1], rgba[2], rgba[3]);
217 }
218 }
219
220 srcRow += image->stride();
221 }
222
223 return img;
224}