8#include <QtGui/qguiapplication.h>
9#include <QtQml/qqmlinfo.h>
10#include <QtQml/qqmlfile.h>
11#include <QtQml/qqmlengine.h>
12#include <QtGui/qmovie.h>
13#if QT_CONFIG(qml_network)
14#include <QtNetwork/qnetworkrequest.h>
15#include <QtNetwork/qnetworkreply.h>
20QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine)
25 int current = movie->currentFrameNumber();
26 if (!frameMap.contains(current)) {
28 QQuickPixmap *pixmap =
nullptr;
29 if (engine && !movie->fileName().isEmpty()) {
30 requestedUrl.setUrl(QString::fromUtf8(
"quickanimatedimage://%1#%2x%3#%4")
31 .arg(movie->fileName())
32 .arg(movie->scaledSize().width())
33 .arg(movie->scaledSize().height())
36 if (!requestedUrl.isEmpty()) {
37 if (QQuickPixmap::isCached(requestedUrl, QRect(), QSize(), 0, QQuickImageProviderOptions()))
38 pixmap =
new QQuickPixmap(engine, requestedUrl);
40 pixmap =
new QQuickPixmap(requestedUrl, movie->currentImage());
42 pixmap =
new QQuickPixmap;
43 pixmap->setImage(movie->currentImage());
45 frameMap.insert(current, pixmap);
48 return frameMap.value(current);
59 Q_Q(QQuickAnimatedImage);
60 const int targetFrame = (finishBehavior == QQuickAnimatedImage::FinishAtInitialFrame)
62 : qMax(movie->frameCount() - 1, 0);
65 movie->jumpToFrame(targetFrame);
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
120
121
122
123
124
125
126
127
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent)
150 : QQuickImage(*(
new QQuickAnimatedImagePrivate), parent)
152 connect(
this, &QQuickImageBase::cacheChanged,
this, &QQuickAnimatedImage::onCacheChanged);
153 connect(
this, &QQuickImageBase::currentFrameChanged,
this, &QQuickAnimatedImage::frameChanged);
154 connect(
this, &QQuickImageBase::currentFrameChanged,
this, &QQuickAnimatedImage::currentFrameChanged);
155 connect(
this, &QQuickImageBase::frameCountChanged,
this, &QQuickAnimatedImage::frameCountChanged);
158QQuickAnimatedImage::~QQuickAnimatedImage()
160 Q_D(QQuickAnimatedImage);
161#if QT_CONFIG(qml_network)
163 d->reply->deleteLater();
170
171
172
173
174
175
177bool QQuickAnimatedImage::isPaused()
const
179 Q_D(
const QQuickAnimatedImage);
182 return d->movie->state()==QMovie::Paused;
185void QQuickAnimatedImage::setPaused(
bool pause)
187 Q_D(QQuickAnimatedImage);
188 if (pause == d->paused)
192 emit pausedChanged();
194 d->movie->setPaused(pause);
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
216bool QQuickAnimatedImage::isPlaying()
const
218 Q_D(
const QQuickAnimatedImage);
221 return d->movie->state()!=QMovie::NotRunning;
224void QQuickAnimatedImage::setPlaying(
bool play)
226 Q_D(QQuickAnimatedImage);
227 if (play == d->playing)
231 emit playingChanged();
238 d->lastFrameNumber = 0;
246
247
248
249
250
251
252
253
254
255int QQuickAnimatedImage::currentFrame()
const
257 Q_D(
const QQuickAnimatedImage);
259 return d->presetCurrentFrame;
260 return d->movie->currentFrameNumber();
263void QQuickAnimatedImage::setCurrentFrame(
int frame)
265 Q_D(QQuickAnimatedImage);
267 d->presetCurrentFrame = frame;
273 d->lastFrameNumber = frame;
274 d->movie->jumpToFrame(frame);
277int QQuickAnimatedImage::frameCount()
const
279 Q_D(
const QQuickAnimatedImage);
282 return d->movie->frameCount();
286
287
288
289
290
291
292
293
294qreal QQuickAnimatedImage::speed()
const
296 Q_D(
const QQuickAnimatedImage);
300void QQuickAnimatedImage::setSpeed(qreal speed)
302 Q_D(QQuickAnimatedImage);
303 if (d->speed != speed) {
306 d->movie->setSpeed(qRound(speed * 100.0));
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327int QQuickAnimatedImage::loops()
const
329 Q_D(
const QQuickAnimatedImage);
333void QQuickAnimatedImage::setLoops(
int loops)
335 Q_D(QQuickAnimatedImage);
336 if (loops < 0 && loops != Infinite) {
337 qmlWarning(
this) <<
"Loops must be AnimatedImage.Infinite, 0, or a positive integer, got"
341 if (d->loops == loops)
345 if (loops == 0 && d->movie && d->movie->state() != QMovie::NotRunning)
350
351
352
353
354
355
356
357
358
359
360
361
362
365
366
367
368
369
370
371
372
373QQuickAnimatedImage::FinishBehavior QQuickAnimatedImage::finishBehavior()
const
375 Q_D(
const QQuickAnimatedImage);
376 return d->finishBehavior;
379void QQuickAnimatedImage::setFinishBehavior(FinishBehavior behavior)
381 Q_D(QQuickAnimatedImage);
382 if (d->finishBehavior == behavior)
384 d->finishBehavior = behavior;
385 emit finishBehaviorChanged();
388void QQuickAnimatedImage::setSource(
const QUrl &url)
390 Q_D(QQuickAnimatedImage);
395 d->lastFrameNumber = 0;
397#if QT_CONFIG(qml_network)
399 d->reply->deleteLater();
404 d->setImage(QImage());
405 d->oldPlaying = isPlaying();
406 d->setMovie(
nullptr);
408 emit sourceChanged(d->url);
410 if (isComponentComplete())
414void QQuickAnimatedImage::load()
416 Q_D(QQuickAnimatedImage);
418 if (d->url.isEmpty()) {
421 d->setImage(QImage());
422 if (sourceSize() != d->oldSourceSize) {
423 d->oldSourceSize = sourceSize();
424 emit sourceSizeChanged();
428 if (isPlaying() != d->oldPlaying)
429 emit playingChanged();
431 const qreal targetDevicePixelRatio = d->effectiveDevicePixelRatio();
432 d->devicePixelRatio = 1.0;
434 const auto context = qmlContext(
this);
435 QUrl loadUrl = context ? context->resolvedUrl(d->url) : d->url;
436 const QUrl resolvedUrl = loadUrl;
437 resolve2xLocalFile(resolvedUrl, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
438 QString lf = QQmlFile::urlToLocalFileOrQrc(loadUrl);
443 d->setMovie(
new QMovie(lf));
444 movieRequestFinished();
446#if QT_CONFIG(qml_network)
450 d->setStatus(Loading);
452 QNetworkRequest req(d->url);
453 req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute,
true);
455 d->reply = qmlEngine(
this)->networkAccessManager()->get(req);
456 connect(d->reply, &QNetworkReply::finished,
this, &QQuickAnimatedImage::movieRequestFinished);
457 connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
this, SLOT(requestProgress(qint64,qint64)));
463void QQuickAnimatedImage::movieRequestFinished()
465 Q_D(QQuickAnimatedImage);
467#if QT_CONFIG(qml_network)
469 auto movie =
new QMovie(d->reply);
473 d->reply->disconnect(
this);
474 d->reply->setParent(movie);
481 if (!d->movie || !d->movie->isValid()) {
482 const QQmlContext *context = qmlContext(
this);
483 qmlWarning(
this) <<
"Error Reading Animated Image File "
484 << (context ? context->resolvedUrl(d->url) : d->url).toString();
485 d->setMovie(
nullptr);
487 d->setImage(QImage());
488 if (sourceSize() != d->oldSourceSize) {
489 d->oldSourceSize = sourceSize();
490 emit sourceSizeChanged();
496 if (isPlaying() != d->oldPlaying)
497 emit playingChanged();
501 connect(d->movie, &QMovie::stateChanged,
this, &QQuickAnimatedImage::playingStatusChanged);
502 connect(d->movie, &QMovie::frameChanged,
this, &QQuickAnimatedImage::movieUpdate);
503 connect(d->movie, &QMovie::finished,
this, &QQuickAnimatedImage::onMovieFinished);
505 d->movie->setCacheMode(QMovie::CacheAll);
506 d->movie->setSpeed(qRound(d->speed * 100.0));
510 bool pausedAtStart = d->paused;
511 if (d->movie && d->playing && d->loops != 0)
513 if (d->movie && pausedAtStart)
514 d->movie->setPaused(
true);
515 if (d->movie && (d->paused || !d->playing || d->loops == 0)) {
516 d->movie->jumpToFrame(d->presetCurrentFrame);
517 d->presetCurrentFrame = 0;
520 QQuickPixmap *pixmap = d->infoForCurrentFrame(qmlEngine(
this));
522 d->setPixmap(*pixmap);
523 if (sourceSize() != d->oldSourceSize) {
524 d->oldSourceSize = sourceSize();
525 emit sourceSizeChanged();
531 if (isPlaying() != d->oldPlaying)
532 emit playingChanged();
535void QQuickAnimatedImage::movieUpdate()
537 Q_D(QQuickAnimatedImage);
543 int currentFrame = d->movie->currentFrameNumber();
545 if (currentFrame < d->lastFrameNumber && d->lastFrameNumber > 0) {
547 if (d->loops != Infinite && d->currentLoop >= d->loops) {
548 d->handleLoopCompletion();
552 currentFrame = d->movie->currentFrameNumber();
555 d->lastFrameNumber = currentFrame;
556 d->setPixmap(*d->infoForCurrentFrame(qmlEngine(
this)));
557 emit QQuickImageBase::currentFrameChanged();
561void QQuickAnimatedImage::playingStatusChanged()
563 Q_D(QQuickAnimatedImage);
565 if ((d->movie->state() != QMovie::NotRunning) != d->playing) {
566 d->playing = (d->movie->state() != QMovie::NotRunning);
567 emit playingChanged();
569 if ((d->movie->state() == QMovie::Paused) != d->paused) {
570 d->paused = (d->movie->state() == QMovie::Paused);
571 emit pausedChanged();
576
577
578
579
580
581
582
583
584
585
587void QQuickAnimatedImage::onMovieFinished()
589 Q_D(QQuickAnimatedImage);
591 if (d->movie->frameCount() <= 1)
593 if (d->loops == Infinite || d->currentLoop < d->loops) {
595 d->lastFrameNumber = 0;
598 d->handleLoopCompletion();
602void QQuickAnimatedImage::onCacheChanged()
604 Q_D(QQuickAnimatedImage);
608 d->movie->setCacheMode(QMovie::CacheNone);
611 d->movie->setCacheMode(QMovie::CacheAll);
615void QQuickAnimatedImage::componentComplete()
617 QQuickItem::componentComplete();
626 Q_Q(QQuickAnimatedImage);
627 const int oldFrameCount = q->frameCount();
631 movie->deleteLater();
638 movie->setScaledSize(sourcesize);
640 if (oldFrameCount != q->frameCount())
641 emit q->frameCountChanged();
646#include "moc_qquickanimatedimage_p.cpp"
void handleLoopCompletion()
void setMovie(QMovie *movie)
Combined button and popup list for selecting options.