gimp-gap r800 - in trunk: . docs/reference/txt gap vid_common vid_enc_avi vid_enc_rawframes
- From: wolfgangh svn gnome org
- To: svn-commits-list gnome org
- Subject: gimp-gap r800 - in trunk: . docs/reference/txt gap vid_common vid_enc_avi vid_enc_rawframes
- Date: Wed, 14 Jan 2009 19:59:24 +0000 (UTC)
Author: wolfgangh
Date: Wed Jan 14 19:59:24 2009
New Revision: 800
URL: http://svn.gnome.org/viewvc/gimp-gap?rev=800&view=rev
Log:
gap frame fetcher uses parasites, area replace (logo remove by resynthesizer wrapper)
Added:
trunk/gap/gap_morph_tween_dialog.c
trunk/gap/gap_morph_tween_dialog.h
trunk/gap/gap_wr_resynth.c (contents, props changed)
Modified:
trunk/ChangeLog
trunk/docs/reference/txt/plug-in-gap-storyboard-master-prop.txt
trunk/gap/Makefile.am
trunk/gap/gap_file_util.c
trunk/gap/gap_filter_iterators.c
trunk/gap/gap_frame_fetcher.c
trunk/gap/gap_image.c
trunk/gap/gap_image.h
trunk/gap/gap_layer_copy.c
trunk/gap/gap_layer_copy.h
trunk/gap/gap_morph_dialog.c
trunk/gap/gap_morph_dialog.h
trunk/gap/gap_morph_exec.c
trunk/gap/gap_morph_exec.h
trunk/gap/gap_morph_main.c
trunk/gap/gap_morph_main.h
trunk/gap/gap_story_dialog.c
trunk/gap/gap_story_file.c
trunk/gap/gap_story_file.h
trunk/gap/gap_story_main.h
trunk/gap/gap_story_properties.c
trunk/gap/gap_story_render_lossless.c
trunk/gap/gap_story_render_processor.c
trunk/gap/gap_story_render_types.h
trunk/gap/gap_story_syntax.c
trunk/gap/gap_story_syntax.h
trunk/vid_common/gap_cme_gui.c
trunk/vid_enc_avi/gap_enc_avi_main.c
trunk/vid_enc_rawframes/gap_enc_rawframes_main.c
Modified: trunk/docs/reference/txt/plug-in-gap-storyboard-master-prop.txt
==============================================================================
--- trunk/docs/reference/txt/plug-in-gap-storyboard-master-prop.txt (original)
+++ trunk/docs/reference/txt/plug-in-gap-storyboard-master-prop.txt Wed Jan 14 19:59:24 2009
@@ -58,5 +58,24 @@
where values greater than 1.0 will amplify the volume.
(with the risk of producing noise on overflow)
+ AreaFormat:
+ This format string triggers automatical logo insertation
+ for all handled clips of type MOVIE.
+ The area format string shall contain the placeholder %s
+ that is replaced by the basename of the currently processed
+ videoclip. The placeholder %06d is replaced by the current
+ framenumber.
+ The storyboard processing builds the filename of a logo image
+ whenever a frame is fetched from a movie clip
+ and pastes the logo into the frame in case the logo image exists.
+ If the format does not contain any placeholder, the same logo
+ will be used in all handled movie clips.
+
+ Frame specific Example:
+ AreaFormat: /logo_frames/%s/logo_frame_%06d.xcf
+ Procesing of frame 7 of movie clip /videos/MY_VIDEO.AVI
+ will paste logo image /logo_frames/MY_VIDEO.AVI/logo_frame_000007.xcf
+ Procesing of frame 22 of movie clip /videos/YOUR_VIDEO.MPEG
+ will paste logo image /logo_frames/YOUR_VIDEO.MPEG/logo_frame_000022.xcf
Modified: trunk/gap/Makefile.am
==============================================================================
--- trunk/gap/Makefile.am (original)
+++ trunk/gap/Makefile.am Wed Jan 14 19:59:24 2009
@@ -107,6 +107,7 @@
gap_wr_color_levels \
gap_wr_color_huesat \
gap_wr_trans \
+ gap_wr_resynth \
gap_wr_opacity
gap_bluebox_SOURCES = \
@@ -236,6 +237,8 @@
gap_morph_exec.h \
gap_morph_dialog.c \
gap_morph_dialog.h \
+ gap_morph_tween_dialog.c \
+ gap_morph_tween_dialog.h \
gap_mov_dialog.h \
gap_mov_exec.h \
gap_libgimpgap.h
@@ -355,6 +358,12 @@
gap_wr_color_huesat.c \
gap_libgimpgap.h
+gap_wr_resynth_SOURCES = \
+ gap_wr_resynth.c \
+ gap_lastvaldesc.c \
+ gap_lastvaldesc.h \
+ gap_libgimpgap.h
+
if OS_WIN32
mwindows = -mwindows
@@ -397,6 +406,7 @@
gap_wr_color_curve_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
gap_wr_color_levels_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
gap_wr_color_huesat_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
+gap_wr_resynth_LDADD = $(LIBGIMPGAP) $(LIBGAPBASE) $(GIMP_LIBS)
EXTRA_DIST = \
README \
Modified: trunk/gap/gap_file_util.c
==============================================================================
--- trunk/gap/gap_file_util.c (original)
+++ trunk/gap/gap_file_util.c Wed Jan 14 19:59:24 2009
@@ -331,9 +331,12 @@
{
struct stat l_stat;
- if (0 == g_stat(filename, &l_stat))
+ if(filename != NULL)
{
- return(l_stat.st_mtime);
+ if (0 == g_stat(filename, &l_stat))
+ {
+ return(l_stat.st_mtime);
+ }
}
return(0);
Modified: trunk/gap/gap_filter_iterators.c
==============================================================================
--- trunk/gap/gap_filter_iterators.c (original)
+++ trunk/gap/gap_filter_iterators.c Wed Jan 14 19:59:24 2009
@@ -434,63 +434,6 @@
} /* end p_delta_drawable */
-
-/* ---------------------------
- * p_delta_drawable_simple
- * ---------------------------
- * simple iteration for drawable id (in case val_from and val_to both refere to
- * the same image (that is already opened in the current gimp session)
- */
-static void
-p_delta_drawable_simple(gint32 *val, gint32 val_from, gint32 val_to, gint32 total_steps, gdouble current_step)
-{
- gint l_nlayers;
- gint32 *l_layers_list;
- gint32 l_tmp_image_id;
- gint l_idx, l_idx_from, l_idx_to;
-
- if(gap_debug)
- {
- printf("p_delta_drawable_simple: START *val drawable_id:%d (from:%d to:%d)\n"
- ,(int)*val
- ,(int)val_from
- ,(int)val_to
- );
- }
- if((val_from < 0) || (val_to < 0))
- {
- return;
- }
-
- l_tmp_image_id = gimp_drawable_get_image(val_from);
-
- /* check if from and to values are both valid drawables within the same image */
- if ((l_tmp_image_id > 0)
- && (l_tmp_image_id = gimp_drawable_get_image(val_to)))
- {
- l_idx_from = -1;
- l_idx_to = -1;
-
- /* check the layerstack index of from and to drawable */
- l_layers_list = gimp_image_get_layers(l_tmp_image_id, &l_nlayers);
- for (l_idx = l_nlayers -1; l_idx >= 0; l_idx--)
- {
- if( l_layers_list[l_idx] == val_from ) l_idx_from = l_idx;
- if( l_layers_list[l_idx] == val_to ) l_idx_to = l_idx;
-
- if((l_idx_from != -1) && (l_idx_to != -1))
- {
- /* OK found both index values, iterate the index (proceed to next layer) */
- p_delta_gint(&l_idx, l_idx_from, l_idx_to, total_steps, current_step);
- *val = l_layers_list[l_idx];
- break;
- }
- }
- g_free (l_layers_list);
- }
-} /* end p_delta_drawable_simple */
-
-
/* ------------------------------------
* p_drawable_is_alive
* ------------------------------------
@@ -568,6 +511,70 @@
return FALSE ; /* INVALID image id */
} /* end p_drawable_is_alive */
+
+/* ---------------------------
+ * p_delta_drawable_simple
+ * ---------------------------
+ * simple iteration for drawable id (in case val_from and val_to both refere to
+ * the same image (that is already opened in the current gimp session)
+ */
+static void
+p_delta_drawable_simple(gint32 *val, gint32 val_from, gint32 val_to, gint32 total_steps, gdouble current_step)
+{
+ gint l_nlayers;
+ gint32 *l_layers_list;
+ gint32 l_tmp_image_id;
+ gint l_idx, l_idx_from, l_idx_to;
+
+ if(gap_debug)
+ {
+ printf("p_delta_drawable_simple: START *val drawable_id:%d (from:%d to:%d)\n"
+ ,(int)*val
+ ,(int)val_from
+ ,(int)val_to
+ );
+ }
+ if((val_from < 0) || (val_to < 0))
+ {
+ return;
+ }
+ if(p_drawable_is_alive(val_from) != TRUE)
+ {
+ return;
+ }
+ if(p_drawable_is_alive(val_to) != TRUE)
+ {
+ return;
+ }
+ l_tmp_image_id = gimp_drawable_get_image(val_from);
+
+ /* check if from and to values are both valid drawables within the same image */
+ if ((l_tmp_image_id > 0)
+ && (l_tmp_image_id = gimp_drawable_get_image(val_to)))
+ {
+ l_idx_from = -1;
+ l_idx_to = -1;
+
+ /* check the layerstack index of from and to drawable */
+ l_layers_list = gimp_image_get_layers(l_tmp_image_id, &l_nlayers);
+ for (l_idx = l_nlayers -1; l_idx >= 0; l_idx--)
+ {
+ if( l_layers_list[l_idx] == val_from ) l_idx_from = l_idx;
+ if( l_layers_list[l_idx] == val_to ) l_idx_to = l_idx;
+
+ if((l_idx_from != -1) && (l_idx_to != -1))
+ {
+ /* OK found both index values, iterate the index (proceed to next layer) */
+ p_delta_gint(&l_idx, l_idx_from, l_idx_to, total_steps, current_step);
+ *val = l_layers_list[l_idx];
+ break;
+ }
+ }
+ g_free (l_layers_list);
+ }
+} /* end p_delta_drawable_simple */
+
+
/* --------------------------------------------
* p_capture_image_name_and_assign_pesistent_id
* --------------------------------------------
Modified: trunk/gap/gap_frame_fetcher.c
==============================================================================
--- trunk/gap/gap_frame_fetcher.c (original)
+++ trunk/gap/gap_frame_fetcher.c Wed Jan 14 19:59:24 2009
@@ -5,6 +5,7 @@
*
* It holds a global image cache of temporary gimp images intended for
* read only access in various gimp-gap render processings.
+ * (those cached images are marked with an image parasite)
*
* There are methods to get the temporary image
* or to get a duplicate that has only one layer at imagesize.
@@ -13,19 +14,19 @@
* For videofiles it holds a cache of open videofile handles.
* (note that caching of videoframes is already available in the videohandle)
*
- * The current implementation of the frame fetcher is NOT multithred save !
+ * The current implementation of the frame fetcher is NOT multithread save !
* (the procedures may drop cached images that are still in use by a concurrent thread
- * further the cache lists can be messe up if they are modified by concurrent threads
+ * further the cache lists can be messed up if they are modified by concurrent threads
* at the same time.
*
* Currently there is no support to keep track of cached images during the full length
- * of a gimp session. This simple version of the frame fetcher is limited
- * to one main program (such as the storyboard or the filtermacro plug-in)
- * and loses its information on exit of the main program.
+ * of a gimp session. Therefore unregister of the last user does NOT drop all resources
+ *
* (If there are still registrated users at exit time, the cached images are still
* loaded in the gimp session)
- * TODO: a more sophisticated version of the frame fetcher may keep its information
- * using the gimp_det_data feature or mark the cached images with a tattoo.
+ *
+ * TODO: user registration shall be serialized and stored via gimp_set_data
+ * to keep track over the entire gimp session.
*
*
@@ -85,10 +86,18 @@
#include "gap_frame_fetcher.h"
-#define GAP_FFETCH_MAX_IMG_CACHE_ELEMENTS 12
+#define GAP_FFETCH_MAX_IMG_CACHE_ELEMENTS 18
#define GAP_FFETCH_MAX_GVC_CACHE_ELEMENTS 6
#define GAP_FFETCH_GVA_FRAMES_TO_KEEP_CACHED 36
+/* the lists of cached images and duplicates are implemented via GIMP image parasites,
+ * where images are simply loaded by GIMP without adding a display and marked with a non persistent parasite.
+ * the GAP_IMAGE_CACHE_PARASITE holds the modification timestamp (mtime) and full filename (inclusive terminating 0)
+ * the GAP_IMAGE_DUP_CACHE_PARASITE holds the gint32 ffetch_user_id
+ */
+
+#define GAP_IMAGE_CACHE_PARASITE "GAP-IMAGE-CACHE-PARASITE"
+#define GAP_IMAGE_DUP_CACHE_PARASITE "GAP-IMAGE-DUP-CACHE-PARASITE"
typedef struct GapFFetchResourceUserElem
@@ -98,31 +107,6 @@
} GapFFetchResourceUserElem;
-
-typedef struct GapFFetchDuplicatedImagesElem
-{
- gint32 ffetch_user_id;
- gint32 image_id;
- void *next;
-} GapFFetchDuplicatedImagesElem;
-
-
-/* -------- types for the image cache ------- */
-
-typedef struct GapFFetchImageCacheElem
-{
- gint32 image_id;
- char *filename;
- void *next;
-} GapFFetchImageCacheElem;
-
-typedef struct GapFFetchImageCache
-{
- GapFFetchImageCacheElem *ic_list;
- gint32 max_img_cache; /* number of images to hold in the cache */
-} GapFFetchImageCache;
-
-
/* -------- types for the video handle cache ------- */
typedef struct GapFFetchGvahandCacheElem
@@ -150,10 +134,6 @@
*************************************************************
*/
-static GapFFetchDuplicatedImagesElem *global_duplicated_images = NULL;
-
-static GapFFetchImageCache *global_imcache = NULL;
-
static GapFFetchGvahandCache *global_gvcache = NULL;
static GapFFetchResourceUserElem *global_rsource_users = NULL;
@@ -163,7 +143,6 @@
*************************************************************
*/
static gint32 p_load_cache_image(const char* filename, gboolean addToCache);
-static void p_drop_image_cache_elem1(GapFFetchImageCache *imcache);
static void p_drop_image_cache(void);
#ifdef GAP_ENABLE_VIDEOAPI_SUPPORT
static void p_drop_gvahand_cache_elem1(GapFFetchGvahandCache *gvcache);
@@ -176,32 +155,6 @@
static void p_add_image_to_list_of_duplicated_images(gint32 image_id, gint32 ffetch_user_id);
-/* ----------------------------------------------------
- * p_find_img_cache_by_image_id
- * ----------------------------------------------------
- */
-static GapFFetchImageCacheElem *
-p_find_img_cache_by_image_id(gint32 image_id)
-{
- GapFFetchImageCacheElem *ic_ptr;
-
- if((global_imcache == NULL) || (image_id < 0))
- {
- return (NULL);
- }
-
- for(ic_ptr = global_imcache->ic_list; ic_ptr != NULL; ic_ptr = (GapFFetchImageCacheElem *)ic_ptr->next)
- {
- if(ic_ptr->image_id == image_id)
- {
- /* image found in cache */
- return(ic_ptr);
- }
- }
-
- return (NULL);
-} /* end p_find_img_cache_by_image_id */
-
/* ----------------------------------------------------
* p_load_cache_image
@@ -210,115 +163,155 @@
static gint32
p_load_cache_image(const char* filename, gboolean addToCache)
{
- gint32 l_idx;
gint32 l_image_id;
- GapFFetchImageCacheElem *ic_ptr;
- GapFFetchImageCacheElem *ic_last;
- GapFFetchImageCacheElem *ic_new;
- GapFFetchImageCache *imcache;
char *l_filename;
+ gint32 *images;
+ gint nimages;
+ gint l_idi;
+ gint l_number_of_cached_images;
+ gint32 l_first_chached_image_id;
+ GimpParasite *l_parasite;
+
+
if(filename == NULL)
{
- printf("p_load_cache_image: ** ERROR cant load filename == NULL!\n");
+ printf("p_load_cache_image: ** ERROR cant load filename == NULL! pid:%d\n", (int)getpid());
return -1;
}
- if(global_imcache == NULL)
+ l_image_id = -1;
+ l_first_chached_image_id = -1;
+ l_number_of_cached_images = 0;
+ images = gimp_image_list(&nimages);
+ for(l_idi=0; l_idi < nimages; l_idi++)
{
- /* init the global_image cache */
- global_imcache = g_malloc0(sizeof(GapFFetchImageCache));
- global_imcache->ic_list = NULL;
- global_imcache->max_img_cache = GAP_FFETCH_MAX_IMG_CACHE_ELEMENTS;
- }
+ l_parasite = gimp_image_parasite_find(images[l_idi], GAP_IMAGE_CACHE_PARASITE);
- imcache = global_imcache;
- ic_last = imcache->ic_list;
-
- l_idx = 0;
- for(ic_ptr = imcache->ic_list; ic_ptr != NULL; ic_ptr = (GapFFetchImageCacheElem *)ic_ptr->next)
- {
- l_idx++;
- if(strcmp(filename, ic_ptr->filename) == 0)
+ if(l_parasite)
{
- if(gap_debug)
+ gint32 *mtime_ptr;
+ gchar *filename_ptr;
+
+ mtime_ptr = (gint32 *) l_parasite->data;
+ filename_ptr = (gchar *)&l_parasite->data[sizeof(gint32)];
+
+ l_number_of_cached_images++;
+ if (l_first_chached_image_id < 0)
+ {
+ l_first_chached_image_id = images[l_idi];
+ }
+
+ if(strcmp(filename, filename_ptr) == 0)
{
- printf("FrameFetcher: p_load_cache_image CACHE-HIT :%s (image_id:%d)\n"
- , ic_ptr->filename, (int)ic_ptr->image_id);
+ gint32 mtimefile;
+
+ mtimefile = gap_file_get_mtime(filename);
+ if(mtimefile == *mtime_ptr)
+ {
+ /* image found in cache */
+ l_image_id = images[l_idi];
+ }
+ else
+ {
+ /* image found in cache, but has changed modification timestamp
+ * (delete from cache and reload)
+ */
+ if(gap_debug)
+ {
+ printf("FrameFetcher: DELETE because mtime changed : (image_id:%d) name:%s mtimefile:%d mtimecache:%d pid:%d\n"
+ , (int)images[l_idi]
+ , gimp_image_get_filename(images[l_idi])
+ , (int)mtimefile
+ , (int)*mtime_ptr
+ , (int)getpid()
+ );
+ }
+ gap_image_delete_immediate(images[l_idi]);
+ }
+ l_idi = nimages -1; /* force break at next loop iteration */
}
- /* image found in cache, can skip load */
- return(ic_ptr->image_id);
+ gimp_parasite_free(l_parasite);
}
- ic_last = ic_ptr;
+ }
+ if(images)
+ {
+ g_free(images);
+ }
+
+ if (l_image_id >= 0)
+ {
+ if(gap_debug)
+ {
+ printf("FrameFetcher: p_load_cache_image CACHE-HIT :%s (image_id:%d) pid:%d\n"
+ , filename, (int)l_image_id, (int)getpid());
+ }
+ return(l_image_id);
}
l_filename = g_strdup(filename);
l_image_id = gap_lib_load_image(l_filename);
if(gap_debug)
{
- printf("FrameFetcher: loaded imafe from disk:%s (image_id:%d)\n"
- , l_filename, (int)l_image_id);
+ printf("FrameFetcher: loaded image from disk:%s (image_id:%d) pid:%d\n"
+ , l_filename, (int)l_image_id, (int)getpid());
}
if((l_image_id >= 0) && (addToCache == TRUE))
{
- ic_new = g_malloc0(sizeof(GapFFetchImageCacheElem));
- ic_new->filename = l_filename;
- ic_new->image_id = l_image_id;
-
- if(imcache->ic_list == NULL)
- {
- imcache->ic_list = ic_new; /* 1.st elem starts the list */
- }
- else
- {
- ic_last->next = (GapFFetchImageCacheElem *)ic_new; /* add new elem at end of the cache list */
- }
-
- if(l_idx > imcache->max_img_cache)
+ guchar *parasite_data;
+ gint32 parasite_size;
+ gint32 *parasite_mtime_ptr;
+ gchar *parasite_filename_ptr;
+ gint32 len_filename0; /* filename length including the terminating 0 */
+
+ if (l_number_of_cached_images > GAP_FFETCH_MAX_IMG_CACHE_ELEMENTS)
{
- /* chache list has more elements than desired,
- * drop the 1.st (oldest) entry in the chache list
+ /* the image cache already has more elements than desired,
+ * drop the 1st cached image
*/
- p_drop_image_cache_elem1(imcache);
+ if(gap_debug)
+ {
+ printf("FrameFetcher: DELETE because cache is full: (image_id:%d) name:%s number_of_cached_images:%d pid:%d\n"
+ , (int)l_first_chached_image_id
+ , gimp_image_get_filename(images[l_idi])
+ , (int)l_number_of_cached_images
+ , (int)getpid()
+ );
+ }
+ gap_image_delete_immediate(l_first_chached_image_id);
}
- }
- else
- {
- g_free(l_filename);
- }
- return(l_image_id);
-} /* end p_load_cache_image */
-
-/* ----------------------------------------------------
- * p_drop_image_cache_elem1
- * ----------------------------------------------------
- */
-static void
-p_drop_image_cache_elem1(GapFFetchImageCache *imcache)
-{
- GapFFetchImageCacheElem *ic_ptr;
+ /* build parasite data including mtime and full filename with terminating 0 byte */
+ len_filename0 = strlen(filename) + 1;
+ parasite_size = sizeof(gint32) + len_filename0;
+ parasite_data = g_malloc0(parasite_size);
+ parasite_mtime_ptr = (gint32 *)parasite_data;
+ parasite_filename_ptr = (gchar *)¶site_data[sizeof(gint32)];
+
+ *parasite_mtime_ptr = gap_file_get_mtime(filename);
+ memcpy(parasite_filename_ptr, filename, len_filename0);
+
+ /* attach a parasite to mark the image as part of the gap image cache */
+ l_parasite = gimp_parasite_new(GAP_IMAGE_CACHE_PARASITE
+ ,0 /* GIMP_PARASITE_PERSISTENT 0 for non persistent */
+ ,parasite_size
+ ,parasite_data
+ );
- if(imcache)
- {
- ic_ptr = imcache->ic_list;
- if(ic_ptr)
+ if(l_parasite)
{
- if(gap_debug)
- {
- printf("p_drop_image_cache_elem1 delete:%s (image_id:%d)\n"
- , ic_ptr->filename, (int)ic_ptr->image_id);
- }
- gap_image_delete_immediate(ic_ptr->image_id);
- g_free(ic_ptr->filename);
- imcache->ic_list = (GapFFetchImageCacheElem *)ic_ptr->next;
- g_free(ic_ptr);
+ gimp_image_parasite_attach(l_image_id, l_parasite);
+ gimp_parasite_free(l_parasite);
}
+ g_free(parasite_data);
+
}
-} /* end p_drop_image_cache_elem1 */
+ g_free(l_filename);
+ return(l_image_id);
+} /* end p_load_cache_image */
/* ----------------------------------------------------
* p_drop_image_cache
@@ -328,25 +321,54 @@
static void
p_drop_image_cache(void)
{
- GapFFetchImageCache *imcache;
-
+ gint32 *images;
+ gint nimages;
+ gint l_idi;
+
if(gap_debug)
{
- printf("p_drop_image_cache START\n");
+ printf("p_drop_image_cache START pid:%d\n", (int) getpid());
}
- imcache = global_imcache;
- if(imcache)
+
+ images = gimp_image_list(&nimages);
+ for(l_idi=0; l_idi < nimages; l_idi++)
{
- while(imcache->ic_list)
+ GimpParasite *l_parasite;
+
+ l_parasite = gimp_image_parasite_find(images[l_idi], GAP_IMAGE_CACHE_PARASITE);
+
+ if(gap_debug)
{
- p_drop_image_cache_elem1(imcache);
+ printf("FrameFetcher: CHECK (image_id:%d) name:%s pid:%d\n"
+ , (int)images[l_idi]
+ , gimp_image_get_filename(images[l_idi])
+ , (int)getpid()
+ );
+ }
+
+ if(l_parasite)
+ {
+ if(gap_debug)
+ {
+ printf("FrameFetcher: DELETE (image_id:%d) name:%s pid:%d\n"
+ , (int)images[l_idi]
+ , gimp_image_get_filename(images[l_idi])
+ , (int)getpid()
+ );
+ }
+ /* delete image from the duplicates cache */
+ gap_image_delete_immediate(images[l_idi]);
+ gimp_parasite_free(l_parasite);
}
}
- global_imcache = NULL;
+ if(images)
+ {
+ g_free(images);
+ }
if(gap_debug)
{
- printf("p_drop_image_cache END\n");
+ printf("p_drop_image_cache END pid:%d\n", (int)getpid());
}
} /* end p_drop_image_cache */
@@ -528,13 +550,20 @@
static void
p_add_image_to_list_of_duplicated_images(gint32 image_id, gint32 ffetch_user_id)
{
- GapFFetchDuplicatedImagesElem *dupElem;
-
- dupElem = g_new(GapFFetchDuplicatedImagesElem, 1);
- dupElem->next = global_duplicated_images;
- dupElem->image_id = image_id;
- dupElem->ffetch_user_id = ffetch_user_id;
- global_duplicated_images = dupElem;
+ GimpParasite *l_parasite;
+
+ /* attach a parasite to mark the image as part of the gap image duplicates cache */
+ l_parasite = gimp_parasite_new(GAP_IMAGE_DUP_CACHE_PARASITE
+ ,0 /* GIMP_PARASITE_PERSISTENT 0 for non persistent */
+ , sizeof(gint32) /* size of parasite data */
+ ,&ffetch_user_id /* parasite data */
+ );
+
+ if(l_parasite)
+ {
+ gimp_image_parasite_attach(image_id, l_parasite);
+ gimp_parasite_free(l_parasite);
+ }
} /* end p_add_image_to_list_of_duplicated_images */
@@ -547,35 +576,56 @@
void
gap_frame_fetch_delete_list_of_duplicated_images(gint32 ffetch_user_id)
{
- GapFFetchDuplicatedImagesElem *dupElem;
- GapFFetchDuplicatedImagesElem *nextDupElem;
-
- dupElem = global_duplicated_images;
- while(dupElem)
+ gint32 *images;
+ gint nimages;
+ gint l_idi;
+
+ images = gimp_image_list(&nimages);
+ for(l_idi=0; l_idi < nimages; l_idi++)
{
- nextDupElem = dupElem->next;
+ GimpParasite *l_parasite;
+
+ l_parasite = gimp_image_parasite_find(images[l_idi], GAP_IMAGE_DUP_CACHE_PARASITE);
- if (((ffetch_user_id == dupElem->ffetch_user_id) || (ffetch_user_id < 0))
- && (dupElem->image_id >= 0))
+ if(gap_debug)
{
- gap_image_delete_immediate(dupElem->image_id);
- dupElem->image_id = -1; /* set image invalid */
+ printf("FrameFetcher: check (image_id:%d) name:%s pid:%d\n"
+ , (int)images[l_idi]
+ , gimp_image_get_filename(images[l_idi])
+ , (int)getpid()
+ );
}
- if (ffetch_user_id < 0)
+ if(l_parasite)
{
- g_free(dupElem);
+ gint32 *ffetch_user_id_ptr;
+
+ ffetch_user_id_ptr = (gint32 *) l_parasite->data;
+ if((*ffetch_user_id_ptr == ffetch_user_id) || (ffetch_user_id < 0))
+ {
+ if(gap_debug)
+ {
+ printf("FrameFetcher: DELETE duplicate %s (image_id:%d) user_id:%d (%d) name:%s pid:%d\n"
+ , gimp_image_get_filename(images[l_idi])
+ , (int)images[l_idi]
+ , (int)ffetch_user_id
+ , (int)*ffetch_user_id_ptr
+ , gimp_image_get_filename(images[l_idi])
+ , (int)getpid()
+ );
+ }
+ /* delete image from the duplicates cache */
+ gap_image_delete_immediate(images[l_idi]);
+ }
+ gimp_parasite_free(l_parasite);
}
-
- dupElem = nextDupElem;
}
- if (ffetch_user_id < 0)
+ if(images)
{
- global_duplicated_images = NULL;
+ g_free(images);
}
-} /* end gap_frame_fetch_delete_list_of_duplicated_images */
-
+} /* end gap_frame_fetch_delete_list_of_duplicated_images */
@@ -616,6 +666,7 @@
gint32 dup_image_id;
resulting_layer = -1;
+ dup_image_id = -1;
image_id = p_load_cache_image(filename, addToCache);
if (image_id < 0)
{
@@ -657,17 +708,22 @@
if (addToCache != TRUE)
{
- GapFFetchImageCacheElem *ic_elem;
-
- ic_elem = p_find_img_cache_by_image_id(image_id);
-
- if (ic_elem == NULL)
+ GimpParasite *l_parasite;
+
+ l_parasite = gimp_image_parasite_find(image_id, GAP_IMAGE_CACHE_PARASITE);
+
+ if(l_parasite)
+ {
+ gimp_parasite_free(l_parasite);
+ }
+ else
{
/* the original image is not cached
* (delete it because the caller gets the preprocessed duplicate)
*/
gap_image_delete_immediate(image_id);
}
+
}
return(resulting_layer);
@@ -791,7 +847,7 @@
for(usr_ptr = global_rsource_users; usr_ptr != NULL; usr_ptr = (GapFFetchResourceUserElem *)usr_ptr->next)
{
- printf("usr_ptr->ffetch_user_id: %d usr_ptr:%d\n", usr_ptr->ffetch_user_id, usr_ptr);
+ /* printf("usr_ptr->ffetch_user_id: %d usr_ptr:%d\n", usr_ptr->ffetch_user_id, usr_ptr); */
if (usr_ptr->ffetch_user_id >= 0)
{
@@ -814,10 +870,11 @@
if(gap_debug)
{
- printf("gap_frame_fetch_register_user: REGISTRATED ffetch_user_id:%d caller_name:%s new_usr_ptr:%d\n"
+ printf("gap_frame_fetch_register_user: REGISTRATED ffetch_user_id:%d caller_name:%s new_usr_ptr:%d pid:%d\n"
, new_usr_ptr->ffetch_user_id
, caller_name
- , new_usr_ptr
+ , (int)&new_usr_ptr
+ , (int) getpid()
);
}
return (max_ffetch_user_id);
@@ -832,7 +889,15 @@
* cached images and videohandles are kept.
* until the last resource user calls this procedure.
* if there are no more registered users all
- * cached resources and duplicates are dropped)
+ * cached videohandle resources and temporary image duplicates are dropped)
+ * Current restriction:
+ * the current implementation keeps user registration in global data
+ * but filtermacros and storyboard processor typically are running in separate
+ * processes an therefore each process has its own global data.
+ * an empty list of users does not really indicate
+ * that there are no more users (another process may still have users
+ * of cached images)
+ * therefore cached images are NOT dropped
*/
void
gap_frame_fetch_unregister_user(gint32 ffetch_user_id)
@@ -842,8 +907,9 @@
if(gap_debug)
{
- printf("gap_frame_fetch_unregister_user: UNREGISTER ffetch_user_id:%d\n"
+ printf("gap_frame_fetch_unregister_user: UNREGISTER ffetch_user_id:%d pid:%d\n"
, ffetch_user_id
+ , (int) getpid()
);
}
@@ -864,9 +930,10 @@
{
if(gap_debug)
{
- printf("gap_frame_fetch_unregister_user: no more resource users, DROP cached resources\n");
+ printf("gap_frame_fetch_unregister_user: no more resource users, DROP cached duplicates and video handles\n");
}
- gap_frame_fetch_drop_resources();
+ gap_frame_fetch_delete_list_of_duplicated_images(-1);
+ p_drop_vidhandle_cache();
}
} /* end gap_frame_fetch_unregister_user */
Modified: trunk/gap/gap_image.c
==============================================================================
--- trunk/gap/gap_image.c (original)
+++ trunk/gap/gap_image.c Wed Jan 14 19:59:24 2009
@@ -34,6 +34,7 @@
#include <gap_image.h>
+#include <gap_layer_copy.h>
extern int gap_debug;
@@ -259,3 +260,164 @@
}
return (l_layer_id);
} /* end gap_image_get_any_layer */
+
+
+
+/* ------------------------------------
+ * gap_image_merge_to_specified_layer
+ * ------------------------------------
+ * remove all other layers from the image except the specified layer_id
+ * (by removing other layers, make ref_layer_id visible and perform merging)
+ */
+gint32
+gap_image_merge_to_specified_layer(gint32 ref_layer_id, GimpMergeType mergemode)
+{
+ gint32 l_image_id;
+
+ l_image_id = gimp_drawable_get_image(ref_layer_id);
+ if(l_image_id >= 0)
+ {
+ gint32 l_idx;
+ gint l_nlayers;
+ gint32 *l_layers_list;
+
+ l_layers_list = gimp_image_get_layers(l_image_id, &l_nlayers);
+ if(l_layers_list != NULL)
+ {
+ for(l_idx = 0; l_idx < l_nlayers; l_idx++)
+ {
+ gboolean l_visible;
+
+ if (l_layers_list[l_idx] == ref_layer_id)
+ {
+ gimp_drawable_set_visible(l_layers_list[l_idx], TRUE);
+ }
+ else
+ {
+ gimp_image_remove_layer(l_image_id, l_layers_list[l_idx]);
+ }
+ }
+ g_free (l_layers_list);
+ return (gap_image_merge_visible_layers(l_image_id, mergemode));
+ }
+ }
+ return (-1);
+
+} /* end gap_image_merge_to_specified_layer */
+
+
+/* -------------------------------------------------------
+ * gap_image_set_selection_from_selection_or_drawable
+ * -------------------------------------------------------
+ * create a selection in the specified image_id.
+ * The selection is a scaled copy of the selection in another image,
+ * refered by ref_drawable_id, or a Grayscale copy of the specified ref_drawable_id
+ * (in case the refered image has no selection or the flag force_from_drawable is TRUE)
+ *
+ * - operates on a duplicate of the image refered by ref_drawable_id.
+ * - this duplicate is scaled to same size as specified image_id
+ *
+ * return TRUE in case the selection was successfully created .
+ */
+gboolean
+gap_image_set_selection_from_selection_or_drawable(gint32 image_id, gint32 ref_drawable_id
+ , gboolean force_from_drawable)
+{
+ gint32 l_aux_channel_id;
+ gint32 ref_image_id;
+ gint32 work_drawable_id; /* the duplicate of the layer that is used as selction mask */
+ gint32 dup_image_id;
+ gboolean has_selection;
+ gboolean non_empty;
+ gint x1, y1, x2, y2;
+
+ if ((image_id < 0) || (ref_drawable_id < 0))
+ {
+ return (FALSE);
+ }
+ ref_image_id = gimp_drawable_get_image(ref_drawable_id);
+
+ if (ref_image_id < 0)
+ {
+ printf("ref_drawable_id does not refere to a valid image layer_id:%d\n", (int)ref_drawable_id);
+ return (FALSE);
+ }
+
+
+
+ dup_image_id = gimp_image_duplicate(ref_image_id);
+ if (dup_image_id < 0)
+ {
+ printf("duplicating of image failed, refered souce image_id:%d\n", (int)ref_image_id);
+ return (FALSE);
+ }
+ /* clear undo stack */
+ if (gimp_image_undo_is_enabled(dup_image_id))
+ {
+ gimp_image_undo_disable(dup_image_id);
+ }
+
+ if ((gimp_image_width(image_id) != gimp_image_width(dup_image_id))
+ || (gimp_image_height(image_id) != gimp_image_height(dup_image_id)))
+ {
+ if(gap_debug)
+ {
+ printf("scaling tmp image_id: %d\n", (int)dup_image_id);
+ }
+ gimp_image_scale(dup_image_id, gimp_image_width(image_id), gimp_image_height(image_id));
+ }
+
+ has_selection = gimp_selection_bounds(ref_image_id, &non_empty, &x1, &y1, &x2, &y2);
+ if ((has_selection) && (non_empty) && (force_from_drawable != TRUE))
+ {
+ /* use scaled copy of the already exisating selection in the refered image */
+ work_drawable_id = gimp_image_get_selection(dup_image_id);
+ }
+ else
+ {
+ gint32 active_layer_stackposition;
+
+ /* create selection as gray copy of the alt_selection layer */
+
+ active_layer_stackposition = gap_layer_get_stackposition(ref_image_id, ref_drawable_id);
+
+ if(gimp_image_base_type(dup_image_id) != GIMP_GRAY)
+ {
+ if(gap_debug)
+ {
+ printf("convert to GRAYSCALE tmp image_id: %d\n", (int)dup_image_id);
+ }
+ gimp_image_convert_grayscale(dup_image_id);
+ }
+ work_drawable_id = gap_layer_get_id_by_stackposition(dup_image_id, active_layer_stackposition);
+ gimp_layer_resize_to_image_size (work_drawable_id);
+ }
+
+ gimp_selection_all(image_id);
+ //l_sel_channel_id = gimp_image_get_selection(image_id);
+ l_aux_channel_id = gimp_selection_save(image_id);
+
+ /* copy the work drawable (layer or channel) into the selection channel
+ * the work layer is a grayscale copy GRAY or GRAYA of the alt_selection layer
+ * that is already scaled and resized to fit the size of the target image
+ * the work channel is the scaled selection of the image refred by ref_drawable_id
+ *
+ * copying is done into an auxiliary channel from where we regulary load the selection.
+ * this is done because subseqent queries of the selection boudaries will deliver
+ * full channel size rectangle after a direct copy into the selection.
+ */
+ gap_layer_copy_picked_channel (l_aux_channel_id /* dst_drawable_id*/
+ , 0 /* dst_channel_pick */
+ , work_drawable_id /* src_drawable_id */
+ , 0 /* src_channel_pick */
+ , FALSE /* gboolean shadow */
+ );
+
+ gimp_selection_load(l_aux_channel_id);
+ gimp_image_remove_channel(image_id, l_aux_channel_id);
+
+ gap_image_delete_immediate(dup_image_id);
+ return (TRUE);
+
+} /* end gap_image_set_selection_from_selection_or_drawable */
+
Modified: trunk/gap/gap_image.h
==============================================================================
--- trunk/gap/gap_image.h (original)
+++ trunk/gap/gap_image.h Wed Jan 14 19:59:24 2009
@@ -50,6 +50,10 @@
gboolean gap_image_is_alive(gint32 image_id);
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);
+
#endif
Modified: trunk/gap/gap_layer_copy.c
==============================================================================
--- trunk/gap/gap_layer_copy.c (original)
+++ trunk/gap/gap_layer_copy.c Wed Jan 14 19:59:24 2009
@@ -667,6 +667,34 @@
} /* end gap_layer_get_stackposition */
+/* ---------------------------------
+ * gap_layer_get_id_by_stackposition
+ * ---------------------------------
+ * return -1 if the specified image has no layer at specified stackposition
+ */
+gint32
+gap_layer_get_id_by_stackposition(gint32 image_id, gint32 stackposition)
+{
+ gint l_nlayers;
+ gint32 *l_layers_list;
+ gint32 l_layer_id;
+
+ l_layer_id = -1;
+ l_layers_list = gimp_image_get_layers(image_id, &l_nlayers);
+ if(l_layers_list != NULL)
+ {
+ if ((stackposition >= 0) && (stackposition < l_nlayers))
+ {
+ l_layer_id = l_layers_list[stackposition];
+ }
+ g_free (l_layers_list);
+ }
+
+ return (l_layer_id);
+
+} /* end gap_layer_get_id_by_stackposition */
+
+
/* ------------------------
* gap_layer_make_duplicate
* ------------------------
@@ -818,3 +846,4 @@
return (l_new_layer_id);
} /* end gap_layer_create_layer_from_alpha */
+
Modified: trunk/gap/gap_layer_copy.h
==============================================================================
--- trunk/gap/gap_layer_copy.h (original)
+++ trunk/gap/gap_layer_copy.h Wed Jan 14 19:59:24 2009
@@ -79,6 +79,7 @@
void gap_layer_copy_paste_drawable(gint32 image_id, gint32 dst_drawable_id, gint32 src_drawable_id);
gint32 gap_layer_get_stackposition(gint32 image_id, gint32 ref_layer_id);
+gint32 gap_layer_get_id_by_stackposition(gint32 image_id, gint32 stackposition);
gint32 gap_layer_make_duplicate(gint32 src_layer_id, gint32 image_id
Modified: trunk/gap/gap_morph_dialog.c
==============================================================================
--- trunk/gap/gap_morph_dialog.c (original)
+++ trunk/gap/gap_morph_dialog.c Wed Jan 14 19:59:24 2009
@@ -187,7 +187,7 @@
static void on_show_lines_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup);
static void on_use_quality_wp_selection_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup);
static void on_use_gravity_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup);
-static void on_multiple_pointsets_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup);
+static void on_have_workpointsets_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup);
static void on_create_tween_layers_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup);
static void on_radio_op_mode_callback(GtkWidget *widget, gint32 op_mode);
@@ -229,7 +229,7 @@
mgup->mgpp->use_quality_wp_selection = FALSE;
mgup->mgpp->use_gravity = FALSE;
mgup->mgpp->create_tween_layers = TRUE;
- mgup->mgpp->multiple_pointsets = FALSE;
+ mgup->mgpp->have_workpointsets = FALSE;
p_upd_widget_values(mgup);
break;
case GTK_RESPONSE_OK:
@@ -286,8 +286,8 @@
, mgup->mgpp->use_gravity);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgup->create_tween_layers_checkbutton)
, mgup->mgpp->create_tween_layers);
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgup->multiple_pointsets_checkbutton)
- , mgup->mgpp->multiple_pointsets);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (mgup->have_workpointsets_checkbutton)
+ , mgup->mgpp->have_workpointsets);
}
} /* end p_upd_widget_values */
@@ -2822,17 +2822,17 @@
} /* end on_use_gravity_toggled_callback */
/* --------------------------------------
- * on_multiple_pointsets_toggled_callback
+ * on_have_workpointsets_toggled_callback
* --------------------------------------
*/
static void
-on_multiple_pointsets_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup)
+on_have_workpointsets_toggled_callback(GtkWidget *widget, GapMorphGUIParams *mgup)
{
if(mgup)
{
- if(GTK_TOGGLE_BUTTON (mgup->multiple_pointsets_checkbutton)->active)
+ if(GTK_TOGGLE_BUTTON (mgup->have_workpointsets_checkbutton)->active)
{
- mgup->mgpp->multiple_pointsets = TRUE;
+ mgup->mgpp->have_workpointsets = TRUE;
gtk_widget_show(mgup->workpoint_file_lower_label);
gtk_widget_show(mgup->workpoint_file_upper_label);
gtk_widget_show(mgup->workpoint_lower_label);
@@ -2840,14 +2840,14 @@
}
else
{
- mgup->mgpp->multiple_pointsets = FALSE;
+ mgup->mgpp->have_workpointsets = FALSE;
gtk_widget_hide(mgup->workpoint_file_lower_label);
gtk_widget_hide(mgup->workpoint_file_upper_label);
gtk_widget_hide(mgup->workpoint_lower_label);
gtk_widget_hide(mgup->workpoint_upper_label);
}
}
-} /* end on_multiple_pointsets_toggled_callback */
+} /* end on_have_workpointsets_toggled_callback */
/* ---------------------------------------
@@ -3878,15 +3878,15 @@
/* the multiple pointsets checkbutton */
checkbutton = gtk_check_button_new_with_label ( _("Multiple Pointsets"));
- mgup->multiple_pointsets_checkbutton = checkbutton;
+ mgup->have_workpointsets_checkbutton = checkbutton;
#ifdef GAP_MORPH_DEBUG_FEATURES
gtk_widget_show (checkbutton);
#endif
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), mgup->mgpp->multiple_pointsets);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), mgup->mgpp->have_workpointsets);
gtk_table_attach( GTK_TABLE(table), checkbutton, 11, 13, row, row+1,
GTK_FILL, 0, 0, 0 );
g_signal_connect (checkbutton, "toggled",
- G_CALLBACK (on_multiple_pointsets_toggled_callback),
+ G_CALLBACK (on_have_workpointsets_toggled_callback),
mgup);
gimp_help_set_help_data(checkbutton,
_("ON: use 2 or more pointsets from file. "
@@ -3951,10 +3951,10 @@
/* Show the main container */
gtk_widget_show (main_vbox);
- /* force multiple_pointsets callback to show/hide workpoint lables
+ /* force have_workpointsets callback to show/hide workpoint lables
* (those labels are only visible when multiple pontsets are enabled
*/
- on_multiple_pointsets_toggled_callback(mgup->multiple_pointsets_checkbutton, mgup);
+ on_have_workpointsets_toggled_callback(mgup->have_workpointsets_checkbutton, mgup);
on_use_gravity_toggled_callback(mgup->use_gravity_checkbutton, mgup);
on_use_quality_wp_selection_toggled_callback(mgup->use_quality_wp_selection_checkbutton, mgup);
} /* end gap_morph_create_dialog */
Modified: trunk/gap/gap_morph_dialog.h
==============================================================================
--- trunk/gap/gap_morph_dialog.h (original)
+++ trunk/gap/gap_morph_dialog.h Wed Jan 14 19:59:24 2009
@@ -71,7 +71,7 @@
GtkObject *num_shapepoints_adj;
GtkWidget *create_tween_layers_checkbutton;
- GtkWidget *multiple_pointsets_checkbutton;
+ GtkWidget *have_workpointsets_checkbutton;
GapMorphSubWin src_win;
GapMorphSubWin dst_win;
Modified: trunk/gap/gap_morph_exec.c
==============================================================================
--- trunk/gap/gap_morph_exec.c (original)
+++ trunk/gap/gap_morph_exec.c Wed Jan 14 19:59:24 2009
@@ -2,6 +2,12 @@
* 2004.02.12 hof (Wolfgang Hofer)
* layer morphing worker procedures
*
+ * Note:
+ * using multiple workpoint sets is an unfinshed feature and does not work yet.
+ * (this feature was intended for morphing between 2 videos, where each handled video frame
+ * can have its own workpoint set. but his is no practical solution since creating of the
+ * workpoint files is too much manual work)
+ *
*/
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
@@ -187,6 +193,23 @@
);
} /* end p_get_tolerance */
+static void
+p_error_message_with_filename(GimpRunMode run_mode, const char *msg_fmt, const char *filename)
+{
+ char *l_msg;
+
+ l_msg = g_strdup_printf(msg_fmt, filename);
+ printf("%s RUN_MODE:%d\n", l_msg, (int)run_mode);
+
+ if(run_mode != GIMP_RUN_NONINTERACTIVE)
+ {
+ g_message(l_msg);
+ }
+ g_free(l_msg);
+
+}
+
+
/* ---------------------------------
* gap_moprh_exec_save_workpointfile
@@ -299,6 +322,7 @@
, gdouble *gravity_intensity
, gboolean *use_gravity
, gboolean *use_quality_wp_selection
+ , GimpRunMode run_mode
)
{
#define POINT_REC_MAX 512
@@ -345,7 +369,7 @@
l_len = strlen(GAP_MORPH_WORKPOINT_FILE_HEADER);
if(strncmp(l_buff, GAP_MORPH_WORKPOINT_FILE_HEADER, l_len) != 0)
{
- printf("** error file: %s is no workpointfile (header is missing)\n", filename);
+ p_error_message_with_filename(run_mode, _("File: %s\n ==>is no workpointfile (header is missing)"), filename);
fclose(l_fp);
return (NULL);
}
@@ -373,7 +397,7 @@
}
else
{
- printf("** error file: %s is corrupted (LAYER-SIZES: record requires 4 numbers)\n"
+ p_error_message_with_filename(run_mode, _("file: %s\n ==> is corrupted (LAYER-SIZES: record requires 4 numbers)")
, filename);
fclose(l_fp);
return (NULL);
@@ -391,7 +415,7 @@
}
else
{
- printf("** error file: %s is corrupted (TWEEN-STEPS record requires 1 number)\n"
+ p_error_message_with_filename(run_mode, _("file: %s\n ==> is corrupted (TWEEN-STEPS record requires 1 number)")
, filename);
fclose(l_fp);
return (NULL);
@@ -409,7 +433,7 @@
}
else
{
- printf("** error file: %s is corrupted (AFFECT-RADIUS record requires 1 number)\n"
+ p_error_message_with_filename(run_mode, _("file: %s ==> is corrupted (AFFECT-RADIUS record requires 1 number)")
, filename);
fclose(l_fp);
return (NULL);
@@ -431,7 +455,7 @@
}
else
{
- printf("** error file: %s is corrupted (INTENSITY record requires 1 number)\n"
+ p_error_message_with_filename(run_mode, _("file: %s\n ==>is corrupted (INTENSITY record requires 1 number)")
, filename);
fclose(l_fp);
return (NULL);
@@ -453,7 +477,7 @@
}
else
{
- printf("** error file: %s is corrupted (QUALITY-WP-SELECT record requires 1 number)\n"
+ p_error_message_with_filename(run_mode, _("file: %s\n ==>is corrupted (QUALITY-WP-SELECT record requires 1 number)")
, filename);
fclose(l_fp);
return (NULL);
@@ -487,7 +511,7 @@
}
else
{
- printf("** error file: %s is corrupted (WP: record requires 4 numbers)\n"
+ p_error_message_with_filename(run_mode, _("file: %s\n ==> is corrupted (WP: record requires 4 numbers)")
, filename);
fclose(l_fp);
return (NULL);
@@ -524,6 +548,7 @@
,&mgup->mgpp->gravity_intensity
,&mgup->mgpp->use_gravity
,&mgup->mgpp->use_quality_wp_selection
+ ,mgup->mgpp->run_mode
);
return(wp_list);
} /* end gap_moprh_exec_load_workpointfile */
@@ -553,6 +578,7 @@
,&wps->gravity_intensity
,&wps->use_gravity
,&wps->use_quality_wp_selection
+ ,mgpp->run_mode
);
if(wps->wp_list == NULL)
{
@@ -598,6 +624,18 @@
gint ii;
gint wp_idx;
+ if(gap_debug)
+ {
+ printf("p_build_wp_set_table: using multiple workpoint sets\n"
+ " lower_basename:%s\n"
+ " upper_basename:%s\n lower_num:%d upper_num:%d\n"
+ ,lower_basename
+ ,upper_basename
+ ,(int)lower_num
+ ,(int)upper_num
+ );
+ }
+
mlayers->available_wp_sets = 0;
for(ii=MIN(lower_num, upper_num); ii <= MAX(upper_num, lower_num); ii++)
@@ -642,6 +680,13 @@
else
{
/* create 2 workpoint sets from upper and lower file */
+ if(gap_debug)
+ {
+ printf("p_build_wp_set_table: create 2 workpoint sets from upper and lower file\n lower:%s\n upper:%s\n"
+ ,mgpp->workpoint_file_lower
+ ,mgpp->workpoint_file_upper
+ );
+ }
mlayers->available_wp_sets = 2;
mlayers->tab_wp_sets = g_new(GapMorphWarpCoreAPI*, mlayers->available_wp_sets);
mlayers->tab_wp_sets[0] = p_load_workpoint_set(mgpp->workpoint_file_lower, mgpp, mlayers);
@@ -1916,7 +1961,7 @@
gdouble pick_y;
l_col = dstPR.x + x;
- if(mgpp->multiple_pointsets)
+ if(mgpp->have_workpointsets)
{
/* pick based on 2 sets of workpoints */
p_pixel_warp_multipick(wcap_1 /// XXXXX list1
@@ -1952,10 +1997,24 @@
if(mgpp->do_progress)
{
+ gdouble l_total_progress;
+
l_progress += (dstPR.w * dstPR.h);
- gimp_progress_update(mgpp->master_progress
- + (mgpp->layer_progress_step * (l_progress /l_max_progress))
- );
+ l_total_progress = mgpp->master_progress
+ + (mgpp->layer_progress_step * (l_progress /l_max_progress));
+
+ /*
+ * if)gap_debug)
+ * {
+ * printf("Progress: mgpp->master_progress:%f mgpp->layer_progress_step:%f l_total_progress:%f\n"
+ * ,(float)mgpp->master_progress
+ * ,(float)mgpp->layer_progress_step
+ * ,(float)l_total_progress
+ * );
+ * }
+ */
+
+ gimp_progress_update(l_total_progress);
}
}
@@ -1997,6 +2056,12 @@
GimpPixelRgn bgPR;
gpointer pr;
+ if(gap_debug)
+ {
+ printf("p_mix_layers START curr_mix_factor: %f\n"
+ ,(float)curr_mix_factor
+ );
+ }
top_drawable = gimp_drawable_get (top_layer_id);
bg_drawable = gimp_drawable_get (bg_layer_id);
@@ -2152,6 +2217,22 @@
wp_set_2 = NULL;
wp_mix_factor = 1.0;
+ if(gap_debug)
+ {
+ printf("p_create_morph_tween_frame START total_steps:%d current_step:%d\n"
+ " mgpp->create_tween_layers:%d\n"
+ " mgpp->have_workpointsets:%d\n"
+ " mlayers->available_wp_sets:%d\n"
+ " mgpp->render_mode:%d\n"
+ ,(int)total_steps
+ ,(int)current_step
+ ,(int)mgpp->create_tween_layers
+ ,(int)mgpp->have_workpointsets
+ ,(int)mlayers->available_wp_sets
+ ,(int)mgpp->render_mode
+ );
+ }
+
if(mgpp->create_tween_layers)
{
/* size of the new frame */
@@ -2187,7 +2268,7 @@
src_layer_id = mlayers->src_layers[ii];
}
- if((mgpp->multiple_pointsets)
+ if((mgpp->have_workpointsets)
&& (mlayers->available_wp_sets > 1))
{
gint wps_idx;
@@ -2205,7 +2286,6 @@
wp_mix_factor = ref - (gdouble)wps_idx;
}
-
dst_drawable = gimp_drawable_get (dst_layer_id);
/* create the tween frame image */
@@ -2249,8 +2329,6 @@
);
gimp_image_add_layer(curr_image_id, top_layer_id, 0);
-
-
if(!mgpp->render_mode == GAP_MORPH_RENDER_MODE_WARP)
{
@@ -2287,7 +2365,6 @@
, wp_set_2
, wp_mix_factor
);
-
gap_morph_exec_free_workpoint_list(&curr_wp_list_1);
gap_morph_exec_free_workpoint_list(&curr_wp_list_2);
}
@@ -2397,7 +2474,6 @@
// merged_layer_id =
// gap_image_merge_visible_layers(curr_image_id, GIMP_EXPAND_AS_NECESSARY);
-
merged_layer_id =
p_mix_layers(curr_image_id
,bg_layer_id
@@ -2452,6 +2528,10 @@
dst_image_id = -1;
+ if(gap_debug)
+ {
+ printf("p_get_tween_steps_and_layerstacks: START\n");
+ }
if(mgpp->osrc_layer_id >= 0)
{
@@ -2462,7 +2542,10 @@
);
for(ii=0; ii < mlayers->src_nlayers; ii++)
{
- if(gap_debug) printf("src: id[%d]: %d\n", (int)ii, (int)mlayers->src_layers[ii] );
+ if(gap_debug)
+ {
+ printf("src: id[%d]: %d\n", (int)ii, (int)mlayers->src_layers[ii] );
+ }
if(mlayers->src_layers[ii] == mgpp->osrc_layer_id)
{
mlayers->src1_idx = ii; /* src at 1.st step */
@@ -2496,6 +2579,12 @@
if(mgpp->create_tween_layers)
{
mlayers->dst1_idx = mlayers->dst2_idx + (tween_steps -1);
+ if(gap_debug)
+ {
+ printf("p_get_tween_steps_and_layerstacks: create_tween_layers RETURN tween_steps:%d\n"
+ ,(int)tween_steps
+ );
+ }
return(tween_steps);
}
@@ -2534,6 +2623,13 @@
mlayers->src1_idx = MIN((mlayers->src2_idx + (tween_steps -1)) , (mlayers->src_nlayers -1));
+ if(gap_debug)
+ {
+ printf("p_get_tween_steps_and_layerstacks: create_tween_layers END, RETURN tween_steps:%d\n"
+ ,(int)tween_steps
+ );
+ }
+
return(tween_steps);
} /* end p_get_tween_steps_and_layerstacks */
@@ -2559,12 +2655,15 @@
mlayers = &mlayers_struct;
mlayers->tab_wp_sets = NULL;
mlayers->available_wp_sets = 0;
-
+
mgpp->tween_steps = p_get_tween_steps_and_layerstacks(mgpp, mlayers);
- if(mgpp->multiple_pointsets)
+ if(mgpp->have_workpointsets)
{
- /* check for available workpointfile sets and load them */
+ /* check for available workpointfile sets and load them.
+ * (note: this also handles the case when working with a single workpointfile
+ * where the same workpoint file is used both as upper and lower set)
+ */
p_build_wp_set_table(mgpp ,mlayers);
}
@@ -2699,3 +2798,369 @@
return(cp_layer_id);
} /* end gap_morph_execute */
+
+
+
+/* ----------------------------------
+ * p_create_simple_fade_tween_frame
+ * ----------------------------------
+ *
+ * return the newly created tween morphed layer
+ *
+ */
+static gint32
+p_create_simple_fade_tween_frame(gint32 total_steps
+ ,gint32 current_step
+ ,GapMorphGlobalParams *mgpp
+ )
+{
+ gint32 curr_image_id; /* a temp image of current layer size */
+ gint32 bg_layer_id;
+ gint32 top_layer_id;
+ gint32 merged_layer_id;
+ gint32 curr_width;
+ gint32 curr_height;
+ gdouble curr_opacity;
+ gint32 src_layer_id;
+ gint32 dst_layer_id;
+ GimpImageType l_src_type;
+
+ src_layer_id = mgpp->osrc_layer_id;
+ dst_layer_id = mgpp->fdst_layer_id;
+
+
+ /* check size of the new frame */
+ curr_width = gimp_drawable_width(src_layer_id);
+ if (curr_width != gimp_drawable_width(dst_layer_id))
+ {
+ return -1;
+ }
+
+ curr_height = gimp_drawable_height(src_layer_id);
+ if (curr_height != gimp_drawable_height(dst_layer_id))
+ {
+ return -1;
+ }
+
+
+ l_src_type = gimp_drawable_type(src_layer_id);
+ if (l_src_type != gimp_drawable_type(dst_layer_id))
+ {
+ return -1;
+ }
+
+ curr_image_id = -1;
+
+ switch(l_src_type)
+ {
+ case GIMP_RGB_IMAGE: /* 0 */
+ case GIMP_RGBA_IMAGE: /* 1 */
+ curr_image_id = gimp_image_new(curr_width, curr_height, GIMP_RGB);
+ break;
+ case GIMP_GRAY_IMAGE: /* 2 */
+ case GIMP_GRAYA_IMAGE: /* 3 */
+ curr_image_id = gimp_image_new(curr_width, curr_height, GIMP_GRAY);
+ break;
+ case GIMP_INDEXED_IMAGE: /* 4 */
+ case GIMP_INDEXEDA_IMAGE: /* 5 */
+ return -1;
+ break;
+ }
+
+
+ bg_layer_id = gap_layer_copy_to_image (curr_image_id, mgpp->osrc_layer_id);
+ top_layer_id = gap_layer_copy_to_image (curr_image_id, mgpp->fdst_layer_id);
+
+ /* merge BG and TOP Layer (does mix opacity according to current step) */
+ curr_opacity = p_linear_advance((gdouble)total_steps
+ ,(gdouble)current_step
+ ,(gdouble)0.0
+ ,(gdouble)100.0
+ );
+
+ merged_layer_id =
+ p_mix_layers(curr_image_id
+ ,bg_layer_id
+ ,top_layer_id
+ ,curr_width
+ ,curr_height
+ ,(gdouble)(curr_opacity / 100.0)
+ );
+
+ mgpp->master_progress += mgpp->layer_progress_step;
+
+ /* DEBUG code: show duplicate of the temporary tween image */
+ if(FALSE)
+ {
+ gint32 dup_id;
+
+ dup_id = gimp_image_duplicate(curr_image_id);
+ gimp_display_new (dup_id);
+
+ }
+
+ return(merged_layer_id);
+
+} /* end p_create_simple_fade_tween_frame */
+
+
+/* ----------------------------------
+ * gap_morph_render_one_of_n_tweens
+ * ----------------------------------
+ * This procedure creates only one tween (a scene between 2 video frames)
+ * according to the specified total_steps and current_step parameters.
+ * the created tween is part of a new created image
+ * that contians the tween layer.
+ *
+ * return the newly created tween morphed layer
+ *
+ */
+gint32
+gap_morph_render_one_of_n_tweens(GapMorphGlobalParams *mgpp, gdouble total_steps, gdouble current_step)
+{
+ gint32 new_layer_id;
+ GapMorphExeLayerstack mlayers_struct;
+ GapMorphExeLayerstack *mlayers;
+
+ mlayers = &mlayers_struct;
+ mlayers->tab_wp_sets = NULL;
+ mlayers->available_wp_sets = 0;
+ new_layer_id = -1;
+
+ p_get_tween_steps_and_layerstacks(mgpp, mlayers);
+
+ mgpp->create_tween_layers = TRUE;
+
+ /* check if workpoint filename is available */
+ if(mgpp->workpoint_file_lower)
+ {
+ if(*mgpp->workpoint_file_lower != '\0')
+ {
+ /* load a single workpointfile
+ * (note: we use general procedure p_build_wp_set_table and handle the single workpointfile
+ * as mix of upper and lower set that both refere to the same single workpointfile)
+ */
+ p_build_wp_set_table(mgpp ,mlayers);
+ mgpp->have_workpointsets = FALSE;
+ mlayers->available_wp_sets = 0;
+ }
+ }
+
+ /* overrule the number of steps with the explicite parameter value */
+ mgpp->tween_steps = total_steps;
+
+ if(mgpp->do_simple_fade)
+ {
+ /* we have no workpoints available
+ * in this case make an attempt with a fast fade operation
+ * (but restricted to frames of same size and type)
+ */
+ new_layer_id = p_create_simple_fade_tween_frame(total_steps
+ ,current_step
+ ,mgpp
+ );
+
+ }
+
+ if( new_layer_id < 0)
+ {
+ if(gap_debug)
+ {
+ printf("calling the full morph algorithm total_steps:%f current_step:%f\n"
+ ,(float)total_steps
+ ,(float)current_step
+ );
+ }
+ new_layer_id = p_create_morph_tween_frame(total_steps
+ ,current_step
+ ,mgpp
+ ,mlayers
+ );
+ }
+ return (gap_image_merge_to_specified_layer(new_layer_id, GIMP_CLIP_TO_IMAGE));
+} /* end gap_morph_render_one_of_n_tweens */
+
+
+/* ----------------------------------
+ * gap_morph_render_one_tween
+ * ----------------------------------
+ * This procedure creates only one tween (a scene between 2 video frames)
+ * according to the specified mix factor (mgpp->tween_mix_factor)
+ * the created tween is part of a new created image
+ * that contians the tween layer.
+ *
+ * return the newly created tween morphed layer
+ *
+ */
+gint32
+gap_morph_render_one_tween(GapMorphGlobalParams *mgpp)
+{
+ gint32 new_layer_id;
+ gdouble total_steps;
+ gdouble current_step;
+
+ total_steps = 1.0 * 100000;
+ current_step = CLAMP(mgpp->tween_mix_factor, 0.0, 1.0) * 100000;
+
+
+ new_layer_id = gap_morph_render_one_of_n_tweens(mgpp, total_steps, current_step);
+
+ return (new_layer_id);
+} /* end gap_morph_render_one_tween */
+
+
+
+/* ----------------------------------
+ * gap_morph_render_frame_tweens
+ * ----------------------------------
+ *
+ * return the newly created tween morphed layer
+ *
+ */
+gint32
+gap_morph_render_frame_tweens(GapAnimInfo *ainfo_ptr, GapMorphGlobalParams *mgpp)
+{
+ gint32 l_tween_layer_id;
+ gint32 l_tween_frame_nr;
+ gint32 l_rc;
+ gdouble total_steps;
+
+ l_tween_layer_id = -1;
+
+ total_steps = (mgpp->range_to - mgpp->range_from);
+ mgpp->tween_steps = (mgpp->range_to - mgpp->range_from); /// ??? - 1;
+
+ mgpp->master_progress = 0.0;
+ mgpp->layer_progress_step = 0.5 / (gdouble)(MAX(1.0, (total_steps -1.0)));
+ if(mgpp->do_progress)
+ {
+ gimp_progress_init(_("creating morph tween frames..."));
+ }
+
+ if (mgpp->tween_steps > 0)
+ {
+ gint32 l_tmp_image_id;
+ if(ainfo_ptr->new_filename != NULL)
+ {
+ g_free(ainfo_ptr->new_filename);
+ }
+ ainfo_ptr->new_filename = gap_lib_alloc_fname(ainfo_ptr->basename,
+ mgpp->range_to,
+ ainfo_ptr->extension);
+ if(ainfo_ptr->new_filename == NULL)
+ {
+ printf("could not create frame filename for frameNr:%d\n", (int)mgpp->range_to);
+ return -1;
+ }
+
+ if(!g_file_test(ainfo_ptr->new_filename, G_FILE_TEST_EXISTS))
+ {
+ printf("target frame does not exist, name: %s\n", ainfo_ptr->new_filename);
+ if (mgpp->run_mode != GIMP_RUN_NONINTERACTIVE)
+ {
+ g_message(_("target frame does not exist, name: %s"), ainfo_ptr->new_filename);
+ }
+ return -1;
+ }
+
+ /* load current frame */
+ l_tmp_image_id = gap_lib_load_image(ainfo_ptr->new_filename);
+
+ if(gap_debug)
+ {
+ printf("gap_morph_render_frame_tweens to frame: %s l_tmp_image_id:%d RUN_MODE:%d\n"
+ ,ainfo_ptr->new_filename
+ ,(int)l_tmp_image_id
+ ,(int)mgpp->run_mode
+ );
+ }
+
+ mgpp->osrc_layer_id = gap_image_merge_visible_layers(gimp_image_duplicate(mgpp->image_id), GIMP_CLIP_TO_IMAGE);
+ mgpp->fdst_layer_id = gap_image_merge_visible_layers(l_tmp_image_id, GIMP_CLIP_TO_IMAGE);
+
+ if(gap_debug)
+ {
+ printf("gap_morph_render_frame_tweens osrc_layer_id:%d fdst_layer_id:%d \n"
+ ,(int)mgpp->osrc_layer_id
+ ,(int)mgpp->fdst_layer_id
+ );
+ }
+
+ for (l_tween_frame_nr = mgpp->range_from +1; l_tween_frame_nr < mgpp->range_to; l_tween_frame_nr++)
+ {
+ gint32 l_tween_tmp_image_id;
+ gdouble l_current_step;
+
+ mgpp->master_progress = 2.0 * mgpp->layer_progress_step * (l_tween_frame_nr - (mgpp->range_from +1));
+
+ if(l_tween_layer_id >= 0)
+ {
+ /* delete the previous handled tween frame image in memory. (that is already saved to disk
+ * we keep only the last one opened)
+ */
+ gap_image_delete_immediate(gimp_drawable_get_image(l_tween_layer_id));
+ }
+
+ l_current_step = l_tween_frame_nr - mgpp->range_from;
+ if(ainfo_ptr->new_filename != NULL)
+ {
+ g_free(ainfo_ptr->new_filename);
+ }
+ ainfo_ptr->new_filename = gap_lib_alloc_fname(ainfo_ptr->basename,
+ l_tween_frame_nr,
+ ainfo_ptr->extension);
+ if(mgpp->do_progress)
+ {
+ char *l_msg;
+ l_msg = g_strdup_printf(_("creating morph tween frame: %d"), (int)l_tween_frame_nr);
+ gimp_progress_init(l_msg);
+ g_free(l_msg);
+ }
+ if(gap_debug)
+ {
+ printf("gap_morph_render_frame_tweens creating tween:%s\n"
+ ,ainfo_ptr->new_filename
+ );
+ }
+
+ if (mgpp->overwrite_flag != TRUE)
+ {
+ if(g_file_test(ainfo_ptr->new_filename, G_FILE_TEST_EXISTS))
+ {
+ l_tween_layer_id = -1;
+ p_error_message_with_filename(mgpp->run_mode, _("file: %s already exists"), ainfo_ptr->new_filename);
+ break;
+ }
+ }
+
+ l_tween_layer_id = gap_morph_render_one_of_n_tweens(mgpp, total_steps, l_current_step);
+ l_tween_tmp_image_id = gimp_drawable_get_image(l_tween_layer_id);
+ if(gap_debug)
+ {
+ printf("gap_morph_render_frame_tweens saving tween:%s :%d\n"
+ ,ainfo_ptr->new_filename
+ ,(int)l_tween_tmp_image_id
+ );
+ }
+ l_rc = gap_lib_save_named_frame(l_tween_tmp_image_id, ainfo_ptr->new_filename);
+ if(ainfo_ptr->new_filename != NULL)
+ {
+ g_free(ainfo_ptr->new_filename);
+ ainfo_ptr->new_filename = NULL;
+ }
+ if (l_rc < 0)
+ {
+ l_tween_layer_id = -1;
+ p_error_message_with_filename(mgpp->run_mode, _("file: %s save failed"), ainfo_ptr->new_filename);
+ break;
+ }
+
+ }
+ gap_image_delete_immediate(gimp_drawable_get_image(mgpp->osrc_layer_id));
+ gap_image_delete_immediate(gimp_drawable_get_image(mgpp->fdst_layer_id));
+ }
+
+ return(l_tween_layer_id);
+
+} /* end gap_morph_render_frame_tweens */
+
Modified: trunk/gap/gap_morph_exec.h
==============================================================================
--- trunk/gap/gap_morph_exec.h (original)
+++ trunk/gap/gap_morph_exec.h Wed Jan 14 19:59:24 2009
@@ -31,6 +31,7 @@
#include "libgimp/gimp.h"
#include "gap_morph_main.h"
#include "gap_morph_dialog.h"
+#include "gap_libgimpgap.h"
void gap_morph_exec_free_workpoint_list(GapMorphWorkPoint **wp_list);
gboolean gap_moprh_exec_save_workpointfile(const char *filename
@@ -54,6 +55,8 @@
, gdouble *pick_y
);
gint32 gap_morph_execute(GapMorphGlobalParams *mgpp);
+gint32 gap_morph_render_one_tween(GapMorphGlobalParams *mgpp);
+gint32 gap_morph_render_frame_tweens(GapAnimInfo *ainfo_ptr, GapMorphGlobalParams *mgpp);
#endif
Modified: trunk/gap/gap_morph_main.c
==============================================================================
--- trunk/gap/gap_morph_main.c (original)
+++ trunk/gap/gap_morph_main.c Wed Jan 14 19:59:24 2009
@@ -37,6 +37,7 @@
#include "gap_morph_main.h"
#include "gap_morph_exec.h"
#include "gap_morph_dialog.h"
+#include "gap_morph_tween_dialog.h"
#include "gap_pview_da.h"
/* for pointfile loader (workaround) */
@@ -48,11 +49,13 @@
#include "gap-intl.h"
/* Defines */
-#define PLUG_IN_NAME "plug_in_gap_morph_layers"
-#define PLUG_IN_PRINT_NAME "Morph Layers"
-#define PLUG_IN_IMAGE_TYPES "RGBA, GRAYA"
-#define PLUG_IN_AUTHOR "Wolfgang Hofer (hof gimp org)"
-#define PLUG_IN_COPYRIGHT "Wolfgang Hofer"
+#define PLUG_IN_NAME "plug_in_gap_morph_layers"
+#define PLUG_IN_NAME_TWEEN "plug_in_gap_morph_tween" /* render missing tween(s) between frames */
+#define PLUG_IN_NAME_ONE_TWEEN "plug_in_gap_morph_one_tween" /* single tween rendering */
+#define PLUG_IN_PRINT_NAME "Morph Layers"
+#define PLUG_IN_IMAGE_TYPES "RGBA, GRAYA"
+#define PLUG_IN_AUTHOR "Wolfgang Hofer (hof gimp org)"
+#define PLUG_IN_COPYRIGHT "Wolfgang Hofer"
int gap_debug = 0; /* 1 == print debug infos , 0 dont print debug infos */
@@ -70,7 +73,7 @@
, "\0" /* char workpoint_file_lower[1024] */
, "\0" /* char workpoint_file_upper[1024] */
, TRUE /* gboolean create_tween_layers */
-, FALSE /* gboolean multiple_pointsets */
+, FALSE /* gboolean have_workpointsets */
, FALSE /* gboolean use_quality_wp_selection */
, FALSE /* gboolean use_gravity */
, 2.0 /* gdouble gravity_intensity */
@@ -79,6 +82,11 @@
, FALSE /* gboolean do_progress */
, 0.0 /* gdouble master_progress */
, 0.0 /* gdouble layer_progress_step */
+, 0.0 /* gdouble tween_mix_factor */
+, -1 /* long range_from */
+, -1 /* long range_to */
+, FALSE /* gboolean overwrite_flag */
+, FALSE /* gboolean do_simple_fade */
};
@@ -89,6 +97,7 @@
gint *nreturn_vals, /* number of parameters returned */
GimpParam ** return_vals); /* parameters to be returned */
+static gint32 p_handle_PLUG_IN_NAME_TWEEN(GapMorphGlobalParams *mgpp);
/* Global Variables */
GimpPlugInInfo PLUG_IN_INFO =
@@ -109,12 +118,46 @@
{ GIMP_PDB_INT32, "create_tween_layers", "TRUE: Do create tween layers, FALSE: operate on existing layers"},
{ GIMP_PDB_STRING, "workpoint_file_1", "Name of a Morph/Warp workpointfile"
"(create such file(s) with the save button in the GUI at INTERACTIVE runmode)"},
- { GIMP_PDB_STRING, "workpoint_file_2", "Name of an ptional 2nd Morph/Warp workpointfile."
+ { GIMP_PDB_STRING, "workpoint_file_2", "Name of an optional 2nd Morph/Warp workpointfile."
" (pass an empty string or the same name as the 1st file"
" if you want to operate with one workpoint file)"},
};
+static GimpParamDef in_tween_args[] = {
+ { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive."},
+ { GIMP_PDB_IMAGE, "start_image", "from frame image (must be a frame with GIMP-GAP typical number part in the imagefilename)" },
+ { GIMP_PDB_DRAWABLE, "drawable", "ignored"},
+ { GIMP_PDB_INT32, "to_frame_nr", "frame number of the next available frame"},
+ { GIMP_PDB_INT32, "overwrite", "0 == do not overwrite, 1 == overrite existing frames"},
+ { GIMP_PDB_INT32, "do_simple_fade", "0 == use morph algorithm, 1 == use simple fade operation (ignore the workpoint_file) "},
+ { GIMP_PDB_STRING, "workpoint_file", "Name of a Morph/Warp workpointfile"
+ "(create such file(s) with the save button in the GUI "
+ "of the plug_in_gap_morph_layers, or specify an emty string"
+ "that starts with 0x00 to operate as simple video fade)"},
+ };
+static GimpParamDef out_tween_args[] = {
+ { GIMP_PDB_DRAWABLE, "tween_drawable", "the last one of the newly created tween(s) (a layer in a newly created frame image)"},
+ };
+
+static GimpParamDef in_one_tween_args[] = {
+ { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive."},
+ { GIMP_PDB_IMAGE, "image", "(not relevant)" },
+ { GIMP_PDB_DRAWABLE, "src_drawable", "source drawable (usually a layer)"},
+ { GIMP_PDB_DRAWABLE, "dst_drawable", "destination drawable (usually a layer)"},
+ { GIMP_PDB_FLOAT, "tween_mix_factor", "a value between 0.0 and 1.0 where 0 delivers a copy of the src layer"
+ "1 delivers a copy of the destination layer,"
+ "other value deliver a mix according to morph algortihm" },
+ { GIMP_PDB_INT32, "do_simple_fade", "0 == use morph algorithm, 1 == use simple fade operation (ignore the workpoint_file) "},
+ { GIMP_PDB_STRING, "workpoint_file", "Name of a Morph/Warp workpointfile"
+ "(create such file(s) with the save button in the GUI "
+ "of the plug_in_gap_morph_layers, or specify an emty string"
+ "that starts with 0x00 to operate as simple video fade)"},
+ };
+static GimpParamDef out_one_tween_args[] = {
+ { GIMP_PDB_DRAWABLE, "tween_drawable", "newly created tween (a layer in a newly created image)"},
+ };
+
MAIN ()
static void query (void)
@@ -151,10 +194,139 @@
NULL /* out_args */
);
- // gimp_plugin_menu_branch_register("<Image>", "Video");
- gimp_plugin_menu_register (PLUG_IN_NAME, N_("<Image>/Video/"));
+ /* the actual installation of the plugin */
+ gimp_install_procedure (PLUG_IN_NAME_TWEEN,
+ "Render tween frames via morhing",
+ "This plug-in creates and saves image frames that are a mix of the specified image frame and the frame with to_frame_nr, "
+ "The typical usage is to create the frame images of missing frame numbers in a series of anim frame images. "
+ "the overwrite flag allows overwriting of already existing frames between the start frame image "
+ "and the frame with to_frame_nr"
+ "Morphing is controled by workpoints. A Workpoint file can be created and edited with the help "
+ "of the Morph feature in the Video menu. "
+ "Note: without workpoints the resulting tween is calculated as simple fade operation. "
+ ,
+ PLUG_IN_AUTHOR,
+ PLUG_IN_COPYRIGHT,
+ GAP_VERSION_WITH_DATE,
+ N_("Morph Tweenframes..."),
+ PLUG_IN_IMAGE_TYPES,
+ GIMP_PLUGIN,
+ G_N_ELEMENTS (in_tween_args),
+ G_N_ELEMENTS (out_tween_args),
+ in_tween_args,
+ out_tween_args
+ );
+
+
+ /* the actual installation of the plugin */
+ gimp_install_procedure (PLUG_IN_NAME_ONE_TWEEN,
+ "Render one tween via morhing",
+ "This plug-in creates a new image that is a mix of the specified src_drawable and dst_drawable, "
+ "the mixing is done based on a morphing transformation where the tween_mix_factor "
+ "determines how much the result looks like source or destination. "
+ "source and destination may differ in size and can be in different images. "
+ "Morphing is controled by workpoints. A Workpoint file can be created and edited with the help "
+ "of the Morph feature in the Video menu. "
+ "Note: without workpoints the resulting tween is calculated as simple fade operation. "
+ ,
+ PLUG_IN_AUTHOR,
+ PLUG_IN_COPYRIGHT,
+ GAP_VERSION_WITH_DATE,
+ N_("Morph One Tween..."),
+ PLUG_IN_IMAGE_TYPES,
+ GIMP_PLUGIN,
+ G_N_ELEMENTS (in_one_tween_args),
+ G_N_ELEMENTS (out_one_tween_args),
+ in_one_tween_args,
+ out_one_tween_args
+ );
+
+
+ {
+ /* Menu names */
+ const char *menupath_image_video_morph = N_("<Image>/Video/Morph/");
+
+ //gimp_plugin_menu_branch_register("<Image>", "Video/Morph");
+
+ gimp_plugin_menu_register (PLUG_IN_NAME, menupath_image_video_morph);
+ gimp_plugin_menu_register (PLUG_IN_NAME_TWEEN, menupath_image_video_morph);
+ gimp_plugin_menu_register (PLUG_IN_NAME_ONE_TWEEN, menupath_image_video_morph);
+ }
}
+/* ----------------------------------
+ * p_handle_PLUG_IN_NAME_TWEEN
+ * ----------------------------------
+ *
+ * return the newly created tween morphed layer
+ *
+ */
+static gint32
+p_handle_PLUG_IN_NAME_TWEEN(GapMorphGlobalParams *mgpp)
+{
+ gint32 l_tween_layer_id;
+ GapAnimInfo *ainfo_ptr;
+
+ gboolean l_rc;
+ gboolean l_run_flag;
+
+ l_tween_layer_id = -1;
+ l_rc = FALSE;
+ l_run_flag = TRUE;
+
+ ainfo_ptr = gap_lib_alloc_ainfo(mgpp->image_id, mgpp->run_mode);
+ if(ainfo_ptr != NULL)
+ {
+ if (0 == gap_lib_dir_ainfo(ainfo_ptr))
+ {
+ mgpp->range_from = ainfo_ptr->curr_frame_nr;
+ /* mgpp->range_to is already set at noninteractive call. for interacive cals this is set in the following dialog
+ */
+ if(mgpp->run_mode == GIMP_RUN_INTERACTIVE)
+ {
+ if(0 != gap_lib_chk_framechange(ainfo_ptr)) { l_run_flag = FALSE; }
+ else
+ {
+ if(*ainfo_ptr->extension == '\0' && ainfo_ptr->frame_cnt == 0)
+ {
+ /* plugin was called on a frame without extension and without framenumer in its name
+ * (typical for new created images named like 'Untitled'
+ */
+ g_message(_("Operation cancelled.\n"
+ "GAP video plug-ins only work with filenames\n"
+ "that end in numbers like _000001.xcf.\n"
+ "==> Rename your image, then try again."));
+ return -1;
+ }
+ l_rc = gap_morph_frame_tweens_dialog(ainfo_ptr, mgpp);
+ mgpp->do_progress = TRUE;
+ }
+
+ if((0 != gap_lib_chk_framechange(ainfo_ptr)) || (!l_rc))
+ {
+ l_run_flag = FALSE;
+ }
+
+ }
+
+ if(l_run_flag == TRUE)
+ {
+ /* render tween frames and write them as framefiles to disc () */
+ l_tween_layer_id = gap_morph_render_frame_tweens(ainfo_ptr, mgpp);
+ }
+
+ }
+ gap_lib_free_ainfo(&ainfo_ptr);
+ }
+
+ return(l_tween_layer_id);
+
+} /* end p_handle_PLUG_IN_NAME_TWEEN */
+
+/* -------------------------------------
+ * run
+ * -------------------------------------
+ */
static void
run (const gchar *name, /* name of plugin */
gint nparams, /* number of in-paramters */
@@ -177,20 +349,26 @@
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
/* always return at least the status to the caller. */
- static GimpParam values[1];
+ static GimpParam values[2];
INIT_I18N();
-
l_env = g_getenv("GAP_DEBUG");
if(l_env != NULL)
{
if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1;
}
- if(gap_debug) fprintf(stderr, "\n\nDEBUG: run %s\n", name);
+ if(gap_debug)
+ {
+ printf("\n\nDEBUG: run %s RUN_MODE:%d\n", name, (int)run_mode);
+ }
run_flag = FALSE;
+ if (strcmp(name, PLUG_IN_NAME_TWEEN) == 0)
+ {
+ run_flag = TRUE;
+ }
/* initialize the return of the status */
values[0].type = GIMP_PDB_STATUS;
values[0].data.d_status = status;
@@ -202,24 +380,41 @@
image_id = param[1].data.d_int32;
drawable_id = param[2].data.d_drawable;
mgpp->do_progress = FALSE;
+ mgpp->image_id = image_id;
+ mgpp->run_mode = run_mode;
+
switch (run_mode)
{
case GIMP_RUN_INTERACTIVE:
- /* Possibly retrieve data from a previous run */
- gimp_get_data (PLUG_IN_NAME, mgpp);
- mgpp->osrc_layer_id = drawable_id;
- mgpp->fdst_layer_id = gap_morph_exec_find_dst_drawable(image_id, drawable_id);
- run_flag = gap_morph_dialog(mgpp);
- mgpp->do_progress = TRUE;
+ if (strcmp(name, PLUG_IN_NAME) == 0)
+ {
+ /* Possibly retrieve data from a previous run */
+ gimp_get_data (PLUG_IN_NAME, mgpp);
+ mgpp->osrc_layer_id = drawable_id;
+ mgpp->fdst_layer_id = gap_morph_exec_find_dst_drawable(image_id, drawable_id);
+ run_flag = gap_morph_dialog(mgpp);
+ mgpp->do_progress = TRUE;
+ }
+ else if (strcmp(name, PLUG_IN_NAME_ONE_TWEEN) == 0)
+ {
+ mgpp->tween_mix_factor = 0.5;
+ /* Possibly retrieve data from a previous run */
+ gimp_get_data (PLUG_IN_NAME_ONE_TWEEN, mgpp);
+ mgpp->osrc_layer_id = drawable_id;
+ mgpp->fdst_layer_id = gap_morph_exec_find_dst_drawable(image_id, drawable_id);
+ run_flag = gap_morph_one_tween_dialog(mgpp);
+ mgpp->do_progress = TRUE;
+ }
break;
case GIMP_RUN_NONINTERACTIVE:
/* check to see if invoked with the correct number of parameters */
- if (nparams == G_N_ELEMENTS (in_args))
+ if ((nparams == G_N_ELEMENTS (in_args))
+ && (strcmp(name, PLUG_IN_NAME) == 0))
{
- mgpp->multiple_pointsets = TRUE; /* use pointset(s) from file */
+ mgpp->have_workpointsets = TRUE; /* use pointset(s) from file */
/* set defaults for params that may be specified in the workpointfiles
* (the defaults will take effect only if the file does not contain such settings)
@@ -273,6 +468,99 @@
run_flag = TRUE;
}
+ else if ((nparams == G_N_ELEMENTS (in_one_tween_args))
+ && (strcmp(name, PLUG_IN_NAME_ONE_TWEEN) == 0))
+ {
+ /* set defaults for params that may be specified in the workpointfiles
+ * (the defaults will take effect only if the file does not contain such settings)
+ */
+ mgpp->use_quality_wp_selection = FALSE;
+ mgpp->have_workpointsets = FALSE; /* operate with a single workpointfile */
+ mgpp->use_gravity = FALSE;
+ mgpp->gravity_intensity = 2.0;
+ mgpp->affect_radius = 100.0;
+ mgpp->tween_steps = 1; /* (in this mode always render only one tween) */
+ mgpp->render_mode = GAP_MORPH_RENDER_MODE_MORPH;
+ mgpp->create_tween_layers = TRUE;
+
+ mgpp->osrc_layer_id = param[2].data.d_drawable;
+ mgpp->fdst_layer_id = param[3].data.d_drawable;
+ mgpp->tween_mix_factor = param[4].data.d_float;
+ mgpp->do_simple_fade = (param[5].data.d_int32 != 0);
+ if(param[6].data.d_string != NULL)
+ {
+ if(param[6].data.d_string[0] != '\0')
+ {
+ g_snprintf(mgpp->workpoint_file_lower
+ , sizeof(mgpp->workpoint_file_lower)
+ , "%s", param[6].data.d_string);
+ g_snprintf(mgpp->workpoint_file_upper
+ , sizeof(mgpp->workpoint_file_upper)
+ , "%s", param[6].data.d_string);
+ }
+ else
+ {
+ mgpp->have_workpointsets = FALSE; /* no pointset file available */
+ }
+ run_flag = TRUE;
+ }
+ else
+ {
+ printf("%s: noninteractive call requires a not-NULL workpoint_file parameter\n"
+ , PLUG_IN_NAME_ONE_TWEEN
+ );
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+
+
+ }
+ else if ((nparams == G_N_ELEMENTS (in_one_tween_args))
+ && (strcmp(name, PLUG_IN_NAME_TWEEN) == 0))
+ {
+ /* set defaults for params that may be specified in the workpointfiles
+ * (the defaults will take effect only if the file does not contain such settings)
+ */
+ mgpp->use_quality_wp_selection = FALSE;
+ mgpp->have_workpointsets = FALSE; /* operate with a single workpointfile */
+ mgpp->use_gravity = FALSE;
+ mgpp->gravity_intensity = 2.0;
+ mgpp->affect_radius = 100.0;
+ mgpp->tween_steps = 1; /* (will be calculated later as difference of handled frame numbers) */
+ mgpp->render_mode = GAP_MORPH_RENDER_MODE_MORPH;
+ mgpp->create_tween_layers = TRUE;
+
+ mgpp->osrc_layer_id = -1; /* is created later as merged copy of the specified image */
+ mgpp->fdst_layer_id = -1; /* is created later as merged copy of the frame rfered by to_frame_nr parameter */
+ mgpp->range_to = param[3].data.d_int32;
+ mgpp->overwrite_flag = (param[4].data.d_int32 != 0);
+ mgpp->do_simple_fade = (param[5].data.d_int32 != 0);
+ mgpp->tween_mix_factor = 1.0; /* not relevant here */
+ if(param[6].data.d_string != NULL)
+ {
+ if(param[6].data.d_string[0] != '\0')
+ {
+ g_snprintf(mgpp->workpoint_file_lower
+ , sizeof(mgpp->workpoint_file_lower)
+ , "%s", param[6].data.d_string);
+ g_snprintf(mgpp->workpoint_file_upper
+ , sizeof(mgpp->workpoint_file_upper)
+ , "%s", param[6].data.d_string);
+ }
+ else
+ {
+ mgpp->have_workpointsets = FALSE; /* no pointset file available */
+ }
+ run_flag = TRUE;
+ }
+ else
+ {
+ printf("%s: noninteractive call requires a not-NULL workpoint_file parameter\n"
+ , PLUG_IN_NAME_TWEEN
+ );
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+
+ }
else
{
printf("%s: noninteractive call wrong nuber %d of params were passed. (%d params are required)\n"
@@ -285,12 +573,15 @@
break;
case GIMP_RUN_WITH_LAST_VALS:
- /* Possibly retrieve data from a previous run */
- gimp_get_data (PLUG_IN_NAME, mgpp);
- mgpp->osrc_layer_id = drawable_id;
- mgpp->fdst_layer_id = gap_morph_exec_find_dst_drawable(image_id, drawable_id);
- run_flag = gap_morph_dialog(mgpp);
- mgpp->do_progress = TRUE;
+ if (strcmp(name, PLUG_IN_NAME) == 0)
+ {
+ /* Possibly retrieve data from a previous run */
+ gimp_get_data (PLUG_IN_NAME, mgpp);
+ mgpp->osrc_layer_id = drawable_id;
+ mgpp->fdst_layer_id = gap_morph_exec_find_dst_drawable(image_id, drawable_id);
+ run_flag = gap_morph_dialog(mgpp);
+ mgpp->do_progress = TRUE;
+ }
break;
default:
@@ -300,15 +591,48 @@
if ((status == GIMP_PDB_SUCCESS)
&& (run_flag))
{
+ if (strcmp(name, PLUG_IN_NAME) == 0)
+ {
+ gap_morph_execute(mgpp);
+ /* Store variable states for next run */
+ if (run_mode == GIMP_RUN_INTERACTIVE)
+ {
+ gimp_set_data (PLUG_IN_NAME, mgpp, sizeof (GapMorphGlobalParams));
+ }
+ }
+ else if ((strcmp(name, PLUG_IN_NAME_ONE_TWEEN) == 0) || (strcmp(name, PLUG_IN_NAME_TWEEN) == 0))
+ {
+ gint32 tween_layer_id;
+
+ if (strcmp(name, PLUG_IN_NAME_ONE_TWEEN) == 0)
+ {
+ tween_layer_id = gap_morph_render_one_tween(mgpp);
+ }
+ else if (strcmp(name, PLUG_IN_NAME_TWEEN) == 0)
+ {
+ tween_layer_id = p_handle_PLUG_IN_NAME_TWEEN(mgpp);
+ }
+
+
+ values[1].type = GIMP_PDB_DRAWABLE;
+ values[1].data.d_int32 = tween_layer_id;
+ values[1].data.d_drawable = tween_layer_id;
+ *nreturn_vals = 2;
+ if (tween_layer_id < 0)
+ {
+ status = GIMP_PDB_EXECUTION_ERROR;
+ }
+ else
+ {
+ if (run_mode == GIMP_RUN_INTERACTIVE)
+ {
+ /* Store variable states for next run */
+ gimp_set_data (name, mgpp, sizeof (GapMorphGlobalParams));
+ gimp_display_new(gimp_drawable_get_image(tween_layer_id));
+ }
+ }
+ }
- mgpp->image_id = image_id;
- mgpp->run_mode = run_mode;
-
- gap_morph_execute(mgpp);
-
- /* Store variable states for next run */
- if (run_mode == GIMP_RUN_INTERACTIVE)
- gimp_set_data (PLUG_IN_NAME, mgpp, sizeof (GapMorphGlobalParams));
}
values[0].data.d_status = status;
} /* end run */
Modified: trunk/gap/gap_morph_main.h
==============================================================================
--- trunk/gap/gap_morph_main.h (original)
+++ trunk/gap/gap_morph_main.h Wed Jan 14 19:59:24 2009
@@ -85,7 +85,7 @@
char workpoint_file_upper[GAP_MORPH_WORKPOINT_FILENAME_MAX_LENGTH];
gboolean create_tween_layers; /* FALSE: operate on existing layers only */
- gboolean multiple_pointsets; /* FALSE: use the default workpointset master_wp_list
+ gboolean have_workpointsets; /* FALSE: use the default workpointset master_wp_list
* TRUE: use lower_wp_list and upper_wp_list
* foreach handled frame the
* lower and upper list are fetched from
@@ -102,7 +102,11 @@
gdouble master_progress;
gdouble layer_progress_step;
-
+ gdouble tween_mix_factor; /* 0.0 upto 1.0 wher 0.0 gives source layer 1.0 dest layer as resut */
+ gint32 range_from;
+ gint32 range_to;
+ gboolean overwrite_flag;
+ gboolean do_simple_fade; /* bypass morph algortihm when renderiing tweens and use simple fade instead */
} GapMorphGlobalParams;
typedef struct GapMorphWarpCoreAPI { /* nickname: wcap */
Added: trunk/gap/gap_morph_tween_dialog.c
==============================================================================
--- (empty file)
+++ trunk/gap/gap_morph_tween_dialog.c Wed Jan 14 19:59:24 2009
@@ -0,0 +1,536 @@
+/* gap_morph_one_tween_dialog.c
+ *
+ * This module handles the GAP morph tween dialog
+ */
+/* 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.
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "gap_morph_main.h"
+#include "gap_morph_tween_dialog.h"
+#include "gap-intl.h"
+
+extern int gap_debug; /* 1 == print debug infos , 0 dont print debug infos */
+
+#define SCALE_WIDTH 200
+#define SPIN_BUTTON_WIDTH 60
+
+typedef struct MorphTweenGui { /* nickname: mtg */
+ GapMorphGlobalParams *mgpp;
+ GtkWidget *morph_filesel;
+ GtkWidget *morph_entry;
+ } MorphTweenGui;
+
+
+/* ----------------------------
+ * p_selectionConstraintFunc
+ * ----------------------------
+ *
+ */
+static gint
+p_selectionConstraintFunc (gint32 image_id,
+ gint32 drawable_id,
+ gpointer data)
+{
+ if (image_id < 0)
+ return FALSE;
+
+ /* dont accept layers from indexed images */
+ if (gimp_drawable_is_indexed (drawable_id))
+ return FALSE;
+
+ return TRUE;
+} /* end p_selectionConstraintFunc */
+
+/* -----------------------------
+ * p_layerSelectionComboCallback
+ * -----------------------------
+ *
+ */
+static void
+p_layerSelectionComboCallback (GtkWidget *widget)
+{
+ gint idValue;
+ gint32 *layerIdPtr;
+
+ if(gap_debug)
+ {
+ printf("p_layerSelectionComboCallback START\n");
+ }
+
+ gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &idValue);
+ layerIdPtr = g_object_get_data (G_OBJECT (widget), "layerIdPtr");
+
+ if(gap_debug)
+ {
+ printf("p_layerSelectionComboCallback idValue:%d\n", idValue);
+ }
+
+ if (layerIdPtr)
+ {
+ *layerIdPtr = idValue;
+ }
+
+} /* end p_layerSelectionComboCallback */
+
+
+
+
+/* --------------------------
+ * FILESEL
+ * --------------------------
+ */
+static void
+p_filesel_close_cb(GtkWidget *widget, MorphTweenGui *mtg)
+{
+ if(mtg->morph_filesel == NULL) return; /* filesel is already closed */
+
+ gtk_widget_destroy(GTK_WIDGET(mtg->morph_filesel));
+ mtg->morph_filesel = NULL;
+}
+
+static void
+p_filesel_ok_cb(GtkWidget *widget, MorphTweenGui *mtg)
+{
+ const gchar *filename;
+
+ if(mtg->morph_filesel == NULL) return; /* filesel is already closed */
+
+ filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (mtg->morph_filesel));
+
+ gtk_entry_set_text(GTK_ENTRY(mtg->morph_entry), filename);
+
+ p_filesel_close_cb(widget, mtg);
+}
+
+/* --------------------------------------
+ * p_filesel_open_cb
+ * --------------------------------------
+ */
+static void
+p_filesel_open_cb(GtkWidget *widget, MorphTweenGui *mtg)
+{
+ GtkWidget *filesel;
+ GapMorphGlobalParams *mgpp;
+
+ if(mtg->morph_filesel != NULL)
+ {
+ gtk_window_present(GTK_WINDOW(mtg->morph_filesel));
+ return; /* filesel is already open */
+ }
+
+ filesel = gtk_file_selection_new (_("Enter Morph Workpoint filename"));
+ mtg->morph_filesel = filesel;
+ mgpp = mtg->mgpp;
+
+ gtk_window_set_position (GTK_WINDOW (filesel), GTK_WIN_POS_MOUSE);
+
+ gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel),
+ &mgpp->workpoint_file_lower[0]);
+ gtk_widget_show (filesel);
+
+ g_signal_connect (G_OBJECT (filesel), "destroy",
+ G_CALLBACK (p_filesel_close_cb),
+ mtg);
+
+ g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button),
+ "clicked",
+ G_CALLBACK (p_filesel_ok_cb),
+ mtg);
+ g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button),
+ "clicked",
+ G_CALLBACK (p_filesel_close_cb),
+ mtg);
+}
+
+/* -----------------------------------------------------
+ * p_check_workpoint_file_and_use_single_fade_if_missing
+ * -----------------------------------------------------
+ */
+static void
+p_check_workpoint_file_and_use_single_fade_if_missing(GapMorphGlobalParams *mgpp)
+{
+ if(g_file_test(&mgpp->workpoint_file_lower[0], G_FILE_TEST_EXISTS))
+ {
+ mgpp->do_simple_fade = FALSE; /* use morph algortihm when workpoint file is available */
+ }
+ else
+ {
+ mgpp->do_simple_fade = TRUE; /* use simple fade because we have no workpoint file */
+ }
+}
+
+/* --------------------------------------
+ * p_morph_workpoint_entry_update_cb
+ * --------------------------------------
+ */
+static void
+p_morph_workpoint_entry_update_cb(GtkWidget *widget, GapMorphGlobalParams *mgpp)
+{
+ g_snprintf(&mgpp->workpoint_file_lower[0]
+ , sizeof(mgpp->workpoint_file_lower)
+ , "%s"
+ , gtk_entry_get_text(GTK_ENTRY(widget))
+ );
+ g_snprintf(&mgpp->workpoint_file_upper[0]
+ , sizeof(mgpp->workpoint_file_upper)
+ , "%s"
+ , gtk_entry_get_text(GTK_ENTRY(widget))
+ );
+ if(gap_debug)
+ {
+ printf("p_morph_workpoint_entry_update_cb workpoint_file_lower: %s\n"
+ , &mgpp->workpoint_file_lower[0]);
+ }
+
+ p_check_workpoint_file_and_use_single_fade_if_missing(mgpp);
+
+} /* end p_morph_workpoint_entry_update_cb */
+
+
+
+/* --------------------------------------
+ * p_create_morph_workpoint_entry
+ * --------------------------------------
+ */
+static void
+p_create_morph_workpoint_entry(GapMorphGlobalParams *mgpp, MorphTweenGui *mtg, gint row, GtkWidget *table)
+{
+ GtkWidget *entry;
+ GtkWidget *label;
+ GtkWidget *button;
+
+ /* morph workpoint entry */
+ label = gtk_label_new (_("Morph Workpoint file:"));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+ GTK_FILL, GTK_FILL, 4, 0);
+ gtk_widget_show (label);
+
+ entry = gtk_entry_new();
+ mtg->morph_entry = entry;
+ gtk_widget_set_size_request(entry, SCALE_WIDTH, -1);
+ if(mgpp->workpoint_file_lower[0] != '\0')
+ {
+ gtk_entry_set_text(GTK_ENTRY(entry), &mgpp->workpoint_file_lower[0]);
+ }
+ gtk_table_attach(GTK_TABLE(table), entry, 1, 2, row, row + 1, GTK_FILL, GTK_FILL | GTK_EXPAND, 4, 0);
+ gimp_help_set_help_data(entry, _("Name of a Workpointfile created with the Morph feature\n"
+ "(note that tweens are created via simple fade operations when no workpointfile is available))"), NULL);
+ gtk_widget_show(entry);
+
+ g_signal_connect(G_OBJECT(entry), "changed",
+ G_CALLBACK (p_morph_workpoint_entry_update_cb),
+ mgpp);
+
+
+ /* Button to invoke filebrowser */
+ button = gtk_button_new_with_label ( "..." );
+ gtk_widget_set_size_request(button, SPIN_BUTTON_WIDTH, -1);
+ g_object_set_data (G_OBJECT (button), "mgpp", (gpointer)mgpp);
+ gtk_table_attach( GTK_TABLE(table), button, 2, 3, row, row +1,
+ 0, 0, 0, 0 );
+ gtk_widget_show (button);
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (p_filesel_open_cb),
+ mtg);
+} /* end p_create_morph_workpoint_entry */
+
+/* --------------------------------------
+ * gap_morph_one_tween_dialog
+ * --------------------------------------
+ */
+gboolean
+gap_morph_one_tween_dialog(GapMorphGlobalParams *mgpp)
+{
+ MorphTweenGui morphTweenGui;
+ MorphTweenGui *mtg;
+ GtkWidget *dialog;
+ GtkWidget *main_vbox;
+ GtkWidget *label;
+ GtkWidget *table;
+ GtkWidget *combo;
+ GtkObject *adj;
+ gint row;
+ gboolean run;
+
+ mtg = &morphTweenGui;
+ mtg->mgpp = mgpp;
+ mtg->morph_filesel = NULL;
+ p_check_workpoint_file_and_use_single_fade_if_missing(mgpp);
+
+ gimp_ui_init (GAP_MORPH_TWEEN_PLUGIN_NAME, TRUE);
+
+ dialog = gimp_dialog_new (_("Create one tween"), GAP_MORPH_TWEEN_PLUGIN_NAME,
+ NULL, 0,
+ gimp_standard_help_func, GAP_MORPH_TWEEN_HELP_ID,
+
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK,
+
+ NULL);
+
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ gimp_window_set_transient (GTK_WINDOW (dialog));
+
+ main_vbox = gtk_vbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
+ gtk_widget_show (main_vbox);
+
+
+ /* Controls */
+ table = gtk_table_new (3, 3, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
+ gtk_widget_show (table);
+
+ row = 0;
+
+ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row,
+ _("tween mix:"), SCALE_WIDTH, 7,
+ mgpp->tween_mix_factor, 0.0, 1.0, 0.1, 0.1, 3,
+ TRUE, 0, 0,
+ NULL, NULL);
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (gimp_double_adjustment_update),
+ &mgpp->tween_mix_factor);
+
+ row++;
+
+ /* layer combo_box (source) */
+ label = gtk_label_new (_("Source Layer:"));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+ GTK_FILL, GTK_FILL, 4, 0);
+ gtk_widget_show (label);
+
+ /* layer combo_box (Sample from where to pick the alternative selection */
+ combo = gimp_layer_combo_box_new (p_selectionConstraintFunc, NULL);
+
+ g_object_set_data (G_OBJECT (combo), "layerIdPtr", &mgpp->osrc_layer_id);
+ gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), mgpp->osrc_layer_id,
+ G_CALLBACK (p_layerSelectionComboCallback),
+ NULL);
+
+ gtk_table_attach (GTK_TABLE (table), combo, 1, 3, row, row + 1,
+ GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+ gtk_widget_show (combo);
+
+ row++;
+
+ /* layer combo_box (source) */
+ label = gtk_label_new (_("Destination Layer:"));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+ GTK_FILL, GTK_FILL, 4, 0);
+ gtk_widget_show (label);
+
+ /* layer combo_box (Sample from where to pick the alternative selection */
+ combo = gimp_layer_combo_box_new (p_selectionConstraintFunc, NULL);
+
+ g_object_set_data (G_OBJECT (combo), "layerIdPtr", &mgpp->fdst_layer_id);
+ gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), mgpp->fdst_layer_id,
+ G_CALLBACK (p_layerSelectionComboCallback),
+ NULL);
+
+ gtk_table_attach (GTK_TABLE (table), combo, 1, 3, row, row + 1,
+ GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+ gtk_widget_show (combo);
+
+ row++;
+
+ p_create_morph_workpoint_entry(mgpp, mtg, row, table);
+
+ /* Done */
+
+ gtk_widget_show (dialog);
+
+ run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
+
+ gtk_widget_destroy (dialog);
+
+ return run;
+} /* end gap_morph_one_tween_dialog */
+
+
+/* --------------------------------------
+ * gap_morph_frame_tweens_dialog
+ * --------------------------------------
+ */
+gboolean
+gap_morph_frame_tweens_dialog(GapAnimInfo *ainfo_ptr, GapMorphGlobalParams *mgpp)
+{
+ MorphTweenGui morphTweenGui;
+ MorphTweenGui *mtg;
+ GtkWidget *dialog;
+ GtkWidget *main_vbox;
+ GtkWidget *table;
+ GtkObject *adj;
+ GtkWidget *scale;
+ GtkWidget *spinbutton;
+ GtkWidget *label;
+ gint row;
+ gboolean run;
+ gboolean isFrameMissing;
+
+ mgpp->range_from = ainfo_ptr->curr_frame_nr;
+ mgpp->range_to = ainfo_ptr->frame_nr_after_curr_frame_nr;
+ mtg = &morphTweenGui;
+ mtg->mgpp = mgpp;
+ mtg->morph_filesel = NULL;
+ isFrameMissing = FALSE;
+ p_check_workpoint_file_and_use_single_fade_if_missing(mgpp);
+
+
+ if(gap_debug)
+ {
+ printf("gap_morph_frame_tweens_dialog: mgpp->range_from%d mgpp->range_to:%d first:%d, curr:%d, last:%d after_curr:%d\n"
+ , (int)mgpp->range_from
+ , (int)mgpp->range_to
+ , (int)ainfo_ptr->first_frame_nr
+ , (int)ainfo_ptr->curr_frame_nr
+ , (int)ainfo_ptr->last_frame_nr
+ , (int)ainfo_ptr->frame_nr_after_curr_frame_nr
+ );
+ }
+
+ isFrameMissing = (ainfo_ptr->curr_frame_nr +1) != ainfo_ptr->frame_nr_after_curr_frame_nr;
+
+ gimp_ui_init (GAP_MORPH_TWEEN_PLUGIN_NAME, TRUE);
+
+ dialog = gimp_dialog_new (_("Create Tween Frames"), GAP_MORPH_TWEEN_PLUGIN_NAME,
+ NULL, 0,
+ gimp_standard_help_func, GAP_MORPH_TWEEN_HELP_ID,
+
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK,
+
+ NULL);
+
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ gimp_window_set_transient (GTK_WINDOW (dialog));
+
+ main_vbox = gtk_vbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
+ gtk_widget_show (main_vbox);
+
+
+ /* Controls */
+ table = gtk_table_new (3, 3, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
+ gtk_widget_show (table);
+
+ row = 0;
+ /* morph workpoint entry */
+ label = gtk_label_new (_("Information:"));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+ GTK_FILL, GTK_FILL, 4, 0);
+ gtk_widget_show (label);
+
+ if (isFrameMissing)
+ {
+ char *msg;
+ msg = g_strdup_printf(_("this operation creates %d mising frames between frame %d and %d")
+ ,(int)(mgpp->range_to - mgpp->range_from) -1
+ ,(int)mgpp->range_from
+ ,(int)mgpp->range_to
+ );
+ label = gtk_label_new (msg);
+ g_free(msg);
+ mgpp->overwrite_flag = FALSE;
+ }
+ else
+ {
+ label = gtk_label_new (_("WARNING this operation will overwrite all frames between the specified frame range"));
+ mgpp->overwrite_flag = TRUE;
+ }
+ gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
+ gtk_table_attach (GTK_TABLE (table), label, 1, 3, row, row + 1,
+ GTK_FILL, GTK_FILL, 4, 0);
+ gtk_widget_show (label);
+
+ row++;
+
+ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row,
+ _("From:"), SCALE_WIDTH, 7,
+ mgpp->range_from, ainfo_ptr->first_frame_nr, ainfo_ptr->last_frame_nr, 1.0, 10.0, 0,
+ TRUE, 0, 0,
+ NULL, NULL);
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (gimp_int_adjustment_update),
+ &mgpp->range_from);
+
+ scale = g_object_get_data(G_OBJECT (adj), "scale");
+ spinbutton = g_object_get_data(G_OBJECT (adj), "spinbutton");
+ gtk_widget_set_sensitive(scale, FALSE);
+ gtk_widget_set_sensitive(spinbutton, FALSE);
+
+ row++;
+
+ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row,
+ _("To:"), SCALE_WIDTH, 7,
+ mgpp->range_to, mgpp->range_from +1, ainfo_ptr->last_frame_nr, 1.0, 10.0, 0,
+ TRUE, 0, 0,
+ NULL, NULL);
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (gimp_int_adjustment_update),
+ &mgpp->range_to);
+ if (isFrameMissing)
+ {
+ scale = g_object_get_data(G_OBJECT (adj), "scale");
+ spinbutton = g_object_get_data(G_OBJECT (adj), "spinbutton");
+ gtk_widget_set_sensitive(scale, FALSE);
+ gtk_widget_set_sensitive(spinbutton, FALSE);
+ }
+
+ row++;
+
+ p_create_morph_workpoint_entry(mgpp, mtg, row, table);
+
+ /* Done */
+
+ gtk_widget_show (dialog);
+
+ run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
+
+ gtk_widget_destroy (dialog);
+
+ return run;
+} /* end gap_morph_frame_tweens_dialog */
+
Added: trunk/gap/gap_morph_tween_dialog.h
==============================================================================
--- (empty file)
+++ trunk/gap/gap_morph_tween_dialog.h Wed Jan 14 19:59:24 2009
@@ -0,0 +1,44 @@
+/* gap_morph_one_tween_dialog.h
+ *
+ * This module handles the GAP morph tween dialog
+ */
+/* 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:
+ * version 2.1.0a; 2004/03/31 hof: created
+ */
+
+#ifndef _gap_morph_tween_dialog_H
+#define _gap_morph_tween_dialog_H
+
+#include "libgimp/gimp.h"
+#include "gap_libgimpgap.h"
+#include "gap_morph_main.h"
+#include "gap_libgimpgap.h"
+
+#define GAP_MORPH_ONE_TWEEN_PLUGIN_NAME "plug_in_gap_morph_one_tween"
+#define GAP_MORPH_ONE_TWEEN_HELP_ID "plug-in-gap-morph-one-tween"
+
+#define GAP_MORPH_TWEEN_PLUGIN_NAME "plug_in_gap_morph_tween"
+#define GAP_MORPH_TWEEN_HELP_ID "plug-in-gap-morph-tween"
+
+gboolean gap_morph_one_tween_dialog(GapMorphGlobalParams *mgpp);
+gboolean gap_morph_frame_tweens_dialog(GapAnimInfo *ainfo_ptr, GapMorphGlobalParams *mgpp);
+
+#endif
Modified: trunk/gap/gap_story_dialog.c
==============================================================================
--- trunk/gap/gap_story_dialog.c (original)
+++ trunk/gap/gap_story_dialog.c Wed Jan 14 19:59:24 2009
@@ -8680,7 +8680,7 @@
static void
p_tabw_master_prop_dialog(GapStbTabWidgets *tabw, gboolean new_flag)
{
- GapArrArg argv[11];
+ GapArrArg argv[12];
static char *radio_args[4] = { N_("automatic"), "libmpeg3", "libavformat", "quicktime4linux" };
static char *radio_aspect_args[3] = { N_("none"), "4:3", "16:9"};
gint l_ii;
@@ -8701,6 +8701,8 @@
gchar buf_preferred_decoder[60];
gchar buf_aspect_string[40];
gchar *label_txt;
+ gchar l_master_insert_area_format[GAP_STORY_MAX_STORYFILENAME_LEN];
+
gboolean l_rc;
stb_dst = p_tabw_get_stb_ptr (tabw);
@@ -8719,7 +8721,7 @@
gap_story_get_master_pixelsize(stb_dst, &l_master_width, &l_master_height);
label_txt = NULL;
- l_ii = 0; l_ii_width = l_ii;
+ l_ii = 0;
if(new_flag)
{
gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_FILESEL);
@@ -8928,6 +8930,25 @@
argv[l_ii].flt_default = argv[l_ii].flt_ret;
l_ii++;
+ l_master_insert_area_format[0] = '\0';
+ if (stb_dst->master_insert_area_format)
+ {
+ g_snprintf(&l_master_insert_area_format[0], sizeof(l_master_insert_area_format), "%s"
+ , stb_dst->master_insert_area_format
+ );
+ }
+ gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_FILESEL);
+ argv[l_ii].label_txt = _("AreaFormat:");
+ argv[l_ii].entry_width = 250; /* pixel */
+ argv[l_ii].help_txt = _("Format string for area replacement in movie clips. (e.g automatic logo insert)"
+ "this string shall contain \%s as placeholder for the basename of a videoclip and "
+ "optional \%06d as placeholder for the framenumber.");
+ argv[l_ii].text_buf_len = sizeof(l_master_insert_area_format);
+ argv[l_ii].text_buf_ret = &l_master_insert_area_format[0];
+
+
+
+ l_ii++;
gap_arr_arg_init(&argv[l_ii], GAP_ARR_WGT_DEFAULT_BUTTON);
argv[l_ii].label_txt = _("Reset"); /* should use GIMP_STOCK_RESET if possible */
argv[l_ii].help_txt = _("Reset parameters to inital values");
@@ -8988,6 +9009,7 @@
{
if(strcmp(stb_dst->preferred_decoder, buf_preferred_decoder) != 0)
{
+ stb_dst->unsaved_changes = TRUE;
g_free(stb_dst->preferred_decoder);
stb_dst->preferred_decoder = g_strdup(buf_preferred_decoder);
@@ -9000,6 +9022,7 @@
}
else
{
+ stb_dst->unsaved_changes = TRUE;
stb_dst->preferred_decoder = g_strdup(buf_preferred_decoder);
gap_story_vthumb_close_videofile(sgpp);
}
@@ -9008,12 +9031,42 @@
{
if(stb_dst->preferred_decoder)
{
+ stb_dst->unsaved_changes = TRUE;
g_free(stb_dst->preferred_decoder);
}
stb_dst->preferred_decoder = NULL;
}
- /* check for changes of master properties */
+
+ if (l_master_insert_area_format[0] != '\0')
+ {
+ if (stb_dst->master_insert_area_format)
+ {
+ if (strcmp(stb_dst->master_insert_area_format, &l_master_insert_area_format[0]) != 0)
+ {
+ stb_dst->unsaved_changes = TRUE;
+ }
+ g_free(stb_dst->master_insert_area_format);
+ }
+ else
+ {
+ stb_dst->unsaved_changes = TRUE;
+ }
+ stb_dst->master_insert_area_format = g_strdup(&l_master_insert_area_format[0]);
+ }
+ else
+ {
+ if (stb_dst->master_insert_area_format)
+ {
+ stb_dst->unsaved_changes = TRUE;
+ g_free(stb_dst->master_insert_area_format);
+ stb_dst->master_insert_area_format = NULL;
+ }
+ }
+
+
+
+ /* check for further changes of master properties */
if((stb_dst->master_width != stb_dup->master_width)
|| (stb_dst->master_height != stb_dup->master_height)
|| (stb_dst->master_framerate != stb_dup->master_framerate)
Modified: trunk/gap/gap_story_file.c
==============================================================================
--- trunk/gap/gap_story_file.c (original)
+++ trunk/gap/gap_story_file.c Wed Jan 14 19:59:24 2009
@@ -303,22 +303,26 @@
return;
}
- printf("master_type : %d\n", (int)stb->master_type );
- printf("master_width : %d\n", (int)stb->master_width );
- printf("master_height : %d\n", (int)stb->master_height );
- printf("master_framerate : %f\n", (float)stb->master_framerate );
- printf("master_aspect_ratio : %f (%d : %d)\n"
+ printf("master_type : %d\n", (int)stb->master_type );
+ printf("master_width : %d\n", (int)stb->master_width );
+ printf("master_height : %d\n", (int)stb->master_height );
+ printf("master_framerate : %f\n", (float)stb->master_framerate );
+ printf("master_aspect_ratio : %f (%d : %d)\n"
, (float)stb->master_aspect_ratio
, (int)stb->master_aspect_width
, (int)stb->master_aspect_height
);
- printf("master_1is_toplayer : %d\n", (int)stb->master_vtrack1_is_toplayer );
- printf("layout_cols : %d\n", (int)stb->layout_cols );
- printf("layout_rows : %d\n", (int)stb->layout_rows );
- printf("layout_thumbsize : %d\n", (int)stb->layout_thumbsize );
+ printf("master_1is_toplayer : %d\n", (int)stb->master_vtrack1_is_toplayer );
+ if (stb->master_insert_area_format)
+ {
+ printf("master_insert_area_format :%s", stb->master_insert_area_format);
+ }
+ printf("layout_cols : %d\n", (int)stb->layout_cols );
+ printf("layout_rows : %d\n", (int)stb->layout_rows );
+ printf("layout_thumbsize : %d\n", (int)stb->layout_thumbsize );
- printf("stb_parttype : %d\n", (int)stb->stb_parttype );
- printf("stb_unique_id : %d\n", (int)stb->stb_unique_id );
+ printf("stb_parttype : %d\n", (int)stb->stb_parttype );
+ printf("stb_unique_id : %d\n", (int)stb->stb_unique_id );
GapStorySection *active_section;
@@ -618,6 +622,7 @@
stb->master_aspect_ratio = 0.0; /* 0.0 for none */
stb->master_aspect_width = 0;
stb->master_aspect_height = 0;
+ stb->master_insert_area_format = NULL;
stb->layout_cols = -1;
stb->layout_rows = -1;
@@ -1465,6 +1470,10 @@
{
g_free(stb->warnline);
}
+ if(stb->master_insert_area_format)
+ {
+ g_free(stb->master_insert_area_format);
+ }
/* Note: Dont try to g_free stb->currline
* it points to memory that is controlled (and already free'd) by the parser
@@ -3146,6 +3155,15 @@
if(*l_wordval[1]) { stb->preferred_decoder = g_strdup(l_wordval[1]); }
goto cleanup; /* master RECORD does not create frame range elements */
}
+ /* Master informations: GAP_STBKEY_VID_MASTER_INSERT_AREA */
+ if (strcmp(l_record_key, GAP_STBKEY_VID_MASTER_INSERT_AREA) == 0)
+ {
+ char *l_format_ptr = l_wordval[1];
+ if(*l_format_ptr) { p_flip_dir_separators(l_format_ptr);;
+ stb->master_insert_area_format = g_strdup(l_format_ptr);
+ }
+ goto cleanup; /* master RECORD does not create frame range elements */
+ }
/* Master informations: GAP_STBKEY_AUD_MASTER_VOLUME */
@@ -4938,6 +4956,21 @@
}
}
+ if (stb->master_insert_area_format)
+ {
+ if(*stb->master_insert_area_format != '\0')
+ {
+ gap_stb_syntax_get_parname_tab(GAP_STBKEY_VID_MASTER_INSERT_AREA
+ ,&l_parnam_tab
+ );
+ fprintf(fp, "%s %s:\"%s\"\n"
+ , GAP_STBKEY_VID_MASTER_INSERT_AREA
+ , l_parnam_tab.parname[1]
+ , stb->master_insert_area_format
+ );
+ }
+ }
+
} /* end p_story_save_header */
@@ -7082,6 +7115,10 @@
{
stb_dup->preferred_decoder = g_strdup(stb_ptr->preferred_decoder);
}
+ if(stb_ptr->master_insert_area_format)
+ {
+ stb_dup->master_insert_area_format = g_strdup(stb_ptr->master_insert_area_format);
+ }
stb_dup->layout_cols = stb_ptr->layout_cols;
stb_dup->layout_rows = stb_ptr->layout_rows;
@@ -7765,10 +7802,26 @@
stb->master_samplerate = stb_sample->master_samplerate;
stb->master_volume = stb_sample->master_volume;
stb->unsaved_changes = TRUE;
+ if(stb->preferred_decoder)
+ {
+ g_free(stb->preferred_decoder);
+ stb->preferred_decoder = NULL;
+ }
if(stb_sample->preferred_decoder)
{
stb->preferred_decoder = g_strdup(stb_sample->preferred_decoder);
}
+
+ if(stb->master_insert_area_format)
+ {
+ g_free(stb->master_insert_area_format);
+ stb->master_insert_area_format = NULL;
+ }
+ if(stb_sample->master_insert_area_format)
+ {
+ stb->master_insert_area_format = g_strdup(stb_sample->master_insert_area_format);
+ }
+
}
}
} /* end gap_story_set_properties_like_sample_storyboard */
@@ -9263,3 +9316,20 @@
}
return (vref_list);
} /* end gap_story_get_video_file_ref_list */
+
+
+/* -------------------------------------
+ * gap_story_build_basename
+ * -------------------------------------
+ * return a duplicate of the basename part of the specified filename.
+ * leading directory path and drive letter (for WinOS) is cut off
+ * the caller is responsible to g_free the returned string.
+ */
+char *
+gap_story_build_basename(const char *filename)
+{
+ char *basename;
+
+ basename = g_filename_display_basename(filename);
+ return(basename);
+} /* end gap_story_build_basename */
Modified: trunk/gap/gap_story_file.h
==============================================================================
--- trunk/gap/gap_story_file.h (original)
+++ trunk/gap/gap_story_file.h Wed Jan 14 19:59:24 2009
@@ -276,7 +276,9 @@
gboolean unsaved_changes;
GapStoryEditSettings *edit_settings;
- } GapStoryBoard;
+
+ gchar *master_insert_area_format;
+ } GapStoryBoard;
typedef struct GapStoryLocateRet {
@@ -472,5 +474,6 @@
, const char *preferred_decoder
, gint32 max_ref_framenr);
GapStoryVideoFileRef * gap_story_get_video_file_ref_list(GapStoryBoard *stb);
+char * gap_story_build_basename(const char *filename);
#endif
Modified: trunk/gap/gap_story_main.h
==============================================================================
--- trunk/gap/gap_story_main.h (original)
+++ trunk/gap/gap_story_main.h Wed Jan 14 19:59:24 2009
@@ -172,6 +172,7 @@
GtkWidget *dur_time_label;
GtkWidget *pingpong_toggle;
GtkWidget *comment_entry;
+ GtkWidget *pw_fmac_filesel;
GtkWidget *fmac_entry;
GtkObject *pw_spinbutton_from_adj;
GtkObject *pw_spinbutton_to_adj;
Modified: trunk/gap/gap_story_properties.c
==============================================================================
--- trunk/gap/gap_story_properties.c (original)
+++ trunk/gap/gap_story_properties.c Wed Jan 14 19:59:24 2009
@@ -153,6 +153,9 @@
static void p_filesel_pw_ok_cb (GtkWidget *widget, GapStbPropWidget *pw);
static void p_filesel_pw_close_cb ( GtkWidget *widget, GapStbPropWidget *pw);
static void p_pw_filesel_button_cb ( GtkWidget *w, GapStbPropWidget *pw);
+static void p_pw_fmac_filesel_pw_ok_cb (GtkWidget *widget, GapStbPropWidget *pw);
+static void p_pw_fmac_filesel_pw_close_cb ( GtkWidget *widget, GapStbPropWidget *pw);
+static void p_pw_fmac_filesel_button_cb ( GtkWidget *w, GapStbPropWidget *pw);
static void p_pw_comment_entry_update_cb(GtkWidget *widget, GapStbPropWidget *pw);
static void p_pw_fmac_entry_update_cb(GtkWidget *widget, GapStbPropWidget *pw);
static void p_pw_update_info_labels_and_cliptype_senstivity(GapStbPropWidget *pw);
@@ -939,12 +942,12 @@
stb_elem = stb_elem_new;
if(gap_debug)
- {
- printf("AUTO SCENE NEW_ELEM linked to list: drop:%d, video_id:%d\n"
- ,(int)drop_th_data
- ,(int)video_id
- );
- }
+ {
+ printf("AUTO SCENE NEW_ELEM linked to list: drop:%d, video_id:%d\n"
+ ,(int)drop_th_data
+ ,(int)video_id
+ );
+ }
if((stb_elem->record_type == GAP_STBREC_VID_MOVIE)
&& (drop_th_data)
@@ -1128,7 +1131,7 @@
, l_th_bpp
, TRUE /* allow_grab_src_data */
, stb_elem_refptr->flip_request
- , GAP_STB_FLIP_NONE /* flip_status */
+ , GAP_STB_FLIP_NONE /* flip_status */
);
if(!l_th_data_was_grabbed)
{
@@ -1168,7 +1171,7 @@
gap_pview_render_f_from_pixbuf (pv_ptr
, pixbuf
, stb_elem_refptr->flip_request
- , GAP_STB_FLIP_NONE /* flip_status */
+ , GAP_STB_FLIP_NONE /* flip_status */
);
g_object_unref(pixbuf);
}
@@ -1194,7 +1197,7 @@
gap_pview_render_f_from_image (pv_ptr
, l_image_id
, stb_elem_refptr->flip_request
- , GAP_STB_FLIP_NONE /* flip_status */
+ , GAP_STB_FLIP_NONE /* flip_status */
);
/* create thumbnail (to speed up acces next time) */
@@ -2359,6 +2362,106 @@
/* ==================================================== END FILESEL stuff ====== */
+/* ==================================================== START FMAC FILESEL stuff ====== */
+/* --------------------------------
+ * p_pw_fmac_filesel_pw_ok_cb
+ * --------------------------------
+ */
+static void
+p_pw_fmac_filesel_pw_ok_cb (GtkWidget *widget
+ ,GapStbPropWidget *pw)
+{
+ const gchar *fmacname;
+ gchar *dup_fmacname;
+
+ if(pw == NULL) return;
+ if(pw->pw_fmac_filesel == NULL) return;
+
+ dup_fmacname = NULL;
+ fmacname = gtk_file_selection_get_filename (GTK_FILE_SELECTION (pw->pw_fmac_filesel));
+ if(fmacname)
+ {
+ dup_fmacname = g_strdup(fmacname);
+ }
+
+ gtk_widget_destroy(GTK_WIDGET(pw->pw_fmac_filesel));
+
+ if(dup_fmacname)
+ {
+ gtk_entry_set_text(GTK_ENTRY(pw->fmac_entry), dup_fmacname);
+ g_free(dup_fmacname);
+ }
+
+ pw->pw_fmac_filesel = NULL;
+} /* end p_pw_fmac_filesel_pw_ok_cb */
+
+
+/* -----------------------------
+ * p_pw_fmac_filesel_pw_close_cb
+ * -----------------------------
+ */
+static void
+p_pw_fmac_filesel_pw_close_cb ( GtkWidget *widget
+ , GapStbPropWidget *pw)
+{
+ if(pw->pw_fmac_filesel == NULL) return;
+
+ gtk_widget_destroy(GTK_WIDGET(pw->pw_fmac_filesel));
+ pw->pw_fmac_filesel = NULL; /* indicate that filesel is closed */
+
+} /* end p_pw_fmac_filesel_pw_close_cb */
+
+
+
+/* -----------------------------
+ * p_pw_fmac_filesel_button_cb
+ * -----------------------------
+ */
+static void
+p_pw_fmac_filesel_button_cb ( GtkWidget *w
+ , GapStbPropWidget *pw)
+{
+ GtkWidget *filesel = NULL;
+
+ if(pw->scene_detection_busy)
+ {
+ return;
+ }
+
+ if(pw->pw_fmac_filesel != NULL)
+ {
+ gtk_window_present(GTK_WINDOW(pw->pw_fmac_filesel));
+ return; /* filesel is already open */
+ }
+ if(pw->stb_elem_refptr == NULL) { return; }
+
+ filesel = gtk_file_selection_new ( _("Set Filtermacro Filename"));
+ pw->pw_fmac_filesel = filesel;
+
+ gtk_window_set_position (GTK_WINDOW (filesel), GTK_WIN_POS_MOUSE);
+ g_signal_connect (GTK_FILE_SELECTION (filesel)->ok_button,
+ "clicked", G_CALLBACK (p_pw_fmac_filesel_pw_ok_cb),
+ pw);
+ g_signal_connect (GTK_FILE_SELECTION (filesel)->cancel_button,
+ "clicked", G_CALLBACK (p_pw_fmac_filesel_pw_close_cb),
+ pw);
+ g_signal_connect (filesel, "destroy",
+ G_CALLBACK (p_pw_fmac_filesel_pw_close_cb),
+ pw);
+
+
+ if(pw->stb_elem_refptr->filtermacro_file)
+ {
+ gtk_file_selection_set_filename (GTK_FILE_SELECTION (filesel),
+ pw->stb_elem_refptr->filtermacro_file);
+ }
+ gtk_widget_show (filesel);
+
+} /* end p_pw_fmac_filesel_button_cb */
+
+
+/* ==================================================== END FMAC FILESEL stuff ====== */
+
/* ----------------------------
@@ -3061,80 +3164,80 @@
{
case GAP_STB_TARGET_STORYBOARD_ELEM:
{
- GapStbFrameWidget **fw_drop_ptr;
+ GapStbFrameWidget **fw_drop_ptr;
- fw_drop_ptr = (GapStbFrameWidget **)selection_data->data;
- fw_drop = *fw_drop_ptr;
- if(gap_debug)
- {
+ fw_drop_ptr = (GapStbFrameWidget **)selection_data->data;
+ fw_drop = *fw_drop_ptr;
+ if(gap_debug)
+ {
printf("on_clip_elements_dropped_as_mask_ref FW_DROP:%d\n", (int)fw_drop);
}
- if (fw_drop == NULL)
- {
+ if (fw_drop == NULL)
+ {
return;
- }
- tabw_src = (GapStbTabWidgets *)fw_drop->tabw;
- if ((tabw_src == NULL)
- || ((tabw_src != sgpp->cll_widgets) && (tabw_src != sgpp->stb_widgets)))
- {
+ }
+ tabw_src = (GapStbTabWidgets *)fw_drop->tabw;
+ if ((tabw_src == NULL)
+ || ((tabw_src != sgpp->cll_widgets) && (tabw_src != sgpp->stb_widgets)))
+ {
/* if tabw of the droped frame widget
* is not equal to one of stb_widgets or cll_widgets
* assume that the sender was another application
* which is not supported for drop type GAP_STB_TARGET_STORYBOARD_ELEM.
*/
return;
- }
+ }
- if(fw_drop->stb_elem_refptr)
- {
- gchar *mask_name_new;
-
- GapStoryElem *known_maskdef_elem;
-
-
- p_pw_push_undo_and_set_unsaved_changes(pw);
-
- mask_name_new = NULL;
- known_maskdef_elem = gap_story_find_maskdef_equal_to_ref_elem(pw->stb_refptr
- , fw_drop->stb_elem_refptr);
+ if(fw_drop->stb_elem_refptr)
+ {
+ gchar *mask_name_new;
+
+ GapStoryElem *known_maskdef_elem;
+
+
+ p_pw_push_undo_and_set_unsaved_changes(pw);
+
+ mask_name_new = NULL;
+ known_maskdef_elem = gap_story_find_maskdef_equal_to_ref_elem(pw->stb_refptr
+ , fw_drop->stb_elem_refptr);
if(known_maskdef_elem)
{
mask_name_new = g_strdup(known_maskdef_elem->mask_name);
}
else
{
- GapStoryElem *stb_elem_dup;
+ GapStoryElem *stb_elem_dup;
- mask_name_new = gap_story_generate_unique_maskname(pw->stb_refptr);
+ mask_name_new = gap_story_generate_unique_maskname(pw->stb_refptr);
/* implicite create a new mask definition from the dropped
* clip and change properties of current pw to refere
* to the newly created mask definition
*/
- stb_elem_dup = gap_story_elem_duplicate(fw_drop->stb_elem_refptr);
+ stb_elem_dup = gap_story_elem_duplicate(fw_drop->stb_elem_refptr);
if(stb_elem_dup->mask_name)
{
g_free(stb_elem_dup->mask_name);
}
stb_elem_dup->mask_name = g_strdup(mask_name_new);
- stb_elem_dup->track = GAP_STB_MASK_TRACK_NUMBER;
- gap_story_list_append_elem(pw->stb_refptr, stb_elem_dup);
+ stb_elem_dup->track = GAP_STB_MASK_TRACK_NUMBER;
+ gap_story_list_append_elem(pw->stb_refptr, stb_elem_dup);
pw->go_recreate_request = TRUE;
}
-
- /* set mask reference */
- if(mask_name_new)
- {
- if(pw->stb_elem_refptr->mask_name)
- {
- g_free(pw->stb_elem_refptr->mask_name);
- }
- pw->stb_elem_refptr->mask_name = g_strdup(mask_name_new);
- gtk_entry_set_text(GTK_ENTRY(pw->pw_mask_name_entry), mask_name_new);
- g_free(mask_name_new);
+
+ /* set mask reference */
+ if(mask_name_new)
+ {
+ if(pw->stb_elem_refptr->mask_name)
+ {
+ g_free(pw->stb_elem_refptr->mask_name);
+ }
+ pw->stb_elem_refptr->mask_name = g_strdup(mask_name_new);
+ gtk_entry_set_text(GTK_ENTRY(pw->pw_mask_name_entry), mask_name_new);
+ g_free(mask_name_new);
p_pw_render_layermask(pw);
- }
- p_pw_update_properties(pw);
- }
+ }
+ p_pw_update_properties(pw);
+ }
}
break;
@@ -3520,6 +3623,7 @@
pw->dur_time_label = NULL;
pw->pingpong_toggle = NULL;
pw->comment_entry = NULL;
+ pw->pw_fmac_filesel = NULL;
pw->fmac_entry = NULL;
pw->pw_spinbutton_from_adj = NULL;
pw->pw_spinbutton_to_adj = NULL;
@@ -4424,28 +4528,47 @@
- /* the filtermacro entry */
- entry = gtk_entry_new ();
- gtk_widget_set_size_request(entry, PW_ENTRY_WIDTH, -1);
- if(pw->stb_elem_refptr)
+ /* filtermacro entry and filesel invoker button */
{
- if(pw->stb_elem_refptr->filtermacro_file)
+ GtkWidget *hbox_fmac;
+
+ hbox_fmac = gtk_hbox_new (FALSE, 1);
+ gtk_widget_show (hbox_fmac);
+ gtk_table_attach_defaults (GTK_TABLE(table), hbox_fmac, 1, 2, row, row+1);
+
+ /* the filtermacro entry */
+ entry = gtk_entry_new ();
+ gtk_widget_set_size_request(entry, PW_ENTRY_WIDTH, -1);
+ if(pw->stb_elem_refptr)
{
- gtk_entry_set_text(GTK_ENTRY(entry), pw->stb_elem_refptr->filtermacro_file);
+ if(pw->stb_elem_refptr->filtermacro_file)
+ {
+ gtk_entry_set_text(GTK_ENTRY(entry), pw->stb_elem_refptr->filtermacro_file);
+ }
}
- }
- gtk_table_attach_defaults (GTK_TABLE(table), entry, 1, 2, row, row+1);
- g_signal_connect(G_OBJECT(entry), "changed",
+ gtk_box_pack_start (GTK_BOX (hbox_fmac), entry, TRUE, TRUE, 1);
+
+ g_signal_connect(G_OBJECT(entry), "changed",
G_CALLBACK(p_pw_fmac_entry_update_cb),
pw);
- gtk_widget_show (entry);
- gimp_help_set_help_data (entry, _("filter macro to be performed when frames "
+ gtk_widget_show (entry);
+ gimp_help_set_help_data (entry, _("filter macro to be performed when frames "
"of this clips are rendered. "
"A 2nd macrofile is implicite referenced by naming convetion "
"via the keyword .VARYING (as suffix or before the extension)")
, NULL);
- pw->fmac_entry = entry;
+ pw->fmac_entry = entry;
+
+
+ /* the filesel invoker button */
+ button = gtk_button_new_with_label ("...");
+ gtk_box_pack_start (GTK_BOX (hbox_fmac), button, FALSE, FALSE, 1);
+ g_signal_connect(G_OBJECT(button), "clicked",
+ G_CALLBACK(p_pw_fmac_filesel_button_cb),
+ pw);
+ gtk_widget_show (button);
+ }
/* fmac_total_steps threshold spinbutton */
Modified: trunk/gap/gap_story_render_lossless.c
==============================================================================
--- trunk/gap/gap_story_render_lossless.c (original)
+++ trunk/gap/gap_story_render_lossless.c Wed Jan 14 19:59:24 2009
@@ -603,7 +603,7 @@
{
FILE *fp;
char *fname;
- char *l_env;
+ const char *l_env;
gint32 l_dump_chunk_frames;
l_dump_chunk_frames = 0;
@@ -796,7 +796,7 @@
gint32 check_flags_result;
gint32 check_flags_mask;
gboolean is_mpeg_integrity_check_done;
- const char *vcodec_name_chunk;
+ char *vcodec_name_chunk;
vcodec_name_chunk = GVA_get_codec_name(l_frn_elem->gvahand
,GVA_VIDEO_CODEC
Modified: trunk/gap/gap_story_render_processor.c
==============================================================================
--- trunk/gap/gap_story_render_processor.c (original)
+++ trunk/gap/gap_story_render_processor.c Wed Jan 14 19:59:24 2009
@@ -248,7 +248,8 @@
static void p_clear_vattr_array(GapStoryRenderVTrackArray *vtarr);
-
+static gboolean p_fmt_string_has_framenumber_format(const char *fmt_string);
+static gboolean p_fmt_string_has_videobasename_format(const char *fmt_string);
static void p_storyboard_analyze(GapStoryBoard *stb
, gint32 *mainsection_frame_count
, GapStoryRenderVidHandle *vidhand
@@ -367,6 +368,17 @@
, const char *section_name
);
static void p_stb_render_result_monitoring(GapStbFetchData *gfd, gint32 master_frame_nr);
+
+
+static void p_paste_logo_pattern(gint32 drawable_id
+ , gint32 logo_pattern_id
+ , gint32 offsetX
+ , gint32 offsetY
+ );
+
+static void p_do_insert_area_processing(GapStbFetchData *gfd
+ , GapStoryRenderVidHandle *vidhand);
+
static gint32 p_story_render_fetch_composite_image_private(GapStoryRenderVidHandle *vidhand
, gint32 master_frame_nr /* starts at 1 */
@@ -2127,6 +2139,86 @@
}
} /* end p_clear_vattr_array */
+/* -------------------------------------
+ * p_fmt_string_has_framenumber_format
+ * -------------------------------------
+ * return true if the specified format string contains "%06d" (or "%02d" up to "%09d")
+ * false if the format has no such numeric part for the framenumber.
+ *
+ */
+static gboolean
+p_fmt_string_has_framenumber_format(const char *fmt_string)
+{
+ const char *ptr;
+ gboolean l_found;
+
+ l_found = FALSE;
+ ptr = fmt_string;
+ while(ptr)
+ {
+ if(ptr[0] == '\0')
+ {
+ break;
+ }
+
+ if (ptr[0] == '%')
+ {
+ if(ptr[1] != '\0')
+ {
+ if(ptr[2] != '\0')
+ {
+ if(ptr[3] != '\0')
+ {
+ if((ptr[1] == '0') && (ptr[3] == 'd'))
+ {
+ if((ptr[2] >= '2') && (ptr[2] <= '9'))
+ {
+ l_found = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ ptr++;
+ }
+ return (l_found);
+
+} /* end p_fmt_string_has_framenumber_format */
+
+/* -------------------------------------
+ * p_fmt_string_has_videobasename_format
+ * -------------------------------------
+ * return true if the specified format string contains "%s"
+ * false if the format has no such videobasename placeholder part.
+ *
+ */
+static gboolean
+p_fmt_string_has_videobasename_format(const char *fmt_string)
+{
+ const char *ptr;
+ gboolean l_found;
+
+ l_found = FALSE;
+ ptr = fmt_string;
+ while(ptr)
+ {
+ if(ptr[0] == '\0')
+ {
+ break;
+ }
+
+ if ((ptr[0] == '%') && (ptr[1] == 's'))
+ {
+ l_found = TRUE;
+ break;
+ }
+ ptr++;
+ }
+ return (l_found);
+
+} /* end p_fmt_string_has_videobasename_format */
/* ----------------------------------------------------
* p_storyboard_analyze
@@ -2185,6 +2277,16 @@
vidhand->preferred_decoder = g_strdup(stb->preferred_decoder);
}
+ vidhand->master_insert_area_format = NULL;
+ if(stb->master_insert_area_format)
+ {
+ vidhand->master_insert_area_format = g_strdup(stb->master_insert_area_format);
+ vidhand->master_insert_area_format_has_framenumber =
+ p_fmt_string_has_framenumber_format(vidhand->master_insert_area_format);
+ vidhand->master_insert_area_format_has_videobasename =
+ p_fmt_string_has_videobasename_format(vidhand->master_insert_area_format);
+ }
+
if(stb->master_volume >= 0)
{
vidhand->master_volume = stb->master_volume;
@@ -3467,6 +3569,10 @@
vidhand->frn_list = NULL;
vidhand->preferred_decoder = NULL;
+ vidhand->master_insert_area_format = NULL;
+ vidhand->master_insert_area_format_has_videobasename = FALSE;
+ vidhand->master_insert_area_format_has_framenumber = FALSE;
+
vidhand->do_gimp_progress = do_gimp_progress;
*vidhand->progress = 0.0;
vidhand->sterr = p_new_stb_error();
@@ -4004,6 +4110,19 @@
, (int)total_steps
);
}
+
+ if(! gimp_drawable_has_alpha (layer_id))
+ {
+ /* some filtermacros do not work with layer that do not have an alpha channel
+ * and cause gimp to fail on attempt to call gimp_pixel_rgn_init
+ * with both dirty and shadow flag set to TRUE
+ * in this situation GIMP displays the error message
+ * "expected tile ack and received: 5"
+ * and causes the called plug-in to exit immediate without success
+ * Therfore always add an alpha channel before calling a filtermacro.
+ */
+ gimp_layer_add_alpha(layer_id);
+ }
if((filtermacro_file_to == NULL)
|| (total_steps <= 1))
@@ -4109,8 +4228,6 @@
gap_story_render_debug_print_frame_elem(frn_elem, -77);
}
- layer_id = gap_layer_flip(layer_id, flip_request);
-
/* execute input track specific filtermacro (optional if supplied)
* local_stepcount (usually delivered by procedure p_fetch_framename)
* is used to define fmac_current_step
@@ -4124,6 +4241,16 @@
, frn_elem->fmac_total_steps
);
+ if(gap_debug)
+ {
+ printf("p_transform_and_add_layer: FILTERMACRO DONE at layer_id: %d, tmp_image_id:%d\n"
+ , (int)layer_id
+ ,(int)tmp_image_id );
+ }
+
+ layer_id = gap_layer_flip(layer_id, flip_request);
+
+
/* expand layer to tmp image size (before applying any scaling) */
gimp_layer_resize_to_image_size(layer_id);
@@ -4455,7 +4582,7 @@
gimp_pixel_rgn_get_rect (&pixel_rgn, pixelrow_data
, 0
, l_src_row
- , drawable->width
+ , drawable->width
, 1);
for(l_idx=0;l_idx < l_rowstride; l_idx += drawable->bpp)
{
@@ -5146,6 +5273,159 @@
} /* end p_stb_render_result_monitoring */
+/* ------------------------
+ * p_paste_logo_pattern
+ * ------------------------
+ * replace logo area with the specified logo pattern
+ */
+static void
+p_paste_logo_pattern(gint32 drawable_id
+ , gint32 logo_pattern_id
+ , gint32 offsetX
+ , gint32 offsetY
+ )
+{
+ gint32 l_fsel_layer_id;
+ gint l_src_offset_x;
+ gint l_src_offset_y;
+ gint32 image_id;
+
+ image_id = gimp_drawable_get_image(drawable_id);
+ gimp_selection_all(gimp_drawable_get_image(logo_pattern_id));
+
+ /* findout the offsets of the replacement_pattern layer within the source Image */
+ gimp_drawable_offsets(logo_pattern_id, &l_src_offset_x, &l_src_offset_y );
+
+ gimp_edit_copy(logo_pattern_id);
+ l_fsel_layer_id = gimp_edit_paste(drawable_id, TRUE); /* FALSE paste clear selection */
+ gimp_selection_none(gimp_drawable_get_image(logo_pattern_id));
+
+ if(gap_debug)
+ {
+ gint l_fsel_offset_x;
+ gint l_fsel_offset_y;
+
+ gimp_drawable_offsets(l_fsel_layer_id, &l_fsel_offset_x, &l_fsel_offset_y );
+
+ printf("p_paste_logo_pattern: l_src_offsets: (%d %d) fsel:(%d %d) final offsets: (%d %d) rep_id:%d\n"
+ ,(int)l_src_offset_x
+ ,(int)l_src_offset_y
+ ,(int)l_fsel_offset_x
+ ,(int)l_fsel_offset_y
+ ,(int)(offsetX + l_src_offset_x)
+ ,(int)(offsetY + l_src_offset_y)
+ ,(int)logo_pattern_id
+ );
+ }
+
+ gimp_layer_set_offsets(l_fsel_layer_id
+ , offsetX + l_src_offset_x
+ , offsetY + l_src_offset_y);
+
+ gimp_floating_sel_anchor(l_fsel_layer_id);
+
+} /* end p_copy_and_paste_replacement_pattern */
+
+
+
+/* -------------------------------------
+ * p_do_insert_area_processing
+ * -------------------------------------
+ */
+static void
+p_do_insert_area_processing(GapStbFetchData *gfd
+ , GapStoryRenderVidHandle *vidhand)
+{
+ char *logo_imagename;
+ char *videofilename_without_path;
+
+
+ videofilename_without_path = gap_story_build_basename(gfd->framename);
+
+ if (vidhand->master_insert_area_format_has_framenumber)
+ {
+ if (vidhand->master_insert_area_format_has_videobasename)
+ {
+ logo_imagename =
+ g_strdup_printf(vidhand->master_insert_area_format
+ , videofilename_without_path
+ , gfd->localframe_index /* videoFrameNr */
+ );
+ }
+ else
+ {
+ logo_imagename =
+ g_strdup_printf(vidhand->master_insert_area_format
+ , gfd->localframe_index /* videoFrameNr */
+ );
+ }
+ }
+ else
+ {
+ if (vidhand->master_insert_area_format_has_videobasename)
+ {
+ logo_imagename =
+ g_strdup_printf(vidhand->master_insert_area_format
+ , videofilename_without_path
+ );
+ }
+ else
+ {
+ logo_imagename = g_strdup(vidhand->master_insert_area_format);
+ }
+ }
+
+ if(gap_debug)
+ {
+ printf("p_do_insert_area_processing: format:%s\n video:%s\n logo_imagename:%s\n"
+ , vidhand->master_insert_area_format
+ , videofilename_without_path
+ , logo_imagename
+ );
+ }
+
+
+ if(g_file_test(logo_imagename, G_FILE_TEST_EXISTS))
+ {
+ gint32 logo_image_id;
+ gint32 logo_layer_id;
+
+ if (vidhand->master_insert_area_format_has_framenumber)
+ {
+ logo_image_id = gap_lib_load_image(logo_imagename);
+ }
+ else
+ {
+ /* use framefetcher cache in case all frames shall get the same logo */
+ logo_image_id = gap_frame_fetch_orig_image(vidhand->ffetch_user_id
+ , logo_imagename
+ , TRUE /* enable caching */
+ );
+ }
+
+ if(logo_image_id < 0)
+ {
+ printf("p_do_insert_area_processing: ERROR could not load logo_imagename:%s\n", logo_imagename);
+ return;
+ }
+
+
+ gimp_selection_none(logo_image_id);
+ logo_layer_id = p_prepare_RGB_image(logo_image_id);
+
+ p_paste_logo_pattern(gfd->layer_id
+ , logo_layer_id
+ , 0, 0 /* offest_X, offset_Y */
+ );
+ if (vidhand->master_insert_area_format_has_framenumber)
+ {
+ /* do not keep individual per frame logo images cached
+ */
+ gap_image_delete_immediate(logo_image_id);
+ }
+ }
+
+} /* end p_do_insert_area_processing */
/* --------------------------------------------
* p_story_render_fetch_composite_image_private
@@ -5291,13 +5571,19 @@
}
}
}
- g_free(gfd->framename);
if(gfd->tmp_image_id < 0)
{
+ g_free(gfd->framename);
return -1;
}
gfd->layer_id = p_prepare_RGB_image(gfd->tmp_image_id);
+ if((gfd->frn_type == GAP_FRN_MOVIE) && (vidhand->master_insert_area_format))
+ {
+ p_do_insert_area_processing(gfd, vidhand);
+ }
+
p_conditional_delace_drawable(gfd, gfd->layer_id);
+ g_free(gfd->framename);
}
}
Modified: trunk/gap/gap_story_render_types.h
==============================================================================
--- trunk/gap/gap_story_render_types.h (original)
+++ trunk/gap/gap_story_render_types.h Wed Jan 14 19:59:24 2009
@@ -291,6 +291,9 @@
GapStoryRenderAudioRangeElem *aud_list;
GapStoryRenderErrors *sterr;
char *preferred_decoder;
+ char *master_insert_area_format; /* Format for logo replacement */
+ gboolean master_insert_area_format_has_videobasename;
+ gboolean master_insert_area_format_has_framenumber;
/* master video settings found in the storyboard file */
gdouble master_framerate;
Modified: trunk/gap/gap_story_syntax.c
==============================================================================
--- trunk/gap/gap_story_syntax.c (original)
+++ trunk/gap/gap_story_syntax.c Wed Jan 14 19:59:24 2009
@@ -280,6 +280,10 @@
,"decoder"
,NULL
);
+ p_add_keyword(GAP_STBKEY_VID_MASTER_INSERT_AREA
+ ,"format"
+ ,NULL
+ );
p_add_keyword(GAP_STBKEY_MAIN_SECTION
,NULL
);
Modified: trunk/gap/gap_story_syntax.h
==============================================================================
--- trunk/gap/gap_story_syntax.h (original)
+++ trunk/gap/gap_story_syntax.h Wed Jan 14 19:59:24 2009
@@ -43,6 +43,7 @@
#define GAP_STBKEY_VID_MASTER_FRAME_ASPECT "VID_MASTER_FRAME_ASPECT"
#define GAP_STBKEY_VID_MASTER_LAYERSTACK "VID_MASTER_LAYERSTACK"
#define GAP_STBKEY_VID_PREFERRED_DECODER "VID_PREFERRED_DECODER"
+#define GAP_STBKEY_VID_MASTER_INSERT_AREA "VID_MASTER_INSERT_AREA"
#define GAP_STBKEY_MAIN_SECTION "MAIN_SECTION"
#define GAP_STBKEY_SUB_SECTION "SUB_SECTION"
Added: trunk/gap/gap_wr_resynth.c
==============================================================================
--- (empty file)
+++ trunk/gap/gap_wr_resynth.c Wed Jan 14 19:59:24 2009
@@ -0,0 +1,773 @@
+/* gap_wr_resynth.c
+ * provides automated animated apply support for the 3rd party resynthesizer plug-in.
+ * Useful to remove unwanted logos when processing video frames.
+ * PRECONDITIONS:
+ * Requires resynthesizer plug-in.
+ * (resynthesizer-0.16.tar.gz is available in the gimp plug-in registry)
+ * NOTE this wrapper also supports an extended variant plug-in-resynthesizer-s
+ * that has an additional seed parameter.
+ */
+
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * Copyright (C) 2008 Wolfgang Hofer
+ * hof gimp org
+ *
+ * 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.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "gap_lastvaldesc.h"
+#include "gap_lastvaldesc.h"
+#include "gap_libgimpgap.h"
+
+#include "gap-intl.h"
+
+/***** Macro definitions *****/
+#define PLUG_IN_PROC "plug_in_wr_resynth"
+#define PLUG_IN_VERSION "0.16"
+#define PLUG_IN_AUTHOR "Wolfgang Hofer (hof gimp org)"
+#define PLUG_IN_COPYRIGHT "Wolfgang Hofer"
+
+#define PLUG_IN_BINARY "gap_wr_resynth"
+
+
+#define PLUG_IN_RESYNTHESIZER "plug-in-resynthesizer"
+#define PLUG_IN_RESYNTHESIZER_WITH_SEED "plug-in-resynthesizer-s" /* unpublished prvate version */
+
+
+
+/***** Magic numbers *****/
+
+#define SCALE_WIDTH 200
+#define SPIN_BUTTON_WIDTH 60
+
+/***** Types *****/
+
+
+typedef struct {
+ gint32 corpus_border_radius;
+ gint32 alt_selection;
+ gint32 seed;
+} TransValues;
+
+static TransValues glob_vals =
+{
+ 20 /* corpus_border_radius */
+, -1 /* alt_selection (drawable id or -1 for using original selection) */
+, 4711 /* seed for random number generator */
+};
+
+
+
+
+/***** Prototypes *****/
+
+static void query (void);
+static void run (const gchar *name,
+ gint nparams,
+ const GimpParam *param,
+ gint *nreturn_vals,
+ GimpParam **return_vals);
+
+static gint p_selectionConstraintFunc (gint32 image_id,
+ gint32 drawable_id,
+ gpointer data);
+static gboolean p_dialog(TransValues *val_ptr, gint32 drawable_id);
+static gint32 p_process_layer(gint32 image_id, gint32 drawable_id, TransValues *val_ptr);
+
+/***** Variables *****/
+
+const GimpPlugInInfo PLUG_IN_INFO =
+{
+ NULL, /* init_proc */
+ NULL, /* quit_proc */
+ query, /* query_proc */
+ run /* run_proc */
+};
+
+static GimpParamDef in_args[] = {
+ { GIMP_PDB_INT32, "run-mode", "Interactive, non-interactive" },
+ { GIMP_PDB_IMAGE, "image", "Input image" },
+ { GIMP_PDB_DRAWABLE, "drawable", "The drawable (typically a layer)" },
+ { GIMP_PDB_INT32, "corpus_border_radius", "Radius to take texture from" },
+ { GIMP_PDB_DRAWABLE, "alt_selection", "id of a drawable to replace the selection (use -1 to operate with selection of the input image)" },
+ { GIMP_PDB_INT32, "seed", "seed for random numbers (use -1 to init with current time)" }
+ };
+
+
+static gint global_number_in_args = G_N_ELEMENTS (in_args);
+static gint global_number_out_args = 0;
+
+/* Global Variables */
+int gap_debug = 0; /* 1 == print debug infos , 0 dont print debug infos */
+
+
+/***** Functions *****/
+
+MAIN()
+
+/* ------------------
+ * query
+ * ------------------
+ */
+static void
+query (void)
+{
+
+ static GimpLastvalDef lastvals[] =
+ {
+ GIMP_LASTVALDEF_GINT32 (GIMP_ITER_TRUE, glob_vals.corpus_border_radius, "corpus_border_radius"),
+ GIMP_LASTVALDEF_DRAWABLE (GIMP_ITER_TRUE, glob_vals.alt_selection, "alt_selection"),
+ GIMP_LASTVALDEF_GINT32 (GIMP_ITER_TRUE, glob_vals.seed, "seed")
+ };
+
+ /* registration for last values buffer structure (useful for animated filter apply) */
+ gimp_lastval_desc_register(PLUG_IN_PROC,
+ &glob_vals,
+ sizeof(glob_vals),
+ G_N_ELEMENTS (lastvals),
+ lastvals);
+
+
+ gimp_install_procedure (PLUG_IN_PROC,
+ N_("Smart selection eraser."),
+ "Remove an object from an image by extending surrounding texture to cover it. "
+ "The object can be represented by the current selection "
+ "or by an alternative selction (provided as parameter alt_selection) "
+ "If the image, that is refered by the alt_selction drawable_id has a selction "
+ "then the refred selection is used to identify the object. "
+ "otherwise a grayscale copy of the alt_selection drawable_id will be used "
+ "to identify the object that shall be replaced. "
+ "alt_selection value -1 indicates that the selection of the input image shall be used. "
+ "Requires resynthesizer plug-in. (available in the gimp plug-in registry) "
+ "The smart selection eraser wrapper provides ability to run in GIMP_GAP filtermacros "
+ "when processing video frames (typically for removing unwanted logos from video frames)."
+ "(using the same seed value for all frames is recommanded) ",
+ "Wolfgang Hofer",
+ "Wolfgang Hofer",
+ PLUG_IN_VERSION,
+ N_("Smart selection eraser..."),
+ "RGB*, GRAY*",
+ GIMP_PLUGIN,
+ global_number_in_args, global_number_out_args,
+ in_args, NULL);
+
+ {
+ /* Menu names */
+ const char *menupath_image_video_layer = N_("<Image>/Video/Layer/Enhance/");
+
+ gimp_plugin_menu_register (PLUG_IN_PROC, menupath_image_video_layer);
+ }
+
+} /* end query */
+
+
+static void
+run (const gchar *name, /* name of plugin */
+ gint nparams, /* number of in-paramters */
+ const GimpParam * param, /* in-parameters */
+ gint *nreturn_vals, /* number of out-parameters */
+ GimpParam ** return_vals) /* out-parameters */
+{
+ const gchar *l_env;
+ gint32 image_id = -1;
+ gint32 drawable_id = -1;
+ gint32 trans_drawable_id = -1;
+
+ /* Get the runmode from the in-parameters */
+ GimpRunMode run_mode = param[0].data.d_int32;
+
+ /* status variable, use it to check for errors in invocation usualy only
+ during non-interactive calling */
+ GimpPDBStatusType status = GIMP_PDB_SUCCESS;
+
+ /* always return at least the status to the caller. */
+ static GimpParam values[2];
+
+ INIT_I18N();
+
+ l_env = g_getenv("GAP_DEBUG");
+ if(l_env != NULL)
+ {
+ if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1;
+ }
+
+ if(gap_debug) printf("\n\nDEBUG: run %s\n", name);
+
+ /* initialize the return of the status */
+ values[0].type = GIMP_PDB_STATUS;
+ values[0].data.d_status = status;
+ values[1].type = GIMP_PDB_DRAWABLE;
+ values[1].data.d_drawable = -1;
+ *nreturn_vals = 1;
+ *return_vals = values;
+
+
+ /* get image and drawable */
+ image_id = param[1].data.d_int32;
+ drawable_id = param[2].data.d_int32;
+
+ if (strcmp (name, PLUG_IN_PROC) == 0)
+ {
+ if(gimp_drawable_is_layer(drawable_id))
+ {
+ gboolean run_flag;
+
+ /* Initial values */
+ glob_vals.corpus_border_radius = 20;
+ glob_vals.alt_selection = -1;
+ run_flag = TRUE;
+
+ /* Possibly retrieve data from a previous run */
+ gimp_get_data (name, &glob_vals);
+
+ switch (run_mode)
+ {
+ case GIMP_RUN_INTERACTIVE:
+
+ /* Get information from the dialog */
+ run_flag = p_dialog(&glob_vals, drawable_id);
+ break;
+
+ case GIMP_RUN_NONINTERACTIVE:
+ /* check to see if invoked with the correct number of parameters */
+ if (nparams >= global_number_in_args)
+ {
+ glob_vals.corpus_border_radius = param[3].data.d_int32;
+ glob_vals.alt_selection = param[4].data.d_int32;
+ glob_vals.seed = param[5].data.d_int32;
+ }
+ else
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+ break;
+
+ case GIMP_RUN_WITH_LAST_VALS:
+ break;
+
+ default:
+ break;
+ }
+
+
+
+ /* here the action starts, we transform the drawable */
+ if(run_flag)
+ {
+ trans_drawable_id = p_process_layer(image_id
+ , drawable_id
+ , &glob_vals
+ );
+ if (trans_drawable_id < 0)
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+ else
+ {
+ values[1].data.d_drawable = drawable_id;
+
+ /* Store variable states for next run
+ * (the parameters for the transform wrapper plugins are stored
+ * even if they contain just a dummy
+ * this is done to fullfill the GIMP-GAP LAST_VALUES conventions
+ * for filtermacro and animated calls)
+ */
+ if (run_mode == GIMP_RUN_INTERACTIVE)
+ {
+ gimp_set_data (name, &glob_vals, sizeof (TransValues));
+ }
+ }
+ }
+ }
+ else
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ if (run_mode == GIMP_RUN_INTERACTIVE)
+ {
+ g_message(_("The plug-in %s\noperates only on layers\n"
+ "(but was called on mask or channel)")
+ , name
+ );
+ }
+ }
+
+ }
+ else
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+
+
+ if (status == GIMP_PDB_SUCCESS)
+ {
+
+ /* If run mode is interactive, flush displays, else (script) don't
+ * do it, as the screen updates would make the scripts slow
+ */
+ if (run_mode != GIMP_RUN_NONINTERACTIVE)
+ gimp_displays_flush ();
+
+ }
+ values[0].data.d_status = status;
+} /* end run */
+
+
+/* ----------------------------
+ * p_selectionConstraintFunc
+ * ----------------------------
+ *
+ */
+static gint
+p_selectionConstraintFunc (gint32 image_id,
+ gint32 drawable_id,
+ gpointer data)
+{
+ if (image_id < 0)
+ return FALSE;
+
+ /* dont accept layers from indexed images */
+ if (gimp_drawable_is_indexed (drawable_id))
+ return FALSE;
+
+ return TRUE;
+} /* end p_selectionConstraintFunc */
+
+
+/* ----------------------------
+ * p_selectionComboCallback
+ * ----------------------------
+ *
+ */
+static void
+p_selectionComboCallback (GtkWidget *widget)
+{
+ gint idValue;
+
+ if(gap_debug)
+ {
+ printf("p_selectionComboCallback START\n");
+ }
+
+ gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &idValue);
+
+ if(gap_debug)
+ {
+ printf("p_selectionComboCallback idValue:%d\n", idValue);
+ }
+ glob_vals.alt_selection = idValue;
+
+} /* end p_selectionComboCallback */
+
+
+/* --------------------------
+ * p_dialog
+ * --------------------------
+ */
+static gboolean
+p_dialog (TransValues *val_ptr, gint32 drawable_id)
+{
+ GtkWidget *dialog;
+ GtkWidget *main_vbox;
+ GtkWidget *label;
+ GtkWidget *table;
+ GtkWidget *combo;
+ GtkObject *adj;
+ gint row;
+ gboolean run;
+ gboolean isResynthesizerInstalled;
+
+ gint nparams_resynth;
+ gint nparams_resynth_s;
+
+
+ nparams_resynth_s = gap_pdb_procedure_available(PLUG_IN_RESYNTHESIZER_WITH_SEED);
+ nparams_resynth = gap_pdb_procedure_available(PLUG_IN_RESYNTHESIZER);
+ isResynthesizerInstalled = ((nparams_resynth_s >= 0) || (nparams_resynth >= 0));
+ val_ptr->alt_selection = -1;
+
+ gimp_ui_init (PLUG_IN_BINARY, TRUE);
+
+ if (isResynthesizerInstalled)
+ {
+ dialog = gimp_dialog_new (_("Smart selection eraser"), PLUG_IN_BINARY,
+ NULL, 0,
+ gimp_standard_help_func, PLUG_IN_PROC,
+
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK,
+
+ NULL);
+
+ }
+ else
+ {
+ dialog = gimp_dialog_new (_("Smart selection eraser"), PLUG_IN_BINARY,
+ NULL, 0,
+ gimp_standard_help_func, PLUG_IN_PROC,
+
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+
+ NULL);
+
+ }
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ gimp_window_set_transient (GTK_WINDOW (dialog));
+
+ main_vbox = gtk_vbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
+ gtk_widget_show (main_vbox);
+
+
+ /* Controls */
+ table = gtk_table_new (3, 3, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
+ gtk_widget_show (table);
+
+ row = 0;
+ if (isResynthesizerInstalled != TRUE)
+ {
+ label = gtk_label_new (_("The Resynthesizer plug-in is required for this operation but is not installed"
+ "Resynthesizer is available at the gimp plug-in registry"));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 2, row, row + 1,
+ GTK_FILL, GTK_FILL, 4, 0);
+ gtk_widget_show (label);
+
+ row++;
+ }
+ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row,
+ _("Border Radius:"), SCALE_WIDTH, 7,
+ val_ptr->corpus_border_radius, 0.0, 1000.0, 1.0, 10.0, 0,
+ TRUE, 0, 0,
+ NULL, NULL);
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (gimp_int_adjustment_update),
+ &val_ptr->corpus_border_radius);
+
+ row++;
+
+ if (nparams_resynth_s > 0)
+ {
+ adj = gimp_scale_entry_new (GTK_TABLE (table), 0, row,
+ _("Seed:"), SCALE_WIDTH, 7,
+ val_ptr->seed, -1.0, 10000.0, 1.0, 10.0, 0,
+ TRUE, 0, 0,
+ NULL, NULL);
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (gimp_int_adjustment_update),
+ &val_ptr->seed);
+
+ row++;
+ }
+
+ /* layer combo_box (alt_selection) */
+ label = gtk_label_new (_("Set Selection:"));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+ GTK_FILL, GTK_FILL, 4, 0);
+ gtk_widget_show (label);
+
+ /* layer combo_box (Sample from where to pick the alternative selection */
+ combo = gimp_layer_combo_box_new (p_selectionConstraintFunc, NULL);
+
+ gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), drawable_id,
+ G_CALLBACK (p_selectionComboCallback),
+ NULL);
+
+ gtk_table_attach (GTK_TABLE (table), combo, 1, 3, row, row + 1,
+ GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+ gtk_widget_show (combo);
+
+ /* Done */
+
+ gtk_widget_show (dialog);
+
+ run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
+
+ gtk_widget_destroy (dialog);
+
+ return run;
+} /* end p_dialog */
+
+
+/* --------------------------------
+ * p_pdb_call_resynthesizer
+ * --------------------------------
+ * check if non official variant with additional seed parameter
+ * is installed. if not use the official published resynthesizer 0.16
+ */
+static gboolean
+p_pdb_call_resynthesizer(gint32 image_id, gint32 layer_id, gint32 corpus_layer_id, gint32 seed)
+{
+ char *l_called_proc;
+ GimpParam *return_vals;
+ int nreturn_vals;
+ gint nparams_resynth_s;
+
+ nparams_resynth_s = gap_pdb_procedure_available(PLUG_IN_RESYNTHESIZER_WITH_SEED);
+ if (nparams_resynth_s >= 0)
+ {
+ l_called_proc = PLUG_IN_RESYNTHESIZER_WITH_SEED;
+ return_vals = gimp_run_procedure (l_called_proc,
+ &nreturn_vals,
+ GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
+ GIMP_PDB_IMAGE, image_id,
+ GIMP_PDB_DRAWABLE, layer_id, /* input drawable (to be processed) */
+ GIMP_PDB_INT32, 0, /* vtile Make tilable vertically */
+ GIMP_PDB_INT32, 0, /* htile Make tilable horizontally */
+ GIMP_PDB_INT32, 1, /* Dont change border pixels */
+ GIMP_PDB_INT32, corpus_layer_id, /* corpus, Layer to use as corpus */
+ GIMP_PDB_INT32, -1, /* inmask Layer to use as input mask, -1 for none */
+ GIMP_PDB_INT32, -1, /* outmask Layer to use as output mask, -1 for none */
+ GIMP_PDB_FLOAT, 0.0, /* map_weight Weight to give to map, if map is used */
+ GIMP_PDB_FLOAT, 0.117, /* autism Sensitivity to outliers */
+ GIMP_PDB_INT32, 16, /* neighbourhood Neighbourhood size */
+ GIMP_PDB_INT32, 500, /* trys Search thoroughness */
+ GIMP_PDB_INT32, seed, /* seed for random number generation */
+ GIMP_PDB_END);
+ }
+ else
+ {
+ l_called_proc = PLUG_IN_RESYNTHESIZER;
+ return_vals = gimp_run_procedure (l_called_proc,
+ &nreturn_vals,
+ GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
+ GIMP_PDB_IMAGE, image_id,
+ GIMP_PDB_DRAWABLE, layer_id, /* input drawable (to be processed) */
+ GIMP_PDB_INT32, 0, /* vtile Make tilable vertically */
+ GIMP_PDB_INT32, 0, /* htile Make tilable horizontally */
+ GIMP_PDB_INT32, 1, /* Dont change border pixels */
+ GIMP_PDB_INT32, corpus_layer_id, /* corpus, Layer to use as corpus */
+ GIMP_PDB_INT32, -1, /* inmask Layer to use as input mask, -1 for none */
+ GIMP_PDB_INT32, -1, /* outmask Layer to use as output mask, -1 for none */
+ GIMP_PDB_FLOAT, 0.0, /* map_weight Weight to give to map, if map is used */
+ GIMP_PDB_FLOAT, 0.117, /* autism Sensitivity to outliers */
+ GIMP_PDB_INT32, 16, /* neighbourhood Neighbourhood size */
+ GIMP_PDB_INT32, 500, /* trys Search thoroughness */
+ GIMP_PDB_END);
+ }
+
+ if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
+ {
+ gimp_destroy_params(return_vals, nreturn_vals);
+ return (TRUE);
+ }
+
+ g_message(_("The call of plug-in %s\nfailed.\n"
+ "probably the 3rd party plug-in resynthesizer is not installed or is not compatible to version:%s")
+ , l_called_proc
+ , "resynthesizer-0.16"
+ );
+ gimp_destroy_params(return_vals, nreturn_vals);
+ printf("GAP: Error: PDB call of %s failed (image_id:%d), d_status:%d\n"
+ , l_called_proc
+ , (int)image_id
+ , (int)return_vals[0].data.d_status
+ );
+ return(FALSE);
+} /* end p_pdb_call_resynthesizer */
+
+/* --------------------------
+ * p_create_corpus_layer
+ * --------------------------
+ * create the corpus layer that builds the reference pattern
+ * for the resynthesizer call. The reference pattern is built
+ * as duplicate of the original image reduced to the area around the current selection.
+ * (grown by corpus_border_radius)
+ * Note that the duplicate image has a selection, that includes the gorwn area
+ * around the orignal selection, but EXCLUDES the original selection
+ * (that is the area holding the object that has to be replaced
+ * by pattern of the surrounding area)
+ * returns the layer_id of the reference pattern.
+ */
+static gint32
+p_create_corpus_layer(gint32 image_id, gint32 drawable_id, TransValues *val_ptr)
+{
+ gint32 dup_image_id;
+ gint32 channel_id;
+ gint32 channel_2_id;
+ GimpRGB bck_color;
+ GimpRGB white_opaque_color;
+ gboolean has_selection;
+ gboolean non_empty;
+ gint x1, y1, x2, y2;
+ gint32 active_layer_stackposition;
+ gint32 active_dup_layer_id;
+
+
+ active_layer_stackposition = gap_layer_get_stackposition(image_id, drawable_id);
+
+ dup_image_id = gimp_image_duplicate(image_id);
+
+ channel_id = gimp_selection_save(dup_image_id);
+ gimp_selection_grow(dup_image_id, val_ptr->corpus_border_radius);
+ gimp_selection_invert(dup_image_id);
+
+ gimp_context_get_background(&bck_color);
+ channel_2_id = gimp_selection_save(dup_image_id);
+
+ gimp_selection_load(channel_id);
+
+ gimp_rgba_set_uchar (&white_opaque_color, 255, 255, 255, 255);
+ gimp_context_set_background(&white_opaque_color);
+ gimp_edit_clear(channel_2_id);
+
+
+ gimp_context_set_background(&bck_color); /* restore original background color */
+
+ gimp_selection_load(channel_2_id);
+
+ gimp_selection_invert(dup_image_id);
+
+ has_selection = gimp_selection_bounds(dup_image_id, &non_empty, &x1, &y1, &x2, &y2);
+ gimp_image_crop(dup_image_id, (x2 - x1), (y2 - y1), x1, y1);
+
+ gimp_selection_invert(dup_image_id);
+ active_dup_layer_id = gap_layer_get_id_by_stackposition(dup_image_id, active_layer_stackposition);
+
+ if (1==0)
+ {
+ /* debug code shows the duplicate image by adding a display */
+ gimp_display_new(dup_image_id);
+ }
+ return (active_dup_layer_id);
+
+} /* end p_create_corpus_layer */
+
+
+
+/* --------------------------
+ * p_set_alt_selection
+ * --------------------------
+ * create selection as Grayscale copy of the specified alt_selection layer
+ * - operates on a duplicate of the image references by alt_selection
+ * - this duplicate is scaled to same size as specified image_id
+ *
+ * - if alt_selection refers to an image that has a selction
+ * then use this selction instead of the layer itself.
+ */
+static gboolean
+p_set_alt_selection(gint32 image_id, gint32 drawable_id, TransValues *val_ptr)
+{
+ if(gap_debug)
+ {
+ printf("p_set_alt_selection: drawable_id:%d alt_selection:%d\n"
+ ,(int)drawable_id
+ ,(int)val_ptr->alt_selection
+ );
+ }
+
+ if ((drawable_id == val_ptr->alt_selection) || (drawable_id < 0))
+ {
+ return (FALSE);
+ }
+ return (gap_image_set_selection_from_selection_or_drawable(image_id, val_ptr->alt_selection, FALSE));
+}
+
+
+/* --------------------------
+ * p_process_layer
+ * --------------------------
+ */
+static gint32
+p_process_layer(gint32 image_id, gint32 drawable_id, TransValues *val_ptr)
+{
+ gboolean has_selection;
+ gboolean non_empty;
+ gboolean alt_selection_success;
+ gint x1, y1, x2, y2;
+ gint32 trans_drawable_id;
+
+ if(gap_debug)
+ {
+ printf("corpus_border_radius: %d\n", (int)val_ptr->corpus_border_radius);
+ printf("alt_selection: %d\n", (int)val_ptr->alt_selection);
+ printf("seed: %d\n", (int)val_ptr->seed);
+ }
+
+ gimp_image_undo_group_start(image_id);
+
+
+ trans_drawable_id = -1;
+ alt_selection_success = FALSE;
+
+ if(val_ptr->alt_selection >= 0)
+ {
+ if(gap_debug)
+ {
+ printf("creating alt_selection: %d\n", (int)val_ptr->alt_selection);
+ }
+ alt_selection_success = p_set_alt_selection(image_id, drawable_id, val_ptr);
+ }
+
+ has_selection = gimp_selection_bounds(image_id, &non_empty, &x1, &y1, &x2, &y2);
+
+ /* here the action starts, we create the corpus_layer_id that builds the reference pattern
+ * (the corpus is created in a spearate image and has an expanded selection
+ * that excludes the unwanted parts)
+ * then start the resynthesizer plug-in to replace selcted (e.g. unwanted parts) of the
+ * processed layer (e.g. drawable_id)
+ */
+ if (non_empty)
+ {
+ gint32 corpus_layer_id;
+ gint32 corpus_image_id;
+
+ trans_drawable_id = drawable_id;
+
+ corpus_layer_id = p_create_corpus_layer(image_id, drawable_id, val_ptr);
+
+ p_pdb_call_resynthesizer(image_id, drawable_id, corpus_layer_id, val_ptr->seed);
+
+ /* delete the temporary working duplicate */
+ corpus_image_id = gimp_drawable_get_image(corpus_layer_id);
+ gimp_image_delete(corpus_image_id);
+ }
+ else
+ {
+ g_message("Please make a selection (cant operate on empty selection)");
+ }
+
+ if(alt_selection_success)
+ {
+ gimp_selection_none(image_id);
+ }
+
+ gimp_image_undo_group_end(image_id);
+
+ return (trans_drawable_id);
+
+} /* end p_process_layer */
+
Modified: trunk/vid_common/gap_cme_gui.c
==============================================================================
--- trunk/vid_common/gap_cme_gui.c (original)
+++ trunk/vid_common/gap_cme_gui.c Wed Jan 14 19:59:24 2009
@@ -2728,7 +2728,7 @@
(GtkAttachOptions) (0), 0, 0);
- label = gtk_label_new ("1");
+ label = gtk_label_new ("######");
gpp->cme__label_enc_stat_frames_total = label;
gtk_widget_show (label);
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
@@ -2747,7 +2747,7 @@
(GtkAttachOptions) (0), 0, 0);
- label = gtk_label_new ("0");
+ label = gtk_label_new ("######");
gpp->cme__label_enc_stat_frames_done = label;
gtk_widget_show (label);
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
@@ -2766,7 +2766,7 @@
(GtkAttachOptions) (0), 0, 0);
- label = gtk_label_new ("0");
+ label = gtk_label_new ("######");
gpp->cme__label_enc_stat_frames_encoded = label;
gtk_widget_show (label);
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
@@ -2785,7 +2785,7 @@
(GtkAttachOptions) (0), 0, 0);
- label = gtk_label_new ("0");
+ label = gtk_label_new ("######");
gpp->cme__label_enc_stat_frames_copied_lossless = label;
gtk_widget_show (label);
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
@@ -3874,7 +3874,7 @@
if(label)
{
char *buffer;
- buffer = g_strdup_printf("%d", value);
+ buffer = g_strdup_printf("%6d", value);
/* repeat the right alingnment of the label
* (without this workaround my gtk version 2.10.14 shows just
* the highest digit of the number, probably because the size at creation time
Modified: trunk/vid_enc_avi/gap_enc_avi_main.c
==============================================================================
--- trunk/vid_enc_avi/gap_enc_avi_main.c (original)
+++ trunk/vid_enc_avi/gap_enc_avi_main.c Wed Jan 14 19:59:24 2009
@@ -857,7 +857,7 @@
}
}
- //if(gap_debug)
+ if(gap_debug)
{
printf("l_dont_recode_frames:%d\n", l_dont_recode_frames);
}
@@ -905,7 +905,7 @@
/* 1:1 lossless copy one VIDEO FRAME */
l_cnt_reused_frames++;
- //if (gap_debug)
+ if (gap_debug)
{
printf("DEBUG: 1:1 copy of frame %d (fetch as chunk OK) chunk_ptr:%d chunk_size:%d chunk_hdr_size:%d\n"
, (int)l_cur_frame_nr
@@ -929,7 +929,7 @@
gint32 l_app0_len;
l_cnt_encoded_frames++;
- //if (gap_debug)
+ if (gap_debug)
{
printf("DEBUG: saving recoded frame %d (fetch as chunk FAILED)\n", (int)l_cur_frame_nr);
}
@@ -967,8 +967,7 @@
buffer = gap_gve_jpeg_drawable_encode_jpeg(l_drawable, epp->jpeg_interlaced,
&l_FRAME_size, epp->jpeg_quality, epp->jpeg_odd_even, FALSE, l_app0_buffer, l_app0_len);
}
- else if ((strcmp(epp->codec_name, GAP_AVI_CODEC_JPEG) == 0)
- || (strcmp(epp->codec_name, GAP_AVI_CODEC_MJPG) == 0))
+ else if (strcmp(epp->codec_name, GAP_AVI_CODEC_PNG) == 0)
{
/* Compress the picture into a PNG */
buffer = gap_gve_png_drawable_encode_png(l_drawable, epp->png_interlaced,
@@ -993,10 +992,6 @@
}
buffer = gap_gve_raw_BGR_drawable_encode(l_drawable, &l_FRAME_size, l_vflip, l_app0_buffer, l_app0_len);
}
- else if (strcmp(epp->codec_name, GAP_AVI_CODEC_PNG) == 0)
- {
- printf("PNG codec not implemented yet.\n");
- }
#ifdef ENABLE_LIBXVIDCORE
else
{
Modified: trunk/vid_enc_rawframes/gap_enc_rawframes_main.c
==============================================================================
--- trunk/vid_enc_rawframes/gap_enc_rawframes_main.c (original)
+++ trunk/vid_enc_rawframes/gap_enc_rawframes_main.c Wed Jan 14 19:59:24 2009
@@ -721,7 +721,7 @@
GimpRunMode l_save_runmode;
GapGveMasterEncoderStatus encStatus;
- //if(gap_debug)
+ if(gap_debug)
{
printf("p_rawframe_encode: START\n");
printf(" videoname: %s\n", gpp->val.videoname);
@@ -755,7 +755,7 @@
if(p_is_videoname_jpeg(gpp->val.videoname) == TRUE)
{
l_check_flags += GAP_VID_CHCHK_FLAG_JPG;
- //if(gap_debug)
+ if(gap_debug)
{
printf("check fetched chunks for JPEG frames activated\n");
}
@@ -857,7 +857,7 @@
gboolean l_saveOk;
l_cnt_reused_frames++;
- //if (gap_debug)
+ if (gap_debug)
{
printf("DEBUG: 1:1 copy of frame %d (fetch as chunk OK) chunk_ptr:%d chunk_size:%d chunk_hdr_size:%d\n"
, (int)l_cur_frame_nr
@@ -877,7 +877,7 @@
else
{
l_cnt_encoded_frames++;
- //if (gap_debug)
+ if (gap_debug)
{
printf("DEBUG: saving recoded frame %d (fetch as chunk FAILED)\n", (int)l_cur_frame_nr);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]