After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 338380 - animation playback should have zoom feature
animation playback should have zoom feature
Status: RESOLVED FIXED
Product: GIMP
Classification: Other
Component: Plugins
git master
Other All
: Low enhancement
: 2.10
Assigned To: Jehan
GIMP Bugs
Depends on:
Blocks:
 
 
Reported: 2006-04-13 18:41 UTC by Nick Smith
Modified: 2013-04-20 23:35 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Patch for animationplay.c (5.15 KB, patch)
2007-06-09 15:06 UTC, Paul Seidel
needs-work Details | Review
adds speed control to animationplay.c (12.47 KB, patch)
2007-06-11 10:36 UTC, Paul Seidel
committed Details | Review
UI mockup (17.70 KB, image/png)
2007-06-18 08:38 UTC, Sven Neumann
  Details
adds a combobox for speed control (6.32 KB, patch)
2007-06-18 16:11 UTC, Paul Seidel
needs-work Details | Review
uses integer values to differentiate duration factor values (8.26 KB, patch)
2007-06-19 20:36 UTC, Paul Seidel
committed Details | Review

Description Nick Smith 2006-04-13 18:41:04 UTC
When playing animated GIFs, zooming in to check for mistakes comes in handy.  I
have to use the HTML image tag's width and height attributes to do the same
thing.  2x, 4x, and maybe 8x and a custom value could be used.

Also, the playback feature should have a speed-control feature to play
animations back at a slower speed without having to repeatedly click the "step"
button several dozen times for long animations.  All that's needed is to
multiply the delay time by some value, like 4.
Comment 1 Sven Neumann 2006-04-14 08:22:52 UTC
Sure, why not. If someone wants to implement this functionality, we would certainly accept such a change.
Comment 2 Sven Neumann 2006-04-19 10:26:10 UTC
This should be easy enough to be done by someone who wants to start contributing to GIMP. Adding the gnome-love keyword. Whoever wants to work on this should definitely base his/her work on the CVS HEAD branch because there have been substantial changes to the plug-in since 2.2.
Comment 3 Sven Neumann 2006-04-25 12:21:46 UTC
Zoom functionality would be very nice to have because currently the plug-in doesn't work very well if the image is very large or very small.
Comment 4 Nick Smith 2006-04-26 07:08:53 UTC
I just did some strange test by creating a gigantic animated GIF file.  I made it as 1600x1200, which is my system resolution.  It's so big and there's no way to resize it, I can't see anything on the bottom.  The window itself is so big, I have to move the window around just to be able to close it with the X (I can still right-click on the window on the task bar and close it that way).  Unless you run at a resolution of something like 1680x1400 or higher, you won't see the entire window.  In this case, adding scroll bars and limiting the window size used by default to 3/4 the resolution is recommended.  Of course animated GIFs don't get that big as there's little point in it, except maybe an animated series of screenshots.  For very small animated GIFs, it's hard to really pick out the details.  Trying to resize the window of the gigantic animated GIF has strange behavior as well, likely related to Windows rather than the GIMP.  All resizing the window does is makes the buttons cover more area without affecting the image.

Try previewing this test animated GIF I made:

http://www.ulillillia.us/temporary/hugeGIFtest.gif
Comment 5 Paul Seidel 2007-05-01 15:21:10 UTC
I'd like to take on this feature request for a university course dealing with development processes in open source projects.
Comment 6 Sven Neumann 2007-05-02 06:31:01 UTC
Please base your work on a recent development release or on SVN trunk then. Let us know if you need any help.
Comment 7 Paul Seidel 2007-06-09 15:06:32 UTC
Created attachment 89648 [details] [review]
Patch for animationplay.c

adds three popup items for speed control
Comment 8 Paul Seidel 2007-06-09 15:07:24 UTC
I implemented a first version for the speed control feature.
At the moment it just shows three new items in the popup menu to double, halve and reset the speed in a range from 1/8x to 8x. There is no visual feedback as to which speed is currently set, but the appropriate options are getting insensitive when either being too slow or too fast.

