gimp/plug-ins/perl/examples/sethspin

216 lines
7.8 KiB
Perl
Executable File

#!/usr/app/bin/perl
eval 'exec /usr/app/bin/perl -S $0 ${1+"$@"}'
if 0; # not running under some shell
#
# Note: Seth has transferred the maintainer `position' to me, so bother me
# instead of him now :-)
# - Steinar H. Gunderson <sgunderson@bigfoot.com>
# This one's all mine. Well, its GPL/Artisitic but I'm the author and creator.
# You need gimp 1.1 or better for this; too much has changed, and I don't think
# 1.0.x had a perspective PDB function anyway
# Here's the working theory on this:
# There's a function called spinlayer which will spin from a spinlayer to a
# destlayer. It won't touch those 2 layers at all, and will leave its results
# on the top of the layer stack.
#
# If the user wants to spin back, it will take 1/2 the layers otherwise required
# per call to the spin_layer, so that the number of total layers comes out the
# same.
#
# The main function makes a new image, copies the source and destination onto it
# with appropriate offsets, and passes this image with the bottom 2 layers to
# spin_layer. At the end, remove the original 2 layers, since they won't be
# needed, and add in some Layer comments for timing your gif.
#
################################################################################
# Many thanks to Steinar and Marc, for expressing an intrest in the script that
# kept me going, and to Steinar in particular for helping me track down why the
# script was crashing gimp (hint - don't make layers of height=0, and if you do
# make sure you're logging to console since the Gtk messagebox will never show
# up due to a rapid segfault).
#
# Just a comment on that: We fixed the bug, so height=0 no longer segfaults, but
# gives the error message it should. However, if GIMP segfaults, you should try
# logging to console to make sure you get all applicable error messages. This
# will make it _much_ easier to find the bug. - Steinar
#
# Revision History:
# 1.0 - Initial (too early) release
# 1.1 - Second (still ugly) release: Made the perspective setting actually do
# something
# 1.2 - Used some of the convienence functions, and made things a little eaiser
# from the user's standpoint too. Also moved it from the
# Filters->Animations-> menu to Xtns->Animations. I think its
# clearer whats going on this way. It also works w/ any 2 layers now.
# 1.5 - Some debugging by Steinar and myself to make it work again.
# 1.6 - Moved some renaming into the main loop, more cleanups.
#
# TODO: Clean it up; allow for other effects (skewing, ripples?) while spinning;
# Seth Burgess
# <sjburges@gimp.org>
use Gimp; # No qw(:auto) - Trying to use all OO-styling
use Gimp::Fu;
use Gimp::Util;
# Gimp::set_trace(TRACE_ALL);
sub saw { # a sawtooth function on PI
($val) = @_;
if ($val < 3.14159/2.0) {
return ($val/3.14159);
} elsif ($val < 3.14159) {
return (-1+$val/3.14159);
} elsif ($val < 3.14159+3.14159/2.0) {
return ($val/3.14159);
} else {
return (-1+$val/3.14159);
}
}
sub spin_layer { # the function for actually spinning the layer
my ($img, $spin, $dest, $numframes, $prp) = @_;
my $floater, # The transformed image
$framelay, # The background color
$frameno; # The current frame
# Now let's spin it!
$stepsize = 3.14159/$numframes; # in radians
$frameno = 0;
for ($i=0; $i<=3.14159; $i+=$stepsize) {
Gimp->progress_update ($i/3.14159);
# create a new layer for spinning
$framelay = ($i < 3.14159/2.0) ? $spin->copy(1) : $dest->copy(1);
$img->add_layer($framelay, 0);
$floater = $framelay->copy(1);
$img->add_layer($floater, 0);
# spin it a step
$img->selection_all();
@x = $img->selection_bounds();
$img->selection_none();
# x[1],x[2] x[3],x[2]
# x[1],x[4] x[3],x[4]
my($y1, $y3);
$y1 = int($x[2]+$spin->height *sin($i)/2);
$y3 = int($x[4]-$spin->height *sin($i)/2);
# height must be != 0
$y3++ if ($y1 == $y3);
$floater = Gimp->perspective($floater, 1,
$x[1]+saw($i)*$prp*$framelay->width,$y1,
$x[3]-saw($i)*$prp*$framelay->width,$y1,
$x[1]-saw($i)*$prp*$framelay->width,$y3,
$x[3]+saw($i)*$prp*$framelay->width,$y3);
$framelay->fill(1); # BG-IMAGE-FILL
# merge the two layers together before we continue
$img->set_visible($floater, $framelay);
$framelay = $img->merge_visible_layers(0);
$frameno++;
$framelay->set_name("Spin Layer $frameno (50ms)");
}
}
register "seth_spin",
"Seth Spin",
"Take one image. Spin it about the horizontal axis, and end up with another image. I made it for easy web buttons.",
"Seth Burgess",
"Seth Burgess <sjburges\@gimp.org>",
"1.6",
N_"<Toolbox>/Xtns/Animation/Seth Spin",
"*",
[
[PF_DRAWABLE, "source", "What drawable to spin from?"],
[PF_DRAWABLE, "destination","What drawable to spin to?"],
[PF_INT8, "frames", "How many frames to use?", 16],
[PF_COLOR, "background", "What color to use for background if not transparent", [0,0,0]],
[PF_SLIDER, "perspective", "How much perspective effect to get", 40, [0,255,5]],
[PF_TOGGLE, "spin_back", "Also spin back?" , 1],
[PF_TOGGLE, "convert_indexed", "Convert to indexed?", 1],
],
[],
['gimp-1.1'],
sub {
my($src,$dest,$frames,$color,$perspective,$spinback,$indexed) = @_;
$oldbackground = Gimp->palette_get_background();
Gimp->palette_set_background($color);
$perspective = $perspective/255.0; # PF_SLIDER doesn't work right for < 1
Gimp->progress_init(__"Seth Spin...",-1);
# Copy souce and destination to new image
$maxwide = ($src->width > $dest->width) ? $src->width : $dest->width;
$maxhigh = ($src->height > $dest->height) ? $src->height: $dest->height;
$img = Gimp->image_new($maxwide, $maxhigh, RGB);
$tmpimglayer = $img->add_new_layer(0,3,1); # have to have a layer before displaying
$img->display_new;
$src->edit_copy();
$spinlayer = $tmpimglayer->edit_paste(1);
$spinlayer->floating_sel_to_layer();
$dest->edit_copy();
$destlayer = $tmpimglayer->edit_paste(1);
$destlayer->floating_sel_to_layer();
$tmpimglayer->remove_layer; # remove temporary layer.
# set the layer size to be the full layer for each copied layer
$spinlayer->resize($maxwide, $maxhigh, $spinlayer->offsets);
$destlayer->resize($maxwide, $maxhigh, $destlayer->offsets);
# need an even number of frames for spinback
if ($frames%2 && $spinback) {
$frames++;
Gimp->message(__"An even number of frames is needed for spin back.\nAdjusted frames up to $frames");
}
spin_layer($img, $spinlayer, $destlayer, $spinback ? $frames/2 : $frames, $perspective);
# go back from destination to spinlayer if spinning back
if ($spinback) {
@layerlist = $img->get_layers();
spin_layer($img, $destlayer, $spinlayer, $frames/2, $perspective);
}
# remove the original 2 pasted layers
$img->remove_layer($destlayer);
$img->remove_layer($spinlayer);
# unhide and name layers (Give timings)
@all_layers = $img->get_layers;
$img->set_visible(@all_layers);
if ($spinback) {
$all_layers[$frames/2-1]->set_name(__"Spin Layer DEST (250ms)");
}
$all_layers[$frames-1]->set_name(__"Spin Layer SRC (250ms)");
# indexed conversion wants a display for some reason
if ($indexed) {
$img->convert_indexed(1,MAKE_PALETTE,255,0,1,"buffy" );
}
Gimp->palette_set_background($oldbackground);
return();
};
exit main;