File: sethspin

package info (click to toggle)
libgimp-perl 2.0.dfsg-5
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 2,112 kB
  • ctags: 462
  • sloc: perl: 10,026; sh: 207; ansic: 207; makefile: 70
file content (220 lines) | stat: -rwxr-xr-x 8,088 bytes parent folder | download
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