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

mcallegari / qlcplus / 12611954629

04 Jan 2025 04:17PM UTC coverage: 31.468% (-0.5%) from 31.963%
12611954629

Pull #1649

github

web-flow
Merge d17d3ec9b into 3ed321c32
Pull Request #1649: Function Wizard: create Effects

2 of 53 new or added lines in 2 files covered. (3.77%)

2597 existing lines in 15 files now uncovered.

14093 of 44785 relevant lines covered (31.47%)

26791.82 hits per line

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

4.02
/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)
8✔
38
    : RGBAlgorithm(doc)
39
    , m_filename("")
40
    , m_animatedSource(false)
41
    , m_animationStyle(Static)
42
    , m_xOffset(0)
43
    , m_yOffset(0)
8✔
44
{
45
}
8✔
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()
8✔
59
{
60
}
8✔
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::reloadImage()
×
112
{
113
    m_animatedSource = false;
×
114

115
    if (m_filename.isEmpty())
×
116
    {
117
        qDebug() << "[RGBImage] Empty image!";
118
        return;
119
    }
120

121
    QMutexLocker locker(&m_mutex);
×
122

123
    if (m_filename.endsWith(".gif"))
×
124
    {
125
        m_animatedPlayer.setFileName(m_filename);
×
126
        if (m_animatedPlayer.frameCount() > 1)
×
127
            m_animatedSource = true;
×
128
    }
129

130
    if (m_animatedSource == false)
×
131
    {
132
        if (!m_image.load(m_filename))
×
133
        {
134
            qDebug() << "[RGBImage] Failed to load" << m_filename;
135
            return;
136
        }
137
    }
138
}
139

140
/****************************************************************************
141
 * Animation
142
 ****************************************************************************/
143

144
void RGBImage::setAnimationStyle(RGBImage::AnimationStyle ani)
×
145
{
146
    if (ani >= Static && ani <= Animation)
×
147
        m_animationStyle = ani;
×
148
    else
149
        m_animationStyle = Static;
×
150
}
×
151

152
RGBImage::AnimationStyle RGBImage::animationStyle() const
×
153
{
154
    return m_animationStyle;
×
155
}
156

157
QString RGBImage::animationStyleToString(RGBImage::AnimationStyle ani)
×
158
{
159
    switch (ani)
×
160
    {
161
        default:
×
162
        case Static:
163
            return QString("Static");
×
164
        case Horizontal:
×
165
            return QString("Horizontal");
×
166
        case Vertical:
×
167
            return QString("Vertical");
×
168
        case Animation:
×
169
            return QString("Animation");
×
170
    }
171
}
172

173
RGBImage::AnimationStyle RGBImage::stringToAnimationStyle(const QString& str)
×
174
{
175
    if (str == QString("Horizontal"))
×
176
        return Horizontal;
177
    else if (str == QString("Vertical"))
×
178
        return Vertical;
179
    else if (str == QString("Animation"))
×
180
        return Animation;
181
    else
182
        return Static;
×
183
}
184

185
QStringList RGBImage::animationStyles()
×
186
{
187
    QStringList list;
188
    list << animationStyleToString(Static);
×
189
    list << animationStyleToString(Horizontal);
×
190
    list << animationStyleToString(Vertical);
×
191
    list << animationStyleToString(Animation);
×
192
    return list;
×
193
}
194

195
void RGBImage::setXOffset(int offset)
×
196
{
197
    m_xOffset = offset;
×
198
}
×
199

200
int RGBImage::xOffset() const
×
201
{
202
    return m_xOffset;
×
203
}
204

205
void RGBImage::setYOffset(int offset)
×
206
{
207
    m_yOffset = offset;
×
208
}
×
209

210
int RGBImage::yOffset() const
×
211
{
212
    return m_yOffset;
×
213
}
214

215
/****************************************************************************
216
 * RGBAlgorithm
217
 ****************************************************************************/
218

219
int RGBImage::rgbMapStepCount(const QSize& size)
×
220
{
221
    QMutexLocker locker(&m_mutex);
×
222

223
    switch (animationStyle())
×
224
    {
225
        default:
226
        case Static:
227
            return 1;
228
        case Horizontal:
×
229
            return m_image.width();
×
230
        case Vertical:
×
231
            return m_image.height();
×
232
        case Animation:
×
233
            qDebug() << m_image.width() << " " << size.width() << " " << (m_image.width() / size.width());
234
            return MAX(1, m_image.width() / size.width());
×
235
    }
236
}
237

238
void RGBImage::rgbMapSetColors(QVector<uint> &colors)
×
239
{
240
    Q_UNUSED(colors);
UNCOV
241
}
×
242

UNCOV
243
QVector<uint> RGBImage::rgbMapGetColors()
×
244
{
UNCOV
245
    return QVector<uint>();
×
246
}
247

