From fcd23ba6fcbb344975e44c43cd94902bf15571ef Mon Sep 17 00:00:00 2001 From: "Adam D. Moss" Date: Sat, 12 May 2001 13:57:38 +0000 Subject: [PATCH] Cunningly decrease the efficiency of the plugin. Add semi-broken code to 2001-05-12 Adam D. Moss * plug-ins/common/animoptimize.c: Cunningly decrease the efficiency of the plugin. Add semi-broken code to find or remove the statistical mode pixels across all frames (ie. the animation background). Checked in mainly to avoid tree-drift until I have time to finish this. --- ChangeLog | 9 + plug-ins/common/animoptimize.c | 1194 ++++++++++++++++++-------------- 2 files changed, 679 insertions(+), 524 deletions(-) diff --git a/ChangeLog b/ChangeLog index 09cd7e20ff..674eec71f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2001-05-12 Adam D. Moss + + * plug-ins/common/animoptimize.c: Cunningly decrease + the efficiency of the plugin. Add semi-broken code + to find or remove the statistical mode pixels across + all frames (ie. the animation background). Checked in + mainly to avoid tree-drift until I have time to finish + this. + 2001-05-11 Michael Natterer * app/Makefile.am diff --git a/plug-ins/common/animoptimize.c b/plug-ins/common/animoptimize.c index 49b8f481ee..267c3105c3 100644 --- a/plug-ins/common/animoptimize.c +++ b/plug-ins/common/animoptimize.c @@ -1,7 +1,7 @@ /* - * Animation Optimizer plug-in version 1.0.4 + * Animation Optimizer plug-in version 1.1.0 [ALPHA] * - * (c) Adam D. Moss, 1997-2000 + * (c) Adam D. Moss, 1997-2001 * adam@gimp.org * adam@foxbox.org * @@ -11,6 +11,13 @@ /* * REVISION HISTORY: * + * 2001-04-28 : version 1.1.0 [ALPHA] + * Support automated background (or foreground) removal. + * It's half-broken. + * Eliminated special optimized frame alignment cases -- + * we're not trying to be real-time like animationplay + * and it complicates the code. + * * 2000-08-30 : version 1.0.4 * Change default frame duration from 125ms to 100ms for * consistancy. @@ -83,6 +90,14 @@ typedef enum } DisposeType; +typedef enum +{ + OPOPTIMIZE = 0L, + OPUNOPTIMIZE = 1L, + OPFOREGROUND = 2L, + OPBACKGROUND = 3L +} operatingMode; + /* Declare local functions. */ static void query (void); @@ -131,7 +146,7 @@ static GimpImageType drawabletype_alpha; static guchar pixelstep; static guchar *palette; static gint ncolours; -static gboolean optimize; +static operatingMode opmode; MAIN () @@ -153,12 +168,13 @@ query (void) static gint nreturn_args = sizeof (return_args) / sizeof (return_args[0]); gimp_install_procedure ("plug_in_animationoptimize", - "This plugin applies various optimizations to" - " a GIMP layer-based animation.", + "This procedure applies various optimizations to" + " a GIMP layer-based animation in an attempt to" + " reduce the final file size.", "", "Adam D. Moss ", "Adam D. Moss ", - "1997-98", + "1997-2001", N_("/Filters/Animation/Animation Optimize"), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, @@ -166,7 +182,7 @@ query (void) args, return_args); gimp_install_procedure ("plug_in_animationunoptimize", - "This plugin 'simplifies' a GIMP layer-based" + "This procedure 'simplifies' a GIMP layer-based" " animation that has been AnimationOptimized. This" " makes the animation much easier to work with if," " for example, the optimized version is all you" @@ -174,12 +190,41 @@ query (void) "", "Adam D. Moss ", "Adam D. Moss ", - "1997-98", + "1997-2001", N_("/Filters/Animation/Animation UnOptimize"), "RGB*, INDEXED*, GRAY*", GIMP_PLUGIN, nargs, nreturn_args, args, return_args); + + gimp_install_procedure ("plug_in_animation_remove_backdrop", + "This procedure attempts to remove the backdrop" + " from a GIMP layer-based animation, leaving" + " the foreground animation over transparency.", + "", + "Adam D. Moss ", + "Adam D. Moss ", + "2001", + N_("/Filters/Animation/Animation: Remove Backdrop"), + "RGB*, INDEXED*, GRAY*", + GIMP_PLUGIN, + nargs, nreturn_args, + args, return_args); + + gimp_install_procedure ("plug_in_animation_find_backdrop", + "This procedure attempts to remove the foreground" + " from a GIMP layer-based animation, leaving" + " a one-layered image containing only the" + " constant backdrop image.", + "", + "Adam D. Moss ", + "Adam D. Moss ", + "2001", + N_("/Filters/Animation/Animation: Find Backdrop"), + "RGB*, INDEXED*, GRAY*", + GIMP_PLUGIN, + nargs, nreturn_args, + args, return_args); } static void @@ -205,19 +250,25 @@ run (gchar *name, status = GIMP_PDB_CALLING_ERROR; } } - INIT_I18N(); - + INIT_I18N(); + /* Check the procedure name we were called with, to decide what needs to be done. */ if (strcmp(name,"plug_in_animationoptimize")==0) - optimize = TRUE; + opmode = OPOPTIMIZE; + else if (strcmp(name,"plug_in_animationunoptimize")==0) + opmode = OPUNOPTIMIZE; + else if (strcmp(name,"plug_in_animation_find_backdrop")==0) + opmode = OPBACKGROUND; + else if (strcmp(name,"plug_in_animation_remove_backdrop")==0) + opmode = OPFOREGROUND; else - optimize = FALSE; /* UnOptimize */ - + g_error("GAH!!!"); + if (status == GIMP_PDB_SUCCESS) { image_id = param[1].data.d_image; - + new_image_id = do_optimizations(run_mode); if (run_mode != GIMP_RUN_NONINTERACTIVE) @@ -244,22 +295,114 @@ total_alpha(guchar* imdata, guint32 numpix, guchar bytespp) memset(imdata, 0, numpix*bytespp); } + +static void +compose_row(int frame_num, + DisposeType dispose, + int row_num, + unsigned char *dest, + int dest_width, + GimpDrawable *drawable, + const gboolean cleanup) +{ + static unsigned char *line_buf = NULL; + guchar *srcptr; + GimpPixelRgn pixel_rgn; + gint rawx, rawy, rawbpp, rawwidth, rawheight; + int i; + gboolean has_alpha; + + if (cleanup) + { + if (line_buf) + { + g_free(line_buf); + line_buf = NULL; + } + + return; + } + + if (dispose == DISPOSE_REPLACE) + { + total_alpha (dest, dest_width, pixelstep); + } + + gimp_drawable_offsets (drawable->id, + &rawx, + &rawy); + + rawheight = gimp_drawable_height (drawable->id); + + /* this frame has nothing to give us for this row; return */ + if (row_num >= rawheight + rawy || + row_num < rawy) + return; + + rawbpp = gimp_drawable_bpp (drawable->id); + rawwidth = gimp_drawable_width (drawable->id); + has_alpha = gimp_drawable_has_alpha (drawable->id); + + if (line_buf) + { + g_free(line_buf); + line_buf = NULL; + } + line_buf = g_malloc(rawwidth * rawbpp); + + /* Initialise and fetch the raw new frame row */ + + gimp_pixel_rgn_init (&pixel_rgn, + drawable, + 0, row_num - rawy, + rawwidth, 1, + FALSE, + FALSE); + gimp_pixel_rgn_get_rect (&pixel_rgn, + line_buf, + 0, row_num - rawy, + rawwidth, 1); + + /* render... */ + + srcptr = line_buf; + + for (i=rawx; i=0 && iid) == 0) +g_warning("stat fun"); + + for (this_frame_num=0; this_frame_num= 128) + { + /* fprintf(stderr, "%d ", */ + /* these_rows[this_frame_num][i * pixelstep + pixelstep -1]); */ + for (j=0; j best_count) + { + best_count = count[j][i]; + best_r = red[j][i]; + best_g = green[j][i]; + best_b = blue[j][i]; + } + } + + back_frame[width * pixelstep * row +i*pixelstep + 0] = best_r; + if (pixelstep == 4) + { + back_frame[width * pixelstep * row +i*pixelstep + 1] = + best_g; + back_frame[width * pixelstep * row +i*pixelstep + 2] = + best_b; + } + back_frame[width * pixelstep * row +i*pixelstep +pixelstep-1] = + (best_count == 0) ? 0 : 255; + + if (best_count == 0) + g_warning("yayyyy!"); + } + /* memcpy(&back_frame[width * pixelstep * row], + these_rows[0], + width * pixelstep);*/ } - - /* only get a new 'raw' drawable-data buffer if this and - the previous raw buffer were different sizes*/ - - if ((rawwidth*rawheight*rawbpp) - != - ((gimp_drawable_width (drawable->id)* - gimp_drawable_height (drawable->id)* - gimp_drawable_bpp (drawable->id)))) + + g_warning("stat fun over"); + + for (this_frame_num=0; this_frame_numid)) * - (gimp_drawable_height (drawable->id)) * - (gimp_drawable_bpp (drawable->id))); + g_free(these_rows[this_frame_num]); + g_free(red[this_frame_num]); + g_free(green[this_frame_num]); + g_free(blue[this_frame_num]); + g_free(count[this_frame_num]); } + g_free(these_rows); + g_free(red); + g_free(green); + g_free(blue); + g_free(count); + g_free(num_colours); + } +#endif - rawwidth = gimp_drawable_width (drawable->id); - rawheight = gimp_drawable_height (drawable->id); - rawbpp = gimp_drawable_bpp (drawable->id); - - /* Initialise and fetch the whole raw new frame */ - - gimp_pixel_rgn_init (&pixel_rgn, - drawable, + if (opmode == OPBACKGROUND) + { + new_layer_id = gimp_layer_new(new_image_id, + "Backgroundx", + width, height, + drawabletype_alpha, + 100.0, + GIMP_NORMAL_MODE); + + gimp_image_add_layer (new_image_id, new_layer_id, 0); + + drawable = gimp_drawable_get (new_layer_id); + + gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, - drawable->width, drawable->height, - FALSE, - FALSE); - gimp_pixel_rgn_get_rect (&pixel_rgn, - rawframe, + width, height, + TRUE, FALSE); + gimp_pixel_rgn_set_rect (&pixel_rgn, back_frame, 0, 0, - drawable->width, drawable->height); - /* gimp_pixel_rgns_register (1, &pixel_rgn);*/ - - gimp_drawable_offsets (drawable->id, - &rawx, - &rawy); - - - /* render... */ - - switch (imagetype) + width, height); + gimp_drawable_flush (drawable); + gimp_drawable_detach (drawable); + } + else + { + for (this_frame_num=0; this_frame_numid)) - { /* alpha RGB, same size */ - destptr = this_frame; - srcptr = rawframe; - - i = rawwidth*rawheight; - while (i--) - { - if (!((*(srcptr+3))&128)) - { - srcptr += 4; - destptr += 4; - continue; - } - *(destptr++) = *(srcptr++); - *(destptr++) = *(srcptr++); - *(destptr++) = *(srcptr++); - *(destptr++) = 255; - srcptr++; - } - } - else /* RGB no alpha, same size */ - { - destptr = this_frame; - srcptr = rawframe; - - i = rawwidth*rawheight; - while (i--) - { - *(destptr++) = *(srcptr++); - *(destptr++) = *(srcptr++); - *(destptr++) = *(srcptr++); - *(destptr++) = 255; - } - } - } - else - { - /* --- These are suboptimal catch-all cases for when --- */ - /* --- this frame is bigger/smaller than the preview --- */ - /* --- buffer, and/or offset within it. --- */ - - /* FIXME: FINISH ME! [done?] */ - - if (gimp_drawable_has_alpha (drawable->id)) - { /* RGB alpha, diff size */ - - destptr = this_frame; - srcptr = rawframe; - - for (j=rawy; j=0 && i=0 && j=0 && i=0 && jid)) - { /* I alpha, same size */ - destptr = this_frame; - srcptr = rawframe; - - i = rawwidth*rawheight; - while (i--) - { - if (!(*(srcptr+1))) - { - srcptr += 2; - destptr += 2; - continue; - } - *(destptr++) = *(srcptr); - *(destptr++) = 255; - srcptr+=2; - } - } - else /* I, no alpha, same size */ - { - destptr = this_frame; - srcptr = rawframe; - - i = rawwidth*rawheight; - while (i--) - { - *(destptr++) = *(srcptr); - *(destptr++) = 255; - srcptr++; - } - } - } - else - { - /* --- These are suboptimal catch-all cases for when --- */ - /* --- this frame is bigger/smaller than the preview --- */ - /* --- buffer, and/or offset within it. --- */ - - /* FIXME: FINISH ME! */ - - if (gimp_drawable_has_alpha (drawable->id)) - { /* I alpha, diff size */ - - srcptr = rawframe; - - for (j=rawy; j=0 && i=0 && j=0 && i=0 && jid) == 0) { - for (xit=0; xitrbox_right) rbox_right=xit; - if (yitrbox_bottom) rbox_bottom=yit; - } - if (keep_pix) - { - if (xitbbox_right) bbox_right=xit; - if (yitbbox_bottom) bbox_bottom=yit; - } - else - { - /* pixel didn't change this frame - make - * it transparent in our optimized buffer! + } + /* Check if just 'last' is transparent */ + if (!(last_frame[yit*width*pixelstep + xit*pixelstep + + pixelstep-1]&128) + && + (this_frame[yit*width*pixelstep + xit*pixelstep + + pixelstep-1]&128)) + { + keep_pix = TRUE; + opaq_pix = TRUE; + goto decided; + } + /* If 'last' and 'this' are opaque, we have + * to check if they're the same colour - we + * only have to keep the pixel if 'last' or + * 'this' are opaque and different. */ - opti_frame[yit*width*pixelstep + xit*pixelstep - + pixelstep-1] = 0; - } - } /* xit */ - } /* yit */ + keep_pix = FALSE; + opaq_pix = TRUE; + for (byteit=0; byteitrbox_right) rbox_right=xit; + if (yitrbox_bottom) rbox_bottom=yit; + } + if (keep_pix) + { + if (xitbbox_right) bbox_right=xit; + if (yitbbox_bottom) bbox_bottom=yit; + } + else + { + /* pixel didn't change this frame - make + * it transparent in our optimized buffer! + */ + opti_frame[yit*width*pixelstep + xit*pixelstep + + pixelstep-1] = 0; + } + } /* xit */ + } /* yit */ - if (!can_combine) - { - bbox_left = rbox_left; - bbox_top = rbox_top; - bbox_right = rbox_right; - bbox_bottom = rbox_bottom; - } - - bbox_right++; - bbox_bottom++; - - /* - * Collapse opti_frame data down such that the data - * which occupies the bounding box sits at the start - * of the data (for convenience with ..set_rect()). - */ - destptr = opti_frame; - /* - * If can_combine, then it's safe to use our optimized - * alpha information. Otherwise, an opaque pixel became - * transparent this frame, and we'll have to use the - * actual true frame's alpha. - */ - if (can_combine) - srcptr = opti_frame; - else - srcptr = this_frame; - for (yit=bbox_top; yit