[graphics/krita/krita/6.0] libs/ui/animation: Allow iterating encoder frames multiple times

Carsten Hartenfels <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 34760a7870b00ba4baa9dd5c208ee473ad340229 by Carsten Hartenfels.
Committed on 27/07/2026 at 17:19.
Pushed by hartenfels into branch 'krita/6.0'.

Allow iterating encoder frames multiple times

GIF needs this because it must iterate the frames twice: once to create
a palette and then again to actually render the animated image. This
commit allows rewinding the iterator and specifying a ratio for the
progress slider so that it doesn't show 100% when the encoding is only
halfway done.

M  +14   -2    libs/ui/animation/KisMediaEncoderWrapper.cpp
M  +8    -1    libs/ui/animation/KisMediaEncoderWrapper.h

https://invent.kde.org/graphics/krita/-/commit/34760a7870b00ba4baa9dd5c208ee473ad340229

diff --git a/libs/ui/animation/KisMediaEncoderWrapper.cpp b/libs/ui/animation/KisMediaEncoderWrapper.cpp
index 67c8c95a613..2a2344dcd51 100644
--- a/libs/ui/animation/KisMediaEncoderWrapper.cpp
+++ b/libs/ui/animation/KisMediaEncoderWrapper.cpp
@@ -96,8 +96,12 @@ bool KisMediaEncoderRunnable::nextFrame(Frame &outFrame)
         }
 
         if (instances != 0) {
-            m_outputFrameNo += instances;
-            Q_EMIT sigProgressUpdated(m_outputFrameNo);
+            // GIF must spin through the input frames twice, once to generate a
+            // palette and then again to actually render the animated image. It
+            // sets the multiplier to 0.5 so that the progress bar shows values
+            // that make sense for the user, rather than reaching 100% halfway.
+            m_outputFrameNo += double(instances) * m_outputFrameNoMultiplier;
+            Q_EMIT sigProgressUpdated(int(m_outputFrameNo));
 
             // If we're on the last frame, we can append the linger time.
             if (fileIndex == lastIndex && m_needsLingerAfter) {
@@ -122,6 +126,14 @@ bool KisMediaEncoderRunnable::nextFrame(Frame &outFrame)
     return false;
 }
 
+void KisMediaEncoderRunnable::rewindFrames()
+{
+    m_inputTime = 0;
+    m_inputFileIndex = 0;
+    m_needsPreviewBefore = true;
+    m_needsLingerAfter = true;
+}
+
 KisMediaEncoderRunnable::EncodeResult KisMediaEncoderRunnable::prepareAndEncode(QString &outErrorMessage)
 {
     if (m_cancel) {
diff --git a/libs/ui/animation/KisMediaEncoderWrapper.h b/libs/ui/animation/KisMediaEncoderWrapper.h
index 2e0a7126fc4..062654d8bfb 100644
--- a/libs/ui/animation/KisMediaEncoderWrapper.h
+++ b/libs/ui/animation/KisMediaEncoderWrapper.h
@@ -111,7 +111,13 @@ protected:
         return m_cancel;
     }
 
+    void setOutputFrameNoMultiplier(double outputFrameNoMultiplier)
+    {
+        m_outputFrameNoMultiplier = outputFrameNoMultiplier;
+    }
+
     bool nextFrame(Frame &outFrame);
+    void rewindFrames();
 
 private:
     EncodeResult prepareAndEncode(QString &outErrorMessage);
@@ -119,7 +125,8 @@ private:
     KisMediaEncoderWrapperSettings m_settings;
     double m_inputTime = 0.0;
     int m_inputFileIndex = 0;
-    int m_outputFrameNo = 0;
+    double m_outputFrameNo = 0.0;
+    double m_outputFrameNoMultiplier = 1.0;
     bool m_needsPreviewBefore = true;
     bool m_needsLingerAfter = true;
     bool m_cancel = false;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.