1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
|
#!/opt/bin/perl
#
# 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.
# 1.7 - Fixed up set_name to drawable_set_name
#
# 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->drawable_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.7",
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)
# (note that image_set_visible used here is a Gimp::Util function)
@all_layers = $img->get_layers;
$img->set_visible(@all_layers);
if ($spinback) {
$all_layers[$frames/2-1]->drawable_set_name(__"Spin Layer DEST (250ms)");
}
$all_layers[$frames-1]->drawable_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;
=head1 LICENSE
Copyright Seth Burgess.
Distrubuted under the same terms as Gimp-Perl.
=cut
|