• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mcallegari / qlcplus / 13633248611

03 Mar 2025 02:31PM UTC coverage: 31.871% (+0.4%) from 31.5%
13633248611

push

github

web-flow
actions: add chrpath to profile

14689 of 46089 relevant lines covered (31.87%)

26426.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

6.04
/engine/src/rgbimage.cpp
1
/*
2
  Q Light Controller Plus
3
  rgbimage.cpp
4

5
  Copyright (c) Heikki Junnila
6
  Copyright (c) Jano Svitok
7
  Copyright (c) Massimo Callegari
8

9
  Licensed under the Apache License, Version 2.0 (the "License");
10
  you may not use this file except in compliance with the License.
11
  You may obtain a copy of the License at
12

13
      http://www.apache.org/licenses/LICENSE-2.0.txt
14

15
  Unless required by applicable law or agreed to in writing, software
16
  distributed under the License is distributed on an "AS IS" BASIS,
17
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
  See the License for the specific language governing permissions and
19
  limitations under the License.
20
*/
21

22
#include <QXmlStreamReader>
23
#include <QXmlStreamWriter>
24
#include <QPainter>
25
#include <QDebug>
26

27
#include "rgbimage.h"
28
#include "qlcmacros.h"
29
#include "doc.h"
30

31
#define KXMLQLCRGBImageFilename       QString("Filename")
32
#define KXMLQLCRGBImageAnimationStyle QString("Animation")
33
#define KXMLQLCRGBImageOffset         QString("Offset")
34
#define KXMLQLCRGBImageOffsetX        QString("X")
35
#define KXMLQLCRGBImageOffsetY        QString("Y")
36

37
RGBImage::RGBImage(Doc * doc)
17✔
38
    : RGBAlgorithm(doc)
39
    , m_filename("")
17✔
40
    , m_animatedSource(false)
17✔
41
    , m_animationStyle(Static)
17✔
42
    , m_xOffset(0)
17✔
43
    , m_yOffset(0)
17✔
44
{
45
}
17✔
46

47
RGBImage::RGBImage(const RGBImage& i)
×
48
    : RGBAlgorithm(i.doc())
49
    , m_filename(i.filename())
×
50
    , m_animatedSource(i.animatedSource())
×
51
    , m_animationStyle(i.animationStyle())
×
52
    , m_xOffset(i.xOffset())
×
53
    , m_yOffset(i.yOffset())
×
54
{
55
    reloadImage();
×
56
}
×
57

58
RGBImage::~RGBImage()
17✔
59
{
60
}
17✔
61

62
RGBAlgorithm* RGBImage::clone() const
×
63
{
64
    RGBImage* image = new RGBImage(*this);
×
65
    return static_cast<RGBAlgorithm*> (image);
×
66
}
67

68
/****************************************************************************
69
 * Image file
70
 ****************************************************************************/
71

72
void RGBImage::setFilename(const QString& filename)
×
73
{
74
    m_filename = filename;
×
75
    reloadImage();
×
76
}
×
77

78
QString RGBImage::filename() const
×
79
{
80
    return m_filename;
×
81
}
82

83
void RGBImage::setImageData(int width, int height, const QByteArray &pixelData)
×
84
{
85
    QMutexLocker locker(&m_mutex);
×
86

87
    qDebug() << "[RGBImage] setting image data:" << width << height << pixelData.length();
88
    QImage newImg(width, height, QImage::Format_RGB888);
×
89
    newImg.fill(Qt::black);
×
90

91
    int i = 0;
92
    for (int y = 0; y < height; y++)
×
93
    {
94
        for (int x = 0; x < width; x++)
×
95
        {
96
            if (i + 3 > pixelData.length())
×
97
                break;
98
            QRgb pixel = qRgb((uchar)pixelData.at(i), (uchar)pixelData.at(i + 1), (uchar)pixelData.at(i + 2));
×
99
            newImg.setPixel(x, y, pixel);
×
100
            i+=3;
×
101
        }
102
    }
103
    m_image = newImg;
×
104
}
×
105

106
bool RGBImage::animatedSource() const
×
107
{
108
    return m_animatedSource;
×
109
}
110

111
void RGBImage::rewindAnimation()
×
112
{
113
    if (m_animatedSource)
×
114
        m_animatedPlayer.jumpToFrame(0);
×
115
}
×
116