248
void RGBImage::rgbMap(const QSize& size, uint rgb, int step, RGBMap &map)
×
249
{
250
    Q_UNUSED(rgb);
251

UNCOV
252
    QMutexLocker locker(&m_mutex);
×
253

UNCOV
254
    if (m_animatedSource == false && (m_image.width() == 0 || m_image.height() == 0))
×
255
        return;
256

257
    int xOffs = xOffset();
×
258
    int yOffs = yOffset();
×
259

260
    switch(animationStyle())
×
261
    {
262
        default:
263
        case Static:
264
        break;
UNCOV
265
        case Horizontal:
×
266
            xOffs += step;
×
UNCOV
267
        break;
×
268
        case Vertical:
×
269
            yOffs += step;
×
UNCOV
270
        break;
×
UNCOV
271
        case Animation:
×
272
            xOffs += step * size.width();
×
273
        break;
×
274
    }
275

276
    if (m_animatedSource)
×
277
    {
278
        m_animatedPlayer.jumpToNextFrame();
×
279
        m_image = m_animatedPlayer.currentImage().scaled(size);
×
280
    }
281

282
    map.resize(size.height());
×
283
    for (int y = 0; y < size.height(); y++)
×
284
    {
UNCOV
285
        map[y].resize(size.width());
×
UNCOV
286
        for (int x = 0; x < size.width(); x++)
×
287
        {
UNCOV
288
            int x1 = (x + xOffs) % m_image.width();
×
UNCOV
289
            int y1 = (y + yOffs) % m_image.height();
×
290

UNCOV
291
            map[y][x] = m_image.pixel(x1,y1);
×
UNCOV
292
            if (qAlpha(map[y][x]) == 0)
×
293
                map[y][x] = 0;
×
294
        }
295
    }
296
}
297

298
QString RGBImage::name() const
7✔
299
{
300
    return QString("Image");
7✔
301
}
302

303
QString RGBImage::author() const
×
304
{
305
    return QString("Jano Svitok");
×
306
}
307

308
int RGBImage::apiVersion() const
×
309
{
310
    return 1;
×
311
}
312

313
RGBAlgorithm::Type RGBImage::type() const
×
314
{
315
    return RGBAlgorithm::Image;
×
316
}
317

318
int RGBImage::acceptColors() const
×
319
{
UNCOV
320
    return 0;
×
321
}
322

323
bool RGBImage::loadXML(QXmlStreamReader &root)
×
324
{
UNCOV
325
    if (root.name() != KXMLQLCRGBAlgorithm)
×
326
    {
327
        qWarning() << Q_FUNC_INFO << "RGB Algorithm node not found";
×
UNCOV
328
        return false;
×
329
    }
330

331
    if (root.attributes().value(KXMLQLCRGBAlgorithmType).toString() != KXMLQLCRGBImage)
×
332
    {
333
        qWarning() << Q_FUNC_INFO << "RGB Algorithm is not Image";
×
UNCOV
334
        return false;
×
335
    }
336

337
    while (root.readNextStartElement())
×
338
    {
339
        if (root.name() == KXMLQLCRGBImageFilename)
×
340
        {
UNCOV
341
            setFilename(doc()->denormalizeComponentPath(root.readElementText()));
×
342
        }
UNCOV
343
        else if (root.name() == KXMLQLCRGBImageAnimationStyle)
×
344
        {
345
            setAnimationStyle(stringToAnimationStyle(root.readElementText()));
×
346
        }
347
        else if (root.name() == KXMLQLCRGBImageOffset)
×
348
        {
UNCOV
349
            QString str;
×
350
            int value;
351
            bool ok;
352
            QXmlStreamAttributes attrs = root.attributes();
×
353

354
            str = attrs.value(KXMLQLCRGBImageOffsetX).toString();
×
355
            ok = false;
×
356
            value = str.toInt(&ok);
×
UNCOV
357
            if (ok == true)
×
358
                setXOffset(value);
×
359
            else
UNCOV
360
                qWarning() << Q_FUNC_INFO << "Invalid X offset:" << str;
×
361

UNCOV
362
            str = attrs.value(KXMLQLCRGBImageOffsetY).toString();
×
363
            ok = false;
×
364
            value = str.toInt(&ok);
×
UNCOV
365
            if (ok == true)
×
UNCOV
366
                setYOffset(value);
×
367
            else
UNCOV
368
                qWarning() << Q_FUNC_INFO << "Invalid Y offset:" << str;
×
UNCOV
369
            root.skipCurrentElement();
×
370
        }
371
        else
372
        {
UNCOV
373
            qWarning() << Q_FUNC_INFO << "Unknown RGBImage tag:" << root.name();
×
UNCOV
374
            root.skipCurrentElement();
×
375
        }
376
    }
377

378
    return true;
379
}
380

UNCOV
381
bool RGBImage::saveXML(QXmlStreamWriter *doc) const
×
382
{
383
    Q_ASSERT(doc != NULL);
384

385
    doc->writeStartElement(KXMLQLCRGBAlgorithm);
×
UNCOV
386
    doc->writeAttribute(KXMLQLCRGBAlgorithmType, KXMLQLCRGBImage);
×
387

388
    doc->writeTextElement(KXMLQLCRGBImageFilename, this->doc()->normalizeComponentPath(m_filename));
×
389

390
    doc->writeTextElement(KXMLQLCRGBImageAnimationStyle, animationStyleToString(animationStyle()));
×
391

UNCOV
392
    doc->writeStartElement(KXMLQLCRGBImageOffset);
×
UNCOV
393
    doc->writeAttribute(KXMLQLCRGBImageOffsetX, QString::number(xOffset()));
×
UNCOV
394
    doc->writeAttribute(KXMLQLCRGBImageOffsetY, QString::number(yOffset()));
×
UNCOV
395
    doc->writeEndElement();
×
396

397
    /* End the <Algorithm> tag */
UNCOV
398
    doc->writeEndElement();
×
399

UNCOV
400
    return true;
×
401
}
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

© 2026 Coveralls, Inc