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

mcallegari / qlcplus / 8440834527

26 Mar 2024 06:08PM UTC coverage: 31.709% (-0.4%) from 32.081%
8440834527

Pull #1422

github

web-flow
Merge 34f746340 into 7e2ec9324
Pull Request #1422: RgbScript make stage colors available to scripts

50 of 898 new or added lines in 11 files covered. (5.57%)

9 existing lines in 4 files now uncovered.

15408 of 48592 relevant lines covered (31.71%)

22631.0 hits per line

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

3.7
/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)
7✔
38
    : RGBAlgorithm(doc)
39
    , m_filename("")
40
    , m_animatedSource(false)
41
    , m_animationStyle(Static)
42
    , m_xOffset(0)
43
    , m_yOffset(0)
7✔
44
{
45
}
7✔
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()
7✔
59
{
60
}
7✔
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::rgbMap(const QSize& size, uint rgb, int step, RGBMap &map, uint (&rawColors)[RGBAlgorithmRawColorCount])
×
239
{
240
    Q_UNUSED(rgb);
241
    Q_UNUSED(rawColors);
242

243
    QMutexLocker locker(&m_mutex);
×
244

245
    if (m_animatedSource == false && (m_image.width() == 0 || m_image.height() == 0))
×
246
        return;
×
247

248
    int xOffs = xOffset();
×
249
    int yOffs = yOffset();
×
250

251
    switch(animationStyle())
×
252
    {
253
        default:
×
254
        case Static:
255
        break;
×
256
        case Horizontal:
×
257
            xOffs += step;
×
258
        break;
×
259
        case Vertical:
×
260
            yOffs += step;
×
261
        break;
×
262
        case Animation:
×
263
            xOffs += step * size.width();
×
264
        break;
×
265
    }
266

267
    if (m_animatedSource)
×
268
    {
269
        m_animatedPlayer.jumpToNextFrame();
×
270
        m_image = m_animatedPlayer.currentImage().scaled(size);
×
271
    }
272

273
    map.resize(size.height());
×
274
    for (int y = 0; y < size.height(); y++)
×
275
    {
276
        map[y].resize(size.width());
×
277
        for (int x = 0; x < size.width(); x++)
×
278
        {
279
            int x1 = (x + xOffs) % m_image.width();
×
280
            int y1 = (y + yOffs) % m_image.height();
×
281

282
            map[y][x] = m_image.pixel(x1,y1);
×
283
            if (qAlpha(map[y][x]) == 0)
×
284
                map[y][x] = 0;
×
285
        }
286
    }
287
}
288

289
QString RGBImage::name() const
6✔
290
{
291
    return QString("Image");
6✔
292
}
293

294
QString RGBImage::author() const
×
295
{
296
    return QString("Jano Svitok");
×
297
}
298

299
int RGBImage::apiVersion() const
×
300
{
301
    return 1;
×
302
}
303

304
RGBAlgorithm::Type RGBImage::type() const
×
305
{
306
    return RGBAlgorithm::Image;
×
307
}
308

309
int RGBImage::acceptColors() const
×
310
{
311
    return 0;
×
312
}
313

314
bool RGBImage::loadXML(QXmlStreamReader &root)
×
315
{
316
    if (root.name() != KXMLQLCRGBAlgorithm)
×
317
    {
318
        qWarning() << Q_FUNC_INFO << "RGB Algorithm node not found";
×
319
        return false;
×
320
    }
321

322
    if (root.attributes().value(KXMLQLCRGBAlgorithmType).toString() != KXMLQLCRGBImage)
×
323
    {
324
        qWarning() << Q_FUNC_INFO << "RGB Algorithm is not Image";
×
325
        return false;
×
326
    }
327

328
    while (root.readNextStartElement())
×
329
    {
330
        if (root.name() == KXMLQLCRGBImageFilename)
×
331
        {
332
            setFilename(doc()->denormalizeComponentPath(root.readElementText()));
×
333
        }
334
        else if (root.name() == KXMLQLCRGBImageAnimationStyle)
×
335
        {
336
            setAnimationStyle(stringToAnimationStyle(root.readElementText()));
×
337
        }
338
        else if (root.name() == KXMLQLCRGBImageOffset)
×
339
        {
340
            QString str;
×
341
            int value;
342
            bool ok;
343
            QXmlStreamAttributes attrs = root.attributes();
×
344

345
            str = attrs.value(KXMLQLCRGBImageOffsetX).toString();
×
346
            ok = false;
×
347
            value = str.toInt(&ok);
×
348
            if (ok == true)
×
349
                setXOffset(value);
×
350
            else
351
                qWarning() << Q_FUNC_INFO << "Invalid X offset:" << str;
×
352

353
            str = attrs.value(KXMLQLCRGBImageOffsetY).toString();
×
354
            ok = false;
×
355
            value = str.toInt(&ok);
×
356
            if (ok == true)
×
357
                setYOffset(value);
×
358
            else
359
                qWarning() << Q_FUNC_INFO << "Invalid Y offset:" << str;
×
360
            root.skipCurrentElement();
×
361
        }
362
        else
363
        {
364
            qWarning() << Q_FUNC_INFO << "Unknown RGBImage tag:" << root.name();
×
365
            root.skipCurrentElement();
×
366
        }
367
    }
368

369
    return true;
×
370
}
371

372
bool RGBImage::saveXML(QXmlStreamWriter *doc) const
×
373
{
374
    Q_ASSERT(doc != NULL);
×
375

376
    doc->writeStartElement(KXMLQLCRGBAlgorithm);
×
377
    doc->writeAttribute(KXMLQLCRGBAlgorithmType, KXMLQLCRGBImage);
×
378

379
    doc->writeTextElement(KXMLQLCRGBImageFilename, this->doc()->normalizeComponentPath(m_filename));
×
380

381
    doc->writeTextElement(KXMLQLCRGBImageAnimationStyle, animationStyleToString(animationStyle()));
×
382

383
    doc->writeStartElement(KXMLQLCRGBImageOffset);
×
384
    doc->writeAttribute(KXMLQLCRGBImageOffsetX, QString::number(xOffset()));
×
385
    doc->writeAttribute(KXMLQLCRGBImageOffsetY, QString::number(yOffset()));
×
386
    doc->writeEndElement();
×
387

388
    /* End the <Algorithm> tag */
389
    doc->writeEndElement();
×
390

391
    return true;
×
392
}
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