117
void RGBImage::reloadImage()
×
118
{
119
    m_animatedSource = false;
×
120

121
    if (m_filename.isEmpty())
×
122
    {
123
        qDebug() << "[RGBImage] Empty image!";
124
        return;
×
125
    }
126

127
    QMutexLocker locker(&m_mutex);
×
128

129
    if (m_filename.endsWith(".gif"))
×
130
    {
131
        m_animatedPlayer.setFileName(m_filename);
×
132
        if (m_animatedPlayer.frameCount() > 1)
×
133
            m_animatedSource = true;
×
134
    }
135

136
    if (m_animatedSource == false)
×
137
    {
138
        if (!m_image.load(m_filename))
×
139
        {
140
            qDebug() << "[RGBImage] Failed to load" << m_filename;
141
            return;
142
        }
143
    }
144
}
145

146
/****************************************************************************
147
 * Animation
148
 ****************************************************************************/
149

150
void RGBImage::setAnimationStyle(RGBImage::AnimationStyle ani)
×
151
{
152
    if (ani >= Static && ani <= Animation)
×
153
        m_animationStyle = ani;
×
154
    else
155
        m_animationStyle = Static;
×
156
}
×
157

158
RGBImage::AnimationStyle RGBImage::animationStyle() const
×
159
{
160
    return m_animationStyle;
×
161
}
162

163
QString RGBImage::animationStyleToString(RGBImage::AnimationStyle ani)
×
164
{
165
    switch (ani)
×
166
    {
167
        default:
×
168
        case Static:
169
            return QString("Static");
×
170
        case Horizontal:
×
171
            return QString("Horizontal");
×
172
        case Vertical:
×
173
            return QString("Vertical");
×
174
        case Animation:
×
175
            return QString("Animation");
×
176
    }
177
}
178

179
RGBImage::AnimationStyle RGBImage::stringToAnimationStyle(const QString& str)
×
180
{
181
    if (str == QString("Horizontal"))
×
182
        return Horizontal;
183
    else if (str == QString("Vertical"))
×
184
        return Vertical;
185
    else if (str == QString("Animation"))
×
186
        return Animation;
187
    else
188
        return Static;
×
189
}
190

191
QStringList RGBImage::animationStyles()
×
192
{
193
    QStringList list;
194
    list << animationStyleToString(Static);
×
195
    list << animationStyleToString(Horizontal);
×
196
    list << animationStyleToString(Vertical);
×
197
    list << animationStyleToString(Animation);
×
198
    return list;
×
199
}
200

201
void RGBImage::setXOffset(int offset)
×
202
{
203
    m_xOffset = offset;
×
204
}
×
205

206
int RGBImage::xOffset() const
×
207
{
208
    return m_xOffset;
×
209
}
210

211
void RGBImage::setYOffset(int offset)
×
212
{
213
    m_yOffset = offset;
×
214
}
×
215

216
int RGBImage::yOffset() const
×
217
{
218
    return m_yOffset;
×
219
}
220

221
/****************************************************************************
222
 * RGBAlgorithm
223
 ****************************************************************************/
224

225
int RGBImage::rgbMapStepCount(const QSize& size)
×
226
{
227
    QMutexLocker locker(&m_mutex);
×
228

229
    switch (animationStyle())
×
230
    {
231
        default:
232
        case Static:
233
            return 1;
234
        case Horizontal:
×
235
            return m_image.width();
×
236
        case Vertical:
×
237
            return m_image.height();
×
238
        case Animation:
239
            qDebug() << m_image.width() << " " << size.width() << " " << (m_image.width() / size.width());
240
            return MAX(1, m_image.width() / size.width());
×
241
    }
242
}
243

244
void RGBImage::rgbMapSetColors(QVector<uint> &colors)
×
245
{
246
    Q_UNUSED(colors);
247
}
×
248

249
QVector<uint> RGBImage::rgbMapGetColors()
×
250
{
251
    return QVector<uint>();
×
252
}
253

254
void RGBImage::rgbMap(const QSize& size, uint rgb, int step, RGBMap &map)
×
255
{
256
    Q_UNUSED(rgb);
257

258
    QMutexLocker locker(&m_mutex);
×
259

260
    if (m_animatedSource == false && (m_image.width() == 0 || m_image.height() == 0))
×
261
        return;
262

263
    int xOffs = xOffset();
×
264
    int yOffs = yOffset();
×
265

266
    switch(animationStyle())
×
267
    {
268
        default:
269
        case Static:
270
        break;
271
        case Horizontal:
×
272
            xOffs += step;
×
273
        break;
×
274
        case Vertical:
×
275
            yOffs += step;
×
276
        break;
×
277
        case Animation:
278
            xOffs += step * size.width();
×
279
        break;
×
280
    }
281

282
    if (m_animatedSource)
×
283
    {
284
        m_animatedPlayer.jumpToNextFrame();
×
285
        m_image = m_animatedPlayer.currentImage().scaled(size);
×
286
    }
287

288
    map.resize(size.height());
×
289
    for (int y = 0; y < size.height(); y++)
×
290
    {
291
        map[y].resize(size.width());
×
292
        for (int x = 0; x < size.width(); x++)
×
293
        {
294
            int x1 = (x + xOffs) % m_image.width();
×
295
            int y1 = (y + yOffs) % m_image.height();
×
296

297
            map[y][x] = m_image.pixel(x1,y1);
×
298
            if (qAlpha(map[y][x]) == 0)
×
299
                map[y][x] = 0;
×
300
        }
301
    }
302
}
303