I tried to mess around with the toolbar to add a MenuToolButton but did not succeed with this.

The zoom feature seems to be more difficult because I see no other option than to resize the raw image data arrays by hand.
Comment 9 Sven Neumann 2007-06-09 16:49:22 UTC
Please use a double instead of a float. And perhaps with more actions being added, it would be a good idea to give the actions more meaningful identifiers. "reset" could be anything. It would also be nice to get this into the toolbar, the popup menu is somewhat hard to discover.
Comment 10 Sven Neumann 2007-06-10 11:04:09 UTC
The "Reset Playback Speed" action should also be insensitive when the animation is running at original speed.

Perhaps we need to add a statusbar. The playback speed and zoom factor could be displayed there then.
Comment 11 Paul Seidel 2007-06-10 20:25:01 UTC
Comment on attachment 89648 [details] [review]
Patch for animationplay.c

Index: animationplay.c
===================================================================
--- animationplay.c	(Revision 22453)
+++ animationplay.c	(Arbeitskopie)
@@ -62,36 +62,40 @@
                           gint             *nreturn_vals,
                           GimpParam       **return_vals);
 
-static void        do_playback         (void);
+static void        do_playback               (void);
 
-static void        window_destroy      (GtkWidget       *widget);
-static void        play_callback       (GtkToggleAction *action);
-static void        step_callback       (GtkAction       *action);
-static void        rewind_callback     (GtkAction       *action);
-static gboolean    repaint_sda         (GtkWidget       *darea,
-                                        GdkEventExpose  *event,
-                                        gpointer         data);
-static gboolean    repaint_da          (GtkWidget       *darea,
-                                        GdkEventExpose  *event,
-                                        gpointer         data);
+static void        window_destroy            (GtkWidget       *widget);
+static void        play_callback             (GtkToggleAction *action);
+static void        step_callback             (GtkAction       *action);
+static void        rewind_callback           (GtkAction       *action);
+static void        speed_up_callback         (GtkAction       *action);
+static void        speed_down_callback       (GtkAction       *action);
+static void        reset_speed_callback      (GtkAction       *action);
+static gboolean    repaint_sda               (GtkWidget       *darea,
+                                              GdkEventExpose  *event,
+                                              gpointer         data);
+static gboolean    repaint_da                (GtkWidget       *darea,
+                                              GdkEventExpose  *event,
+                                              gpointer         data);
 
-static void        render_frame        (gint32           whichframe);
-static void        show_frame          (void);
-static void        total_alpha_preview (guchar          *ptr);
-static void        init_preview        (void);
+static void        render_frame              (gint32           whichframe);
+static void        show_frame                (void);
+static void        total_alpha_preview       (guchar          *ptr);
+static void        init_preview              (void);
+static void        update_statusbar          (void);
 
 
 /* tag util functions*/
-static gint        parse_ms_tag        (const gchar     *str);
-static DisposeType parse_disposal_tag  (const gchar     *str);
-static DisposeType get_frame_disposal  (guint            whichframe);
-static guint32     get_frame_duration  (guint            whichframe);
-static gboolean    is_disposal_tag     (const gchar     *str,
-                                        DisposeType     *disposal,
-                                        gint            *taglength);
-static gboolean    is_ms_tag           (const gchar     *str,
-                                        gint            *duration,
-                                        gint            *taglength);
+static gint        parse_ms_tag              (const gchar     *str);
+static DisposeType parse_disposal_tag        (const gchar     *str);
+static DisposeType get_frame_disposal        (guint            whichframe);
+static guint32     get_frame_duration        (guint            whichframe);
+static gboolean    is_disposal_tag           (const gchar     *str,
+                                              DisposeType     *disposal,
+                                              gint            *taglength);
+static gboolean    is_ms_tag                 (const gchar     *str,
+                                              gint            *duration,
+                                              gint            *taglength);
 
 
 const GimpPlugInInfo PLUG_IN_INFO =
@@ -125,7 +129,9 @@
 static GimpImageBaseType  imagetype;
 static guchar            *palette;
 static gint               ncolours;
