[gimp-gap] bugfixes, frames convert support for merge visible layers #665142



commit 1a984d667ae275784320dc1f668fa1d52c974f07
Author: Wolfgang Hofer <wolfgangh svn gnome org>
Date:   Wed Nov 30 20:24:14 2011 +0100

    bugfixes, frames convert support for merge visible layers #665142

 ChangeLog                        |   50 +++++++++++++++++++++++++
 gap/gap_fmac_base.c              |    4 +-
 gap/gap_image.c                  |   26 +++++++++++++
 gap/gap_image.h                  |    1 +
 gap/gap_main.c                   |   10 ++++--
 gap/gap_mov_xml_par.c            |   40 +++++++++++++++++----
 gap/gap_range_ops.c              |   75 +++++++++++++++++++++++++++++++-------
 gap/gap_story_render_processor.c |    1 +
 libgapbase/gap_val_file.c        |    4 +-
 libgapbase/gap_val_file.h        |    2 +
 10 files changed, 186 insertions(+), 27 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index f185b44..d7c55d9 100755
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,53 @@
+2011-11-30 Wolfgang Hofer <hof gimp org>
+
+- added option to merge visible layers
+  in the frames convert plug-in
+  This option merges the visible layers (and removes
+  the invisible layers) in the converted copy
+  to keep transparency before calling the file save plug-in.
+  This is useful for formats like PNG that can handle transparency,
+  but can not handle multiple layers.
+  (this feature was suggested in #665142)
+
+
+- Increased limits for animated filter apply last values buffer size
+  allow filtermacro with last values buffer larger than 255 bytes.
+  Note that current processing is still limited by intrnal buffer size for
+  reading one line via gap_val_file procedures.
+
+  gap_val file increased internal buffer to handle line length upto 16000 bytes
+  (old limit was 4000 bytes) GAP_VAL_MAX_BYTES_PER_LINE
+
+  
+- bugfix  Storyboard render processor ignored the move-path transformation
+  in case of processing a frame image in the 1st track 
+  when the move-path was the only transformation.
+
+
+- bugfix  MovePath xml paramfile.
+  Keyframe information was not saved to XML file in case the keyframe number
+  is lower or equal to the lower frame number of the specified frame range.
+  This unexpected behavior is caused by checking for valid relative keyframe number.
+  The save procedure was changed to save the absolute keyframe numbers
+  this fixes the problem and makes the xml file content easier to understand.
+  Note that loading now supports both relative <keyframe nn> and absolute <keyframe_abs nn>
+  to ensure compatibility with already existing move path xml files.
+
+  note that the same problem occurs with the old controlpoint format
+  but will not be fixed there becuse the change would break backwards compatibility
+  -- backwards compatibility is the only reason why the old format is still supported --
+
+ * libgapbase/gap_val_file.c [.h]
+ * gap/gap_fmac_base.c
+
+ * gap/gap_mov_xml_par.c
+ * gap/gap_story_render_processor.c
+
+ * gap/gap_main.c
+ * gap/gap_range_ops.c
+ * gap/gap_image.c [.h]
+
+
 2011-11-23 Wolfgang Hofer <hof gimp org>
 
 - Foreground selection: fixed parameters for non interactive calls.
diff --git a/gap/gap_fmac_base.c b/gap/gap_fmac_base.c
index a4984df..bee3bdd 100644
--- a/gap/gap_fmac_base.c
+++ b/gap/gap_fmac_base.c
@@ -159,7 +159,7 @@ p_scan_fmac_line(GapValTextFileLines *txf_ptr, GimpRunMode run_mode, const char
     /* scan plugin-name */
     l_scan_ptr=&l_buf[0];
     l_plugin_name = &l_buf[1];
-    for(l_idx=1; l_idx < 4000;l_idx++)
+    for(l_idx=1; l_idx < GAP_VAL_MAX_BYTES_PER_LINE;l_idx++)
     {
       if (l_buf[l_idx] == '"')
       {
@@ -199,7 +199,7 @@ p_scan_fmac_line(GapValTextFileLines *txf_ptr, GimpRunMode run_mode, const char
           l_data_byte = strtol(l_scan_ptr, &l_scan_ptr2, 16);
           /* if(gap_debug) printf("p_fmac_execute: l_data_byte:%d\n", (int)l_data_byte); */
 
-          if ((l_data_byte < 0) || (l_data_byte > 255) || (l_scan_ptr == l_scan_ptr2))
+          if ((l_data_byte < 0) || (l_scan_ptr == l_scan_ptr2))
           {
             p_free_fmac_line(fmac_line);
             l_msg = g_strdup_printf (_("filtermacro_file: '%s' is corrupted, could not scan databytes")
diff --git a/gap/gap_image.c b/gap/gap_image.c
index d0a953b..ec3a021 100644
--- a/gap/gap_image.c
+++ b/gap/gap_image.c
@@ -428,3 +428,29 @@ gap_image_set_selection_from_selection_or_drawable(gint32 image_id, gint32 ref_d
 
 }  /* end gap_image_set_selection_from_selection_or_drawable */
 
+
+/* ---------------------------------------
+ * gap_image_remove_invisble_layers
+ * ---------------------------------------
+ */
+void
+gap_image_remove_invisble_layers(gint32 image_id)
+{
+  gint    l_nlayers;
+  gint32 *l_layers_list;
+
+  l_layers_list = gimp_image_get_layers(image_id, &l_nlayers);
+  if(l_layers_list != NULL)
+  {
+    int ii;
+    
+    for(ii=0; ii < l_nlayers; ii++)
+    {
+      if (gimp_drawable_get_visible(l_layers_list[ii]) != TRUE)
+      {
+        gimp_image_remove_layer(image_id, l_layers_list[ii]);
+      }
+    }
+    g_free (l_layers_list);
+  }
+}  /* end gap_image_remove_invisble_layers */
diff --git a/gap/gap_image.h b/gap/gap_image.h
index e41d270..079f9af 100644
--- a/gap/gap_image.h
+++ b/gap/gap_image.h
@@ -53,6 +53,7 @@ gint32    gap_image_get_any_layer(gint32 image_id);
 gint32    gap_image_merge_to_specified_layer(gint32 ref_layer_id, GimpMergeType mergemode);
 gboolean  gap_image_set_selection_from_selection_or_drawable(gint32 image_id, gint32 ref_drawable_id
                               , gboolean force_from_drawable);
+void      gap_image_remove_invisble_layers(gint32 image_id);
 
 
 #endif
diff --git a/gap/gap_main.c b/gap/gap_main.c
index c271c5d..e0a90ab 100644
--- a/gap/gap_main.c
+++ b/gap/gap_main.c
@@ -308,7 +308,9 @@ GimpPlugInInfo PLUG_IN_INFO =
     {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"},
     {GIMP_PDB_INT32, "range_from", "frame nr to start"},
     {GIMP_PDB_INT32, "range_to", "frame nr to stop (can be lower than range_from)"},
-    {GIMP_PDB_INT32, "flatten", "0 .. dont flatten image before save"},
+    {GIMP_PDB_INT32, "flatten", "0 .. dont flatten image before save, "
+                                "1 .. flatten before save,"
+                                "2 .. merge visible layers (cliped to image) and remove invisible layers before save"},
     {GIMP_PDB_INT32, "dest_type", "0=RGB, 1=GRAY, 2=INDEXED"},
     {GIMP_PDB_INT32, "dest_colors", "1 upto 256 (used only for dest_type INDEXED)"},
     {GIMP_PDB_INT32, "dest_dither", "0=no, 1=floyd-steinberg  2=fs/low-bleed, 3=fixed (used only for dest_type INDEXED)"},
@@ -324,7 +326,9 @@ GimpPlugInInfo PLUG_IN_INFO =
     {GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)"},
     {GIMP_PDB_INT32, "range_from", "frame nr to start"},
     {GIMP_PDB_INT32, "range_to", "frame nr to stop (can be lower than range_from)"},
-    {GIMP_PDB_INT32, "flatten", "0 .. dont flatten image before save"},
+    {GIMP_PDB_INT32, "flatten", "0 .. dont flatten image before save, "
+                                "1 .. flatten before save,"
+                                "2 .. merge visible layers (cliped to image) and remove invisible layers before save"},
     {GIMP_PDB_INT32, "dest_type", "0=RGB, 1=GRAY, 2=INDEXED"},
     {GIMP_PDB_INT32, "dest_colors", "1 upto 256 (used only for dest_type INDEXED)"},
     {GIMP_PDB_INT32, "dest_dither", "0=no, 1=floyd-steinberg 2=fs/low-bleed, 3=fixed(used only for dest_type INDEXED)"},
@@ -1457,7 +1461,7 @@ run (const gchar *name
         image_id    = param[1].data.d_image;
         range_from  = param[3].data.d_int32;  /* frame nr to start */
         range_to    = param[4].data.d_int32;  /* frame nr to stop  */
-        nr          = param[5].data.d_int32;  /* flatten (0 == no , 1 == flatten) */
+        nr          = param[5].data.d_int32;  /* flatten (0 == no , 1 == flatten, 2 == merge visible) */
         dest_type   = param[6].data.d_int32;
         dest_colors = param[7].data.d_int32;
         dest_dither = param[8].data.d_int32;
diff --git a/gap/gap_mov_xml_par.c b/gap/gap_mov_xml_par.c
index b08dad8..0aa15d3 100755
--- a/gap/gap_mov_xml_par.c
+++ b/gap/gap_mov_xml_par.c
@@ -123,6 +123,7 @@
 #define GAP_MOVPATH_XML_TOKEN_PX                     "px"
 #define GAP_MOVPATH_XML_TOKEN_PY                     "py"
 #define GAP_MOVPATH_XML_TOKEN_KEYFRAME               "keyframe"
+#define GAP_MOVPATH_XML_TOKEN_KEYFRAME_ABS           "keyframe_abs"
 #define GAP_MOVPATH_XML_TOKEN_SEL_FEATHER_RADIUS     "sel_feather_radius"
 #define GAP_MOVPATH_XML_TOKEN_W_RESIZE               "width_resize"
 #define GAP_MOVPATH_XML_TOKEN_H_RESIZE               "height_resize"
@@ -925,6 +926,15 @@ p_xml_parse_element_controlpoint(const gchar         *element_name,
       userDataPtr->pvals->point[count].keyframe_abs = gap_mov_exec_conv_keyframe_to_abs(keyframe, userDataPtr->pvals);
 
     }
+    else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_KEYFRAME_ABS) == 0)
+    {
+      gint keyframe_abs;
+      
+      userDataPtr->isParseOk = gap_xml_parse_value_gint(*value_cursor, &keyframe_abs);
+      userDataPtr->pvals->point[count].keyframe_abs = keyframe_abs;
+      userDataPtr->pvals->point[count].keyframe = gap_mov_exec_conv_keyframe_to_rel(keyframe_abs, userDataPtr->pvals);
+
+    }
     else if (strcmp (*name_cursor, GAP_MOVPATH_XML_TOKEN_SEL_FEATHER_RADIUS) == 0)
     {
       userDataPtr->isParseOk = gap_xml_parse_value_gdouble(*value_cursor, &userDataPtr->pvals->point[count].sel_feather_radius);
@@ -1588,7 +1598,9 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
       gdouble  px;
       gdouble  py;
       gboolean writeAccelerationCharacteristics;
+      gboolean keyframeInNewLine;
       
+      keyframeInNewLine = FALSE;
       px = pvals->point[l_idx].p_x;
       py = pvals->point[l_idx].p_y;
       
@@ -1626,6 +1638,7 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
             || pvals->point[l_idx].tbry != 1.0
             )
       {
+        keyframeInNewLine = TRUE;
         fprintf(l_fp, "\n      ");
         gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TTLX, pvals->point[l_idx].ttlx, 2, 3);
         gap_xml_write_gdouble_value(l_fp, GAP_MOVPATH_XML_TOKEN_TTLY, pvals->point[l_idx].ttly, 2, 3);
@@ -1666,6 +1679,7 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
       
       if (writeAccelerationCharacteristics == TRUE)
       {
+        keyframeInNewLine = TRUE;
         fprintf(l_fp, "\n      ");
         gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_ACC_POSITION, pvals->point[l_idx].accPosition);
         gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_ACC_OPACITY, pvals->point[l_idx].accOpacity);
@@ -1674,19 +1688,31 @@ gap_mov_xml_par_save(char *filename, GapMovValues *pvals)
         gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_ACC_PERSPECTIVE, pvals->point[l_idx].accPerspective);
         gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_ACC_SEL_FEATHER_RADIUS, pvals->point[l_idx].accSelFeatherRadius);
       }
+
+      if(gap_debug)
+      {
+        printf("idx:%d point_idx_max:%d keyframe:%d keyframe_abs:%d to_keyframe:%d\n"
+          ,l_idx
+          ,pvals->point_idx_max
+          ,pvals->point[l_idx].keyframe
+          ,pvals->point[l_idx].keyframe_abs
+          ,gap_mov_exec_conv_keyframe_to_rel(pvals->point[l_idx].keyframe_abs, pvals)
+          );
+      }
       
       /* check for writing keyframe
        * (the implicite keyframes at first and last controlpoints are not written to file)
        */
       if((l_idx > 0)
       && (l_idx < pvals->point_idx_max)
-      && ((int)pvals->point[l_idx].keyframe > 0))
-      {
-        int keyframe;
-        
-        fprintf(l_fp, "\n      ");
-        keyframe = gap_mov_exec_conv_keyframe_to_rel(pvals->point[l_idx].keyframe_abs, pvals);
-        gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_KEYFRAME, keyframe);
+      && ((int)pvals->point[l_idx].keyframe_abs > 0))
+      { 
+        if(keyframeInNewLine == TRUE)
+        {
+          fprintf(l_fp, "\n      ");
+        }
+        gap_xml_write_int_value(l_fp, GAP_MOVPATH_XML_TOKEN_KEYFRAME_ABS, 
+                                pvals->point[l_idx].keyframe_abs);
       
       }
 
diff --git a/gap/gap_range_ops.c b/gap/gap_range_ops.c
index 2b8c897..fdded21 100644
--- a/gap/gap_range_ops.c
+++ b/gap/gap_range_ops.c
@@ -112,6 +112,11 @@ extern      int gap_debug; /* ==0  ... dont print debug infos */
 #define GAP_HELP_ID_CONVERT          "plug-in-gap-range-convert"
 #define GAP_HELP_ID_TO_MULTILAYER    "plug-in-gap-range-to-multilayer"
 
+
+#define FLATTEN_MODE_NONE           0
+#define FLATTEN_MODE_FLATTEN        1
+#define FLATTEN_MODE_MERGE_VISIBLE  2
+
 /* ============================================================================
  * p_anim_sizechange_dialog
  *   dialog window with 2 (or 4) entry fields
@@ -377,13 +382,14 @@ p_convert_indexed_dialog(gint32 *dest_colors, gint32 *dest_dither,
                                   , N_("Positioned Color Dithering")
                                   , N_("No Color Dithering")
                                   };
-  static int gettextize_loop = 0;
+  static int gettextize_paltype = 0;
+  static int gettextize_dither = 0;
 
-  for (;gettextize_loop < 4; gettextize_loop++)
-    radio_paltype[gettextize_loop] = gettext(radio_paltype[gettextize_loop]);
+  for (;gettextize_paltype < 4; gettextize_paltype++)
+    radio_paltype[gettextize_paltype] = gettext(radio_paltype[gettextize_paltype]);
 
-  for (;gettextize_loop < 4; gettextize_loop++)
-    radio_dither[gettextize_loop] = gettext(radio_dither[gettextize_loop]);
+  for (;gettextize_dither < 4; gettextize_dither++)
+    radio_dither[gettextize_dither] = gettext(radio_dither[gettextize_dither]);
 
   gap_arr_arg_init(&argv[0], GAP_ARR_WGT_RADIO);
   argv[0].label_txt = _("Palette Type");
@@ -495,10 +501,36 @@ p_convert_dialog(GapAnimInfo *ainfo_ptr,
     N_("Convert to Gray"),
     N_("Convert to Indexed")
   };
-  static int gettextize_loop = 0;
+  static char *radio_flatten_modes[3]  = {
+    N_("None"),
+    N_("Flatten"),
+    N_("Merge Visible Layers")
+  };
+  static char *radio_flatten_modes_help[3] = {
+    N_("Do not merge layers before save to the selected fileformat. "
+       "Example: use this when converting to XCF that can handle transparency and multiple layers."),
+    N_("Flatten all resulting frames. Most fileformats can not handle multiple layers "
+       "and need flattened frames (flattening does melt down all layers to one composite layer)."
+       "Example: JPEG can not handle multiple layers and requires flattened frames."),
+    N_("Merge resulting frame down to one layer. This keeps transparency information "
+       "Example: use this for PNG fileformat that can handle transpararency (alpha channel) "
+       "but is limited to one layer)") 
+  };
+    
+  static int gettext_cnt1 = 0;
+  static int gettext_cnt2 = 0;
+  static int gettext_cnt3 = 0;
+
+
+  for (;gettext_cnt1 < 4; gettext_cnt1++)
+    radio_args[gettext_cnt1] = gettext(radio_args[gettext_cnt1]);
+
+  for (;gettext_cnt2 < 3; gettext_cnt2++)
+    radio_flatten_modes[gettext_cnt2] = gettext(radio_flatten_modes[gettext_cnt2]);
+
+  for (;gettext_cnt3 < 3; gettext_cnt3++)
+    radio_flatten_modes_help[gettext_cnt3] = gettext(radio_flatten_modes_help[gettext_cnt3]);
 
-  for (;gettextize_loop < 4; gettextize_loop++)
-    radio_args[gettextize_loop] = gettext(radio_args[gettextize_loop]);
 
   gap_arr_arg_init(&argv[0], GAP_ARR_WGT_INT_PAIR);
   argv[0].constraint = TRUE;
@@ -546,12 +578,15 @@ p_convert_dialog(GapAnimInfo *ainfo_ptr,
   argv[5].radio_argv = radio_args;
   argv[5].radio_ret  = 0;
 
-  gap_arr_arg_init(&argv[6], GAP_ARR_WGT_TOGGLE);
-  argv[6].label_txt = _("Flatten:");
+  gap_arr_arg_init(&argv[6], GAP_ARR_WGT_RADIO);
+  argv[6].label_txt = _("Merge Layers:");
   argv[6].help_txt  = _("Flatten all resulting frames. Most fileformats can not handle multiple layers "
                         "and need flattened frames (flattening does melt down all layers to one composite layer)."
                         "Example: JPEG can not handle multiple layers and requires flattened frames.");
-  argv[6].int_ret   = 1;
+  argv[6].radio_argc  = 3;
+  argv[6].radio_argv = radio_flatten_modes;
+  argv[6].radio_help_argv = radio_flatten_modes_help;
+  argv[6].radio_ret  = 1;
 
   gap_arr_arg_init(&argv[7], GAP_ARR_WGT_HELP_BUTTON);
   argv[7].help_id = GAP_HELP_ID_CONVERT;
@@ -579,7 +614,7 @@ p_convert_dialog(GapAnimInfo *ainfo_ptr,
           *dest_type = 9444;   /*  huh ??  */
            break;
       }
-      *flatten     = (long)(argv[6].int_ret);
+      *flatten     = (long)(argv[6].radio_ret);
 
       *dest_colors = 255;
       *dest_dither = 0;
@@ -1428,7 +1463,21 @@ p_frames_convert(GapAnimInfo *ainfo_ptr,
 
 
        /* flatten current frame image (reduce to single layer) */
-       gimp_image_flatten (l_tmp_image_id);
+       if (flatten == FLATTEN_MODE_MERGE_VISIBLE)
+       {
+         gimp_image_merge_visible_layers (l_tmp_image_id, GIMP_CLIP_TO_IMAGE);
+         /* remove the remaining invisible layers because saving to
+          * imageformats that can not handle multiple layers would
+          * trigger the gimp export dialog (that is not desired
+          * for processing multiple frames) on attempt to save
+          * an image with more than 1 layer.
+          */
+         gap_image_remove_invisble_layers(l_tmp_image_id);
+       }
+       else
+       {
+         gimp_image_flatten (l_tmp_image_id);
+       }
 
        /* save back the current frame with same name */
        if(save_proc_name == NULL)
diff --git a/gap/gap_story_render_processor.c b/gap/gap_story_render_processor.c
index f7a98d8..0ade8ff 100644
--- a/gap/gap_story_render_processor.c
+++ b/gap/gap_story_render_processor.c
@@ -8832,6 +8832,7 @@ p_story_render_fetch_composite_image_private(GapStoryRenderVidHandle *vidhand
          && (gfd->frn_elem->mask_name == NULL)
          && (gfd->trak_filtermacro_file == NULL)
          && (gfd->frn_type != GAP_FRN_ANIMIMAGE)
+         && (gfd->movepath_file_xml == NULL)
          )
          {
            GAP_TIMM_START_FUNCTION(funcIdDirect);
diff --git a/libgapbase/gap_val_file.c b/libgapbase/gap_val_file.c
index 811fdbd..e3ea8d5 100644
--- a/libgapbase/gap_val_file.c
+++ b/libgapbase/gap_val_file.c
@@ -181,7 +181,7 @@ gap_val_load_textfile(const char *filename)
   GapValTextFileLines *txf_ptr;
   GapValTextFileLines *txf_ptr_prev;
   GapValTextFileLines *txf_ptr_root;
-  char         l_buf[4000];
+  char         l_buf[GAP_VAL_MAX_BYTES_PER_LINE +1];
   int   line_nr;
   
   line_nr = 0;
@@ -190,7 +190,7 @@ gap_val_load_textfile(const char *filename)
   l_fp = g_fopen(filename, "r");
   if(l_fp)
   {
-    while(NULL != fgets(l_buf, 4000-1, l_fp))
+    while(NULL != fgets(l_buf, GAP_VAL_MAX_BYTES_PER_LINE, l_fp))
     {
       line_nr++;
       txf_ptr = g_malloc0(sizeof(GapValTextFileLines));
diff --git a/libgapbase/gap_val_file.h b/libgapbase/gap_val_file.h
index cb2d3e1..ace16fd 100644
--- a/libgapbase/gap_val_file.h
+++ b/libgapbase/gap_val_file.h
@@ -29,6 +29,8 @@
 
 #include "libgimp/gimp.h"
 
+#define GAP_VAL_MAX_BYTES_PER_LINE 16000
+
 
 typedef struct GapValTextFileLines {
    char    *line;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]