Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qmnghandler.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qmnghandler_p.h"
5
6#include "qimage.h"
7#include "qvariant.h"
8#include "qcolor.h"
9
10#define MNG_USE_SO
11#include <libmng.h>
12
14
16{
17 Q_DECLARE_PUBLIC(QMngHandler)
18 public:
21 mng_handle hMNG;
29 mng_uint32 iStyle;
30 mng_bool readData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pRead);
31 mng_bool writeData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pWritten);
32 mng_bool processHeader(mng_uint32 iWidth, mng_uint32 iHeight);
36 bool writeImage(const QImage &image);
37 int currentImageNumber() const;
38 int imageCount() const;
39 bool jumpToImage(int imageNumber);
40 bool jumpToNextImage();
41 int nextImageDelay() const;
42 bool setBackgroundColor(const QColor &color);
43 QColor backgroundColor() const;
45};
46
47static mng_bool MNG_DECL myerror(mng_handle /*hMNG*/,
48 mng_int32 iErrorcode,
49 mng_int8 /*iSeverity*/,
50 mng_chunkid iChunkname,
51 mng_uint32 /*iChunkseq*/,
52 mng_int32 iExtra1,
53 mng_int32 iExtra2,
54 mng_pchar zErrortext)
55{
56 qWarning("MNG error %d: %s; chunk %c%c%c%c; subcode %d:%d",
57 iErrorcode,zErrortext,
58 (iChunkname>>24)&0xff,
59 (iChunkname>>16)&0xff,
60 (iChunkname>>8)&0xff,
61 (iChunkname>>0)&0xff,
62 iExtra1,iExtra2);
63 return MNG_TRUE;
64}
65
66static mng_ptr MNG_DECL myalloc(mng_size_t iSize)
67{
68 return (mng_ptr)calloc(1, iSize);
69}
70
71static void MNG_DECL myfree(mng_ptr pPtr, mng_size_t /*iSize*/)
72{
73 free(pPtr);
74}
75
76static mng_bool MNG_DECL myopenstream(mng_handle)
77{
78 return MNG_TRUE;
79}
80
81static mng_bool MNG_DECL myclosestream(mng_handle hMNG)
82{
83 QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
84 pMydata->haveReadAll = true;
85 return MNG_TRUE;
86}
87
88static mng_bool MNG_DECL myreaddata(mng_handle hMNG,
89 mng_ptr pBuf,
90 mng_uint32 iSize,
91 mng_uint32p pRead)
92{
93 QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
94 return pMydata->readData(pBuf, iSize, pRead);
95}
96
97static mng_bool MNG_DECL mywritedata(mng_handle hMNG,
98 mng_ptr pBuf,
99 mng_uint32 iSize,
100 mng_uint32p pWritten)
101{
102 QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
103 return pMydata->writeData(pBuf, iSize, pWritten);
104}
105
106static mng_bool MNG_DECL myprocessheader(mng_handle hMNG,
107 mng_uint32 iWidth,
108 mng_uint32 iHeight)
109{
110 QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
111 return pMydata->processHeader(iWidth, iHeight);
112}
113
114static mng_ptr MNG_DECL mygetcanvasline(mng_handle hMNG,
115 mng_uint32 iLinenr)
116{
117 QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
118 return (mng_ptr)pMydata->image.scanLine(iLinenr);
119}
120
121static mng_bool MNG_DECL myrefresh(mng_handle /*hMNG*/,
122 mng_uint32 /*iX*/,
123 mng_uint32 /*iY*/,
124 mng_uint32 /*iWidth*/,
125 mng_uint32 /*iHeight*/)
126{
127 return MNG_TRUE;
128}
129
130static mng_uint32 MNG_DECL mygettickcount(mng_handle hMNG)
131{
132 QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
133 return pMydata->elapsed++;
134}
135
136static mng_bool MNG_DECL mysettimer(mng_handle hMNG,
137 mng_uint32 iMsecs)
138{
139 QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
140 pMydata->elapsed += iMsecs;
141 pMydata->nextDelay = iMsecs;
142 return MNG_TRUE;
143}
144
145static mng_bool MNG_DECL myprocessterm(mng_handle hMNG,
146 mng_uint8 iTermaction,
147 mng_uint8 /*iIteraction*/,
148 mng_uint32 /*iDelay*/,
149 mng_uint32 iItermax)
150{
151 QMngHandlerPrivate *pMydata = reinterpret_cast<QMngHandlerPrivate *>(mng_get_userdata(hMNG));
152 if (iTermaction == 3)
153 pMydata->iterCount = iItermax;
154 return MNG_TRUE;
155}
156
157static mng_bool MNG_DECL mytrace(mng_handle,
158 mng_int32 iFuncnr,
159 mng_int32 iFuncseq,
160 mng_pchar zFuncname)
161{
162 qDebug("mng trace: iFuncnr: %d iFuncseq: %d zFuncname: %s", iFuncnr, iFuncseq, zFuncname);
163 return MNG_TRUE;
164}
165
167 : haveReadNone(true), haveReadAll(false), elapsed(0), nextDelay(0), iterCount(1),
168 frameIndex(-1), nextIndex(0), frameCount(0), q_ptr(q_ptr)
169{
170 iStyle = (QSysInfo::ByteOrder == QSysInfo::LittleEndian) ? MNG_CANVAS_BGRA8 : MNG_CANVAS_ARGB8;
171 // Initialize libmng
172 hMNG = mng_initialize((mng_ptr)this, myalloc, myfree, mytrace);
173 if (hMNG) {
174 // Set callback functions
175 mng_setcb_errorproc(hMNG, myerror);
176 mng_setcb_openstream(hMNG, myopenstream);
177 mng_setcb_closestream(hMNG, myclosestream);
178 mng_setcb_readdata(hMNG, myreaddata);
179 mng_setcb_writedata(hMNG, mywritedata);
180 mng_setcb_processheader(hMNG, myprocessheader);
181 mng_setcb_getcanvasline(hMNG, mygetcanvasline);
182 mng_setcb_refresh(hMNG, myrefresh);
183 mng_setcb_gettickcount(hMNG, mygettickcount);
184 mng_setcb_settimer(hMNG, mysettimer);
185 mng_setcb_processterm(hMNG, myprocessterm);
186 mng_set_doprogressive(hMNG, MNG_FALSE);
187 mng_set_suspensionmode(hMNG, MNG_TRUE);
188 }
189}
190
192{
193 mng_cleanup(&hMNG);
194}
195
196mng_bool QMngHandlerPrivate::readData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pRead)
197{
198 Q_Q(QMngHandler);
199 *pRead = q->device()->read((char *)pBuf, iSize);
200 return (*pRead > 0) ? MNG_TRUE : MNG_FALSE;
201}
202
203mng_bool QMngHandlerPrivate::writeData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pWritten)
204{
205 Q_Q(QMngHandler);
206 *pWritten = q->device()->write((char *)pBuf, iSize);
207 return MNG_TRUE;
208}
209
210mng_bool QMngHandlerPrivate::processHeader(mng_uint32 iWidth, mng_uint32 iHeight)
211{
212 if (mng_set_canvasstyle(hMNG, iStyle) != MNG_NOERROR)
213 return MNG_FALSE;
215 return MNG_FALSE;
216 image.fill(0);
217 return MNG_TRUE;
218}
219
221{
222 mng_retcode ret;
223 const bool savedHaveReadAll = haveReadAll;
224 if (haveReadNone) {
225 haveReadNone = false;
226 ret = mng_readdisplay(hMNG);
227 } else {
228 ret = mng_display_resume(hMNG);
229 }
230 if ((MNG_NOERROR == ret) || (MNG_NEEDTIMERWAIT == ret)) {
231 *result = image;
232
233 // QTBUG-28894 -- libmng produces an extra frame at the end
234 // of the animation on the first loop only.
235 if (nextDelay == 1 && (!savedHaveReadAll && haveReadAll)) {
236 ret = mng_display_resume(hMNG);
237 }
238
240 if (haveReadAll && (frameCount == 0))
242 return true;
243 }
244 return false;
245}
246
248{
249 mng_reset(hMNG);
250 if (mng_create(hMNG) != MNG_NOERROR)
251 return false;
252
253 this->image = image.convertToFormat(QImage::Format_ARGB32);
254 int w = image.width();
255 int h = image.height();
256
257 if (
258 // width, height, ticks, layercount, framecount, playtime, simplicity
259 (mng_putchunk_mhdr(hMNG, w, h, 1000, 0, 0, 0, 7) == MNG_NOERROR) &&
260 // termination_action, action_after_iterations, delay, iteration_max
261 (mng_putchunk_term(hMNG, 3, 0, 1, 0x7FFFFFFF) == MNG_NOERROR) &&
262 // width, height, bitdepth, colortype, compression, filter, interlace
263 (mng_putchunk_ihdr(hMNG, w, h, 8, 6, 0, 0, 0) == MNG_NOERROR) &&
264 // width, height, colortype, bitdepth, compression, filter, interlace, canvasstyle, getcanvasline
265 (mng_putimgdata_ihdr(hMNG, w, h, 6, 8, 0, 0, 0, iStyle, mygetcanvasline) == MNG_NOERROR) &&
266 (mng_putchunk_iend(hMNG) == MNG_NOERROR) &&
267 (mng_putchunk_mend(hMNG) == MNG_NOERROR) &&
268 (mng_write(hMNG) == MNG_NOERROR)
269 )
270 return true;
271 return false;
272}
273
275{
276// return mng_get_currentframe(hMNG) % imageCount(); not implemented, apparently
277 return frameIndex;
278}
279
281{
282// return mng_get_totalframes(hMNG); not implemented, apparently
283 if (haveReadAll)
284 return frameCount;
285 return 0; // Don't know
286}
287
289{
290 if (imageNumber == nextIndex)
291 return true;
292
293 if ((imageNumber == 0) && haveReadAll && (nextIndex == frameCount)) {
294 // Loop!
295 nextIndex = 0;
296 return true;
297 }
298 if (mng_display_freeze(hMNG) == MNG_NOERROR) {
299 if (mng_display_goframe(hMNG, imageNumber) == MNG_NOERROR) {
300 nextIndex = imageNumber;
301 return true;
302 }
303 }
304 return false;
305}
306
308{
309 const int numImages = imageCount();
310 return numImages > 1 && jumpToImage((currentImageNumber() + 1) % numImages);
311}
312
314{
315 return nextDelay;
316}
317
319{
320 mng_uint16 iRed = (mng_uint16)(color.red() << 8);
321 mng_uint16 iBlue = (mng_uint16)(color.blue() << 8);
322 mng_uint16 iGreen = (mng_uint16)(color.green() << 8);
323 return (mng_set_bgcolor(hMNG, iRed, iBlue, iGreen) == MNG_NOERROR);
324}
325
327{
328 mng_uint16 iRed;
329 mng_uint16 iBlue;
330 mng_uint16 iGreen;
331 if (mng_get_bgcolor(hMNG, &iRed, &iBlue, &iGreen) == MNG_NOERROR)
332 return QColor((iRed >> 8) & 0xFF, (iGreen >> 8) & 0xFF, (iBlue >> 8) & 0xFF);
333 return QColor();
334}
335
340
344
347{
348 Q_D(const QMngHandler);
349 if ((!d->haveReadNone
350 && (!d->haveReadAll || (d->haveReadAll && (d->nextIndex < d->frameCount))))
351 || canRead(device()))
352 {
353 setFormat("mng");
354 return true;
355 }
356 return false;
357}
358
361{
362 if (!device) {
363 qWarning("QMngHandler::canRead() called with no device");
364 return false;
365 }
366
367 return device->peek(8) == "\x8A\x4D\x4E\x47\x0D\x0A\x1A\x0A";
368}
369
372{
373 Q_D(QMngHandler);
374 return canRead() ? d->getNextImage(image) : false;
375}
376
379{
380 Q_D(QMngHandler);
381 return d->writeImage(image);
382}
383
386{
387 Q_D(const QMngHandler);
388 return d->currentImageNumber();
389}
390
393{
394 Q_D(const QMngHandler);
395 return d->imageCount();
396}
397
399bool QMngHandler::jumpToImage(int imageNumber)
400{
401 Q_D(QMngHandler);
402 return d->jumpToImage(imageNumber);
403}
404
407{
408 Q_D(QMngHandler);
409 return d->jumpToNextImage();
410}
411
414{
415 Q_D(const QMngHandler);
416 if (d->iterCount == 0x7FFFFFFF)
417 return -1; // infinite loop
418 return d->iterCount-1;
419}
420
423{
424 Q_D(const QMngHandler);
425 return d->nextImageDelay();
426}
427
430{
431 Q_D(const QMngHandler);
433 return true;
435 return d->backgroundColor();
436 return QVariant();
437}
438
441{
442 Q_D(QMngHandler);
444 d->setBackgroundColor(qvariant_cast<QColor>(value));
445}
446
449{
451 return true;
453 return true;
454 return false;
455}
456
IOBluetoothDevice * device
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
\inmodule QtCore \reentrant
Definition qiodevice.h:34
qint64 peek(char *data, qint64 maxlen)
ImageOption
This enum describes the different options supported by QImageIOHandler.
static bool allocateImage(QSize size, QImage::Format format, QImage *image)
QIODevice * device() const
Returns the device currently assigned to the QImageIOHandler.
void setFormat(const QByteArray &format)
Sets the format of the QImageIOHandler to format.
\inmodule QtGui
Definition qimage.h:37
uchar * scanLine(int)
Returns a pointer to the pixel data at the scanline with index i.
Definition qimage.cpp:1637
@ Format_ARGB32
Definition qimage.h:47
QMngHandler * q_ptr
int imageCount() const
mng_bool processHeader(mng_uint32 iWidth, mng_uint32 iHeight)
QColor backgroundColor() const
mng_bool writeData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pWritten)
int nextImageDelay() const
QMngHandlerPrivate(QMngHandler *q_ptr)
mng_bool readData(mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pRead)
int currentImageNumber() const
bool setBackgroundColor(const QColor &color)
bool writeImage(const QImage &image)
bool jumpToImage(int imageNumber)
bool getNextImage(QImage *result)
int imageCount() const override
\reimp
bool supportsOption(ImageOption option) const override
\reimp
bool read(QImage *image) override
\reimp
int loopCount() const override
\reimp
bool jumpToNextImage() override
\reimp
QVariant option(ImageOption option) const override
\reimp
void setOption(ImageOption option, const QVariant &value) override
\reimp
int currentImageNumber() const override
\reimp
int nextImageDelay() const override
\reimp
bool write(const QImage &image) override
\reimp
bool canRead() const override
\reimp
bool jumpToImage(int imageNumber) override
\reimp
\inmodule QtCore
Definition qsize.h:25
@ ByteOrder
Definition qsysinfo.h:34
@ LittleEndian
Definition qsysinfo.h:30
\inmodule QtCore
Definition qvariant.h:65
#define this
Definition dialogs.cpp:9
Combined button and popup list for selecting options.
Definition image.cpp:4
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
return ret
static mng_bool MNG_DECL myprocessheader(mng_handle hMNG, mng_uint32 iWidth, mng_uint32 iHeight)
static mng_ptr MNG_DECL mygetcanvasline(mng_handle hMNG, mng_uint32 iLinenr)
static mng_uint32 MNG_DECL mygettickcount(mng_handle hMNG)
static mng_bool MNG_DECL myprocessterm(mng_handle hMNG, mng_uint8 iTermaction, mng_uint8, mng_uint32, mng_uint32 iItermax)
static mng_bool MNG_DECL mysettimer(mng_handle hMNG, mng_uint32 iMsecs)
static mng_bool MNG_DECL myreaddata(mng_handle hMNG, mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pRead)
static mng_ptr MNG_DECL myalloc(mng_size_t iSize)
static mng_bool MNG_DECL mywritedata(mng_handle hMNG, mng_ptr pBuf, mng_uint32 iSize, mng_uint32p pWritten)
static mng_bool MNG_DECL myclosestream(mng_handle hMNG)
static mng_bool MNG_DECL myopenstream(mng_handle)
static mng_bool MNG_DECL myrefresh(mng_handle, mng_uint32, mng_uint32, mng_uint32, mng_uint32)
static mng_bool MNG_DECL mytrace(mng_handle, mng_int32 iFuncnr, mng_int32 iFuncseq, mng_pchar zFuncname)
static mng_bool MNG_DECL myerror(mng_handle, mng_int32 iErrorcode, mng_int8, mng_chunkid iChunkname, mng_uint32, mng_int32 iExtra1, mng_int32 iExtra2, mng_pchar zErrortext)
static void MNG_DECL myfree(mng_ptr pPtr, mng_size_t)
GLfloat GLfloat GLfloat w
[0]
GLuint color
[2]
GLfloat GLfloat GLfloat GLfloat h
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLuint GLenum option
static double elapsed(qint64 after, qint64 before)
QByteArray readData()