Functional Problem Solving (CSC 151 2014F) : Labs

Laboratory: Scripting the GIMP Tools


Summary: In this laboratory, you will explore how one writes Scheme programs that instruct the GIMP to create some simple images.

Preparation

a. Start GIMP and enable the DBUS Server.

b. Then start DrRacket and instruct it to (require gigls/unsafe). Click Run.

If things go wrong, see our instructions for running the CSC 151 software. Ask for help if you need it.

c. At the end of this lab is a list of all the important procedures discussed in the corresponding reading. Quickly review that list.

Exercises

Exercise 1: Drawing with Selections

a. Read the following sequence of instructions and describe what the resulting image will look like.

(context-set-bgcolor! "white")
(context-set-fgcolor! "black")
(context-set-brush! "1. Pixel")
(define canvas (image-new 100 100))
(image-draw-line! canvas 0 99 99 0)
(image-select-rectangle! canvas REPLACE 35 35 40 40)
(image-stroke-selection! canvas)
(context-set-fgcolor! "red")
(image-draw-line! canvas 0 0 99 99)
(image-show canvas)

b. Test your prediction experimentally.

c. Explain the cause of any disrepancies you see.

d. Add instructions (without reordering the rest) so that the red line goes all the way from the top-left to the bottom-right corner of the entire image, while retaining the black rectangle in its current location.

If you are still befuddled, you may want to see the notes on this problem.

Exercise 2: Drawing Faces, Revisited

Recall that in the reading on GIMP tools, you experimented with the following set of instructions.

(require gigls/unsafe)
(define smiley (image-new 200 200))

; Draw the primary circle
(image-select-ellipse! smiley REPLACE 
                       10 10 180 180)
(context-set-fgcolor! "yellow")
(image-fill-selection! smiley)

(context-set-fgcolor! "black")
(context-set-brush! "2. Hardness 100" 9)
(image-stroke-selection! smiley)

; Draw the eyes
(image-select-ellipse! smiley REPLACE 
                       50 60 30 20)
(image-select-ellipse! smiley ADD
                       120 60 30 20)
(context-set-fgcolor! "white")
(image-fill-selection! smiley)

(context-set-fgcolor! "black")
(context-set-brush! "2. Hardness 050" 7)
(image-stroke-selection! smiley)

(image-select-ellipse! smiley REPLACE
                       60 60 10 20)
(image-select-ellipse! smiley ADD
                       130 60 10 20)
(context-set-fgcolor! "lightsteelblue")
(image-fill-selection! smiley)

; Smile
(image-select-ellipse! smiley REPLACE 
                       40 60 120 100)
(image-select-ellipse! smiley SUBTRACT
                       40 45 120 100)
(context-set-fgcolor! "white")
(image-fill-selection! smiley)

(context-set-fgcolor! "red")
(context-set-brush! "2. Block 01" 8)
(image-stroke-selection! smiley)

; Get ready to show
(image-select-nothing! smiley)
(image-show smiley)
(context-update-displays!)

a. Open a new DrRacket window or tab and write a series of instructions in the definitions pane to draw a face different than the sample we gave above. You should try a different shape of face, different brushes or colors, and different facial features.

b. What do you expect to happen if you change the size of the image in which you're drawing, such as a 100x100 image or a 300x300 image?

c. Check your answer experimentally.