+static gdouble             duration_factor = 1.0;
 
+
 /* for shaping */
 typedef struct
 {
@@ -136,6 +142,10 @@
 static GtkWidget *shape_window       = NULL;
 static GdkWindow *root_win           = NULL;
 static gboolean   detached           = FALSE;
+static GtkWidget *statusbar          = NULL;
+static gchar     *speed_text         = N_("Speed");
+static guint      message_context_id = 0;
+static guint      message_remove_id;
 
 
 MAIN ()
@@ -450,6 +460,21 @@
       "quit", GTK_STOCK_QUIT,
       NULL, "<control>Q", NULL,
       G_CALLBACK (close_callback)
+    },
+    {
+      "speed_up", GTK_STOCK_GO_UP,
+      N_("Faster"), "<control>L", N_("Increase the speed of the animation"),
+      G_CALLBACK (speed_up_callback)
+    },
+    {
+      "speed_down", GTK_STOCK_GO_DOWN,
+      N_("Slower"), "<control>J", N_("Decrease the speed of the animation"),
+      G_CALLBACK (speed_down_callback)
+    },
+    {
+      "reset_speed", GIMP_STOCK_RESET,
+      N_("Reset speed"), "<control>K", N_("Reset the speed of the animation"),
+      G_CALLBACK (reset_speed_callback)
     }
   };
 
@@ -494,6 +519,10 @@
                                      "    <toolitem action=\"step\" />"
                                      "    <toolitem action=\"rewind\" />"
                                      "    <separator />"
+                                     "    <toolitem action=\"speed_up\" />"
+                                     "    <toolitem action=\"reset_speed\" />"
+                                     "    <toolitem action=\"speed_down\" />"
+                                     "    <separator />"
                                      "    <toolitem action=\"detach\" />"
                                      "    <separator name=\"space\" />"
                                      "    <toolitem action=\"help\" />"
@@ -515,6 +544,9 @@
                                      "    <menuitem action=\"play\" />"
                                      "    <menuitem action=\"step\" />"
                                      "    <menuitem action=\"rewind\" />"
+                                     "    <menuitem action=\"speed_up\" />"
+                                     "    <menuitem action=\"reset_speed\" />"
+                                     "    <menuitem action=\"speed_down\" />"
                                      "    <separator />"
                                      "    <menuitem action=\"detach\" />"
                                      "    <menuitem action=\"close\" />"
@@ -535,13 +567,13 @@
 build_dialog (GimpImageBaseType  basetype,
               gchar             *imagename)
 {
-  GtkWidget   *toolbar;
-  GtkWidget   *frame;
-  GtkWidget   *vbox;
-  GtkWidget   *abox;
-  GtkToolItem *item;
-  GdkCursor   *cursor;
-  gchar       *name;
+  GtkWidget         *toolbar;
+  GtkWidget         *frame;
+  GtkWidget         *vbox;
+  GtkWidget         *abox;
+  GtkToolItem       *item;
+  GdkCursor         *cursor;
+  gchar             *name;
 
   gimp_ui_init (PLUG_IN_BINARY, TRUE);
 
@@ -601,6 +633,11 @@
   gtk_box_pack_start (GTK_BOX (vbox), progress, FALSE, FALSE, 0);
   gtk_widget_show (progress);
 
+  statusbar = gtk_statusbar_new ();
+  gtk_box_pack_start (GTK_BOX (vbox), statusbar, FALSE, FALSE, 0);
+  gtk_widget_show (statusbar);
+  update_statusbar ();
+
   if (total_frames < 2)
     {
       GtkAction *action;
@@ -618,6 +655,10 @@
       gtk_action_set_sensitive (action, FALSE);
     }
 
+  gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager,
+                                                       "/anim-play-popup/reset_speed"),
+                                                       FALSE);
+
   gtk_widget_show (window);
 
   /* let's get into shape. */
@@ -1340,12 +1381,13 @@
   gtk_main_quit ();
 }
 
