blob: 01dc0eeb12cbb8dc6cc8321cde720185e6810967 [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
Jose Fonsecacdf4c0e2019-07-31 12:54:30 +01004#include <algorithm>
José Fonseca52398312013-09-11 18:42:07 +01005#include <sstream>
Martin Schulzeb44232b2016-04-16 19:06:16 +02006#include <memory>
José Fonseca52398312013-09-11 18:42:07 +01007
Zack Rusin952e9d42011-04-09 23:37:21 -04008#include <QDebug>
9#include <QSysInfo>
10
Jose Fonsecabceafec2016-05-05 11:09:52 +010011#include "image.hpp"
José Fonseca52398312013-09-11 18:42:07 +010012
13
Zack Rusin952e9d42011-04-09 23:37:21 -040014ApiSurface::ApiSurface()
15{
16}
17
18QSize ApiSurface::size() const
19{
20 return m_size;
21}
22
23void ApiSurface::setSize(const QSize &size)
24{
25 m_size = size;
26}
27
José Fonseca52398312013-09-11 18:42:07 +010028struct ByteArrayBuf : public std::streambuf
29{
Jose Fonsecac296a3e2015-05-01 17:43:54 +010030 ByteArrayBuf(const QByteArray & a)
José Fonseca52398312013-09-11 18:42:07 +010031 {
Jose Fonsecac296a3e2015-05-01 17:43:54 +010032 setg((char *)a.data(), (char *)a.data(), (char *)a.data() + a.size());
José Fonseca52398312013-09-11 18:42:07 +010033 }
34};
35
Martin Schulzeb44232b2016-04-16 19:06:16 +020036QImage ApiSurface::calculateThumbnail(bool opaque, bool alpha) const
Zack Rusin952e9d42011-04-09 23:37:21 -040037{
Martin Schulzeb44232b2016-04-16 19:06:16 +020038 return m_data.isEmpty() ? QImage{} : calculateThumbnail(m_data, opaque, alpha);
39}
José Fonseca994535d2013-09-12 17:26:34 +010040
Martin Schulzeb44232b2016-04-16 19:06:16 +020041QImage ApiSurface::calculateThumbnail(const QByteArray &data, bool opaque,
42 bool alpha) const
43{
José Fonseca52398312013-09-11 18:42:07 +010044 /*
Zack Rusina69f0de2013-09-12 17:21:51 -040045 * We need to do the conversion to create the thumbnail
José Fonseca52398312013-09-11 18:42:07 +010046 */
Martin Schulzeb44232b2016-04-16 19:06:16 +020047 std::unique_ptr<image::Image> image{imageFromData(data)};
José Fonseca52398312013-09-11 18:42:07 +010048 Q_ASSERT(image);
Martin Schulzeb44232b2016-04-16 19:06:16 +020049 QImage img = qimageFromRawImage(image.get(), 0.0f, 1.0f, opaque, alpha);
50 return thumbnail(img);
51}
52
53void ApiSurface::setData(const QByteArray &data)
54{
55 m_data = data;
Zack Rusin952e9d42011-04-09 23:37:21 -040056}
57
Jose Fonseca93a7c0c2015-05-27 20:52:51 +010058QByteArray ApiSurface::data() const
Zack Rusin952e9d42011-04-09 23:37:21 -040059{
Jose Fonseca93a7c0c2015-05-27 20:52:51 +010060 return m_data;
Zack Rusin952e9d42011-04-09 23:37:21 -040061}
62
Zack Rusinb25c4b92011-11-16 22:43:34 -050063int ApiSurface::depth() const
64{
65 return m_depth;
66}
67
68void ApiSurface::setDepth(int depth)
69{
70 m_depth = depth;
71}
72
Zack Rusine181b992011-11-17 16:00:41 -050073QString ApiSurface::formatName() const
74{
75 return m_formatName;
76}
77
78void ApiSurface::setFormatName(const QString &str)
79{
80 m_formatName = str;
81}
82
83
Zack Rusin952e9d42011-04-09 23:37:21 -040084ApiTexture::ApiTexture()
José Fonseca18081d52011-05-07 00:10:25 +010085 : ApiSurface()
Zack Rusin952e9d42011-04-09 23:37:21 -040086{
87}
88
José Fonseca18081d52011-05-07 00:10:25 +010089QString ApiTexture::label() const
Zack Rusin952e9d42011-04-09 23:37:21 -040090{
José Fonseca18081d52011-05-07 00:10:25 +010091 return m_label;
Zack Rusin952e9d42011-04-09 23:37:21 -040092}
93
José Fonseca18081d52011-05-07 00:10:25 +010094void ApiTexture::setLabel(const QString &str)
Zack Rusin952e9d42011-04-09 23:37:21 -040095{
José Fonseca18081d52011-05-07 00:10:25 +010096 m_label = str;
Zack Rusin952e9d42011-04-09 23:37:21 -040097}
Zack Rusina6846412011-04-10 19:51:44 -040098
99ApiFramebuffer::ApiFramebuffer()
100 : ApiSurface()
101{
102}
103
104QString ApiFramebuffer::type() const
105{
106 return m_type;
107}
108
109void ApiFramebuffer::setType(const QString &str)
110{
111 m_type = str;
112}
Zack Rusinb25c4b92011-11-16 22:43:34 -0500113
Zack Rusina69f0de2013-09-12 17:21:51 -0400114image::Image *
Jose Fonseca93a7c0c2015-05-27 20:52:51 +0100115ApiSurface::imageFromData(const QByteArray &dataArray)
Zack Rusina69f0de2013-09-12 17:21:51 -0400116{
Zack Rusina69f0de2013-09-12 17:21:51 -0400117 image::Image *image;
118
119 /*
120 * Detect the PNG vs PFM images.
121 */
122 const char pngSignature[] = {(char)0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0};
123 if (dataArray.startsWith(pngSignature)) {
124 ByteArrayBuf buf(dataArray);
125 std::istream istr(&buf);
126 image = image::readPNG(istr);
127 } else {
128 image = image::readPNM(dataArray.data(), dataArray.size());
129 }
130
131 return image;
132}
133
134
José Fonseca36509be2013-09-17 15:22:50 +0100135static inline unsigned char clamp(int x)
136{
137 if (x <= 0) {
138 return 0;
139 }
140 if (x > 255) {
141 return 255;
142 }
143 return (unsigned char) x;
144}
145
146static inline unsigned char clamp(float x)
147{
148 if (x <= 0.0f) {
149 return 0;
150 }
151 if (x > 255.0f) {
152 return 255;
153 }
154 return (unsigned char) (x + 0.5f);
155}
156
157
Zack Rusina69f0de2013-09-12 17:21:51 -0400158QImage
José Fonseca36509be2013-09-17 15:22:50 +0100159ApiSurface::qimageFromRawImage(const image::Image *image,
160 float lowerValue,
161 float upperValue,
162 bool opaque,
163 bool alpha)
Zack Rusina69f0de2013-09-12 17:21:51 -0400164{
165 QImage img;
Jose Fonsecacdf4c0e2019-07-31 12:54:30 +0100166 int width = std::min(image->width, 32767U);
167 int height = std::min(image->height, 32767U);
Zack Rusina69f0de2013-09-12 17:21:51 -0400168
169 img = QImage(width, height, QImage::Format_ARGB32);
170
José Fonseca36509be2013-09-17 15:22:50 +0100171 int offset = - lowerValue * 255;
172 int scale = 256 / (upperValue - lowerValue);
173
174 float offset_f = - lowerValue;
175 float scale_f = 255.0f / (upperValue - lowerValue);
176
177 int aMask = (opaque || alpha) ? 0xff : 0;
178
Zack Rusina69f0de2013-09-12 17:21:51 -0400179 const unsigned char *srcRow = image->start();
180 for (int y = 0; y < height; ++y) {
181 QRgb *dst = (QRgb *)img.scanLine(y);
182
183 if (image->channelType == image::TYPE_UNORM8) {
184 const unsigned char *src = srcRow;
185 for (int x = 0; x < width; ++x) {
Zack Rusind36c6ee2013-09-12 17:41:57 -0400186 unsigned char rgba[4] = {0, 0, 0, 0xff};
Zack Rusina69f0de2013-09-12 17:21:51 -0400187 for (int c = 0; c < image->channels; ++c) {
José Fonseca36509be2013-09-17 15:22:50 +0100188 rgba[c] = clamp(((*src++ + offset) * scale) >> 8);
Zack Rusina69f0de2013-09-12 17:21:51 -0400189 }
190 if (image->channels == 1) {
191 // Use gray-scale instead of red
192 rgba[1] = rgba[0];
193 rgba[2] = rgba[0];
194 }
José Fonseca36509be2013-09-17 15:22:50 +0100195 if (alpha) {
196 rgba[2] = rgba[1] = rgba[0] = rgba[3];
197 }
198 rgba[3] |= aMask;
Zack Rusina69f0de2013-09-12 17:21:51 -0400199 dst[x] = qRgba(rgba[0], rgba[1], rgba[2], rgba[3]);
200 }
201 } else {
202 const float *src = (const float *)srcRow;
203 for (int x = 0; x < width; ++x) {
204 unsigned char rgba[4] = {0, 0, 0, 0xff};
205 for (int c = 0; c < image->channels; ++c) {
José Fonseca36509be2013-09-17 15:22:50 +0100206 rgba[c] = clamp((*src++ + offset_f)*scale_f);
Zack Rusina69f0de2013-09-12 17:21:51 -0400207 }
208 if (image->channels == 1) {
209 // Use gray-scale instead of red
210 rgba[1] = rgba[0];
211 rgba[2] = rgba[0];
212 }
José Fonseca36509be2013-09-17 15:22:50 +0100213 if (alpha) {
214 rgba[2] = rgba[1] = rgba[0] = rgba[3];
215 }
216 rgba[3] |= aMask;
Zack Rusina69f0de2013-09-12 17:21:51 -0400217 dst[x] = qRgba(rgba[0], rgba[1], rgba[2], rgba[3]);
218 }
219 }
220
221 srcRow += image->stride();
222 }
223
224 return img;
225}