d. If changing the size of the image yielded results that you found undesirable, summarize how you might fix them. (Don't fix them right now, just indicate how you might fix them.)

e. Now, suppose that we define two names, width and height. Describe how you might change your face code to take those values into account.

(define width 300)
(define height 200)
(define canvas (image-new width height))
...

(If you've learned procedures, you can also consider how to do this using a procedure.)

f. It's not worth the time to update all the parts of your face. Pick a few parts (say, the outline of the face and one eye) and update those parts to take the width and height of the image into account.

Exercise 3: Modifying Existing Images

Suppose we've defined picname as a string naming an image.

(define picname "/home/rebelsky/glimmer/samples/rebelsky-pic.jpg")

a. Write a series of instructions to load and show the picture.

b. Write a procedure, (image-draw-diagonal! image), to draw a diagonal line from the upper-left-hand-corner to the lower-right-hand corner of the given image. Note that you'll need to use image-width and image-height to determine the width and height of the image.

c. Test your procedure on the image from picname.

d. Write a procedure, (image-draw-border! image), to put some kind of border at the edges of the given image. (E.g., select a rectangle ten pixels from each edge and then stroke that rectangle.)

e. Test your procedure on the image from picname.

For Those with Extra Time

Extra 1: Drawing Houses

a. Write a series of instructions that create a new image and then draw a house in in the image. (Yes, you are restricted in that you don't know how to make triangles. Deal with it.)

b. Suppose we start by defining two names, width and height. Describe how you might change your house code to take those values into account.

(define width 300)
(define height 200)
(define canvas (image-new width height))
...

(If you've learned procedures, you can also consider how to do this using a procedure.)

Extra 1: Generalizing smiley faces

Revise your instructions from Exercise 2 so that the drawing adapts to the size of the image.

Recall that you can obtain the width and height of the image using the image-width and image-height procedures.

Reference

(image-new width height)
MediaScheme GIMP Procedure. Create a new image of specified width and height.
(image-load filename)
MediaScheme GIMP Procedure. Load an image from a file. The name of the file is a string (and, unless a named value, typically surrounded by quotation marks).
(image-show image)
MediaScheme GIMP Procedure. Opens a new window with the image.
(image-blot! image col row)
MediaScheme GIMP Procedure. Draw a spot in image at (col,row) with the current brush and foreground color.
(image-draw-line! image col1 row1 col2 row2)
MediaScheme GIMP Procedure. Draw a line in image from (col1,row1) to (col2,row2). Uses the current brush and foreground color.
(image-select-ellipse! image selection-type left top width height)
MediaScheme GIMP Procedure. Select an ellipse whose left margin is left, top margin is top, width is width and height is height. If selection-type is REPLACE, the ellipse replaces the current selection. If selection-type is ADD, the ellipse is added to the current selection. If selection-type is SUBTRACT, the ellipse is subtracted from the current selection. If selection-type is INTERSECT, the ellipse is intersected with the current selection (that is, only points that are in both the current selection and the ellipse remain selected).
(image-select-rectangle! image selection-type left top width height)
MediaScheme GIMP Procedure. Select an rectangle whose left margin is left, top margin is top, width is width and height is height. If selection-type is REPLACE, the rectangle replaces the current selection. If selection-type is ADD, the rectangle is added to the current selection. If selection-type is SUBTRACT, the rectangle is subtracted from the current selection. If selection-type is INTERSECT, the rectangle is intersected with the current selection (that is, only points that are in both the current selection and the rectangle remain selected).
(image-select-all! image)
MediaScheme GIMP Procedure. Selects all of the pixels in the image.
(image-select-nothing! image)
MediaScheme GIMP Procedure. Clears the current selection. Afterwards, nothing is selected.
(image-fill-selection! image)
MediaScheme GIMP Procedure. Fill the selected region of the given image with the current foreground color.
(image-stroke-selection! image)
MediaScheme GIMP Procedure. Traces the edge of the selected region of the given image with the current brush and foreground color.
(context-set-brush! brush-name) , (context-set-brush! brush-name brush-size)
MediaScheme GIMP Procedure. Sets GIMP's current brush to brush-name. If the brush-size is specified, also sets the size of brush. Only works for selected brushes (typically, those that start with a number, like "2. Hardness 100").
(context-set-fgcolor! color)
MediaScheme GIMP Procedure. Sets GIMP's current foreground color to color.
(context-list-brushes)
MediaScheme GIMP Procedure. List all valid brush names.
(context-list-brushes pattern)
MediaScheme GIMP Procedure. List all the valid brush names that contain pattern.
(context-update-displays!)
MediaScheme GIMP Procedure. Update all of the displays to show changes to images.
(usleep usec)
Optional Scheme Procedure. Pause for usec microseconds.

Notes

Notes on Exercise 1: Drawing With Selections

You probably expected the red line to cross the entire image, but it does not. If there is an active selection within an image, GIMP Tools only operates within that selection. Conversely, when there is no active selection, GIMP Tools (such as blotting and drawing lines) work as you would expect.

The best way to solve this is to get into the habit of deselecting when you are done with a particular command on a region by calling image-select-nothing!.