[gimp-gap] bugfixes, frames convert support for merge visible layers #665142
- From: Wolfgang Hofer <wolfgangh src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp-gap] bugfixes, frames convert support for merge visible layers #665142
- Date: Wed, 30 Nov 2011 19:26:56 +0000 (UTC)
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]