+
 static gint
 advance_frame_callback (gpointer data)
 {
   remove_timer();
 
-  timer = g_timeout_add (get_frame_duration ((frame_number + 1) % total_frames),
+  timer = g_timeout_add (get_frame_duration ((frame_number + 1) % total_frames) * duration_factor,
                          advance_frame_callback, NULL);
 
   do_step ();
@@ -1354,6 +1396,7 @@
   return FALSE;
 }
 
+
 static void
 play_callback (GtkToggleAction *action)
 {
@@ -1363,7 +1406,7 @@
   playing = gtk_toggle_action_get_active (action);
 
   if (playing)
-    timer = g_timeout_add (get_frame_duration (frame_number),
+    timer = g_timeout_add (get_frame_duration (frame_number) * duration_factor,
                            advance_frame_callback, NULL);
 
   g_object_set (action,
@@ -1392,6 +1435,103 @@
   show_frame ();
 }
 
+static void
+speed_up_callback (GtkAction *action)
+{
+  if (duration_factor > 0.125)
+    duration_factor /= 2.0;
+ 
+  if (duration_factor <= 0.125)
+    gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager,
+                                                         "/anim-play-popup/speed_up"),
+                                                         FALSE);
+  if (duration_factor == 1.0)
+    gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager,
+                                                         "/anim-play-popup/reset_speed"),
+                                                         FALSE);
+  else
+    gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager,
+                                                         "/anim-play-popup/reset_speed"),
+                                                         TRUE);
+  gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager,
+                                                       "/anim-play-popup/speed_down"),
+                                                       TRUE);
+  update_statusbar ();
+}
+
+static void
+speed_down_callback (GtkAction *action)
+{
+  if (duration_factor < 8.0)
+    duration_factor *= 2.0;
+
+  if (duration_factor >= 8.0)
+    gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager,
+                                                         "/anim-play-popup/speed_down"),
+                                                         FALSE);
+  if (duration_factor == 1.0)
+    gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager,
+                                                         "/anim-play-popup/reset_speed"),
+                                                         FALSE);
+  else
+    gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager,
+                                                         "/anim-play-popup/reset_speed"),
+                                                         TRUE);
+
+
+  gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager,
+                                                       "/anim-play-popup/speed_up"),
+                                                       TRUE);
+  update_statusbar ();
+}
+
+static void
+reset_speed_callback (GtkAction *action)
+{
+  duration_factor = 1.0;
+
+  gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager,
+                                                       "/anim-play-popup/speed_down"),
+                                                       TRUE);
+  gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager,
+                                                       "/anim-play-popup/speed_up"),
+                                                       TRUE);
+  gtk_action_set_sensitive (gtk_ui_manager_get_action (ui_manager,
+                                                       "/anim-play-popup/reset_speed"),
+                                                       FALSE);
+  update_statusbar ();
+}
+
+static void
+update_statusbar (void)
+{
+  gchar *status_message;
+  guint speed_number;
+
+  if (message_context_id == 0)
+    message_context_id = gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), 
+                                                       "display the current speed of playback");
+  else
+    gtk_statusbar_pop (GTK_STATUSBAR (statusbar),
+                       message_context_id);
+
+  if (duration_factor > 1.0)
+    {
+      speed_number = (guint) duration_factor;
+      status_message = g_strdup_printf  ("%s: 1/%dx", speed_text, speed_number);
+    }
+  else
+    {
+      speed_number = (guint) 1.0 / duration_factor;
+      status_message = g_strdup_printf  ("%s: %dx", speed_text, speed_number);
+    }
+
+  message_remove_id = gtk_statusbar_push (GTK_STATUSBAR (statusbar),
+                                          message_context_id,
+                                          status_message);
+  g_free (status_message);
+}
+
 /* tag util. */
 
 static DisposeType
Comment 12 Paul Seidel 2007-06-10 20:29:57 UTC
Oh, sorry about the spammy patch message before.
I'm not very accustomed to the functions of bugzilla.