304
QString RGBImage::name() const
16✔
305
{
306
    return QString("Image");
16✔
307
}
308

309
QString RGBImage::author() const
×
310
{
311
    return QString("Jano Svitok");
×
312
}
313

314
int RGBImage::apiVersion() const
×
315
{
316
    return 1;
×
317
}
318

319
RGBAlgorithm::Type RGBImage::type() const
×
320
{
321
    return RGBAlgorithm::Image;
×
322
}
323

324
int RGBImage::acceptColors() const
×
325
{
326
    return 0;
×
327
}
328

329
bool RGBImage::loadXML(QXmlStreamReader &root)
×
330
{
331
    if (root.name() != KXMLQLCRGBAlgorithm)
×
332
    {
333
        qWarning() << Q_FUNC_INFO << "RGB Algorithm node not found";
×
334
        return false;
×
335
    }
336

337
    if (root.attributes().value(KXMLQLCRGBAlgorithmType).toString() != KXMLQLCRGBImage)
×
338
    {
339
        qWarning() << Q_FUNC_INFO << "RGB Algorithm is not Image";
×
340
        return false;
×
341
    }
342

343
    while (root.readNextStartElement())
×
344
    {
345
        if (root.name() == KXMLQLCRGBImageFilename)
×
346
        {
347
            setFilename(doc()->denormalizeComponentPath(root.readElementText()));
×
348
        }
349
        else if (root.name() == KXMLQLCRGBImageAnimationStyle)
×
350
        {
351
            setAnimationStyle(stringToAnimationStyle(root.readElementText()));
×
352
        }
353
        else if (root.name() == KXMLQLCRGBImageOffset)
×
354
        {
355
            QString str;
356
            int value;
357
            bool ok;
358
            QXmlStreamAttributes attrs = root.attributes();
×
359

360
            str = attrs.value(KXMLQLCRGBImageOffsetX).toString();
×
361
            ok = false;
×
362
            value = str.toInt(&ok);
×
363
            if (ok == true)
×
364
                setXOffset(value);
×
365
            else
366
                qWarning() << Q_FUNC_INFO << "Invalid X offset:" << str;
×
367

368
            str = attrs.value(KXMLQLCRGBImageOffsetY).toString();
×
369
            ok = false;
×
370
            value = str.toInt(&ok);
×
371
            if (ok == true)
×
372
                setYOffset(value);
×
373
            else
374
                qWarning() << Q_FUNC_INFO << "Invalid Y offset:" << str;
×
375
            root.skipCurrentElement();
×
376
        }
×
377
        else
378
        {
379
            qWarning() << Q_FUNC_INFO << "Unknown RGBImage tag:" << root.name();
×
380
            root.skipCurrentElement();
×
381
        }
382
    }
383

384
    return true;
385
}
386

387
bool RGBImage::saveXML(QXmlStreamWriter *doc) const
×
388
{
389
    Q_ASSERT(doc != NULL);
390

391
    doc->writeStartElement(KXMLQLCRGBAlgorithm);
×
392
    doc->writeAttribute(KXMLQLCRGBAlgorithmType, KXMLQLCRGBImage);
×
393

394
    doc->writeTextElement(KXMLQLCRGBImageFilename, this->doc()->normalizeComponentPath(m_filename));
×
395

396
    doc->writeTextElement(KXMLQLCRGBImageAnimationStyle, animationStyleToString(animationStyle()));
×
397

398
    doc->writeStartElement(KXMLQLCRGBImageOffset);
×
399
    doc->writeAttribute(KXMLQLCRGBImageOffsetX, QString::number(xOffset()));
×
400
    doc->writeAttribute(KXMLQLCRGBImageOffsetY, QString::number(yOffset()));
×
401
    doc->writeEndElement();
×
402

403
    /* End the <Algorithm> tag */
404
    doc->writeEndElement();
×
405

406
    return true;
×
407
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc