[gimp/wip/animation: 43/197] plug-ins: support for layer groups in animation-play.
- From: Jehan Pagès <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/animation: 43/197] plug-ins: support for layer groups in animation-play.
- Date: Sat, 7 Oct 2017 03:02:01 +0000 (UTC)
commit af392e2ecb7a78d76b1b4c4413b4111cb3621595
Author: Jehan <jehan girinstud io>
Date: Sun Jun 2 10:39:53 2013 +0900
plug-ins: support for layer groups in animation-play.
Support for groups good in combine/replace mode, not perfect yet in tags mode.
It won't deal with group's compositing mode other than "normal".
plug-ins/common/animation-play.c | 523 ++++++++++++++++++++++----------------
1 files changed, 300 insertions(+), 223 deletions(-)
---
diff --git a/plug-ins/common/animation-play.c b/plug-ins/common/animation-play.c
index 8a40699..aa94e21 100644
--- a/plug-ins/common/animation-play.c
+++ b/plug-ins/common/animation-play.c
@@ -136,6 +136,9 @@ static void clean_exit (void);
/* tag util functions*/
static gint parse_ms_tag (const gchar *str);
+static void rec_set_total_frames (const gint32 layer,
+ gint *min,
+ gint *max);
static void set_total_frames (void);
static DisposeType parse_disposal_tag (const gchar *str);
static gboolean is_disposal_tag (const gchar *str,
@@ -1291,6 +1294,216 @@ init_quality_checkbox (void)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (quality_checkbox), TRUE);
}
+/**
+ * Recursive call to generate frames in TAGS mode.
+ **/
+static void
+rec_init_frames (gint32 layer, GList *previous_frames)
+{
+ Frame *empty_frame = NULL;
+ gchar *layer_name;
+ gchar *nospace_name;
+ GMatchInfo *match_info;
+ gboolean preview_quality;
+ gint32 new_layer;
+ gint j, k;
+
+ if (gimp_item_is_group (layer))
+ {
+ gint num_children;
+ gint32 *children;
+
+ children = gimp_item_get_children (layer, &num_children);
+ for (j = 0; j < num_children; j++)
+ rec_init_frames (children[num_children - j - 1], previous_frames);
+
+ return;
+ }
+
+ layer_name = gimp_item_get_name (layer);
+ nospace_name = g_regex_replace_literal (nospace_reg, layer_name, -1, 0, "", 0, NULL);
+ preview_quality = preview_width != width || preview_height != height;
+
+ if (g_regex_match (all_reg, nospace_name, 0, NULL))
+ {
+ for (j = 0; j < total_frames; j++)
+ {
+ if (! frames[j])
+ {
+ if (! empty_frame)
+ {
+ empty_frame = g_new (Frame, 1);
+ empty_frame->indexes = NULL;
+ empty_frame->updated_indexes = NULL;
+ empty_frame->drawable_id = 0;
+
+ previous_frames = g_list_append (previous_frames, empty_frame);
+ }
+
+ if (! g_list_find (empty_frame->updated_indexes, GINT_TO_POINTER (j)))
+ empty_frame->updated_indexes = g_list_append (empty_frame->updated_indexes, GINT_TO_POINTER
(j));
+
+ frames[j] = empty_frame;
+ }
+ else if (! g_list_find (frames[j]->updated_indexes, GINT_TO_POINTER (j)))
+ frames[j]->updated_indexes = g_list_append (frames[j]->updated_indexes, GINT_TO_POINTER (j));
+ }
+ }
+ else
+ {
+ g_regex_match (layers_reg, nospace_name, 0, &match_info);
+
+ while (g_match_info_matches (match_info))
+ {
+ gchar *tag = g_match_info_fetch (match_info, 1);
+ gchar** tokens = g_strsplit(tag, ",", 0);
+
+ for (j = 0; tokens[j] != NULL; j++)
+ {
+ gchar* hyphen = g_strrstr(tokens[j], "-");
+
+ if (hyphen != NULL)
+ {
+ gint32 first = (gint32) g_ascii_strtoll (tokens[j], NULL, 10);
+ gint32 second = (gint32) g_ascii_strtoll (&hyphen[1], NULL, 10);
+
+ for (k = first; k <= second; k++)
+ {
+ if (! frames[k - frame_number_min])
+ {
+ if (! empty_frame)
+ {
+ empty_frame = g_new (Frame, 1);
+ empty_frame->indexes = NULL;
+ empty_frame->updated_indexes = NULL;
+ empty_frame->drawable_id = 0;
+
+ previous_frames = g_list_append (previous_frames, empty_frame);
+ }
+
+ if (! g_list_find (frames[k - frame_number_min]->updated_indexes, GINT_TO_POINTER
(k - frame_number_min)))
+ empty_frame->updated_indexes = g_list_append (empty_frame->updated_indexes,
GINT_TO_POINTER (k - frame_number_min));
+
+ frames[k - frame_number_min] = empty_frame;
+ }
+ else if (! g_list_find (frames[k - frame_number_min]->updated_indexes, GINT_TO_POINTER
(k - frame_number_min)))
+ frames[k - frame_number_min]->updated_indexes = g_list_append (frames[k -
frame_number_min]->updated_indexes,
+ GINT_TO_POINTER (k -
frame_number_min));
+ }
+ }
+ else
+ {
+ gint32 num = (gint32) g_ascii_strtoll (tokens[j], NULL, 10);
+
+ if (! frames[num - frame_number_min])
+ {
+ if (! empty_frame)
+ {
+ empty_frame = g_new (Frame, 1);
+ empty_frame->indexes = NULL;
+ empty_frame->updated_indexes = NULL;
+ empty_frame->drawable_id = 0;
+
+ previous_frames = g_list_append (previous_frames, empty_frame);
+ }
+
+ if (! g_list_find (frames[num - frame_number_min]->updated_indexes, GINT_TO_POINTER
(num - frame_number_min)))
+ empty_frame->updated_indexes = g_list_append (empty_frame->updated_indexes,
GINT_TO_POINTER (num - frame_number_min));
+
+ frames[num - frame_number_min] = empty_frame;
+ }
+ else if (! g_list_find (frames[num - frame_number_min]->updated_indexes, GINT_TO_POINTER
(num - frame_number_min)))
+ frames[num - frame_number_min]->updated_indexes = g_list_append (frames[num -
frame_number_min]->updated_indexes,
+ GINT_TO_POINTER (num -
frame_number_min));
+ }
+ }
+ g_strfreev (tokens);
+ g_free (tag);
+ g_match_info_next (match_info, NULL);
+ }
+ g_match_info_free (match_info);
+ }
+
+ for (j = 0; j < total_frames; j++)
+ {
+ /* Check which frame must be updated with the current layer. */
+ if (frames[j] && g_list_length (frames[j]->updated_indexes))
+ {
+ new_layer = gimp_layer_new_from_drawable (layer, frames_image_id);
+ gimp_image_insert_layer (frames_image_id, new_layer, 0, 0);
+
+ if (preview_quality)
+ {
+ gint layer_offx, layer_offy;
+
+ gimp_layer_scale (new_layer,
+ (gimp_drawable_width (layer) * (gint) preview_width) / (gint) width,
+ (gimp_drawable_height (layer) * (gint) preview_height) / (gint) height,
+ FALSE);
+ gimp_drawable_offsets (layer, &layer_offx, &layer_offy);
+ gimp_layer_set_offsets (new_layer, (layer_offx * (gint) preview_width) / (gint) width,
+ (layer_offy * (gint) preview_height) / (gint) height);
+ }
+ gimp_layer_resize_to_image_size (new_layer);
+
+ if (frames[j]->drawable_id == 0)
+ {
+ frames[j]->drawable_id = new_layer;
+ frames[j]->indexes = frames[j]->updated_indexes;
+ frames[j]->updated_indexes = NULL;
+ }
+ else if (g_list_length (frames[j]->indexes) == g_list_length (frames[j]->updated_indexes))
+ {
+ gimp_item_set_visible (new_layer, TRUE);
+ gimp_item_set_visible (frames[j]->drawable_id, TRUE);
+
+ frames[j]->drawable_id = gimp_image_merge_visible_layers (frames_image_id, GIMP_CLIP_TO_IMAGE);
+ g_list_free (frames[j]->updated_indexes);
+ frames[j]->updated_indexes = NULL;
+ }
+ else
+ {
+ GList *idx;
+ gboolean move_j = FALSE;
+ Frame *forked_frame = g_new (Frame, 1);
+ gint32 forked_drawable_id = gimp_layer_new_from_drawable (frames[j]->drawable_id,
frames_image_id);
+
+ /* if part only of the frames are updated, we fork the existing frame. */
+ gimp_image_insert_layer (frames_image_id, forked_drawable_id, 0, 1);
+ gimp_item_set_visible (new_layer, TRUE);
+ gimp_item_set_visible (forked_drawable_id, TRUE);
+ forked_drawable_id = gimp_image_merge_visible_layers (frames_image_id, GIMP_CLIP_TO_IMAGE);
+
+ forked_frame->drawable_id = forked_drawable_id;
+ forked_frame->indexes = frames[j]->updated_indexes;
+ forked_frame->updated_indexes = NULL;
+ frames[j]->updated_indexes = NULL;
+
+ for (idx = g_list_first (forked_frame->indexes); idx != NULL; idx = g_list_next (idx))
+ {
+ frames[j]->indexes = g_list_remove (frames[j]->indexes, idx->data);
+ if (GPOINTER_TO_INT (idx->data) != j)
+ frames[GPOINTER_TO_INT (idx->data)] = forked_frame;
+ else
+ /* Frame j must also be moved to the forked frame, but only after the loop. */
+ move_j = TRUE;
+ }
+ if (move_j)
+ frames[j] = forked_frame;
+
+ gimp_item_set_visible (forked_drawable_id, FALSE);
+
+ previous_frames = g_list_append (previous_frames, forked_frame);
+ }
+
+ gimp_item_set_visible (frames[j]->drawable_id, FALSE);
+ }
+ }
+
+ g_free (layer_name);
+ g_free (nospace_name);
+}
+
static void
init_frames (void)
{
@@ -1301,9 +1514,6 @@ init_frames (void)
GtkAction *action;
gint duration = 0;
DisposeType disposal = settings.default_frame_disposal;
- gchar *layer_name;
- gint layer_offx, layer_offy;
- gboolean preview_quality;
gint frame_spin_size;
if (total_frames <= 0)
@@ -1364,7 +1574,7 @@ init_frames (void)
gimp_image_delete (frames_image_id);
- /* Freeing previous frames. */
+ /* Freeing previous frames only once. */
for (idx = g_list_first (previous_frames); idx != NULL; idx = g_list_next (idx))
{
Frame* frame = (Frame*) idx->data;
@@ -1398,189 +1608,14 @@ init_frames (void)
/* Save processing time and memory by not saving history and merged frames. */
gimp_image_undo_disable (frames_image_id);
- preview_quality = preview_width != width || preview_height != height;
-
if (disposal == DISPOSE_TAGS)
{
- gint i, j, k;
- gchar* nospace_name;
- GMatchInfo *match_info;
+ gint i;
for (i = 0; i < total_layers; i++)
{
- Frame *empty_frame = NULL;
-
show_loading_progress (i);
- layer_name = gimp_item_get_name (layers[total_layers - (i + 1)]);
- nospace_name = g_regex_replace_literal (nospace_reg, layer_name, -1, 0, "", 0, NULL);
- if (g_regex_match (all_reg, nospace_name, 0, NULL))
- {
- for (j = 0; j < total_frames; j++)
- {
- if (! frames[j])
- {
- if (! empty_frame)
- {
- empty_frame = g_new (Frame, 1);
- empty_frame->indexes = NULL;
- empty_frame->updated_indexes = NULL;
- empty_frame->drawable_id = 0;
-
- previous_frames = g_list_append (previous_frames, empty_frame);
- }
-
- empty_frame->updated_indexes = g_list_append (empty_frame->updated_indexes,
GINT_TO_POINTER (j));
-
- frames[j] = empty_frame;
- }
- else if (! g_list_find (frames[j]->updated_indexes, GINT_TO_POINTER (j)))
- frames[j]->updated_indexes = g_list_append (frames[j]->updated_indexes, GINT_TO_POINTER
(j));
- }
- }
- else
- {
- g_regex_match (layers_reg, nospace_name, 0, &match_info);
-
- while (g_match_info_matches (match_info))
- {
- gchar *tag = g_match_info_fetch (match_info, 1);
- gchar** tokens = g_strsplit(tag, ",", 0);
-
- for (j = 0; tokens[j] != NULL; j++)
- {
- gchar* hyphen = g_strrstr(tokens[j], "-");
-
- if (hyphen != NULL)
- {
- gint32 first = (gint32) g_ascii_strtoll (tokens[j], NULL, 10);
- gint32 second = (gint32) g_ascii_strtoll (&hyphen[1], NULL, 10);
-
- for (k = first; k <= second; k++)
- {
- if (! frames[k - frame_number_min])
- {
- if (! empty_frame)
- {
- empty_frame = g_new (Frame, 1);
- empty_frame->indexes = NULL;
- empty_frame->updated_indexes = NULL;
- empty_frame->drawable_id = 0;
-
- previous_frames = g_list_append (previous_frames, empty_frame);
- }
-
- empty_frame->updated_indexes = g_list_append
(empty_frame->updated_indexes, GINT_TO_POINTER (k - frame_number_min));
-
- frames[k - frame_number_min] = empty_frame;
- }
- else if (! g_list_find (frames[k - frame_number_min]->updated_indexes,
GINT_TO_POINTER (k - frame_number_min)))
- frames[k - frame_number_min]->updated_indexes = g_list_append (frames[k -
frame_number_min]->updated_indexes,
-
GINT_TO_POINTER (k - frame_number_min));
- }
- }
- else
- {
- gint32 num = (gint32) g_ascii_strtoll (tokens[j], NULL, 10);
-
- if (! frames[num - frame_number_min])
- {
- if (! empty_frame)
- {
- empty_frame = g_new (Frame, 1);
- empty_frame->indexes = NULL;
- empty_frame->updated_indexes = NULL;
- empty_frame->drawable_id = 0;
-
- previous_frames = g_list_append (previous_frames, empty_frame);
- }
-
- empty_frame->updated_indexes = g_list_append (empty_frame->updated_indexes,
GINT_TO_POINTER (num - frame_number_min));
-
- frames[num - frame_number_min] = empty_frame;
- }
- else if (! g_list_find (frames[num - frame_number_min]->updated_indexes,
GINT_TO_POINTER (num - frame_number_min)))
- frames[num - frame_number_min]->updated_indexes = g_list_append (frames[num -
frame_number_min]->updated_indexes,
- GINT_TO_POINTER
(num - frame_number_min));
- }
- }
- g_strfreev (tokens);
- g_free (tag);
- g_match_info_next (match_info, NULL);
- }
- g_match_info_free (match_info);
- }
-
- for (j = 0; j < total_frames; j++)
- {
- /* Check which frame must be updated with the current layer. */
- if (frames[j] && g_list_length (frames[j]->updated_indexes))
- {
- new_layer = gimp_layer_new_from_drawable (layers[total_layers - (i + 1)],
frames_image_id);
- gimp_image_insert_layer (frames_image_id, new_layer, 0, 0);
-
- if (preview_quality)
- {
- gimp_layer_scale (new_layer,
- (gimp_drawable_width (layers[total_layers - (i + 1)]) * (gint)
preview_width) / (gint) width,
- (gimp_drawable_height (layers[total_layers - (i + 1)]) * (gint)
preview_height) / (gint) height,
- FALSE);
- gimp_drawable_offsets (layers[total_layers - (i + 1)], &layer_offx, &layer_offy);
- gimp_layer_set_offsets (new_layer, (layer_offx * (gint) preview_width) / (gint)
width,
- (layer_offy * (gint) preview_height) / (gint) height);
- }
- gimp_layer_resize_to_image_size (new_layer);
-
- if (frames[j]->drawable_id == 0)
- {
- frames[j]->drawable_id = new_layer;
- frames[j]->indexes = frames[j]->updated_indexes;
- frames[j]->updated_indexes = NULL;
- }
- else if (g_list_length (frames[j]->indexes) == g_list_length
(frames[j]->updated_indexes))
- {
- gimp_item_set_visible (new_layer, TRUE);
- gimp_item_set_visible (frames[j]->drawable_id, TRUE);
-
- frames[j]->drawable_id = gimp_image_merge_visible_layers (frames_image_id,
GIMP_CLIP_TO_IMAGE);
- g_list_free (frames[j]->updated_indexes);
- frames[j]->updated_indexes = NULL;
- }
- else
- {
- GList *idx;
- Frame *forked_frame = g_new (Frame, 1);
- gint32 forked_drawable_id = gimp_layer_new_from_drawable (frames[j]->drawable_id,
frames_image_id);
-
- /* if part only of the frames are updated, we fork the existing frame. */
- gimp_image_insert_layer (frames_image_id, forked_drawable_id, 0, 1);
- gimp_item_set_visible (new_layer, TRUE);
- gimp_item_set_visible (forked_drawable_id, TRUE);
- forked_drawable_id = gimp_image_merge_visible_layers (frames_image_id,
GIMP_CLIP_TO_IMAGE);
-
- forked_frame->drawable_id = forked_drawable_id;
- forked_frame->indexes = frames[j]->updated_indexes;
- forked_frame->updated_indexes = NULL;
- frames[j]->updated_indexes = NULL;
-
- for (idx = g_list_first (forked_frame->indexes); idx != NULL; idx = g_list_next
(idx))
- {
- frames[j]->indexes = g_list_remove (frames[j]->indexes, idx->data);
- /* Frame j must also be moved to the forked frame, but only after the loop. */
- if (GPOINTER_TO_INT (idx->data) != j)
- frames[GPOINTER_TO_INT (idx->data)] = forked_frame;
- }
- frames[j] = forked_frame;
- gimp_item_set_visible (forked_drawable_id, FALSE);
-
- previous_frames = g_list_append (previous_frames, forked_frame);
- }
-
- gimp_item_set_visible (frames[j]->drawable_id, FALSE);
- }
- }
-
- g_free (layer_name);
- g_free (nospace_name);
+ rec_init_frames (layers[total_layers - (i + 1)], previous_frames);
}
for (i = 0; i < total_frames; i++)
@@ -1598,7 +1633,9 @@ init_frames (void)
}
else
{
- gint i;
+ gint layer_offx, layer_offy;
+ gchar *layer_name;
+ gint i;
for (i = 0; i < total_frames; i++)
{
@@ -1638,6 +1675,19 @@ init_frames (void)
(layer_offy * (gint) preview_height) / (gint) height);
gimp_layer_resize_to_image_size (new_layer);
+ if (gimp_item_is_group (new_layer))
+ {
+ gint num_children;
+ gint32 *children;
+ gint j;
+
+ /* I want to make all layers in the group visible, so that when I'll make
+ * the group visible too at render time, it will display everything in it. */
+ children = gimp_item_get_children (new_layer, &num_children);
+ for (j = 0; j < num_children; j++)
+ gimp_item_set_visible (children[j], TRUE);
+ }
+
new_frame = gimp_image_merge_visible_layers (frames_image_id, GIMP_CLIP_TO_IMAGE);
frames[i]->drawable_id = new_frame;
gimp_item_set_visible (new_frame, FALSE);
@@ -2517,20 +2567,76 @@ parse_ms_tag (const gchar *str)
}
/**
+ * A recursive call which will call itself for layer groups
+ * and update the min/max progressively.
+ **/
+static void
+rec_set_total_frames (const gint32 layer, gint *min, gint *max)
+{
+ gchar *layer_name;
+ gchar *nospace_name;
+ GMatchInfo *match_info;
+ gint i;
+
+ if (gimp_item_is_group (layer))
+ {
+ gint num_children;
+ gint32 *children;
+
+ children = gimp_item_get_children (layer, &num_children);
+ for (i = 0; i < num_children; i++)
+ rec_set_total_frames (children[i], min, max);
+
+ return;
+ }
+
+ layer_name = gimp_item_get_name (layer);
+ nospace_name = g_regex_replace_literal (nospace_reg, layer_name, -1, 0, "", 0, NULL);
+
+ g_regex_match (layers_reg, nospace_name, 0, &match_info);
+
+ while (g_match_info_matches (match_info))
+ {
+ gchar *tag = g_match_info_fetch (match_info, 1);
+ gchar** tokens = g_strsplit(tag, ",", 0);
+
+ for (i = 0; tokens[i] != NULL; i++)
+ {
+ gchar* hyphen;
+ hyphen = g_strrstr(tokens[i], "-");
+ if (hyphen != NULL)
+ {
+ gint32 first = (gint32) g_ascii_strtoll (tokens[i], NULL, 10);
+ gint32 second = (gint32) g_ascii_strtoll (&hyphen[1], NULL, 10);
+ *max = (second > first && second > *max)? second : *max;
+ *min = (second > first && first < *min)? first : *min;
+ }
+ else
+ {
+ gint32 num = (gint32) g_ascii_strtoll (tokens[i], NULL, 10);
+ *max = (num > *max)? num : *max;
+ *min = (num < *min)? num : *min;
+ }
+ }
+ g_strfreev (tokens);
+ g_free (tag);
+ g_free (layer_name);
+ g_match_info_next (match_info, NULL);
+ }
+
+ g_free (nospace_name);
+ g_match_info_free (match_info);
+}
+
+/**
* Set the `total_frames` for the DISPOSE_TAGS disposal.
* Will set 0 if no layer has frame tags in tags mode, or if there is no layer in combine/replace.
*/
static void
set_total_frames (void)
{
- gchar *layer_name;
- gchar *nospace_name;
- GMatchInfo *match_info;
- gint max = G_MININT;
- gint min = G_MAXINT;
gboolean start_from_first = FALSE;
gboolean end_at_last = FALSE;
- gint i, j;
/* As a special exception, when we start or end at first or last frames,
* we want to stay that way, even with different first and last frames. */
@@ -2545,44 +2651,15 @@ set_total_frames (void)
frame_number_min = 1;
frame_number_max = frame_number_min + total_frames - 1;
}
- else for (i = 0; i < total_layers; i++)
+ else
{
- layer_name = gimp_item_get_name (layers[i]);
- nospace_name = g_regex_replace_literal (nospace_reg, layer_name, -1, 0, "", 0, NULL);
-
- g_regex_match (layers_reg, nospace_name, 0, &match_info);
-
- while (g_match_info_matches (match_info))
- {
- gchar *tag = g_match_info_fetch (match_info, 1);
- gchar** tokens = g_strsplit(tag, ",", 0);
+ gint i;
+ gint max = G_MININT;
+ gint min = G_MAXINT;
- for (j = 0; tokens[j] != NULL; j++)
- {
- gchar* hyphen;
- hyphen = g_strrstr(tokens[j], "-");
- if (hyphen != NULL)
- {
- gint32 first = (gint32) g_ascii_strtoll (tokens[j], NULL, 10);
- gint32 second = (gint32) g_ascii_strtoll (&hyphen[1], NULL, 10);
- max = (second > first && second > max)? second : max;
- min = (second > first && first < min)? first : min;
- }
- else
- {
- gint32 num = (gint32) g_ascii_strtoll (tokens[j], NULL, 10);
- max = (num > max)? num : max;
- min = (num < min)? num : min;
- }
- }
- g_strfreev (tokens);
- g_free (tag);
- g_free (layer_name);
- g_match_info_next (match_info, NULL);
- }
+ for (i = 0; i < total_layers; i++)
+ rec_set_total_frames (layers[i], &min, &max);
- g_free (nospace_name);
- g_match_info_free (match_info);
total_frames = (max > min)? max + 1 - min : 0;
frame_number_min = min;
frame_number_max = max;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]