Summary: In today's laboratory, you will write and install new procedures for use within Script-Fu and the Gimp.
As you should know from your long experience with Scheme, it is relatively easy to group a number of individual commands together into a procedure. Hence, rather than typing instructions one-at-a-time into the GIMP window, we can
For example, here is a simple procedure I wrote that draws the letter F and then puts a "No" sign around it.
;;; Procedure: ;;; no-failure ;;; Parameters: ;;; none ;;; Purpose: ;;; Creates a new image with the universal sign for "No Fs" ;;; Produces: ;;; Nothing. You call this only for the side effect of ;;; drawing a new image. ;;; Preconditions: ;;; Must be called from within Script-Fu. ;;; Postconditions: ;;; A new image appears on the screen. (define no-failure (lambda () (let* ((image-and-layer (gsfu-new-image 256 256)) (image (car image-and-layer)) (layer (cadr image-and-layer))) ; Draw everything on white (gimp-palette-set-background WHITE) ; Draw the silly letter F in blue (gimp-palette-set-foreground BLUE) (gimp-brushes-set-brush "Circle (11)") (gsfu-line layer 96 40 176 40) ; Top stroke (gsfu-line layer 96 40 96 216) ; Down stroke (gsfu-line layer 96 112 148 112) ; Middle stroke ; Draw a nice red circle. (gimp-palette-set-foreground RED) (gimp-brushes-set-brush "Circle (07)") (gimp-ellipse-select image 8 8 240 240 REPLACE 0 0 0) (gimp-edit-stroke layer) (gimp-selection-none image) ; Now we're ready to draw the slash. Basic math tells us that ; the endpoints are offset by radius/(sqrt 2) from the center ; of the circle. (let* ((center 128) (radius 120) (offset (/ radius (sqrt 2)))) (gsfu-line layer (- center offset) (- center offset) (+ center offset) (+ center offset))) ; And display the image (gimp-display-new image))))
a. Create a new Scheme file to hold that procedure. You can use gedit or DrScheme (just don't expect to be able to execute the code within DrScheme). Since the procedure depends on the Glimmer Script-Fu utilities (gsfu), you should also make sure the file loads those utilities by including the following at the top of the file.
(If you like, you can also just make a copy of
b. Load the file into the Script-Fu console by typing
(load filename). For example, if you've stored
your stuff as
images.scm in your
directory, you should use
(no-failure) in the Script-Fu console and see what
no-failure as a template, write and test your own
procedure to draw an interesting picture. Depending on your skill
level, you might draw a smiley face, a stick figure, or something else.
One disadvantage of
no-failure is that it always draws an image
of the same size. What if we want a bigger or smaller image? One
possibility is to make the image size a parameter to
and then make the various numbers depend on the size. Since our image is
naturally square, the width and height should probably be the same.
Here's what I've come up with:
;;; Procedure: ;;; new-no-failure ;;; Parameters: ;;; side, an integer ;;; color, an RGB list ;;; Purpose: ;;; Creates a new image with the universal sign for "No Fs". ;;; The image has width side and height side. ;;; The F in the image has the specified color. ;;; Produces: ;;; Nothing. You call this only for the side effect of ;;; drawing a new image. ;;; Preconditions: ;;; Must be called from within Script-Fu. ;;; Postconditions: ;;; A new image appears on the screen. (define new-no-failure (lambda (side color) (let* ((image-and-layer (gsfu-new-image side side)) (image (car image-and-layer)) (layer (cadr image-and-layer)) (unit (/ side 32))) ; Draw everything on white (gimp-palette-set-background WHITE) ; Draw the silly letter F in blue (gimp-palette-set-foreground color) (gimp-brushes-set-brush "Circle (11)") (gsfu-line layer (* unit 12) (* unit 5) (* unit 20) (* unit 5)) (gsfu-line layer (* unit 12) (* unit 5) (* unit 12) (* unit 27)) (gsfu-line layer (* unit 12) (* unit 14) (* unit 18) (* unit 14)) ; Draw the nice red circle. (gimp-palette-set-foreground RED) (gimp-brushes-set-brush "Circle (07)") (gimp-ellipse-select image unit unit (- side unit unit) (- side unit unit) REPLACE 0 0 0) (gimp-edit-stroke layer) (gimp-selection-none image) ; Now we're ready to draw the slash. Basic math tells us that ; the endpoints are offset by radius/(sqrt 2) from the center ; of the circle. ; direction. (let* ((center (/ side 2)) (radius (- center unit)) (offset (/ radius (sqrt 2)))) (gsfu-line layer (- center offset) (- center offset) (+ center offset) (+ center offset))) ; Display the image (gimp-display-new image) ; And return the image and layer image-and-layer)))
a. Either add
new-no-failure to your file from the first
exercise or create a new file to contain it. You can also copy
b. Load the file into the Script-Fu console.
c. Test the procedure by typing each of the following commands in the Script-Fu console.
(new-no-failure 256 GREEN) (new-no-failure 100 PURPLE)
Generalize your procedure from exercise 2 so that it takes the image size as a parameter. You may choose to build square images (as I did) and take only the length of a side as a parameter or you may choose to build rectangular images and take both width and height as parameters.
With the Script-Fu that you know up to this point, all the cool Script-Fu commands you write are only available to people who are able to use the Script-Fu console. It would also be nice to add Script-Fu commands to the GIMP's various menus. Fortunately, you only need to follow a few simple steps.
1. Write Scheme code that tells the GIMP to add a procedure to the menu. Here, you need to tell the GIMP what parameters your procedure takes so that it can ask the user for those parameters.
2. Put the Scheme code in a place the GIMP can find it. Typically, you'll
put your Scheme code in
(Yes, the period in the
.gimp-1.2 is important.) You'll only
have to do this once per script. My experience suggests that you should
end the file name with
.scm rather than
3. Tell the GIMP that you've added the script by selecting Refresh from the Script-Fu submenu of the Xtns menu. (You should only have to do this when you add or modify the script in the middle of a session. In the future, the GIMP should load your script automatically.)
Steps 2 and 3 are straightforward, so let's consider the first step
in more detail. You add a procedure with the
procedure. That procedure takes a large number of parameters.
<Image>for the image menu or
<Toolbox>/Xtns/for the toolbox extensions menu;
"RGB"but try other options later); and
For each parameter for your procedure, you'll need three additional
For SF-IMAGE and SF-DRAWABLE, the value should be 0; the GIMP will fill them in with the current image and layer. For SF-VALUE, the default value should be in quotation marks, even when it's a number. For SF-COLOR, the color should be a list of three integers (as you explored in the previous lab).
For example, here's what I might use for my
(script-fu-register "new-no-failure" "<Toolbox>/Xtns/Script-Fu/Sample/No Failure" "Draws a \"No Failure\" logo" "Samuel A. Rebelsky" "Copyright (c) 2001 Samuel A. Rebelsky. All Rights Reserved" "Thursday, 5 April 2001" "RGB" SF-VALUE "Side Length" "256" SF-COLOR "Color" BLUE)
I've put this complete example in the file
a. Make a copy of the file in your Gimp scripts directory.
b. Tell Gimp to refresh its Script-Fu list by selectingfrom the menu in the menu.
c. You should now be able to selectfrom a new submenu of the submenu of the menu. Try it and see what happens.
d. Register your own script from the previous exercise. See if you can get it to run.
When doing more complex drawings, you will often find that you draw the same thing again and again at different places and in different sizes. Hence, it is sometimes useful to write helper procedures that can do the precise drawing for you. For example, I decided that I often make the "No" sign, and wrote a helper procedure for that sign. Here's my code.
;;; Procedure: ;;; forbidden ;;; Parameters: ;;; image, an image ;;; layer, a layer associated with that image ;;; x, the x coordinate of the center of the sign ;;; y, the y coordinate of the center of the sign ;;; radius, the radius of the sign ;;; Purpose: ;;; Draws a "forbidden" sign (a circle with a slash) in ;;; red centered at the specified location. ;;; Preconditions: ;;; image and layer are initialized. ;;; x, y, and radius are not negative. ;;; Postconditions: ;;; The image now contains the specified sign. ;;; The brush and foreground color may have changed. (define forbidden (lambda (image layer x y radius) ; Choose a color and paintbrush that seem appropriate. (gimp-palette-set-foreground RED) (gimp-brushes-set-brush "Circle (05)") ; Select the ellipse for the circle. Do the math to see why. ; the particular values were set. (gimp-ellipse-select image (- x radius) (- y radius) (* 2 radius) (* 2 radius) REPLACE 0 0 0) ; Draw the nice red circle. (gimp-edit-stroke layer) ; Now we're ready to draw the slash. Some math tells us that ; it's offset by radius/(sqrt 2) from the center (in each ; direction). (let ((offset (/ radius (sqrt 2)))) (gsfu-line layer (- x offset) (- y offset) (+ x offset) (+ y offset))) ; Unselect all (gimp-selection-none image) ; Flatten the image (gimp-image-flatten image) ))
a. Once again, store that code in a file.
b. Create a new image programmatically and use
to draw on that image in various places and sizes.
c. Write your own helper procedure to draw a rectangle.
d. Write your own helper procedure to draw a circle.
When we write procedures like
forbid, we probably want
to add them to the menu for the current image, rather than the more
general toolbox menu. Here's the command that I've written to add
forbid sign to the popup image menu.
(script-fu-register "forbidden" "<Image>/Script-Fu/Sample/Forbidden Sign" "Draws the legendary forbidden sign" "Samuel A. Rebelsky" "Copyright (c) 2001 Samuel A. Rebelsky. All Rights Reserved" "Tuesday, 3 April 2001" "RGB" SF-IMAGE "Image" 0 SF-DRAWABLE "Drawable" 0 SF-VALUE "Center X" "100" SF-VALUE "Center Y" "100" SF-VALUE "Radius" "50")
You can find everything in
Install and test it. You may find that you have to click on the image after running the script. I'm still working on figuring out that bug. Let me know if you figure anything out.
Wednesday, 4 April 2001 [Samuel A. Rebelsky]
Thursday, 5 April 2001 [Samuel A. Rebelsky]
Tuesday, 29 October 2002 [Samuel A. Rebelsky]
I usually create these pages
on the fly, which means that I rarely
proofread them and they may contain bad grammar and incorrect details.
It also means that I tend to update them regularly (see the history for
more details). Feel free to contact me with any suggestions for changes.
This document was generated by
Siteweaver on Mon Dec 2 09:19:20 2002.
The source to the document was last modified on Wed Oct 30 08:13:12 2002.
This document may be found at