In addition to supporting “standard” data types, such as numbers and strings, Racket also includes libraries that support a number of more sophisticated data types, including a type that the designers call “images”. The image data type supports the creation, combination, and manipulation of a variety of basic shapes. Readers of an earlier generation might consider Racket’s picture type an extension of the ColorForms that they played with as children.
In considering the image data stype, we should ask ourselves the
standard set of five questions: What is the name of the type? It’s
“image”. What is the purpose of the type? To allow people to make
interesting images. How do you express values in this type? We’ve
seen a few ways, including circle
the and rectangle
procedures.
There are more. How does DrRacket display values? As the “expected”
images. What procedures are available? We’ve seen that we can use
above
and beside
. Once again, there are more.
There’s also one other question to ask for this type, since it’s not a standard type: How does one access the type? The answer is straightforward: You add the following line to the top of your definitions pane.
(require 2htdp/image)
You’ve already seen two procedures for creating basic shapes:
(circle
radius
mode
color)
creates a circle and
(rectangle
width
height
mode
color)
creates a rectangle.
> (circle 20 'outline "red")
> (rectangle 40 25 'solid "blue")
There are a few other things you can do with these basic shapes. If,
instead of 'outline
or 'solid
, you use a number between 0 and 255
for the mode, DrRacket uses that number as the opacity of the shape.
> (beside
(rectangle 25 40 255 "blue")
(rectangle 25 40 191 "blue")
(rectangle 25 40 127 "blue")
(rectangle 25 40 63 "blue"))
Opacity will be especially important as we start to overlay shapes.
> (define circles
(beside
(circle 10 255 "red")
(circle 10 191 "red")
(circle 10 127 "red")
(circle 10 63 "red")))
> (above
(overlay circles (rectangle 60 20 255 "blue"))
(overlay circles (rectangle 60 20 191 "blue"))
(overlay circles (rectangle 60 20 127 "blue"))
(overlay circles (rectangle 60 20 63 "blue")))
You can also use different “pen” values when outlining a shape. To
create a pen, you use (pen
color
width
style
cap
join)
where
style
can be 'solid
, 'dot
, 'long-dash
, 'short-dash
, or
'dot-dash
.
cap
can be 'round
, 'projecting
, or 'butt
.
join
can be 'round
, 'bevel
, or 'miter
.
> (define background (rectangle 80 80 'solid "white"))
> (beside
(overlay (circle 30 'outline (pen "red" 4 'solid 'round 'round))
background)
(overlay (circle 30 'outline (pen "red" 6 'dot-dash 'round 'round))
background)
(overlay (circle 30 'outline (pen "red" 8 'short-dash 'butt 'round))
background)
(overlay (circle 30 'outline (pen "red" 8 'short-dash 'projecting 'round))
background))
There are also a variety of other basic shapes.
(triangle
edge
mode
color)
creates an equilateral triangle,
(ellipse
width
height
mode
color)
creates an ellipse, and
(star
side
mode
color)
produces a five-pointed star.
> (beside
(ellipse 40 20 'outline "red")
(ellipse 20 40 'solid "blue")
(triangle 40 'solid "black")
(star 30 'solid "teal")
(star 20 'outline "teal"))
You can find a host of others shapes, including nine different kinds of triangles, a more generalized star, a variety of polygons, and even text and curves in The official DrRacket documentation for images.
While we often think of colors by name (e.g., “red”, “violet”, or “burnt umber”), one of the great advantages of computational image making is that it is possible to describe colors that do not have a name. Moreover, it is often better to use a more precise definition than is possible with a name. After all, we may not agree on what precisely something like “springgreen” or “burlywood” means. (One color scheme that we’ve found has both “Seattle salmon” and “Oregon salmon”. Would you know how those two colors relate?)
In fact, it may not only be more accurate to represent colors non-textually, it may also be more efficient, since color names may require the computer to look up the name in a table.
The most popular scheme for representing colors for display on the computer screen is RGB. In this scheme, we build each color by combining varying amounts of the three primary colors, red, green, and blue. (What, you think that red, yellow, and blue are the primary colors? It turns out that primary works differently when you’re transmitting light, as on the computer screen, than when you’re reflecting light, as when you color with crayons on paper.)
So, for example, purple is created by combining a lot of red, a lot of blue, and essentially no green. You get different purple-like colors by using different amounts of red and blue, and even different ratios of red and blue.
When we describe the amount of red, green, and blue, we traditionally use integers between 0 and 255 to describe each component color. Why do we start with 0? Because we might not want any contribution from that color. Why do we stop with 255? Because 255 is one less than 28 (256), and it turns out that numbers between 0 and 255 are therefore easy to represent on computers. (For those who learned binary in high school or elsewhere, if you have exactly eight binary digits, and you only care to represent positive numbers, you can represent exactly the integers from 0 to 255. This is akin to being able to count up to 999 with three decimal digits.)
If there are 256 possible values for each component, then there are 16,777,216 different colors that we can represent in standard RGB. Can the eye distinguish all of them? Not necessarily. Nonetheless, it is useful to know that this variety is available, and many eyes can make very fine distinctions between nearby colors.
In DrRacket’s image model, you can use the make-color
procedure to
create RGB colors. (make-color
0
255
0)
makes a bright green,
(make-color
0
128
128)
makes a blue-green color, and
(make-color
64
0
64)
makes a relatively dark purple.
> (beside (circle 20 'solid (make-color 0 255 0))
(circle 20 'solid (make-color 0 128 128))
(circle 20 'solid (make-color 64 0 64)))
By themselves, the basic images (ellipses, rectangles, etc.) do not permit us to create much. However, as some of the examples above suggest, we gain a great deal of power by combining existing images into a new image. You’re already seen three basic mechanisms for combining images.
beside
places images side-by-side. If the images have different
heights, their vertical centers are aligned.above
places images in a stack, each above the next. If the images
have different widths, their horizontal centers are aligned.overlay
places images on top of each other. The first image is on
top, then the next one, and so on and so forth. Images are aligned
according to their centers.> (define small-gray (circle 10 'solid "gray"))
> (define medium-red (circle 15 'solid "red"))
> (define large-black (circle 20 'solid "black"))
> (beside small-gray medium-red large-black)
> (above small-gray medium-red large-black)
> (overlay small-gray medium-red large-black)
> (overlay large-black medium-red small-gray)
What if we don’t want things aligned on centers? The Racket iamge library provides alternatives to these three that provide a bit more control.
(beside/align alignment i1 i2 ...)
allows you to align
side-by-side images at the top or bottom (using 'top
and
'bottom
). You can also align at the center, mimicking beside
,
using 'center
(above/align alignment i1 i2 ...)
allows
you to align vertically stacked images at the left, right, or middle
(using 'left
, 'right
, and 'middle
).(overlay/align halign valign i1 i2 ...)
allows you to
align overlaid images.> (define small-gray (circle 10 'solid "gray"))
> (define medium-red (circle 15 'solid "red"))
> (define large-black (circle 20 'solid "black"))
> (beside/align 'top small-gray medium-red large-black)
> (beside/align 'bottom small-gray medium-red large-black)
> (above/align 'left small-gray medium-red large-black)
> (above/align 'right small-gray medium-red large-black)
> (overlay/align 'left 'top small-gray medium-red large-black)
> (overlay/align 'left 'center small-gray medium-red large-black)
> (overlay/align 'left 'bottom small-gray medium-red large-black)
> (overlay/align 'right 'top small-gray medium-red large-black)
> (overlay/align 'right 'top large-black medium-red small-gray)
As the overlay examples suggest, the alignment is based on the “bounding box” of each image, the smallest rectangle that encloses the image.
There’s also another way to overlay images: You can offset the second
one relative to the first with
(overlay-offset
i1
xoff
yoff
i2)
. In this case, the second
one is offset by the specified amount from its original position.
> (define medium-red (circle 15 'solid "red"))
> (define medium-black (circle 15 'solid "black"))
> (overlay/offset medium-red 2 6 medium-black)
> (overlay/offset medium-red 6 2 medium-black)
> (overlay/offset medium-red -3 -3 medium-black)
Write instructions for making a two-by-two checkerboard.
Write instructions for making a simple smiley face.
This section draws upon The DrRacket HtDP/2e Image Guide. The discussion of colors comes from a reading from Grinnell’s CSC 151.