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;
239 d->movie->jumpToFrame(0);
247
248
249
250
251
252
253
254
255
256int QQuickAnimatedImage::currentFrame()
const
258 Q_D(
const QQuickAnimatedImage);
260 return d->presetCurrentFrame;
261 return d->movie->currentFrameNumber();
264void QQuickAnimatedImage::setCurrentFrame(
int frame)
266 Q_D(QQuickAnimatedImage);
268 d->presetCurrentFrame = frame;
274 d->lastFrameNumber = frame;
275 d->movie->jumpToFrame(frame);
278int QQuickAnimatedImage::frameCount()
const
280 Q_D(
const QQuickAnimatedImage);
283 return d->movie->frameCount();
287
288
289
290
291
292
293
294
295qreal QQuickAnimatedImage::speed()
const
297 Q_D(
const QQuickAnimatedImage);
301void QQuickAnimatedImage::setSpeed(qreal speed)
303 Q_D(QQuickAnimatedImage);
304 if (d->speed != speed) {
307 d->movie->setSpeed(qRound(speed * 100.0));
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328int QQuickAnimatedImage::loops()
const
330 Q_D(
const QQuickAnimatedImage);
334void QQuickAnimatedImage::setLoops(
int loops)
336 Q_D(QQuickAnimatedImage);
337 if (loops < 0 && loops != Infinite) {
338 qmlWarning(
this) <<
"Loops must be AnimatedImage.Infinite, 0, or a positive integer, got"
342 if (d->loops == loops)
346 if (loops == 0 && d->movie && d->movie->state() != QMovie::NotRunning)
351
352
353
354
355
356
357
358
359
360
361
362
363
366
367
368
369
370
371
372
373
374QQuickAnimatedImage::FinishBehavior QQuickAnimatedImage::finishBehavior()
const
376 Q_D(
const QQuickAnimatedImage);
377 return d->finishBehavior;
380void QQuickAnimatedImage::setFinishBehavior(FinishBehavior behavior)
382 Q_D(QQuickAnimatedImage);
383 if (d->finishBehavior == behavior)
385 d->finishBehavior = behavior;
386 emit finishBehaviorChanged();
389void QQuickAnimatedImage::setSource(
const QUrl &url)
391 Q_D(QQuickAnimatedImage);
396 d->lastFrameNumber = 0;
398#if QT_CONFIG(qml_network)
400 d->reply->deleteLater();
405 d->setImage(QImage());
406 d->oldPlaying = isPlaying();
407 d->setMovie(
nullptr);
409 emit sourceChanged(d->url);
411 if (isComponentComplete())
415void QQuickAnimatedImage::load()
417 Q_D(QQuickAnimatedImage);
419 if (d->url.isEmpty()) {
422 d->setImage(QImage());
423 if (sourceSize() != d->oldSourceSize) {
424 d->oldSourceSize = sourceSize();
425 emit sourceSizeChanged();
429 if (isPlaying() != d->oldPlaying)
430 emit playingChanged();
432 const qreal targetDevicePixelRatio = d->effectiveDevicePixelRatio();
433 d->devicePixelRatio = 1.0;
435 const auto context = qmlContext(
this);
436 QUrl loadUrl = context ? context->resolvedUrl(d->url) : d->url;
437 const QUrl resolvedUrl = loadUrl;
438 resolve2xLocalFile(resolvedUrl, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
439 QString lf = QQmlFile::urlToLocalFileOrQrc(loadUrl);
444 d->setMovie(
new QMovie(lf));
445 movieRequestFinished();
447#if QT_CONFIG(qml_network)
451 d->setStatus(Loading);
453 QNetworkRequest req(d->url);
454 req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute,
true);
456 d->reply = qmlEngine(
this)->networkAccessManager()->get(req);
457 connect(d->reply, &QNetworkReply::finished,
this, &QQuickAnimatedImage::movieRequestFinished);
458 connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
this, SLOT(requestProgress(qint64,qint64)));
464void QQuickAnimatedImage::movieRequestFinished()
466 Q_D(QQuickAnimatedImage);
468#if QT_CONFIG(qml_network)
470 auto movie =
new QMovie(d->reply);
474 d->reply->disconnect(
this);
475 d->reply->setParent(movie);
482 if (!d->movie || !d->movie->isValid()) {
483 const QQmlContext *context = qmlContext(
this);
484 qmlWarning(
this) <<
"Error Reading Animated Image File "
485 << (context ? context->resolvedUrl(d->url) : d->url).toString();
486 d->setMovie(
nullptr);
488 d->setImage(QImage());
489 if (sourceSize() != d->oldSourceSize) {
490 d->oldSourceSize = sourceSize();
491 emit sourceSizeChanged();
497 if (isPlaying() != d->oldPlaying)
498 emit playingChanged();
502 connect(d->movie, &QMovie::stateChanged,
this, &QQuickAnimatedImage::playingStatusChanged);
503 connect(d->movie, &QMovie::frameChanged,
this, &QQuickAnimatedImage::movieUpdate);
504 connect(d->movie, &QMovie::finished,
this, &QQuickAnimatedImage::onMovieFinished);
506 d->movie->setCacheMode(QMovie::CacheAll);
507 d->movie->setSpeed(qRound(d->speed * 100.0));
511 bool pausedAtStart = d->paused;
512 if (d->movie && d->playing && d->loops != 0)
514 if (d->movie && pausedAtStart)
515 d->movie->setPaused(
true);
516 if (d->movie && (d->paused || !d->playing || d->loops == 0)) {
517 d->movie->jumpToFrame(d->presetCurrentFrame);
518 d->presetCurrentFrame = 0;
521 QQuickPixmap *pixmap = d->infoForCurrentFrame(qmlEngine(
this));
523 d->setPixmap(*pixmap);
524 if (sourceSize() != d->oldSourceSize) {
525 d->oldSourceSize = sourceSize();
526 emit sourceSizeChanged();
532 if (isPlaying() != d->oldPlaying)
533 emit playingChanged();
536void QQuickAnimatedImage::movieUpdate()
538 Q_D(QQuickAnimatedImage);
544 int currentFrame = d->movie->currentFrameNumber();
546 if (currentFrame < d->lastFrameNumber && d->lastFrameNumber > 0) {
548 if (d->loops != Infinite && d->currentLoop >= d->loops) {
549 d->handleLoopCompletion();
553 currentFrame = d->movie->currentFrameNumber();
556 d->lastFrameNumber = currentFrame;
557 d->setPixmap(*d->infoForCurrentFrame(qmlEngine(
this)));
558 emit QQuickImageBase::currentFrameChanged();
562void QQuickAnimatedImage::playingStatusChanged()
564 Q_D(QQuickAnimatedImage);
566 if ((d->movie->state() != QMovie::NotRunning) != d->playing) {
567 d->playing = (d->movie->state() != QMovie::NotRunning);
568 emit playingChanged();
570 if ((d->movie->state() == QMovie::Paused) != d->paused) {
571 d->paused = (d->movie->state() == QMovie::Paused);
572 emit pausedChanged();
577
578
579
580
581
582
583
584
585
586
588void QQuickAnimatedImage::onMovieFinished()
590 Q_D(QQuickAnimatedImage);
592 if (d->movie->frameCount() <= 1)
595 if (d->loops == Infinite || d->currentLoop < d->loops) {
597 d->lastFrameNumber = 0;
600 d->handleLoopCompletion();
604void QQuickAnimatedImage::onCacheChanged()
606 Q_D(QQuickAnimatedImage);
610 d->movie->setCacheMode(QMovie::CacheNone);
613 d->movie->setCacheMode(QMovie::CacheAll);
617void QQuickAnimatedImage::componentComplete()
619 QQuickItem::componentComplete();
628 Q_Q(QQuickAnimatedImage);
629 const int oldFrameCount = q->frameCount();
633 movie->deleteLater();
640 movie->setScaledSize(sourcesize);
642 if (oldFrameCount != q->frameCount())
643 emit q->frameCountChanged();
648#include "moc_qquickanimatedimage_p.cpp"
void handleLoopCompletion()
void setMovie(QMovie *movie)
Combined button and popup list for selecting options.