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

mcallegari / qlcplus / 12548164445

30 Dec 2024 02:54PM UTC coverage: 31.593% (-0.4%) from 31.967%
12548164445

push

github

mcallegari
Merge branch 'master' into crossuniverse

75 of 946 new or added lines in 16 files covered. (7.93%)

15 existing lines in 8 files now uncovered.

14095 of 44615 relevant lines covered (31.59%)

26894.43 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

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

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

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

252
    QMutexLocker locker(&m_mutex);
×
253

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;
265
        case Horizontal:
×
266
            xOffs += step;
×
267
        break;
×
268
        case Vertical:
×
269
            yOffs += step;
×
270
        break;
×
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
    {
285
        map[y].resize(size.width());
×
286
        for (int x = 0; x < size.width(); x++)
×
287
        {
288
            int x1 = (x + xOffs) % m_image.width();
×
289
            int y1 = (y + yOffs) % m_image.height();
×
290

291
            map[y][x] = m_image.pixel(x1,y1);
×
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
{
320
    return 0;
×
321
}
322

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

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

337
    while (root.readNextStartElement())
×
338
    {
339
        if (root.name() == KXMLQLCRGBImageFilename)
×
340
        {
341
            setFilename(doc()->denormalizeComponentPath(root.readElementText()));
×
342
        }
343
        else if (root.name() == KXMLQLCRGBImageAnimationStyle)
×
344
        {
345
            setAnimationStyle(stringToAnimationStyle(root.readElementText()));
×
346
        }
347
        else if (root.name() == KXMLQLCRGBImageOffset)
×
348
        {
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);
×
357
            if (ok == true)
×
358
                setXOffset(value);
×
359
            else
360
                qWarning() << Q_FUNC_INFO << "Invalid X offset:" << str;
×
361

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

378
    return true;
379
}
380

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

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

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

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

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

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

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