From 5c496ad9527487a0d9d33ac0882fab439c993b02 Mon Sep 17 00:00:00 2001 From: Vladimir Belyavsky Date: Sat, 10 Dec 2022 18:20:46 +0300 Subject: AnimatedImage: Add ability to configure sourceSize This allows to reduce memory consumption and improve performance when you need to load and play hi-res GIF files or animated SVG. [ChangeLog][QtQuick][AnimatedImage] It's now possible to configure sourceSize property for AnimatedImage. This might be useful when you need e.g. to play hi-res GIF files in some smaller size. Fixes: QTBUG-57501 Change-Id: I26d464855bbc20e155a8fb589a48842986a3dea4 Reviewed-by: Shawn Rutledge --- src/quick/items/qquickanimatedimage.cpp | 64 +++++++++++----------- src/quick/items/qquickanimatedimage_p.h | 3 - src/quick/items/qquickanimatedimage_p_p.h | 3 +- .../qquickanimatedimage/data/stickmanerror1.qml | 6 -- .../data/stickmansourcesized.qml | 6 ++ .../tst_qquickanimatedimage.cpp | 17 ++++-- 6 files changed, 51 insertions(+), 48 deletions(-) delete mode 100644 tests/auto/quick/qquickanimatedimage/data/stickmanerror1.qml create mode 100644 tests/auto/quick/qquickanimatedimage/data/stickmansourcesized.qml diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp index d40a440d94..7d08782aab 100644 --- a/src/quick/items/qquickanimatedimage.cpp +++ b/src/quick/items/qquickanimatedimage.cpp @@ -26,8 +26,10 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine QUrl requestedUrl; QQuickPixmap *pixmap = nullptr; if (engine && !movie->fileName().isEmpty()) { - requestedUrl.setUrl(QString::fromUtf8("quickanimatedimage://%1#%2") + requestedUrl.setUrl(QString::fromUtf8("quickanimatedimage://%1#%2x%3#%4") .arg(movie->fileName()) + .arg(movie->scaledSize().width()) + .arg(movie->scaledSize().height()) .arg(current)); } if (!requestedUrl.isEmpty()) { @@ -289,14 +291,14 @@ void QQuickAnimatedImage::load() } d->setImage(QImage()); + if (sourceSize() != d->oldSourceSize) { + d->oldSourceSize = sourceSize(); + emit sourceSizeChanged(); + } + d->status = Null; emit statusChanged(d->status); - d->currentSourceSize = QSize(0, 0); - if (d->currentSourceSize != d->oldSourceSize) { - d->oldSourceSize = d->currentSourceSize; - emit sourceSizeChanged(); - } if (isPlaying() != d->oldPlaying) emit playingChanged(); } else { @@ -337,7 +339,6 @@ void QQuickAnimatedImage::load() void QQuickAnimatedImage::movieRequestFinished() { - Q_D(QQuickAnimatedImage); #if QT_CONFIG(qml_network) @@ -363,19 +364,21 @@ void QQuickAnimatedImage::movieRequestFinished() qmlWarning(this) << "Error Reading Animated Image File " << (context ? context->resolvedUrl(d->url) : d->url).toString(); d->setMovie(nullptr); + d->setImage(QImage()); + if (sourceSize() != d->oldSourceSize) { + d->oldSourceSize = sourceSize(); + emit sourceSizeChanged(); + } + if (d->progress != 0) { d->progress = 0; emit progressChanged(d->progress); } + d->status = Error; emit statusChanged(d->status); - d->currentSourceSize = QSize(0, 0); - if (d->currentSourceSize != d->oldSourceSize) { - d->oldSourceSize = d->currentSourceSize; - emit sourceSizeChanged(); - } if (isPlaying() != d->oldPlaying) emit playingChanged(); return; @@ -387,9 +390,6 @@ void QQuickAnimatedImage::movieRequestFinished() d->movie->setCacheMode(QMovie::CacheAll); d->movie->setSpeed(qRound(d->speed * 100.0)); - d->status = Ready; - emit statusChanged(d->status); - if (d->progress != 1.0) { d->progress = 1.0; emit progressChanged(d->progress); @@ -406,21 +406,19 @@ void QQuickAnimatedImage::movieRequestFinished() } QQuickPixmap *pixmap = d->infoForCurrentFrame(qmlEngine(this)); - if (pixmap) + if (pixmap) { d->setPixmap(*pixmap); + if (sourceSize() != d->oldSourceSize) { + d->oldSourceSize = sourceSize(); + emit sourceSizeChanged(); + } + } + + d->status = Ready; + emit statusChanged(d->status); if (isPlaying() != d->oldPlaying) emit playingChanged(); - - if (d->movie) - d->currentSourceSize = d->movie->currentPixmap().size(); - else - d->currentSourceSize = QSize(0, 0); - - if (d->currentSourceSize != d->oldSourceSize) { - d->oldSourceSize = d->currentSourceSize; - emit sourceSizeChanged(); - } } void QQuickAnimatedImage::movieUpdate() @@ -466,12 +464,6 @@ void QQuickAnimatedImage::onCacheChanged() } } -QSize QQuickAnimatedImage::sourceSize() -{ - Q_D(QQuickAnimatedImage); - return d->currentSourceSize; -} - void QQuickAnimatedImage::componentComplete() { QQuickItem::componentComplete(); // NOT QQuickImage @@ -482,6 +474,7 @@ void QQuickAnimatedImagePrivate::setMovie(QMovie *m) { if (movie == m) return; + Q_Q(QQuickAnimatedImage); const int oldFrameCount = q->frameCount(); @@ -489,8 +482,15 @@ void QQuickAnimatedImagePrivate::setMovie(QMovie *m) movie->disconnect(); movie->deleteLater(); } + movie = m; + qDeleteAll(frameMap); + frameMap.clear(); + + if (movie) + movie->setScaledSize(sourcesize); + if (oldFrameCount != q->frameCount()) emit q->frameCountChanged(); } diff --git a/src/quick/items/qquickanimatedimage_p.h b/src/quick/items/qquickanimatedimage_p.h index b8af3e1e40..38beb6d1c3 100644 --- a/src/quick/items/qquickanimatedimage_p.h +++ b/src/quick/items/qquickanimatedimage_p.h @@ -36,8 +36,6 @@ class Q_QUICK_PRIVATE_EXPORT QQuickAnimatedImage : public QQuickImage Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged) Q_PROPERTY(qreal speed READ speed WRITE setSpeed NOTIFY speedChanged REVISION(2, 11)) - // read-only for AnimatedImage - Q_PROPERTY(QSize sourceSize READ sourceSize NOTIFY sourceSizeChanged) QML_NAMED_ELEMENT(AnimatedImage) QML_ADDED_IN_VERSION(2, 0) @@ -61,7 +59,6 @@ public: // Extends QQuickImage's src property void setSource(const QUrl&) override; - virtual QSize sourceSize(); Q_SIGNALS: void playingChanged(); diff --git a/src/quick/items/qquickanimatedimage_p_p.h b/src/quick/items/qquickanimatedimage_p_p.h index 8e2ee8a82d..341ac3bc02 100644 --- a/src/quick/items/qquickanimatedimage_p_p.h +++ b/src/quick/items/qquickanimatedimage_p_p.h @@ -35,7 +35,7 @@ class QQuickAnimatedImagePrivate : public QQuickImagePrivate public: QQuickAnimatedImagePrivate() : playing(true), paused(false), oldPlaying(false), padding(0) - , presetCurrentFrame(0), speed(1.0), currentSourceSize(0, 0), movie(nullptr) + , presetCurrentFrame(0), speed(1.0), movie(nullptr) #if QT_CONFIG(qml_network) , reply(nullptr), redirectCount(0) #endif @@ -51,7 +51,6 @@ public: unsigned padding: 29; int presetCurrentFrame; qreal speed; - QSize currentSourceSize; QMovie *movie; #if QT_CONFIG(qml_network) QNetworkReply *reply; diff --git a/tests/auto/quick/qquickanimatedimage/data/stickmanerror1.qml b/tests/auto/quick/qquickanimatedimage/data/stickmanerror1.qml deleted file mode 100644 index 4f823b3d70..0000000000 --- a/tests/auto/quick/qquickanimatedimage/data/stickmanerror1.qml +++ /dev/null @@ -1,6 +0,0 @@ -import QtQuick 2.0 - -AnimatedImage { - sourceSize: "240x180" - source: "stickman.gif" -} diff --git a/tests/auto/quick/qquickanimatedimage/data/stickmansourcesized.qml b/tests/auto/quick/qquickanimatedimage/data/stickmansourcesized.qml new file mode 100644 index 0000000000..76d277df62 --- /dev/null +++ b/tests/auto/quick/qquickanimatedimage/data/stickmansourcesized.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 + +AnimatedImage { + sourceSize: "80x60" + source: "stickman.gif" +} diff --git a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp index 1a01a8aca5..cb81ec8a07 100644 --- a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp +++ b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp @@ -52,9 +52,9 @@ private slots: void remote(); void remote_data(); void sourceSize(); + void setSourceSize(); void sourceSizeChanges(); void sourceSizeChanges_intermediate(); - void sourceSizeReadOnly(); void invalidSource(); void qtbug_16520(); void progressAndStatusChanges(); @@ -287,12 +287,19 @@ void tst_qquickanimatedimage::sourceSize() delete anim; } -void tst_qquickanimatedimage::sourceSizeReadOnly() +void tst_qquickanimatedimage::setSourceSize() { QQmlEngine engine; - QQmlComponent component(&engine, testFileUrl("stickmanerror1.qml")); - QVERIFY(component.isError()); - QCOMPARE(component.errors().at(0).description(), QString("Invalid property assignment: \"sourceSize\" is a read-only property")); + QQmlComponent component(&engine, testFileUrl("stickmansourcesized.qml")); + QScopedPointer anim(qobject_cast(component.create())); + QVERIFY(anim); + QCOMPARE(anim->sourceSize(), QSize(80, 60)); + + anim->setSourceSize(QSize(40, 30)); + QCOMPARE(anim->sourceSize(), QSize(40, 30)); + + anim->setSourceSize(QSize()); + QCOMPARE(anim->sourceSize(), QSize(160, 120)); } void tst_qquickanimatedimage::invalidSource() -- cgit v1.2.3