mirror of https://github.com/GNOME/gimp.git
1221 lines
38 KiB
C
1221 lines
38 KiB
C
/* gap_mod_layer.c
|
|
* 1998.10.14 hof (Wolfgang Hofer)
|
|
*
|
|
* GAP ... Gimp Animation Plugins
|
|
*
|
|
* This Module contains:
|
|
* modify Layer (perform actions (like raise, set visible, apply filter)
|
|
* - foreach selected layer
|
|
* - in each frame of the selected framerange)
|
|
*
|
|
*/
|
|
/* The GIMP -- an image manipulation program
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/* revision history:
|
|
* gimp 1.1.6; 1999/06/21 hof: bugix: wrong iterator total_steps and direction
|
|
* gimp 1.1.15.1; 1999/05/08 hof: bugix (dont mix GDrawableType with GImageType)
|
|
* version 0.98.00 1998.11.27 hof: - use new module gap_pdb_calls.h
|
|
* version 0.97.00 1998.10.19 hof: - created module
|
|
*/
|
|
|
|
/* SYTEM (UNIX) includes */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
|
|
/* GIMP includes */
|
|
#include "gtk/gtk.h"
|
|
#include "config.h"
|
|
#include "libgimp/stdplugins-intl.h"
|
|
#include "libgimp/gimp.h"
|
|
|
|
/* GAP includes */
|
|
#include "gap_arr_dialog.h"
|
|
#include "gap_filter.h"
|
|
#include "gap_filter_pdb.h"
|
|
#include "gap_pdb_calls.h"
|
|
#include "gap_match.h"
|
|
#include "gap_lib.h"
|
|
#include "gap_range_ops.h"
|
|
#include "gap_mod_layer.h"
|
|
|
|
|
|
extern int gap_debug; /* ==0 ... dont print debug infos */
|
|
|
|
|
|
/* ============================================================================
|
|
* p_layer_modify_dialog
|
|
* retcode
|
|
* 0 ... Generate Paramfile
|
|
* 1 ... Generate Paramfile and start mpeg_encode
|
|
* ============================================================================
|
|
*/
|
|
static
|
|
int p_layer_modify_dialog(t_anim_info *ainfo_ptr,
|
|
gint32 *range_from, gint32 *range_to,
|
|
gint32 *action_mode, gint32 *sel_mode,
|
|
gint32 *sel_case, gint32 *sel_invert,
|
|
char *sel_pattern, char *new_layername)
|
|
{
|
|
static t_arr_arg argv[9];
|
|
static t_but_arg b_argv[2];
|
|
gint l_rc;
|
|
|
|
/* Layer select modes */
|
|
static char *sel_args[7] = { N_("Pattern is equal to LayerName"),
|
|
N_("Pattern is Start of LayerName"),
|
|
N_("Pattern is End of Layername"),
|
|
N_("Pattern is a Part of LayerName"),
|
|
N_("Pattern is LayerstackNumber List"),
|
|
N_("Pattern is REVERSE-stack List"),
|
|
N_("All Visible (ignore Pattern)")
|
|
};
|
|
static char *sel_help[7] = { N_("Select all Layers where Layername is equal to Pattern"),
|
|
N_("Select all Layers where Layername starts with Pattern"),
|
|
N_("Select all Layers where Layername ends up with Pattern"),
|
|
N_("Select all Layers where Layername contains Pattern"),
|
|
N_("Select Layerstack positions.\n0, 4-5, 8\nwhere 0 == Top-layer"),
|
|
N_("Select Layerstack positions.\n0, 4-5, 8\nwhere 0 == BG-layer"),
|
|
N_("Select all visible Layers")
|
|
};
|
|
|
|
/* action items what to do with the selected layer(s) */
|
|
static char *action_args[13] = { N_("Set Layer(s) visible"),
|
|
N_("Set Layer(s) invisible"),
|
|
N_("Set Layer(s) linked"),
|
|
N_("Set Layer(s) unlinked"),
|
|
N_("Raise Layer(s)"),
|
|
N_("Lower Layer(s)"),
|
|
N_("Merge Layer(s) expand as necessary"),
|
|
N_("Merge Layer(s) clipped to image"),
|
|
N_("Merge Layer(s) clipped to bg-layer"),
|
|
N_("Apply filter on Layer(s)"),
|
|
N_("Duplicate Layer(s)"),
|
|
N_("Delete Layer(s)"),
|
|
N_("Rename Layer(s)")
|
|
};
|
|
|
|
|
|
/*
|
|
static char *action_help[13] = {"set all selected layers visible",
|
|
"set all selected layers invisible",
|
|
"set all selected layers linked",
|
|
"set all selected layers unlinked",
|
|
"raise all selected layers",
|
|
"lower all selected layers",
|
|
"merge expand as necessary",
|
|
"merge clipped to image",
|
|
"merge clipped to bg-layer",
|
|
"APPLY FILTER to all selected layers",
|
|
"duplicate all selected layers",
|
|
"delete REMOVES all selected layers",
|
|
"rename all selected layers\nto NewLayername."
|
|
};
|
|
*/
|
|
|
|
int get_textize_loop;
|
|
|
|
for (get_textize_loop = 0; get_textize_loop < 7; get_textize_loop++) {
|
|
sel_args[get_textize_loop] = gettext(sel_args[get_textize_loop]);
|
|
sel_help[get_textize_loop] = gettext(sel_help[get_textize_loop]);
|
|
}
|
|
for (get_textize_loop = 0; get_textize_loop < 13; get_textize_loop++)
|
|
action_args[get_textize_loop] = gettext(action_args[get_textize_loop]);
|
|
|
|
l_rc = -1;
|
|
|
|
/* the 3 Action Buttons */
|
|
b_argv[0].but_txt = _("OK");
|
|
b_argv[0].but_val = 0;
|
|
b_argv[1].but_txt = _("Cancel");
|
|
b_argv[1].but_val = -1;
|
|
|
|
p_init_arr_arg(&argv[0], WGT_LABEL);
|
|
argv[0].label_txt = _("Perform function on one or more Layer(s)\nin all frames of the selected frame range\n");
|
|
|
|
p_init_arr_arg(&argv[1], WGT_INT_PAIR);
|
|
argv[1].constraint = TRUE;
|
|
argv[1].label_txt = _("From Frame:");
|
|
argv[1].help_txt = _("first handled frame");
|
|
argv[1].int_min = (gint)ainfo_ptr->first_frame_nr;
|
|
argv[1].int_max = (gint)ainfo_ptr->last_frame_nr;
|
|
argv[1].int_ret = (gint)ainfo_ptr->curr_frame_nr;
|
|
|
|
p_init_arr_arg(&argv[2], WGT_INT_PAIR);
|
|
argv[2].constraint = TRUE;
|
|
argv[2].label_txt = _("To Frame:");
|
|
argv[2].help_txt = _("last handled frame");
|
|
argv[2].int_min = (gint)ainfo_ptr->first_frame_nr;
|
|
argv[2].int_max = (gint)ainfo_ptr->last_frame_nr;
|
|
argv[2].int_ret = (gint)ainfo_ptr->last_frame_nr;
|
|
|
|
|
|
/* Layer select mode RADIO buttons */
|
|
p_init_arr_arg(&argv[3], WGT_RADIO);
|
|
argv[3].label_txt = _("Select Layer(s):");
|
|
argv[3].radio_argc = 7;
|
|
argv[3].radio_argv = sel_args;
|
|
argv[3].radio_help_argv = sel_help;
|
|
argv[3].radio_ret = 4;
|
|
|
|
/* Layer select pattern string */
|
|
sprintf (sel_pattern, "0");
|
|
p_init_arr_arg(&argv[4], WGT_TEXT);
|
|
argv[4].label_txt = _("Select Pattern:");
|
|
argv[4].entry_width = 140; /* pixel */
|
|
argv[4].help_txt = _("String to identify layer names \nor layerstack position numbers\n0,3-5");
|
|
argv[4].text_buf_len = MAX_LAYERNAME;
|
|
argv[4].text_buf_ret = sel_pattern;
|
|
|
|
/* case sensitive checkbutton */
|
|
p_init_arr_arg(&argv[5], WGT_TOGGLE);
|
|
argv[5].label_txt = _("Case sensitive");
|
|
argv[5].help_txt = _("Lowercase and UPPERCASE letters are considered as different");
|
|
argv[5].int_ret = 1;
|
|
|
|
/* invert selection checkbutton */
|
|
p_init_arr_arg(&argv[6], WGT_TOGGLE);
|
|
argv[6].label_txt = _("Invert Selection");
|
|
argv[6].help_txt = _("Perform actions on all unselected Layers");
|
|
argv[6].int_ret = 0;
|
|
|
|
/* desired action to perform OPTIONMENU */
|
|
p_init_arr_arg(&argv[7], WGT_OPTIONMENU);
|
|
argv[7].label_txt = _("Function:");
|
|
argv[7].radio_argc = 13;
|
|
argv[7].radio_argv = action_args;
|
|
/* argv[7].radio_help_argv = action_help */
|
|
argv[7].help_txt = _("Function to be performed on all selected layers");
|
|
argv[7].radio_ret = 0;
|
|
|
|
/* a new name for the handled Layer(s) */
|
|
*new_layername = '\0';
|
|
p_init_arr_arg(&argv[8], WGT_TEXT);
|
|
argv[8].label_txt = _("New Layername:");
|
|
argv[8].entry_width = 140; /* pixel */
|
|
argv[8].help_txt = _("New Layername for all handled layers \n[####] is replaced by frame number\n(is used on function rename only)");
|
|
argv[8].text_buf_len = MAX_LAYERNAME;
|
|
argv[8].text_buf_ret = new_layername;
|
|
|
|
|
|
l_rc = p_array_std_dialog( _("Frames Modify"),
|
|
_("Settings"),
|
|
9, argv, /* widget array */
|
|
2, b_argv, /* button array */
|
|
0);
|
|
|
|
/* return the entered values */
|
|
*range_from = argv[1].int_ret;
|
|
*range_to = argv[2].int_ret;
|
|
*sel_mode = argv[3].int_ret;
|
|
/* [4] sel_pattern */
|
|
*sel_case = argv[5].int_ret;
|
|
*sel_invert = argv[6].int_ret;
|
|
*action_mode = argv[7].int_ret;
|
|
/* [8] l_new_layername */
|
|
|
|
|
|
return (l_rc);
|
|
} /* end p_layer_modify_dialog */
|
|
|
|
|
|
/* ============================================================================
|
|
* p_pitstop_dialog
|
|
* return -1 on CANCEL
|
|
* 0 on Continue (OK)
|
|
* ============================================================================
|
|
*/
|
|
static gint
|
|
p_pitstop_dialog(gint text_flag, char *filter_procname)
|
|
{
|
|
gchar *l_env;
|
|
gchar *l_msg;
|
|
static t_but_arg l_but_argv[2];
|
|
gint l_but_argc;
|
|
gint l_argc;
|
|
static t_arr_arg l_argv[1];
|
|
int l_continue;
|
|
|
|
|
|
|
|
|
|
l_but_argv[0].but_txt = _("Continue");
|
|
l_but_argv[0].but_val = 0;
|
|
l_but_argv[1].but_txt = _("Cancel");
|
|
l_but_argv[1].but_val = -1;
|
|
|
|
l_but_argc = 2;
|
|
l_argc = 0;
|
|
|
|
/* optional dialog between both calls (to see the effect of 1.call) */
|
|
l_env = g_getenv("GAP_FILTER_PITSTOP");
|
|
if(l_env != NULL)
|
|
{
|
|
if((*l_env == 'N') || (*l_env == 'n'))
|
|
{
|
|
return 0; /* continue without question */
|
|
}
|
|
}
|
|
if(text_flag == 0)
|
|
{
|
|
l_msg = g_strdup_printf (_("2nd call of %s\n(define end-settings)"), filter_procname);
|
|
}
|
|
else
|
|
{
|
|
l_msg = g_strdup_printf ( _("Non-Interactive call of %s\n(for all selected layers)"), filter_procname);
|
|
}
|
|
l_continue = p_array_std_dialog ( _("Animated Filter apply"), l_msg,
|
|
l_argc, l_argv,
|
|
l_but_argc, l_but_argv, 0);
|
|
g_free (l_msg);
|
|
|
|
return (l_continue);
|
|
|
|
} /* end p_pitstop_dialog */
|
|
|
|
|
|
/* ============================================================================
|
|
* p_get_1st_selected
|
|
* return index of the 1.st selected layer
|
|
* or -1 if no selection was found
|
|
* ============================================================================
|
|
*/
|
|
int
|
|
p_get_1st_selected (t_LayliElem * layli_ptr, gint nlayers)
|
|
{
|
|
int l_idx;
|
|
|
|
for(l_idx = 0; l_idx < nlayers; l_idx++)
|
|
{
|
|
if(layli_ptr[l_idx].selected != FALSE)
|
|
{
|
|
return (l_idx);
|
|
}
|
|
}
|
|
return(-1);
|
|
} /* end p_get_1st_selected */
|
|
|
|
|
|
/* ============================================================================
|
|
* p_alloc_layli
|
|
* returns pointer to a new allocated image_id of the new created multilayer image
|
|
* (or NULL on error)
|
|
* ============================================================================
|
|
*/
|
|
|
|
t_LayliElem *
|
|
p_alloc_layli(gint32 image_id, gint32 *l_sel_cnt, gint *nlayers,
|
|
gint32 sel_mode,
|
|
gint32 sel_case,
|
|
gint32 sel_invert,
|
|
char *sel_pattern )
|
|
{
|
|
gint32 *l_layers_list;
|
|
gint32 l_layer_id;
|
|
gint32 l_idx;
|
|
t_LayliElem *l_layli_ptr;
|
|
char *l_layername;
|
|
|
|
*l_sel_cnt = 0;
|
|
|
|
l_layers_list = gimp_image_get_layers(image_id, nlayers);
|
|
if(l_layers_list == NULL)
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
l_layli_ptr = g_new0(t_LayliElem, (*nlayers));
|
|
if(l_layli_ptr == NULL)
|
|
{
|
|
g_free (l_layers_list);
|
|
return(NULL);
|
|
}
|
|
|
|
for(l_idx = 0; l_idx < (*nlayers); l_idx++)
|
|
{
|
|
l_layer_id = l_layers_list[l_idx];
|
|
l_layername = gimp_layer_get_name(l_layer_id);
|
|
l_layli_ptr[l_idx].layer_id = l_layer_id;
|
|
l_layli_ptr[l_idx].visible = gimp_layer_get_visible(l_layer_id);
|
|
l_layli_ptr[l_idx].selected = p_match_layer(l_idx,
|
|
l_layername,
|
|
sel_pattern,
|
|
sel_mode,
|
|
sel_case,
|
|
sel_invert,
|
|
*nlayers, l_layer_id);
|
|
if(l_layli_ptr[l_idx].selected != FALSE)
|
|
{
|
|
(*l_sel_cnt)++; /* count all selected layers */
|
|
}
|
|
if(gap_debug) printf("gap: p_alloc_layli [%d] id:%d, sel:%d %s\n",
|
|
(int)l_idx, (int)l_layer_id,
|
|
(int)l_layli_ptr[l_idx].selected, l_layername);
|
|
g_free (l_layername);
|
|
}
|
|
|
|
g_free (l_layers_list);
|
|
|
|
return( l_layli_ptr );
|
|
} /* end p_alloc_layli */
|
|
|
|
/* ============================================================================
|
|
* p_prevent_empty_image
|
|
* check if the resulting image has at least one layer
|
|
* (gimp 1.0.0 tends to crash on layerless images)
|
|
* ============================================================================
|
|
*/
|
|
|
|
void p_prevent_empty_image(gint32 image_id)
|
|
{
|
|
GImageType l_type;
|
|
guint l_width, l_height;
|
|
gint32 l_layer_id;
|
|
gint l_nlayers;
|
|
gint32 *l_layers_list;
|
|
|
|
l_layers_list = gimp_image_get_layers(image_id, &l_nlayers);
|
|
if(l_layers_list != NULL)
|
|
{
|
|
g_free (l_layers_list);
|
|
}
|
|
else l_nlayers = 0;
|
|
|
|
if(l_nlayers == 0)
|
|
{
|
|
/* the resulting image has no layer, add a transparent dummy layer */
|
|
|
|
/* get info about the image */
|
|
l_width = gimp_image_width(image_id);
|
|
l_height = gimp_image_height(image_id);
|
|
l_type = gimp_image_base_type(image_id);
|
|
|
|
l_type = (l_type * 2); /* convert from GImageType to GDrawableType */
|
|
|
|
/* add a transparent dummy layer */
|
|
l_layer_id = gimp_layer_new(image_id, "dummy",
|
|
l_width, l_height, l_type,
|
|
0.0, /* Opacity full transparent */
|
|
0); /* NORMAL */
|
|
gimp_image_add_layer(image_id, l_layer_id, 0);
|
|
}
|
|
|
|
} /* end p_prevent_empty_image */
|
|
|
|
|
|
/* ============================================================================
|
|
* p_raise_layer
|
|
* raise layer (check if possible before)
|
|
* (without the check each failed attempt would open an inf window)
|
|
* ============================================================================
|
|
*/
|
|
static void
|
|
p_raise_layer (gint32 image_id, gint32 layer_id, t_LayliElem * layli_ptr, gint nlayers)
|
|
{
|
|
if(! gimp_drawable_has_alpha (layer_id)) return; /* has no alpha channel */
|
|
|
|
if(layli_ptr[0].layer_id == layer_id) return; /* is already on top */
|
|
|
|
gimp_image_raise_layer(image_id, layer_id);
|
|
} /* end p_raise_layer */
|
|
|
|
static void
|
|
p_lower_layer (gint32 image_id, gint32 layer_id, t_LayliElem * layli_ptr, gint nlayers)
|
|
{
|
|
if(! gimp_drawable_has_alpha (layer_id)) return; /* has no alpha channel */
|
|
|
|
if(layli_ptr[nlayers-1].layer_id == layer_id) return; /* is already on bottom */
|
|
|
|
if(nlayers > 1)
|
|
{
|
|
if((layli_ptr[nlayers-2].layer_id == layer_id)
|
|
&& (! gimp_drawable_has_alpha (layli_ptr[nlayers-1].layer_id)))
|
|
{
|
|
/* the layer is one step above a "bottom-layer without alpha" */
|
|
return;
|
|
}
|
|
}
|
|
|
|
gimp_image_lower_layer(image_id, layer_id);
|
|
} /* end p_lower_layer */
|
|
|
|
/* ============================================================================
|
|
* p_apply_action
|
|
*
|
|
* perform function (defined by action_mode)
|
|
* on all selcted layer(s)
|
|
*
|
|
* returns 0 if all done OK
|
|
* (or -1 on error)
|
|
* ============================================================================
|
|
*/
|
|
|
|
static int
|
|
p_apply_action(gint32 image_id,
|
|
gint32 action_mode,
|
|
t_LayliElem *layli_ptr,
|
|
gint nlayers,
|
|
gint32 sel_cnt,
|
|
|
|
long from,
|
|
long to,
|
|
long curr,
|
|
char *new_layername,
|
|
char *filter_procname
|
|
)
|
|
{
|
|
int l_idx;
|
|
int l_rc;
|
|
gint32 l_layer_id;
|
|
gint32 l_new_layer_id;
|
|
gint l_merge_mode;
|
|
gint l_vis_result;
|
|
char l_name_buff[MAX_LAYERNAME];
|
|
|
|
if(gap_debug) fprintf(stderr, "gap: p_apply_action START\n");
|
|
|
|
l_rc = 0;
|
|
l_merge_mode = -44; /* none of the flatten modes */
|
|
|
|
if(action_mode == ACM_MERGE_EXPAND) l_merge_mode = FLAM_MERG_EXPAND;
|
|
if(action_mode == ACM_MERGE_IMG) l_merge_mode = FLAM_MERG_CLIP_IMG;
|
|
if(action_mode == ACM_MERGE_BG) l_merge_mode = FLAM_MERG_CLIP_BG;
|
|
|
|
/* merge actions require one call per image */
|
|
if(l_merge_mode != (-44))
|
|
{
|
|
if(sel_cnt < 2)
|
|
{
|
|
return(0); /* OK, nothing to merge */
|
|
}
|
|
|
|
l_vis_result = FALSE;
|
|
|
|
/* set selected layers visible, all others invisible for merge */
|
|
for(l_idx = 0; l_idx < nlayers; l_idx++)
|
|
{
|
|
if(layli_ptr[l_idx].selected == FALSE)
|
|
{
|
|
gimp_layer_set_visible(layli_ptr[l_idx].layer_id, FALSE);
|
|
}
|
|
else
|
|
{
|
|
if(gimp_layer_get_visible(layli_ptr[l_idx].layer_id))
|
|
{
|
|
/* result will we visible if at least one of the
|
|
* selected layers was visible before
|
|
*/
|
|
l_vis_result = TRUE;
|
|
}
|
|
gimp_layer_set_visible(layli_ptr[l_idx].layer_id, TRUE);
|
|
}
|
|
}
|
|
|
|
/* merge all visible layers (i.e. all selected layers) */
|
|
l_layer_id = gimp_image_merge_visible_layers (image_id, l_merge_mode);
|
|
if(l_vis_result == FALSE)
|
|
{
|
|
gimp_layer_set_visible(l_layer_id, FALSE);
|
|
}
|
|
|
|
/* if new_layername is available use that name
|
|
* for the new merged layer
|
|
*/
|
|
if (!p_is_empty (new_layername))
|
|
{
|
|
p_substitute_framenr(&l_name_buff[0], sizeof(l_name_buff),
|
|
new_layername, curr);
|
|
gimp_layer_set_name(l_layer_id, &l_name_buff[0]);
|
|
}
|
|
|
|
/* restore visibility flags after merge */
|
|
for(l_idx = 0; l_idx < nlayers; l_idx++)
|
|
{
|
|
if(layli_ptr[l_idx].selected == FALSE)
|
|
{
|
|
gimp_layer_set_visible(layli_ptr[l_idx].layer_id,
|
|
layli_ptr[l_idx].visible);
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* -----------------------------*/
|
|
/* non-merge actions require calls foreach selected layer */
|
|
for(l_idx = 0; (l_idx < nlayers) && (l_rc == 0); l_idx++)
|
|
{
|
|
l_layer_id = layli_ptr[l_idx].layer_id;
|
|
|
|
/* apply function defined by action_mode */
|
|
if(layli_ptr[l_idx].selected != FALSE)
|
|
{
|
|
if(gap_debug) fprintf(stderr, "gap: p_apply_action on selected LayerID:%d layerstack:%d\n",
|
|
(int)l_layer_id, (int)l_idx);
|
|
switch(action_mode)
|
|
{
|
|
case ACM_SET_VISIBLE:
|
|
gimp_layer_set_visible(l_layer_id, TRUE);
|
|
break;
|
|
case ACM_SET_INVISIBLE:
|
|
gimp_layer_set_visible(l_layer_id, FALSE);
|
|
break;
|
|
case ACM_SET_LINKED:
|
|
l_rc = p_layer_set_linked (l_layer_id, TRUE);
|
|
break;
|
|
case ACM_SET_UNLINKED:
|
|
l_rc = p_layer_set_linked (l_layer_id, FALSE);
|
|
break;
|
|
case ACM_RAISE:
|
|
p_raise_layer(image_id, l_layer_id, layli_ptr, nlayers);
|
|
break;
|
|
case ACM_LOWER:
|
|
p_lower_layer(image_id, l_layer_id, layli_ptr, nlayers);
|
|
break;
|
|
case ACM_APPLY_FILTER:
|
|
l_rc = p_call_plugin(filter_procname,
|
|
image_id,
|
|
l_layer_id,
|
|
RUN_WITH_LAST_VALS);
|
|
if(gap_debug) fprintf(stderr, "gap: p_apply_action FILTER:%s rc =%d\n",
|
|
filter_procname, (int)l_rc);
|
|
break;
|
|
case ACM_DUPLICATE:
|
|
l_new_layer_id = gimp_layer_copy(l_layer_id);
|
|
gimp_image_add_layer (image_id, l_new_layer_id, -1);
|
|
if (!p_is_empty (new_layername))
|
|
{
|
|
p_substitute_framenr(&l_name_buff[0], sizeof(l_name_buff),
|
|
new_layername, curr);
|
|
gimp_layer_set_name(l_new_layer_id, &l_name_buff[0]);
|
|
}
|
|
break;
|
|
case ACM_DELETE:
|
|
gimp_image_remove_layer(image_id, l_layer_id);
|
|
break;
|
|
case ACM_RENAME:
|
|
p_substitute_framenr(&l_name_buff[0], sizeof(l_name_buff),
|
|
new_layername, curr);
|
|
gimp_layer_set_name(l_layer_id, &l_name_buff[0]);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (l_rc);
|
|
} /* end p_apply_action */
|
|
|
|
|
|
/* ============================================================================
|
|
* p_do_filter_dialogs
|
|
* additional dialog steps
|
|
* a) gap_pdb_browser (select the filter)
|
|
* b) 1st interactive filtercall
|
|
* c) 1st pitstop dialog
|
|
* ============================================================================
|
|
*/
|
|
static int
|
|
p_do_filter_dialogs(t_anim_info *ainfo_ptr,
|
|
gint32 image_id, gint32 *dpy_id,
|
|
t_LayliElem * layli_ptr, gint nlayers ,
|
|
char *filter_procname, int filt_len,
|
|
gint *plugin_data_len,
|
|
t_apply_mode *apply_mode
|
|
)
|
|
{
|
|
t_gap_db_browse_result l_browser_result;
|
|
gint32 l_layer_id;
|
|
int l_rc;
|
|
int l_idx;
|
|
static char l_key_from[512];
|
|
static gint l_gtk_init = TRUE; /* gkt_init at 1.st call */
|
|
|
|
if(ainfo_ptr->run_mode == RUN_INTERACTIVE)
|
|
{
|
|
l_gtk_init = FALSE; /* gtk_init was done in 1.st modify dialog before */
|
|
}
|
|
|
|
|
|
/* GAP-PDB-Browser Dialog */
|
|
/* ---------------------- */
|
|
if(gap_db_browser_dialog( _("Select Filter for Animated frames-apply"),
|
|
_("Apply Constant"),
|
|
_("Apply Varying"),
|
|
p_constraint_proc,
|
|
p_constraint_proc_sel1,
|
|
p_constraint_proc_sel2,
|
|
&l_browser_result,
|
|
l_gtk_init /* do not call gtk_init */
|
|
)
|
|
< 0)
|
|
{
|
|
if(gap_debug) fprintf(stderr, "DEBUG: gap_db_browser_dialog cancelled\n");
|
|
return -1;
|
|
}
|
|
|
|
p_arr_gtk_init(FALSE); /* disable the initial gtk_init in gap_arr_dialog's
|
|
* (gtk_init was done before)
|
|
*/
|
|
|
|
strncpy(filter_procname, l_browser_result.selected_proc_name, filt_len-1);
|
|
filter_procname[filt_len-1] = '\0';
|
|
if(l_browser_result.button_nr == 1) *apply_mode = PTYP_VARYING_LINEAR;
|
|
else *apply_mode = PAPP_CONSTANT;
|
|
|
|
/* 1.st INTERACTIV Filtercall dialog */
|
|
/* --------------------------------- */
|
|
/* check for the Plugin */
|
|
|
|
l_rc = p_procedure_available(filter_procname, PTYP_CAN_OPERATE_ON_DRAWABLE);
|
|
if(l_rc < 0)
|
|
{
|
|
fprintf(stderr, "ERROR: Plugin not available or wrong type %s\n", filter_procname);
|
|
return -1;
|
|
}
|
|
|
|
/* get 1.st selected layer (of 1.st handled frame in range ) */
|
|
l_idx = p_get_1st_selected(layli_ptr, nlayers);
|
|
if(l_idx < 0)
|
|
{
|
|
fprintf(stderr, "ERROR: No layer selected in 1.st handled frame\n");
|
|
return (-1);
|
|
}
|
|
l_layer_id = layli_ptr[l_idx].layer_id;
|
|
|
|
/* open a view for the 1.st handled frame */
|
|
*dpy_id = gimp_display_new (image_id);
|
|
|
|
l_rc = p_call_plugin(filter_procname, image_id, l_layer_id, RUN_INTERACTIVE);
|
|
|
|
/* OOPS: cant delete the display here, because
|
|
* closing the last display seems to free up
|
|
* at least parts of the image,
|
|
* and causes crashes if the image_id is used
|
|
* in further gimp procedures
|
|
*/
|
|
/* gimp_display_delete(*dpy_id); */
|
|
|
|
/* get values, then store with suffix "_ITER_FROM" */
|
|
*plugin_data_len = p_get_data(filter_procname);
|
|
if(*plugin_data_len > 0)
|
|
{
|
|
sprintf(l_key_from, "%s_ITER_FROM", filter_procname);
|
|
p_set_data(l_key_from, *plugin_data_len);
|
|
}
|
|
else
|
|
{
|
|
return (-1);
|
|
}
|
|
|
|
if(*apply_mode != PTYP_VARYING_LINEAR)
|
|
{
|
|
return (p_pitstop_dialog(1, filter_procname));
|
|
}
|
|
|
|
return(0);
|
|
} /* end p_do_filter_dialogs */
|
|
|
|
|
|
/* ============================================================================
|
|
* p_do_2nd_filter_dialogs
|
|
* d) [ 2nd interactive filtercall
|
|
* e) 2nd pitstop dialog ]
|
|
*
|
|
* (temporary) open the last frame of the range
|
|
* get its 1.st selected laye
|
|
* and do the Interctive Filtercall (to get the end-values)
|
|
*
|
|
* then close everything (without save).
|
|
* (the last frame will be processed later, with all its selected layers)
|
|
* ============================================================================
|
|
*/
|
|
static gint
|
|
p_do_2nd_filter_dialogs(char *filter_procname,
|
|
t_apply_mode l_apply_mode,
|
|
char *last_frame_filename,
|
|
gint32 sel_mode, gint32 sel_case,
|
|
gint32 sel_invert, char *sel_pattern
|
|
)
|
|
{
|
|
gint32 l_layer_id;
|
|
gint32 l_dpy_id;
|
|
int l_rc;
|
|
int l_idx;
|
|
static char l_key_to[512];
|
|
static char l_key_from[512];
|
|
gint32 l_last_image_id;
|
|
t_LayliElem *l_layli_ptr;
|
|
gint l_nlayers;
|
|
gint32 l_sel_cnt;
|
|
gint l_plugin_data_len;
|
|
|
|
l_layli_ptr = NULL;
|
|
l_rc = -1; /* assume cancel or error */
|
|
l_last_image_id = -1;
|
|
l_dpy_id = -1;
|
|
|
|
/* 2.nd INTERACTIV Filtercall dialog */
|
|
/* --------------------------------- */
|
|
if(last_frame_filename == NULL)
|
|
{
|
|
return (-1); /* there is no 2.nd frame for 2.nd filter call */
|
|
}
|
|
|
|
if(p_pitstop_dialog(0, filter_procname) < 0)
|
|
goto cleanup;
|
|
|
|
/* load last frame into temporary image */
|
|
l_last_image_id = p_load_image(last_frame_filename);
|
|
if (l_last_image_id < 0)
|
|
goto cleanup;
|
|
|
|
/* get informations (id, visible, selected) about all layers */
|
|
l_layli_ptr = p_alloc_layli(l_last_image_id, &l_sel_cnt, &l_nlayers,
|
|
sel_mode, sel_case, sel_invert, sel_pattern);
|
|
|
|
if (l_layli_ptr == NULL)
|
|
goto cleanup;
|
|
|
|
/* get 1.st selected layer (of last handled frame in range ) */
|
|
l_idx = p_get_1st_selected(l_layli_ptr, l_nlayers);
|
|
if(l_idx < 0)
|
|
{
|
|
p_msg_win (RUN_INTERACTIVE, _("GAP Modify: No layer selected in last handled frame"));
|
|
goto cleanup;
|
|
}
|
|
l_layer_id = l_layli_ptr[l_idx].layer_id;
|
|
|
|
/* open a view for the last handled frame */
|
|
l_dpy_id = gimp_display_new (l_last_image_id);
|
|
|
|
/* 2.nd INTERACTIV Filtercall dialog */
|
|
/* --------------------------------- */
|
|
l_rc = p_call_plugin(filter_procname, l_last_image_id, l_layer_id, RUN_INTERACTIVE);
|
|
|
|
/* get values, then store with suffix "_ITER_TO" */
|
|
l_plugin_data_len = p_get_data(filter_procname);
|
|
if(l_plugin_data_len <= 0)
|
|
goto cleanup;
|
|
|
|
sprintf(l_key_to, "%s_ITER_TO", filter_procname);
|
|
p_set_data(l_key_to, l_plugin_data_len);
|
|
|
|
/* get FROM values */
|
|
sprintf(l_key_from, "%s_ITER_FROM", filter_procname);
|
|
l_plugin_data_len = p_get_data(l_key_from);
|
|
p_set_data(filter_procname, l_plugin_data_len);
|
|
|
|
l_rc = p_pitstop_dialog(1, filter_procname);
|
|
|
|
cleanup:
|
|
if(l_dpy_id >= 0) gimp_display_delete(l_dpy_id);
|
|
if(l_last_image_id >= 0) gimp_image_delete(l_last_image_id);
|
|
if(l_layli_ptr != NULL) g_free(l_layli_ptr);
|
|
|
|
return (l_rc);
|
|
|
|
|
|
} /* end p_do_2nd_filter_dialogs */
|
|
|
|
|
|
/* ============================================================================
|
|
* p_frames_modify
|
|
*
|
|
* foreach frame of the range (given by range_from and range_to)
|
|
* perform function defined by action_mode
|
|
* on all selected layer(s) described by sel_mode, sel_case
|
|
* sel_invert and sel_pattern
|
|
* returns 0 if all done OK
|
|
* (or -1 on error or cancel)
|
|
* ============================================================================
|
|
*/
|
|
static gint32
|
|
p_frames_modify(t_anim_info *ainfo_ptr,
|
|
long range_from, long range_to,
|
|
gint32 action_mode, gint32 sel_mode,
|
|
gint32 sel_case, gint32 sel_invert,
|
|
char *sel_pattern, char *new_layername)
|
|
{
|
|
long l_cur_frame_nr;
|
|
long l_step, l_begin, l_end;
|
|
gint32 l_tmp_image_id;
|
|
gint32 l_dpy_id;
|
|
gint l_nlayers;
|
|
gdouble l_percentage, l_percentage_step;
|
|
int l_rc;
|
|
int l_idx;
|
|
gint32 l_sel_cnt;
|
|
t_LayliElem *l_layli_ptr;
|
|
|
|
GParam *l_params;
|
|
gint l_retvals;
|
|
gint l_plugin_data_len;
|
|
char l_filter_procname[256];
|
|
char *l_plugin_iterator;
|
|
gdouble l_cur_step;
|
|
gint l_total_steps;
|
|
t_apply_mode l_apply_mode;
|
|
char *l_last_frame_filename;
|
|
|
|
|
|
|
|
|
|
if(gap_debug) fprintf(stderr, "gap: p_frames_modify START, action_mode=%d sel_mode=%d case=%d, invert=%d patt:%s:\n",
|
|
(int)action_mode, (int)sel_mode, (int)sel_case, (int)sel_invert, sel_pattern);
|
|
|
|
l_percentage = 0.0;
|
|
if(ainfo_ptr->run_mode == RUN_INTERACTIVE)
|
|
{
|
|
gimp_progress_init( _("Modifying Frames/Layer(s)..."));
|
|
}
|
|
|
|
|
|
l_begin = range_from;
|
|
l_end = range_to;
|
|
l_tmp_image_id = -1;
|
|
l_layli_ptr = NULL;
|
|
l_rc = 0;
|
|
l_plugin_iterator = NULL;
|
|
l_plugin_data_len = 0;
|
|
l_apply_mode = PAPP_CONSTANT;
|
|
l_dpy_id = -1;
|
|
l_last_frame_filename = NULL;
|
|
|
|
/* init step direction */
|
|
if(range_from > range_to)
|
|
{
|
|
l_step = -1; /* operate in descending (reverse) order */
|
|
l_percentage_step = 1.0 / ((1.0 + range_from) - range_to);
|
|
|
|
if(range_to < ainfo_ptr->first_frame_nr)
|
|
{ l_begin = ainfo_ptr->first_frame_nr;
|
|
}
|
|
if(range_from > ainfo_ptr->last_frame_nr)
|
|
{ l_end = ainfo_ptr->last_frame_nr;
|
|
}
|
|
|
|
l_total_steps = l_begin - l_end;
|
|
}
|
|
else
|
|
{
|
|
l_step = 1; /* operate in ascending order */
|
|
l_percentage_step = 1.0 / ((1.0 + range_to) - range_from);
|
|
|
|
if(range_from < ainfo_ptr->first_frame_nr)
|
|
{ l_begin = ainfo_ptr->first_frame_nr;
|
|
}
|
|
if(range_to > ainfo_ptr->last_frame_nr)
|
|
{ l_end = ainfo_ptr->last_frame_nr;
|
|
}
|
|
|
|
l_total_steps = l_end - l_begin;
|
|
}
|
|
|
|
l_cur_step = l_total_steps;
|
|
|
|
l_cur_frame_nr = l_begin;
|
|
while(1) /* loop foreach frame in range */
|
|
{
|
|
if(gap_debug) fprintf(stderr, "p_frames_modify While l_cur_frame_nr = %d\n", (int)l_cur_frame_nr);
|
|
|
|
/* build the frame name */
|
|
if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename);
|
|
ainfo_ptr->new_filename = p_alloc_fname(ainfo_ptr->basename,
|
|
l_cur_frame_nr,
|
|
ainfo_ptr->extension);
|
|
if(ainfo_ptr->new_filename == NULL)
|
|
goto error;
|
|
|
|
/* load current frame into temporary image */
|
|
l_tmp_image_id = p_load_image(ainfo_ptr->new_filename);
|
|
if(l_tmp_image_id < 0)
|
|
goto error;
|
|
|
|
/* get informations (id, visible, selected) about all layers */
|
|
l_layli_ptr = p_alloc_layli(l_tmp_image_id, &l_sel_cnt, &l_nlayers,
|
|
sel_mode, sel_case, sel_invert, sel_pattern);
|
|
|
|
if(l_layli_ptr == NULL)
|
|
{
|
|
printf("gap: p_frames_modify: cant alloc layer info list\n");
|
|
goto error;
|
|
}
|
|
|
|
if((l_cur_frame_nr == l_begin) && (action_mode == ACM_APPLY_FILTER))
|
|
{
|
|
/* ------------- 1.st frame: extra dialogs for APPLY_FILTER ---------- */
|
|
|
|
if(l_sel_cnt < 1)
|
|
{
|
|
p_msg_win(RUN_INTERACTIVE, _("No selected Layer in start frame"));
|
|
goto error;
|
|
}
|
|
|
|
if(l_begin != l_end)
|
|
{
|
|
l_last_frame_filename = p_alloc_fname(ainfo_ptr->basename,
|
|
l_end,
|
|
ainfo_ptr->extension);
|
|
}
|
|
|
|
/* additional dialog steps a) gap_pdb_browser (select the filter)
|
|
* b) 1st interactive filtercall
|
|
* c) 1st pitstop dialog
|
|
* d) [ 2nd interactive filtercall
|
|
* e) 2nd pitstop dialog ]
|
|
*/
|
|
|
|
l_rc = p_do_filter_dialogs(ainfo_ptr,
|
|
l_tmp_image_id, &l_dpy_id,
|
|
l_layli_ptr, l_nlayers,
|
|
&l_filter_procname[0], sizeof(l_filter_procname),
|
|
&l_plugin_data_len,
|
|
&l_apply_mode
|
|
);
|
|
|
|
if(l_last_frame_filename != NULL)
|
|
{
|
|
if((l_rc == 0) && (l_apply_mode == PTYP_VARYING_LINEAR))
|
|
{
|
|
l_rc = p_do_2nd_filter_dialogs(&l_filter_procname[0],
|
|
l_apply_mode,
|
|
l_last_frame_filename,
|
|
sel_mode, sel_case, sel_invert, sel_pattern
|
|
);
|
|
}
|
|
|
|
g_free(l_last_frame_filename);
|
|
l_last_frame_filename = NULL;
|
|
}
|
|
|
|
/* the 1st selected layer has been filtered
|
|
* in the INTERACTIVE call b)
|
|
* therefore we unselect this layer, to avoid
|
|
* a 2nd processing
|
|
*/
|
|
l_idx = p_get_1st_selected(l_layli_ptr, l_nlayers);
|
|
if(l_idx >= 0)
|
|
{
|
|
l_layli_ptr[l_idx].selected = FALSE;
|
|
l_sel_cnt--;
|
|
}
|
|
|
|
/* check for matching Iterator PluginProcedures */
|
|
if(l_apply_mode == PTYP_VARYING_LINEAR )
|
|
{
|
|
l_plugin_iterator = p_get_iterator_proc(&l_filter_procname[0]);
|
|
}
|
|
}
|
|
|
|
if(l_rc != 0)
|
|
goto error;
|
|
|
|
/* perform function (defined by action_mode) on selcted layer(s) */
|
|
l_rc = p_apply_action(l_tmp_image_id,
|
|
action_mode,
|
|
l_layli_ptr,
|
|
l_nlayers,
|
|
l_sel_cnt,
|
|
l_begin, l_end, l_cur_frame_nr,
|
|
new_layername,
|
|
&l_filter_procname[0]
|
|
);
|
|
if(l_rc != 0)
|
|
{
|
|
if(gap_debug) fprintf(stderr, "gap: p_frames_modify p_apply-action failed. rc=%d\n", (int)l_rc);
|
|
goto error;
|
|
}
|
|
|
|
/* free layli info table for the current frame */
|
|
if(l_layli_ptr != NULL)
|
|
{
|
|
g_free(l_layli_ptr);
|
|
l_layli_ptr = NULL;
|
|
}
|
|
|
|
/* check if the resulting image has at least one layer */
|
|
p_prevent_empty_image(l_tmp_image_id);
|
|
|
|
/* save current frame with same name */
|
|
l_rc = p_save_named_frame(l_tmp_image_id, ainfo_ptr->new_filename);
|
|
if(l_rc < 0)
|
|
{
|
|
printf("gap: p_frames_modify save frame %d failed.\n", (int)l_cur_frame_nr);
|
|
goto error;
|
|
}
|
|
else l_rc = 0;
|
|
|
|
/* iterator call (for filter apply with varying values) */
|
|
if((action_mode == ACM_APPLY_FILTER)
|
|
&& (l_plugin_iterator != NULL) && (l_apply_mode == PTYP_VARYING_LINEAR ))
|
|
{
|
|
l_cur_step -= 1.0;
|
|
/* call plugin-specific iterator, to modify
|
|
* the plugin's last_values
|
|
*/
|
|
if(gap_debug) fprintf(stderr, "DEBUG: calling iterator %s current frame:%d\n",
|
|
l_plugin_iterator, (int)l_cur_frame_nr);
|
|
l_params = gimp_run_procedure (l_plugin_iterator,
|
|
&l_retvals,
|
|
PARAM_INT32, RUN_NONINTERACTIVE,
|
|
PARAM_INT32, l_total_steps, /* total steps */
|
|
PARAM_FLOAT, (gdouble)l_cur_step, /* current step */
|
|
PARAM_INT32, l_plugin_data_len, /* length of stored data struct */
|
|
PARAM_END);
|
|
if (l_params[0].data.d_status == FALSE)
|
|
{
|
|
fprintf(stderr, "ERROR: iterator %s failed\n", l_plugin_iterator);
|
|
l_rc = -1;
|
|
}
|
|
|
|
g_free(l_params);
|
|
}
|
|
|
|
|
|
/* close display (if open) */
|
|
if (l_dpy_id >= 0)
|
|
{
|
|
gimp_display_delete(l_dpy_id);
|
|
l_dpy_id = -1;
|
|
}
|
|
|
|
/* destroy the tmp image */
|
|
gimp_image_delete(l_tmp_image_id);
|
|
|
|
if(l_rc != 0)
|
|
goto error;
|
|
|
|
|
|
|
|
if(ainfo_ptr->run_mode == RUN_INTERACTIVE)
|
|
{
|
|
l_percentage += l_percentage_step;
|
|
gimp_progress_update (l_percentage);
|
|
}
|
|
|
|
/* advance to next frame */
|
|
if(l_cur_frame_nr == l_end)
|
|
break;
|
|
l_cur_frame_nr += l_step;
|
|
|
|
} /* end while(1) loop foreach frame in range */
|
|
|
|
if(gap_debug) fprintf(stderr, "p_frames_modify End OK\n");
|
|
|
|
return 0;
|
|
|
|
error:
|
|
if(gap_debug) fprintf(stderr, "gap: p_frames_modify exit with Error\n");
|
|
|
|
if (l_dpy_id >= 0)
|
|
{
|
|
gimp_display_delete(l_dpy_id);
|
|
l_dpy_id = -1;
|
|
}
|
|
if(l_tmp_image_id >= 0) gimp_image_delete(l_tmp_image_id);
|
|
if(l_layli_ptr != NULL) g_free(l_layli_ptr);
|
|
if(l_plugin_iterator != NULL) g_free(l_plugin_iterator);
|
|
return -1;
|
|
|
|
} /* end p_frames_modify */
|
|
|
|
|
|
/* ============================================================================
|
|
* gap_mod_layer
|
|
* ============================================================================
|
|
*/
|
|
|
|
gint gap_mod_layer(GRunModeType run_mode, gint32 image_id,
|
|
gint32 range_from, gint32 range_to,
|
|
gint32 action_mode, gint32 sel_mode,
|
|
gint32 sel_case, gint32 sel_invert,
|
|
char *sel_pattern, char *new_layername)
|
|
{
|
|
int l_rc;
|
|
t_anim_info *ainfo_ptr;
|
|
gint32 l_from;
|
|
gint32 l_to;
|
|
gint32 l_action_mode;
|
|
gint32 l_sel_mode;
|
|
gint32 l_sel_case;
|
|
gint32 l_sel_invert;
|
|
|
|
char l_sel_pattern[MAX_LAYERNAME];
|
|
char l_new_layername[MAX_LAYERNAME];
|
|
|
|
l_rc = 0;
|
|
|
|
|
|
ainfo_ptr = p_alloc_ainfo(image_id, run_mode);
|
|
if(ainfo_ptr != NULL)
|
|
{
|
|
|
|
if (0 == p_dir_ainfo(ainfo_ptr))
|
|
{
|
|
if(run_mode == RUN_INTERACTIVE)
|
|
{
|
|
l_rc = p_layer_modify_dialog (ainfo_ptr, &l_from, &l_to,
|
|
&l_action_mode,
|
|
&l_sel_mode, &sel_case, &sel_invert,
|
|
&l_sel_pattern[0], &l_new_layername[0]);
|
|
|
|
}
|
|
else
|
|
{
|
|
l_from = range_from;
|
|
l_to = range_to;
|
|
l_action_mode = action_mode;
|
|
l_sel_mode = sel_mode;
|
|
l_sel_case = sel_case;
|
|
l_sel_invert = sel_invert;
|
|
|
|
strncpy(&l_sel_pattern[0], sel_pattern, sizeof(l_sel_pattern) -1);
|
|
l_sel_pattern[sizeof(l_sel_pattern) -1] = '\0';
|
|
strncpy(&l_new_layername[0], new_layername, sizeof(l_new_layername) -1);
|
|
l_new_layername[sizeof(l_new_layername) -1] = '\0';
|
|
}
|
|
|
|
if(l_rc >= 0)
|
|
{
|
|
l_rc = p_save_named_frame(ainfo_ptr->image_id, ainfo_ptr->old_filename);
|
|
if(l_rc >= 0)
|
|
{
|
|
l_rc = p_frames_modify(ainfo_ptr, l_from, l_to,
|
|
l_action_mode,
|
|
l_sel_mode, sel_case, sel_invert,
|
|
&l_sel_pattern[0], &l_new_layername[0]
|
|
);
|
|
p_load_named_frame(ainfo_ptr->image_id, ainfo_ptr->old_filename);
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
p_free_ainfo(&ainfo_ptr);
|
|
}
|
|
|
|
|
|
return(l_rc);
|
|
}
|
|
|
|
|