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()) {
420 d->loadedForDevicePixelRatio = 0;
423 d->setImage(QImage());
424 if (sourceSize() != d->oldSourceSize) {
425 d->oldSourceSize = sourceSize();
426 emit sourceSizeChanged();
430 if (isPlaying() != d->oldPlaying)
431 emit playingChanged();
433 const qreal targetDevicePixelRatio = d->devicePixelRatioForLoading();
434 d->devicePixelRatio = 1.0;
436 const auto context = qmlContext(
this);
437 QUrl loadUrl = context ? context->resolvedUrl(d->url) : d->url;
438 const QUrl resolvedUrl = loadUrl;
439 resolve2xLocalFile(resolvedUrl, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
440 QString lf = QQmlFile::urlToLocalFileOrQrc(loadUrl);
445 d->setMovie(
new QMovie(lf));
446 movieRequestFinished();
448#if QT_CONFIG(qml_network)
452 d->setStatus(Loading);
454 QNetworkRequest req(d->url);
455 req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute,
true);
457 d->reply = qmlEngine(
this)->networkAccessManager()->get(req);
458 connect(d->reply, &QNetworkReply::finished,
this, &QQuickAnimatedImage::movieRequestFinished);
459 connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
this, SLOT(requestProgress(qint64,qint64)));
465void QQuickAnimatedImage::movieRequestFinished()
467 Q_D(QQuickAnimatedImage);
469#if QT_CONFIG(qml_network)
471 auto movie =
new QMovie(d->reply);
475 d->reply->disconnect(
this);
476 d->reply->setParent(movie);
483 if (!d->movie || !d->movie->isValid()) {
484 const QQmlContext *context = qmlContext(
this);
485 qmlWarning(
this) <<
"Error Reading Animated Image File "
486 << (context ? context->resolvedUrl(d->url) : d->url).toString();
487 d->setMovie(
nullptr);
489 d->setImage(QImage());
490 if (sourceSize() != d->oldSourceSize) {
491 d->oldSourceSize = sourceSize();
492 emit sourceSizeChanged();
498 if (isPlaying() != d->oldPlaying)
499 emit playingChanged();
503 connect(d->movie, &QMovie::stateChanged,
this, &QQuickAnimatedImage::playingStatusChanged);
504 connect(d->movie, &QMovie::frameChanged,
this, &QQuickAnimatedImage::movieUpdate);
505 connect(d->movie, &QMovie::finished,
this, &QQuickAnimatedImage::onMovieFinished);
507 d->movie->setCacheMode(QMovie::CacheAll);
508 d->movie->setSpeed(qRound(d->speed * 100.0));
512 bool pausedAtStart = d->paused;
513 if (d->movie && d->playing && d->loops != 0)
515 if (d->movie && pausedAtStart)
516 d->movie->setPaused(
true);
517 if (d->movie && (d->paused || !d->playing || d->loops == 0)) {
518 d->movie->jumpToFrame(d->presetCurrentFrame);
519 d->presetCurrentFrame = 0;
522 QQuickPixmap *pixmap = d->infoForCurrentFrame(qmlEngine(
this));
524 d->setPixmap(*pixmap);
525 if (sourceSize() != d->oldSourceSize) {
526 d->oldSourceSize = sourceSize();
527 emit sourceSizeChanged();
533 if (isPlaying() != d->oldPlaying)
534 emit playingChanged();
537void QQuickAnimatedImage::movieUpdate()
539 Q_D(QQuickAnimatedImage);
545 int currentFrame = d->movie->currentFrameNumber();
547 if (currentFrame < d->lastFrameNumber && d->lastFrameNumber > 0) {
549 if (d->loops != Infinite && d->currentLoop >= d->loops) {
550 d->handleLoopCompletion();
554 currentFrame = d->movie->currentFrameNumber();
557 d->lastFrameNumber = currentFrame;
558 d->setPixmap(*d->infoForCurrentFrame(qmlEngine(
this)));
559 emit QQuickImageBase::currentFrameChanged();
563void QQuickAnimatedImage::playingStatusChanged()
565 Q_D(QQuickAnimatedImage);
567 if ((d->movie->state() != QMovie::NotRunning) != d->playing) {
568 d->playing = (d->movie->state() != QMovie::NotRunning);
569 emit playingChanged();
571 if ((d->movie->state() == QMovie::Paused) != d->paused) {
572 d->paused = (d->movie->state() == QMovie::Paused);
573 emit pausedChanged();
578
579
580
581
582
583
584
585
586
587
589void QQuickAnimatedImage::onMovieFinished()
591 Q_D(QQuickAnimatedImage);
593 if (d->movie->frameCount() <= 1)
596 if (d->loops == Infinite || d->currentLoop < d->loops) {
598 d->lastFrameNumber = 0;
601 d->handleLoopCompletion();
605void QQuickAnimatedImage::onCacheChanged()
607 Q_D(QQuickAnimatedImage);
611 d->movie->setCacheMode(QMovie::CacheNone);
614 d->movie->setCacheMode(QMovie::CacheAll);
618void QQuickAnimatedImage::componentComplete()
620 QQuickItem::componentComplete();
629 Q_Q(QQuickAnimatedImage);
630 const int oldFrameCount = q->frameCount();
634 movie->deleteLater();
643 movie->setScaledSize(sourcesize);
645 if (oldFrameCount != q->frameCount())
646 emit q->frameCountChanged();
651#include "moc_qquickanimatedimage_p.cpp"
void handleLoopCompletion()
void setMovie(QMovie *movie)
Combined button and popup list for selecting options.