Nevertheless, I changed all the things you asked me for.
So we got three new actions in the popup menu as well as in the toolbar.
I added a status bar which shows the current speed as you proposed.
Comment 13 Manish Singh 2007-06-11 03:16:29 UTC
Please submit the above patch as an attachment.
Comment 14 Paul Seidel 2007-06-11 10:36:41 UTC
Created attachment 89735 [details] [review]
adds speed control to animationplay.c
Comment 15 Sven Neumann 2007-06-18 06:53:04 UTC
To get us further, I have now committed this patch with some modifications. In particular I have removed the speed controls from the toolbar as I found that they take up too much space there.

2007-06-18  Sven Neumann  <sven@gimp.org>

	* plug-ins/common/animationplay.c: applied modified patch from
	Paul Seidel that adds controls for the playback speed (bug #338380).

We can try to improve the plug-in further from here.
Comment 16 Sven Neumann 2007-06-18 08:38:18 UTC
Created attachment 90192 [details]
UI mockup

I suggest that we streamline the UI somewhat. Instead of adding a statusbar below the progressbar, we could have a combo-box next to the progress-bar. A tooltip could indicate that it controls the playback speed. See attached screenshot.
Comment 17 Paul Seidel 2007-06-18 16:11:06 UTC
Created attachment 90217 [details] [review]
adds a combobox for speed control

I added a combobox to the dialog as proposed and removed all references to the statusbar.The active combobox item is automatically changed when using the popup menu and the popup menu entries are sensitive/insensitive depending on the speed chosen with the combobox. The patch is based on the latest SVN copy (Rev 22794).
Comment 18 Sven Neumann 2007-06-19 06:34:41 UTC
That looks nice but there's a small problem. Something that I should have already pointed out earlier. You can't reliably compare double values for equality using the == operator. What I suggest you do is to use an integer or perhaps an enum for the various possible playback speeds. Then just change this integer value in the action callbacks. You can then also use a GimpIntComboBox.
Comment 19 Paul Seidel 2007-06-19 20:36:52 UTC
Created attachment 90297 [details] [review]
uses integer values to differentiate duration factor values

With this patch the speed control now uses the index values of the combo box to differentiate between the various duration factor values.
The correct value for the factor is now calculated by using "get_duration_factor" when creating the timeout object.
Comment 20 Sven Neumann 2007-06-20 20:06:06 UTC
I have applied this patch with some minor modifications. Thanks a lot for your contribution:

2007-06-20  Sven Neumann  <sven@gimp.org>

	* plug-ins/common/animationplay.c: applied patch from Paul Seidel
	with further improvements to the playback speed control (bug #338380).

I think we can now consider the playback speed aspect fixed. Changing the summary accordingly.
Comment 21 weskaggs 2008-02-14 16:02:24 UTC
Removing "gnome-love" keyword because code has been committed, and it isn't clear the gnome-love is appropriate for the remaining issues.
Comment 22 Sven Neumann 2008-02-15 07:38:00 UTC
The summary has been changed after the code has been committed to reflect what still needs to be done. And the keyword is fully appropriate for that.
Comment 23 Jehan 2012-10-17 17:55:53 UTC
A zooming feature is indeed very needed. Not only zooming-in, but also out!
As I was working on image quite high resolution, actually bigger than my screen, I could not access/see the buttons and the status bar.

I will work on this in a few weeks, if none steps before me (looks like so).
Comment 24 Jehan 2012-12-16 15:31:26 UTC
I have developed the feature. It includes zooming in/out, default zoom out when starting the plug-in so that the window does not go out of screen, and scrolling so that you can scale bigger than your screen size but still have the window in-screen.

I am waiting for the bug 690265 to be confirmed before uploading the patch.
Comment 25 Jehan 2013-04-20 23:32:25 UTC
Committed on master. As discussed with Mitch at the time, because of bug 690265, the current version limits down zooming to 50% (zooming out below half does not work). This limitation will be removed when bug 690265 will be fixed.

commit 5c38715cce591c80409dd20d037ef28b1a06fcfc
Author: Jehan <jehan@girinstud.io>
Date:   Mon Dec 17 00:26:20 2012 +0900

    Bug 338380: zoom and scrolling feature on animation playback plugin.