1089 lines
44 KiB
Racket
1089 lines
44 KiB
Racket
#lang scribble/doc
|
|
|
|
@(require (for-label (only-in racket/contract and/c or/c any/c not/c)
|
|
2htdp/image
|
|
(except-in lang/htdp-beginner make-posn posn? posn-x posn-y image?)
|
|
lang/posn
|
|
racket/gui/base
|
|
(only-in racket/base path-string?))
|
|
lang/posn
|
|
"shared.ss"
|
|
"image-util.ss"
|
|
scribble/decode
|
|
scribble/manual)
|
|
|
|
@teachpack["image"]{Images}
|
|
|
|
@(define mode/color-text
|
|
(make-splice
|
|
@list{If the @racket[mode] is @racket['outline] or @racket["outline"], then the last
|
|
argument can be a @racket[pen] struct or an @racket[image-color?], but if the @racket[mode]
|
|
is @racket['solid] or @racket["solid"], then the last argument must be an
|
|
@racket[image-color?].}))
|
|
|
|
@defmodule[#:require-form beginner-require 2htdp/image]
|
|
|
|
The image teachpack provides a number of basic image construction functions, along with
|
|
combinators for building more complex images out of existing images. Basic images include
|
|
various polygons, ellipses and circles, and text, as well as bitmaps (typically bitmaps
|
|
come about via the @onscreen{Insert Image...} menu item in DrRacket).
|
|
Existing images can be rotated, scaled, and overlaid on top of each other.
|
|
|
|
@section{Basic Images}
|
|
|
|
@defproc*[([(circle [radius (and/c real? (not/c negative?))]
|
|
[mode mode?]
|
|
[color image-color?])
|
|
image?]
|
|
[(circle [radius (and/c real? (not/c negative?))]
|
|
[outline-mode (or/c 'outline "outline")]
|
|
[pen-or-color (or/c pen? image-color?)])
|
|
image?])]{
|
|
Constructs a circle with the given radius, height, mode, and color.
|
|
|
|
@mode/color-text
|
|
|
|
@image-examples[(circle 30 "outline" "red")
|
|
(circle 20 "solid" "blue")]
|
|
|
|
}
|
|
|
|
@defproc*[([(ellipse [width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))]
|
|
[mode mode?]
|
|
[color image-color?])
|
|
image?]
|
|
[(ellipse [width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))]
|
|
[mode (or/c 'outline "outline")]
|
|
[pen-or-color (or/c image-color? pen?)])
|
|
image?])]{
|
|
Constructs an ellipsis with the given width, height, mode, and color.
|
|
|
|
@mode/color-text
|
|
|
|
@image-examples[(ellipse 40 20 "outline" "black")
|
|
(ellipse 20 40 "solid" "blue")]
|
|
}
|
|
|
|
@defproc*[([(triangle [side-length (and/c real? (not/c negative?))]
|
|
[mode mode?]
|
|
[color image-color?])
|
|
image?]
|
|
[(triangle [side-length (and/c real? (not/c negative?))]
|
|
[outline-mode (or/c 'outline "outline")]
|
|
[pen-or-color (or/c pen? image-color?)])
|
|
image?])]{
|
|
|
|
Constructs a upward-pointing equilateral triangle.
|
|
The @racket[side-length] argument
|
|
determines the
|
|
length of the side of the triangle.
|
|
|
|
@mode/color-text
|
|
|
|
@image-examples[(triangle 40 "solid" "tan")]
|
|
|
|
}
|
|
|
|
@defproc*[([(right-triangle [side-length1 (and/c real? (not/c negative?))]
|
|
[side-length2 (and/c real? (not/c negative?))]
|
|
[mode mode?]
|
|
[color image-color?])
|
|
image?]
|
|
[(right-triangle [side-length1 (and/c real? (not/c negative?))]
|
|
[side-length2 (and/c real? (not/c negative?))]
|
|
[outline-mode (or/c 'outline "outline")]
|
|
[pen-or-color (or/c pen? image-color?)])
|
|
image?])]{
|
|
|
|
Constructs a triangle with a right angle where the two sides adjacent
|
|
to the right angle have lengths @racket[side-length1] and @racket[side-length2].
|
|
|
|
@mode/color-text
|
|
|
|
@image-examples[(right-triangle 36 48 "solid" "black")]
|
|
}
|
|
|
|
@defproc*[([(isosceles-triangle [side-length (and/c real? (not/c negative?))]
|
|
[angle angle?]
|
|
[mode mode?]
|
|
[color image-color?])
|
|
image?]
|
|
[(isosceles-triangle [side-length (and/c real? (not/c negative?))]
|
|
[angle angle?]
|
|
[outline-mode (or/c 'outline "outline")]
|
|
[pen-or-color (or/c pen? image-color?)])
|
|
image?])]{
|
|
|
|
Creates a triangle with two equal-length sides, of length @racket[side-length]
|
|
where the angle between those sides is @racket[angle]. The third
|
|
leg is straight, horizontally. If the angle is less than
|
|
@racket[180], then the triangle will point up and if the @racket[angle]
|
|
is more, then the triangle will point down.
|
|
|
|
@mode/color-text
|
|
|
|
@image-examples[(isosceles-triangle 200 170 "solid" "seagreen")
|
|
(isosceles-triangle 60 30 "solid" "aquamarine")
|
|
(isosceles-triangle 60 330 "solid" "lightseagreen")]
|
|
}
|
|
|
|
|
|
@defproc*[([(square [side-len (and/c real? (not/c negative?))]
|
|
[mode mode?]
|
|
[color image-color?])
|
|
image?]
|
|
[(square [side-len (and/c real? (not/c negative?))]
|
|
[outline-mode (or/c 'outline "outline")]
|
|
[pen-or-color (or/c pen? image-color?)])
|
|
image?])]{
|
|
|
|
Constructs a square.
|
|
|
|
@mode/color-text
|
|
|
|
@image-examples[(square 40 "solid" "slateblue")
|
|
(square 50 "outline" "darkmagenta")]
|
|
|
|
}
|
|
|
|
@defproc*[([(rectangle [width real?]
|
|
[height real?]
|
|
[mode mode?]
|
|
[color image-color?])
|
|
image?]
|
|
[(rectangle [width real?]
|
|
[height real?]
|
|
[outline-mode (or/c 'outline "outline")]
|
|
[pen-or-color (or/c pen? image-color?)])
|
|
image?])]{
|
|
Constructs a rectangle with the given width, height, mode, and color.
|
|
|
|
@mode/color-text
|
|
|
|
@image-examples[(rectangle 40 20 "outline" "black")
|
|
(rectangle 20 40 "solid" "blue")]
|
|
}
|
|
|
|
@defproc*[([(rhombus [side-length (and/c real? (not/c negative?))]
|
|
[angle angle?]
|
|
[mode mode?]
|
|
[color image-color?])
|
|
image?]
|
|
[(rhombus [side-length (and/c real? (not/c negative?))]
|
|
[angle angle?]
|
|
[outline-mode (or/c 'outline "outline")]
|
|
[pen-or-color (or/c pen? image-color?)])
|
|
image?])]{
|
|
|
|
Constructs a four sided polygon with all equal sides and thus where opposite angles are equal to each
|
|
other. The top and bottom pair of angles is @racket[angle] and the left and right are @racket[(- 180 angle)].
|
|
|
|
@mode/color-text
|
|
|
|
@image-examples[(rhombus 40 45 "solid" "magenta")
|
|
(rhombus 80 150 "solid" "mediumpurple")]
|
|
}
|
|
|
|
@defproc*[([(regular-polygon [side-length (and/c real? (not/c negative?))]
|
|
[side-count side-count?]
|
|
[mode mode?]
|
|
[color image-color?])
|
|
image?]
|
|
[(regular-polygon [side-length (and/c real? (not/c negative?))]
|
|
[side-count side-count?]
|
|
[outline-mode (or/c 'outline "outline")]
|
|
[pen-or-color (or/c pen? image-color?)])
|
|
image?])]{
|
|
Constructs a regular polygon with @racket[side-count] sides.
|
|
|
|
@mode/color-text
|
|
|
|
@image-examples[(regular-polygon 50 3 "outline" "red")
|
|
(regular-polygon 40 4 "outline" "blue")
|
|
(regular-polygon 20 8 "solid" "red")]
|
|
}
|
|
|
|
@defproc*[([(star [side-length (and/c real? (not/c negative?))]
|
|
[mode mode?]
|
|
[color image-color?])
|
|
image?]
|
|
[(star [side-length (and/c real? (not/c negative?))]
|
|
[outline-mode (or/c 'outline "outline")]
|
|
[color (or/c pen? image-color?)])
|
|
image?])]{
|
|
Constructs a star with five points. The @racket[side-length] argument
|
|
determines the side length of the enclosing pentagon.
|
|
|
|
@mode/color-text
|
|
|
|
@image-examples[(star 40 "solid" "gray")]
|
|
|
|
}
|
|
|
|
@defproc*[([(star-polygon [side-length (and/c real? (not/c negative?))]
|
|
[side-count side-count?]
|
|
[step-count step-count?]
|
|
[mode mode?]
|
|
[color image-color?])
|
|
image?]
|
|
[(star-polygon [side-length (and/c real? (not/c negative?))]
|
|
[side-count side-count?]
|
|
[step-count step-count?]
|
|
[outline-mode (or/c 'outline "outline")]
|
|
[pen-or-color (or/c pen? image-color?)])
|
|
image?])]{
|
|
|
|
Constructs an arbitrary regular star polygon (a generalization of the regular polygons).
|
|
The polygon is enclosed by a regular polygon with @racket[side-count] sides each
|
|
@racket[side-length] long. The polygon is actually constructed by going from vertex to
|
|
vertex around the regular polgon, but skipping over every @racket[step-count] vertices.
|
|
|
|
For examples, if @racket[side-count] is @racket[5] and @racket[step-count] is @racket[2],
|
|
then this function produces a shape just like @racket[star].
|
|
|
|
@mode/color-text
|
|
|
|
@image-examples[(star-polygon 40 5 2 "solid" "seagreen")
|
|
(star-polygon 40 7 3 "outline" "darkred")
|
|
(star-polygon 20 10 3 "solid" "cornflowerblue")]
|
|
|
|
}
|
|
|
|
@defproc*[([(polygon [vertices (listof posn?)]
|
|
[mode mode?]
|
|
[color image-color?])
|
|
image?]
|
|
[(polygon [vertices (listof posn?)]
|
|
[outline-mode (or/c 'outline "outline")]
|
|
[pen-or-color (or/c pen? image-color?)])
|
|
image?])]{
|
|
Constructs a polygon connecting the given vertices.
|
|
|
|
@mode/color-text
|
|
|
|
@image-examples[(polygon (list (make-posn 0 0)
|
|
(make-posn -10 20)
|
|
(make-posn 60 0)
|
|
(make-posn -10 -20))
|
|
"solid"
|
|
"burlywood")
|
|
(polygon (list (make-posn 0 0)
|
|
(make-posn 0 40)
|
|
(make-posn 20 40)
|
|
(make-posn 20 60)
|
|
(make-posn 40 60)
|
|
(make-posn 40 20)
|
|
(make-posn 20 20)
|
|
(make-posn 20 0))
|
|
"solid"
|
|
"plum")
|
|
(underlay
|
|
(rectangle 80 80 "solid" "mediumseagreen")
|
|
(polygon
|
|
(list (make-posn 0 0)
|
|
(make-posn 50 0)
|
|
(make-posn 0 50)
|
|
(make-posn 50 50))
|
|
"outline"
|
|
(make-pen "darkslategray" 10 "solid" "round" "round")))
|
|
|
|
(underlay
|
|
(rectangle 90 80 "solid" "mediumseagreen")
|
|
(polygon
|
|
(list (make-posn 0 0)
|
|
(make-posn 50 0)
|
|
(make-posn 0 50)
|
|
(make-posn 50 50))
|
|
"outline"
|
|
(make-pen "darkslategray" 10 "solid" "projecting" "miter")))]
|
|
}
|
|
|
|
@defproc[(line [x1 real?] [y1 real?] [pen-or-color (or/c pen? image-color?)]) image?]{
|
|
Constructs an image representing a line segment that connects the points
|
|
(0,0) to (x1,y1).
|
|
|
|
@image-examples[(line 30 30 "black")
|
|
(line -30 20 "red")
|
|
(line 30 -20 "red")]
|
|
}
|
|
|
|
@defproc[(add-line [image image?]
|
|
[x1 real?] [y1 real?]
|
|
[x2 real?] [y2 real?]
|
|
[pen-or-color (or/c pen? image-color?)])
|
|
image?]{
|
|
|
|
Adds a line to the image @racket[image], starting from the point (@racket[x1],@racket[y1])
|
|
and going to the point (@racket[x2],@racket[y2]).
|
|
Unlike @racket[scene+line], if the line passes outside of @racket[image], the image
|
|
gets larger to accomodate the line.
|
|
|
|
@image-examples[(add-line (ellipse 40 40 "outline" "maroon")
|
|
0 40 40 0 "maroon")
|
|
(add-line (rectangle 40 40 "solid" "gray")
|
|
-10 50 50 -10 "maroon")
|
|
(add-line
|
|
(rectangle 100 100 "solid" "darkolivegreen")
|
|
25 25 75 75
|
|
(make-pen "goldenrod" 30 "solid" "round" "round"))]
|
|
}
|
|
|
|
@defproc[(add-curve [image image?]
|
|
[x1 real?] [y1 real?] [angle1 angle?] [pull1 real?]
|
|
[x2 real?] [y2 real?] [angle2 angle?] [pull2 real?]
|
|
[pen-or-color (or/c pen? image-color?)])
|
|
image?]{
|
|
|
|
Adds a curve to @racket[image], starting at the point
|
|
(@racket[x1],@racket[y1]), and ending at the point
|
|
(@racket[x2],@racket[y2]).
|
|
|
|
The @racket[angle1] and @racket[angle2] arguments specify the
|
|
angle that the curve has as it leaves the initial point and
|
|
as it reaches the final point, respectively.
|
|
|
|
The @racket[pull1] and @racket[pull2] arguments control how
|
|
long the curve tries to stay with that angle. Larger numbers
|
|
mean that the curve stays with the angle longer.
|
|
|
|
Unlike @racket[scene+curve], if the line passes outside of @racket[image], the image
|
|
gets larger to accomodate the curve.
|
|
|
|
|
|
@image-examples[(add-curve (rectangle 100 100 "solid" "black")
|
|
20 20 0 1/3
|
|
80 80 0 1/3
|
|
"white")
|
|
(add-curve (rectangle 100 100 "solid" "black")
|
|
20 20 0 1
|
|
80 80 0 1
|
|
"white")
|
|
(add-curve
|
|
(add-curve
|
|
(rectangle 40 100 "solid" "black")
|
|
20 10 180 1/2
|
|
20 90 180 1/2
|
|
(make-pen "white" 4 "solid" "round" "round"))
|
|
20 10 0 1/2
|
|
20 90 0 1/2
|
|
(make-pen "white" 4 "solid" "round" "round"))
|
|
|
|
(add-curve (rectangle 100 100 "solid" "black")
|
|
-20 -20 0 1
|
|
120 120 0 1
|
|
"red")]
|
|
}
|
|
|
|
@defproc[(text [string string?] [font-size (and/c integer? (<=/c 1 255))] [color image-color?])
|
|
image?]{
|
|
|
|
Constructs an image that draws the given string, using the font size and color.
|
|
|
|
@image-examples[(text "Hello" 24 "olive")
|
|
(text "Goodbye" 36 "indigo")]
|
|
}
|
|
|
|
@defproc[(text/font [string string?] [font-size (and/c integer? (<=/c 1 255))] [color image-color?]
|
|
[face (or/c string? #f)]
|
|
[family (or/c 'default 'decorative 'roman 'script 'swiss 'modern 'symbol 'system)]
|
|
[style (or/c 'normal 'italic 'slant)]
|
|
[weight (or/c 'normal 'bold 'light)]
|
|
[underline? any/c])
|
|
image?]{
|
|
|
|
Constructs an image that draws the given string, using a complete font specification.
|
|
|
|
The @racket[face] and the @racket[family] combine to give the complete typeface. If
|
|
@racket[face] is available on the system, it is used, but if not then a default typeface
|
|
based on the @racket[family] is chosen. The @racket[style] controls if the face is italic
|
|
or not (under Windows and Mac OS X, @racket['slant] and @racket['italic] are the same),
|
|
the @racket[weight] controls if it is boldface (or light), and @racket[underline?]
|
|
determines if the face is underlined. For more details on these arguments, see @racket[font%],
|
|
which ultimately is what this code uses to draw the font.
|
|
|
|
@image-examples[(text/font "Hello" 24 "olive"
|
|
"Gill Sans" 'swiss 'normal 'bold #f)
|
|
(text/font "Goodbye" 18 "indigo"
|
|
#f 'modern 'italic 'normal #f)
|
|
(text/font "not really a link" 18 "blue"
|
|
#f 'roman 'normal 'normal #t)]
|
|
}
|
|
|
|
@defform/subs[(bitmap bitmap-spec)
|
|
([bitmap-spec rel-string
|
|
id])]{
|
|
|
|
Loads the bitmap specified by @racket[bitmap-spec]. If @racket[bitmap-spec] is a string, it is treated as a
|
|
relative path. If it is an identifier, it is treated like a require spec and used to refer to a file
|
|
in a collection.
|
|
|
|
@image-examples[(bitmap icons/stop-16x16.png)
|
|
(bitmap icons/b-run.png)]
|
|
}
|
|
|
|
@section{Overlaying Images}
|
|
|
|
@defproc[(overlay [i1 image?] [i2 image?] [is image?] ...) image?]{
|
|
Overlays all of its arguments building a single image. The first argument goes
|
|
on top of the second argument, which goes on top of the third argument, etc.
|
|
The images are all lined up on their centers.
|
|
|
|
@image-examples[(overlay (rectangle 30 60 "solid" "orange")
|
|
(ellipse 60 30 "solid" "purple"))
|
|
(overlay (ellipse 10 10 "solid" "red")
|
|
(ellipse 20 20 "solid" "black")
|
|
(ellipse 30 30 "solid" "red")
|
|
(ellipse 40 40 "solid" "black")
|
|
(ellipse 50 50 "solid" "red")
|
|
(ellipse 60 60 "solid" "black"))
|
|
(overlay (regular-polygon 20 5 "solid" (make-color 50 50 255))
|
|
(regular-polygon 26 5 "solid" (make-color 100 100 255))
|
|
(regular-polygon 32 5 "solid" (make-color 150 150 255))
|
|
(regular-polygon 38 5 "solid" (make-color 200 200 255))
|
|
(regular-polygon 44 5 "solid" (make-color 250 250 255)))]
|
|
|
|
}
|
|
|
|
@defproc[(overlay/align [x-place x-place?] [y-place y-place?] [i1 image?] [i2 image?] [is image?] ...) image?]{
|
|
Overlays all of its image arguments, much like the @racket[overlay] function, but using
|
|
@racket[x-place] and @racket[y-place] to determine where the images are lined up. For example, if
|
|
@racket[x-place] and @racket[y-place] are both @racket["middle"], then the images are lined up
|
|
on their centers.
|
|
|
|
@image-examples[(overlay/align "left" "middle"
|
|
(rectangle 30 60 "solid" "orange")
|
|
(ellipse 60 30 "solid" "purple"))
|
|
(overlay/align "right" "bottom"
|
|
(rectangle 20 20 "solid" "silver")
|
|
(rectangle 30 30 "solid" "seagreen")
|
|
(rectangle 40 40 "solid" "silver")
|
|
(rectangle 50 50 "solid" "seagreen"))]
|
|
|
|
|
|
}
|
|
|
|
@defproc[(overlay/xy [i1 image?] [x real?] [y real?] [i2 image?]) image?]{
|
|
Constructs an image by overlaying @racket[i1] on top of @racket[i2] after
|
|
shifting @racket[i2] over by @racket[x] pixels to the right and @racket[y]
|
|
pixels down.
|
|
@image-examples[(overlay/xy (rectangle 20 20 "outline" "black")
|
|
20 0
|
|
(rectangle 20 20 "outline" "black"))
|
|
(overlay/xy (rectangle 20 20 "solid" "red")
|
|
20 20
|
|
(rectangle 20 20 "solid" "black"))
|
|
(overlay/xy (rectangle 20 20 "solid" "red")
|
|
-20 -20
|
|
(rectangle 20 20 "solid" "black"))
|
|
(overlay/xy
|
|
(overlay/xy (ellipse 40 40 "outline" "black")
|
|
10
|
|
15
|
|
(ellipse 10 10 "solid" "forestgreen"))
|
|
20
|
|
15
|
|
(ellipse 10 10 "solid" "forestgreen"))]
|
|
}
|
|
|
|
@defproc[(underlay [i1 image?] [i2 image?] [is image?] ...) image?]{
|
|
Underlays all of its arguments building a single image.
|
|
|
|
It behaves like @racket[overlay], but with the arguments in the reverse order.
|
|
That is, the first argument goes
|
|
underneath of the second argument, which goes underneath the third argument, etc.
|
|
The images are all lined up on their centers.
|
|
|
|
@image-examples[(underlay (rectangle 30 60 "solid" "orange")
|
|
(ellipse 60 30 "solid" "purple"))
|
|
(underlay (ellipse 10 60 "solid" "red")
|
|
(ellipse 20 50 "solid" "black")
|
|
(ellipse 30 40 "solid" "red")
|
|
(ellipse 40 30 "solid" "black")
|
|
(ellipse 50 20 "solid" "red")
|
|
(ellipse 60 10 "solid" "black"))]
|
|
|
|
}
|
|
|
|
@defproc[(underlay/align [x-place x-place?] [y-place y-place?] [i1 image?] [i2 image?] [is image?] ...) image?]{
|
|
Underlays all of its image arguments, much like the @racket[underlay] function, but using
|
|
@racket[x-place] and @racket[y-place] to determine where the images are lined up. For example, if
|
|
@racket[x-place] and @racket[y-place] are both @racket["middle"], then the images are lined up
|
|
on their centers.
|
|
|
|
@image-examples[(underlay/align "left" "middle"
|
|
(rectangle 30 60 "solid" "orange")
|
|
(ellipse 60 30 "solid" "purple"))
|
|
(underlay/align "right" "top"
|
|
(rectangle 50 50 "solid" "seagreen")
|
|
(rectangle 40 40 "solid" "silver")
|
|
(rectangle 30 30 "solid" "seagreen")
|
|
(rectangle 20 20 "solid" "silver"))]
|
|
|
|
|
|
}
|
|
|
|
@defproc[(underlay/xy [i1 image?] [x real?] [y real?] [i2 image?]) image?]{
|
|
Constructs an image by underlaying @racket[i1] underneath of @racket[i2] after
|
|
shifting @racket[i2] over by @racket[x] pixels to the right and @racket[y]
|
|
pixels down.
|
|
|
|
This is the same as @racket[(overlay/xy i2 (- x) (- y) i1)].
|
|
|
|
@image-examples[(underlay/xy (rectangle 20 20 "outline" "black")
|
|
20 0
|
|
(rectangle 20 20 "outline" "black"))
|
|
(underlay/xy (rectangle 20 20 "solid" "red")
|
|
20 20
|
|
(rectangle 20 20 "solid" "black"))
|
|
(underlay/xy (rectangle 20 20 "solid" "red")
|
|
-20 -20
|
|
(rectangle 20 20 "solid" "black"))
|
|
(underlay/xy
|
|
(underlay/xy (ellipse 40 40 "solid" "gray")
|
|
10
|
|
15
|
|
(ellipse 10 10 "solid" "forestgreen"))
|
|
20
|
|
15
|
|
(ellipse 10 10 "solid" "forestgreen"))]
|
|
}
|
|
|
|
|
|
@defproc[(beside [i1 image?] [i2 image?] [is image?] ...) image?]{
|
|
Constructs an image by placing all of the argument images in a
|
|
horizontal row, aligned along their centers.
|
|
|
|
@image-examples[(beside (ellipse 20 70 "solid" "gray")
|
|
(ellipse 20 50 "solid" "darkgray")
|
|
(ellipse 20 30 "solid" "dimgray")
|
|
(ellipse 20 10 "solid" "black"))]
|
|
|
|
|
|
}
|
|
|
|
@defproc[(beside/align [y-place y-place?] [i1 image?] [i2 image?] [is image?] ...) image?]{
|
|
Constructs an image by placing all of the argument images in a horizontal row, lined
|
|
up as indicated by the @racket[y-place] argument. For example, if @racket[y-place]
|
|
is @racket["middle"], then the images are placed side by side with their centers
|
|
lined up with each other.
|
|
|
|
@image-examples[(beside/align "bottom"
|
|
(ellipse 20 70 "solid" "lightsteelblue")
|
|
(ellipse 20 50 "solid" "mediumslateblue")
|
|
(ellipse 20 30 "solid" "slateblue")
|
|
(ellipse 20 10 "solid" "navy"))
|
|
|
|
(beside/align "top"
|
|
(ellipse 20 70 "solid" "mediumorchid")
|
|
(ellipse 20 50 "solid" "darkorchid")
|
|
(ellipse 20 30 "solid" "purple")
|
|
(ellipse 20 10 "solid" "indigo"))
|
|
|
|
(beside/align "baseline"
|
|
(text "ijy" 18 "black")
|
|
(text "ijy" 24 "black"))]
|
|
|
|
|
|
}
|
|
|
|
|
|
@defproc[(above [i1 image?] [i2 image?] [is image?] ...) image?]{
|
|
Constructs an image by placing all of the argument images in a
|
|
vertical row, aligned along their centers.
|
|
|
|
@image-examples[(above (ellipse 70 20 "solid" "gray")
|
|
(ellipse 50 20 "solid" "darkgray")
|
|
(ellipse 30 20 "solid" "dimgray")
|
|
(ellipse 10 20 "solid" "black"))]
|
|
|
|
|
|
}
|
|
|
|
@defproc[(above/align [x-place x-place?] [i1 image?] [i2 image?] [is image?] ...) image?]{
|
|
Constructs an image by placing all of the argument images in a vertical row, lined
|
|
up as indicated by the @racket[x-place] argument. For example, if @racket[x-place]
|
|
is @racket["middle"], then the images are placed above each other with their centers
|
|
lined up.
|
|
|
|
@image-examples[(above/align "right"
|
|
(ellipse 70 20 "solid" "gold")
|
|
(ellipse 50 20 "solid" "goldenrod")
|
|
(ellipse 30 20 "solid" "darkgoldenrod")
|
|
(ellipse 10 20 "solid" "sienna"))
|
|
|
|
(above/align "left"
|
|
(ellipse 70 20 "solid" "yellowgreen")
|
|
(ellipse 50 20 "solid" "olivedrab")
|
|
(ellipse 30 20 "solid" "darkolivegreen")
|
|
(ellipse 10 20 "solid" "darkgreen"))]
|
|
|
|
|
|
}
|
|
|
|
@section{Placing Images & Scenes}
|
|
|
|
Placing images into scenes is particularly useful when building worlds
|
|
and universes using @racket[2htdp/universe].
|
|
|
|
@defproc[(empty-scene [width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))])
|
|
image?]{
|
|
|
|
Creates an empty scene, i.e., a rectangle with a black outline.
|
|
|
|
@image-examples[(empty-scene 160 90)]
|
|
|
|
}
|
|
|
|
@defproc[(place-image [image image?] [x real?] [y real?] [scene image?]) image?]{
|
|
|
|
Places @racket[image] onto @racket[scene] with its center at the coordinates
|
|
(@racket[x],@racket[y]) and crops the resulting image so that it has the
|
|
same size as @racket[scene]. The coordinates are relative to the top-left
|
|
of @racket[scene].
|
|
|
|
@image-examples[(place-image
|
|
(triangle 32 "solid" "red")
|
|
24 24
|
|
(rectangle 48 48 "solid" "gray"))
|
|
|
|
(place-image
|
|
(triangle 64 "solid" "red")
|
|
24 24
|
|
(rectangle 48 48 "solid" "gray"))
|
|
|
|
(place-image
|
|
(circle 4 "solid" "white")
|
|
18 20
|
|
(place-image
|
|
(circle 4 "solid" "white")
|
|
0 6
|
|
(place-image
|
|
(circle 4 "solid" "white")
|
|
14 2
|
|
(place-image
|
|
(circle 4 "solid" "white")
|
|
8 14
|
|
(rectangle 24 24 "solid" "goldenrod")))))]
|
|
}
|
|
@defproc[(place-image/align [image image?] [x real?] [y real?] [x-place x-place?] [y-place y-place?][scene image?])
|
|
image?]{
|
|
|
|
Like @racket[place-image], but uses @racket[image]'s @racket[x-place] and
|
|
@racket[y-place] to anchor the image. Also, like
|
|
@racket[place-image], @racket[place-image/align]
|
|
crops the resulting image so that it has the
|
|
same size as @racket[scene].
|
|
|
|
@image-examples[(place-image/align (triangle 48 "solid" "yellowgreen")
|
|
64 64 "right" "bottom"
|
|
(rectangle 64 64 "solid" "mediumgoldenrod"))
|
|
(beside
|
|
(place-image/align (circle 8 "solid" "tomato")
|
|
0 0 "center" "center"
|
|
(rectangle 32 32 "outline" "black"))
|
|
(place-image/align (circle 8 "solid" "tomato")
|
|
8 8 "center" "center"
|
|
(rectangle 32 32 "outline" "black"))
|
|
(place-image/align (circle 8 "solid" "tomato")
|
|
16 16 "center" "center"
|
|
(rectangle 32 32 "outline" "black"))
|
|
(place-image/align (circle 8 "solid" "tomato")
|
|
24 24 "center" "center"
|
|
(rectangle 32 32 "outline" "black"))
|
|
(place-image/align (circle 8 "solid" "tomato")
|
|
32 32 "center" "center"
|
|
(rectangle 32 32 "outline" "black")))]
|
|
}
|
|
|
|
@defproc[(scene+line [image image?]
|
|
[x1 real?] [y1 real?]
|
|
[x2 real?] [y2 real?]
|
|
[color image-color?])
|
|
image?]{
|
|
|
|
Adds a line to the image @racket[scene], starting from the point (@racket[x1],@racket[y1])
|
|
and going to the point (@racket[x2],@racket[y2]); unlike
|
|
@racket[add-line], this function crops the resulting image to the size of @racket[scene].
|
|
|
|
@image-examples[(scene+line (ellipse 40 40 "outline" "maroon")
|
|
0 40 40 0 "maroon")
|
|
(scene+line (rectangle 40 40 "solid" "gray")
|
|
-10 50 50 -10 "maroon")
|
|
(scene+line
|
|
(rectangle 100 100 "solid" "darkolivegreen")
|
|
25 25 100 100
|
|
(make-pen "goldenrod" 30 "solid" "round" "round"))]
|
|
}
|
|
|
|
@defproc[(scene+curve [scene image?]
|
|
[x1 real?] [y1 real?] [angle1 angle?] [pull1 real?]
|
|
[x2 real?] [y2 real?] [angle2 angle?] [pull2 real?]
|
|
[color image-color?])
|
|
image?]{
|
|
|
|
Adds a curve to @racket[scene], starting at the point
|
|
(@racket[x1],@racket[y1]), and ending at the point
|
|
(@racket[x2],@racket[y2]).
|
|
|
|
The @racket[angle1] and @racket[angle2] arguments specify the
|
|
angle that the curve has as it leaves the initial point and
|
|
as it reaches the final point, respectively.
|
|
|
|
The @racket[pull1] and @racket[pull2] arguments control how
|
|
long the curve tries to stay with that angle. Larger numbers
|
|
mean that the curve stays with the angle longer.
|
|
|
|
Unlike @racket[add-curve], this function crops the curve, only showing
|
|
the parts that fit onto @racket[scene].
|
|
|
|
@image-examples[(scene+curve (rectangle 100 100 "solid" "black")
|
|
20 20 0 1/3
|
|
80 80 0 1/3
|
|
"white")
|
|
(scene+curve (rectangle 100 100 "solid" "black")
|
|
20 20 0 1
|
|
80 80 0 1
|
|
"white")
|
|
(scene+curve
|
|
(add-curve
|
|
(rectangle 40 100 "solid" "black")
|
|
20 10 180 1/2
|
|
20 90 180 1/2
|
|
"white")
|
|
20 10 0 1/2
|
|
20 90 0 1/2
|
|
"white")
|
|
|
|
(scene+curve (rectangle 100 100 "solid" "black")
|
|
-20 -20 0 1
|
|
120 120 0 1
|
|
"red")]
|
|
}
|
|
|
|
|
|
@section{Rotating, Scaling, Flipping, Cropping, and Framing Images}
|
|
|
|
@defproc[(rotate [angle angle?] [image image?]) image?]{
|
|
Rotates @racket[image] by @racket[angle] degrees in a counter-clockwise direction.
|
|
|
|
@image-examples[(rotate 45 (ellipse 60 20 "solid" "olivedrab"))
|
|
(rotate 5 (rectangle 50 50 "outline" "black"))
|
|
(rotate 45
|
|
(beside/align
|
|
"center"
|
|
(rectangle 40 20 "solid" "darkseagreen")
|
|
(rectangle 20 100 "solid" "darkseagreen")))]
|
|
|
|
}
|
|
|
|
@defproc[(scale [factor (and/c real? positive?)] [image image?]) image?]{
|
|
|
|
Scales @racket[image] by @racket[factor].
|
|
|
|
The pen sizes are also scaled and thus draw thicker (or thinner)
|
|
lines than the original image, unless the pen was size
|
|
@racket[0]. That pen size is treated specially to mean ``the
|
|
smallest available line'' and thus it always draws a one pixel
|
|
wide line; this is also the case for @racket['outline] and @racket["outline"]
|
|
shapes that are drawn with an @racket[image-color?] instead of
|
|
a @racket[pen].
|
|
|
|
|
|
@image-examples[(scale 2 (ellipse 20 30 "solid" "blue"))
|
|
(ellipse 40 60 "solid" "blue")]
|
|
|
|
|
|
|
|
}
|
|
|
|
@defproc[(scale/xy [x-factor (and/c real? positive?)] [y-factor (and/c real? positive?)] [image image?]) image?]{
|
|
Scales @racket[image] by @racket[x-factor] horizontally and by
|
|
@racket[y-factor] vertically.
|
|
|
|
@image-examples[(scale/xy 3
|
|
2
|
|
(ellipse 20 30 "solid" "blue"))
|
|
(ellipse 60 60 "solid" "blue")]
|
|
}
|
|
|
|
@defproc[(flip-horizontal [image image?]) image?]{
|
|
Flips @scheme[image] left to right.
|
|
|
|
@image-examples[(beside
|
|
(rotate 30 (square 50 "solid" "red"))
|
|
(flip-horizontal
|
|
(rotate 30 (square 50 "solid" "blue"))))]
|
|
}
|
|
|
|
@defproc[(flip-vertical [image image?]) image?]{
|
|
Flips @scheme[image] top to bottom.
|
|
|
|
@image-examples[(above
|
|
(star 40 "solid" "firebrick")
|
|
(scale/xy 1 1/2 (flip-vertical (star 40 "solid" "gray"))))]
|
|
}
|
|
|
|
@defproc[(crop [x real?] [y real?]
|
|
[width (and/c real? (not/c negative?))]
|
|
[height (and/c real? (not/c negative?))]
|
|
[image image?])
|
|
image?]{
|
|
|
|
Crops @racket[image] to the rectangle with the upper left at the point (@racket[x],@racket[y])
|
|
and with @racket[width] and @racket[height].
|
|
|
|
@image-examples[(crop 0 0 40 40 (circle 40 "solid" "chocolate"))
|
|
(crop 40 60 40 60 (ellipse 80 120 "solid" "dodgerblue"))
|
|
(above
|
|
(beside (crop 40 40 40 40 (circle 40 "solid" "palevioletred"))
|
|
(crop 0 40 40 40 (circle 40 "solid" "lightcoral")))
|
|
(beside (crop 40 0 40 40 (circle 40 "solid" "lightcoral"))
|
|
(crop 0 0 40 40 (circle 40 "solid" "palevioletred"))))]
|
|
|
|
}
|
|
|
|
@defproc[(frame [image image?]) image?]{
|
|
Returns an image just like @racket[image], except
|
|
with a black, single pixel frame drawn around the
|
|
bounding box of the image.
|
|
|
|
@image-examples[(frame (ellipse 20 20 "outline" "black"))]
|
|
|
|
Generally speaking, this function is useful to
|
|
debug image constructions, i.e., to see where
|
|
certain sub-images appear within some larger image.
|
|
|
|
@image-examples[(beside
|
|
(ellipse 20 70 "solid" "lightsteelblue")
|
|
(frame (ellipse 20 50 "solid" "mediumslateblue"))
|
|
(ellipse 20 30 "solid" "slateblue")
|
|
(ellipse 20 10 "solid" "navy"))]
|
|
}
|
|
|
|
@section{Image Properties}
|
|
|
|
@defproc[(image-width [i image?]) (and/c integer? (not/c negative?) exact?)]{
|
|
Returns the width of @racket[i].
|
|
|
|
@image-examples[(image-width (ellipse 30 40 "solid" "orange"))
|
|
(image-width (circle 30 "solid" "orange"))
|
|
(image-width (beside (circle 20 "solid" "orange")
|
|
(circle 20 "solid" "purple")))
|
|
(image-width (rectangle 0 10 "solid" "purple"))]
|
|
}
|
|
|
|
@defproc[(image-height [i image?]) (and/c integer? (not/c negative?) exact?)]{
|
|
Returns the height of @racket[i].
|
|
|
|
@image-examples[(image-height (ellipse 30 40 "solid" "orange"))
|
|
(image-height (circle 30 "solid" "orange"))
|
|
(image-height (overlay (circle 20 "solid" "orange")
|
|
(circle 30 "solid" "purple")))
|
|
(image-height (rectangle 10 0 "solid" "purple"))]
|
|
}
|
|
|
|
@defproc[(image-baseline [i image?]) (and/c integer? (not/c negative?) exact?)]{
|
|
Returns the distance from the top of the image to its baseline.
|
|
Unless the image was constructed with @racket[text] or @racket[text/font],
|
|
this will be the same as its height.
|
|
|
|
@image-examples[(image-baseline (text "Hello" 24 "black"))
|
|
(image-height (text "Hello" 24 "black"))
|
|
(image-baseline (rectangle 100 100 "solid" "black"))
|
|
(image-height (rectangle 100 100 "solid" "black"))]
|
|
}
|
|
|
|
@section{Image Predicates}
|
|
|
|
This section lists predicates for the basic structures provided by the image library.
|
|
|
|
@defproc[(image? [x any/c]) boolean?]{
|
|
Determines if @racket[x] is an image. Images are returned by functions
|
|
like @racket[ellipse] and @racket[rectangle] and
|
|
accepted by functions like @racket[overlay] and @racket[beside].
|
|
|
|
Additionally, images inserted into a DrRacket window are treated as
|
|
bitmap images, as are instances of @racket[image-snip%] and @racket[bitmap%].
|
|
}
|
|
|
|
@defproc[(mode? [x any/c]) boolean?]{
|
|
Determines if @racket[x] is a mode suitable for
|
|
constructing images. It can be one of
|
|
@racket['solid], @racket["solid"], @racket['outline],
|
|
or @racket["outline"], indicating if the shape is
|
|
filled in or not.
|
|
}
|
|
|
|
@defproc[(image-color? [x any/c]) boolean?]{
|
|
|
|
Determines if @racket[x] represents a color. Strings, symbols,
|
|
and @racket[color] structs are allowed as colors.
|
|
|
|
For example,
|
|
@racket["magenta"], @racket["black"], @racket['orange], and @racket['purple]
|
|
are allowed. Colors are not case-sensitive, so
|
|
@racket["Magenta"], @racket["Black"], @racket['Orange], and @racket['Purple]
|
|
are also allowed, and are the same colors as in the previous sentence.
|
|
If a string or symbol color name is not recognized, black is used in its place.
|
|
|
|
The complete list of colors is available in the documentation for
|
|
@racket[color-database<%>].
|
|
|
|
}
|
|
|
|
@defstruct[color ([red (and/c natural-number/c (<=/c 255))]
|
|
[green (and/c natural-number/c (<=/c 255))]
|
|
[blue (and/c natural-number/c (<=/c 255))])]{
|
|
The @racket[color] struct defines a color with red, green, and blue components
|
|
that range from @racket[0] to @racket[255].
|
|
}
|
|
|
|
@defproc[(y-place? [x any/c]) boolean?]{
|
|
Determines if @racket[x] is a placement option
|
|
for the vertical direction. It can be one
|
|
of
|
|
@racket["top"],
|
|
@racket['top],
|
|
@racket["bottom"],
|
|
@racket['bottom],
|
|
@racket["middle"],
|
|
@racket['middle],
|
|
@racket["center"],
|
|
@racket['center],
|
|
@racket["baseline"], or
|
|
@racket['baseline].
|
|
|
|
The baseline of an image is the place where the bottoms any letters line up, not counting descenders, e.g. the tail on ``y'' or ``g'' or ``j''.
|
|
|
|
|
|
}
|
|
|
|
@defproc[(x-place? [x any/c]) boolean?]{
|
|
Determines if @racket[x] is a placement option
|
|
for the horizontal direction. It can be one
|
|
of @racket["left"],
|
|
@racket['left],
|
|
@racket["right"],
|
|
@racket['right],
|
|
@racket["middle"],
|
|
@racket['middle],
|
|
@racket["center"], or
|
|
@racket['center].
|
|
}
|
|
|
|
@defproc[(angle? [x any/c]) boolean?]{
|
|
Determines if @racket[x] is an angle, namely
|
|
a real number between @racket[0] (inclusive)
|
|
and @racket[360] (exclusive).
|
|
}
|
|
|
|
@defproc[(side-count? [x any/c]) boolean?]{
|
|
Determines if @racket[x] is an integer
|
|
greater than or equal to @racket[3].
|
|
}
|
|
|
|
@defproc[(step-count? [x any/c]) boolean?]{
|
|
Determines if @racket[x] is an integer greater than or equal to @racket[1].
|
|
}
|
|
|
|
@defstruct[pen ([color image-color?]
|
|
[width (and/c real? (<=/c 0 255))]
|
|
[style pen-style?]
|
|
[cap pen-cap?]
|
|
[join pen-join?])]{
|
|
The @racket[pen] struct specifies how the drawing library draws lines.
|
|
|
|
|
|
A good default for @racket[style] is @racket["solid"], and
|
|
good default values for the @racket[cap] and @racket[join] fields
|
|
are @racket["round"].
|
|
|
|
Using @racket[0] as a width is special; it means to always draw the
|
|
smallest possible, but visible, pen. This means that the pen will always
|
|
be one pixel in size, no matter how the image is scaled.
|
|
}
|
|
|
|
@defproc[(pen-style? [x any/c]) boolean?]{
|
|
Determines if @racket[x] is a valid pen style.
|
|
It can be one of
|
|
@racket["solid"], @racket['solid],
|
|
@racket["dot"], @racket['dot],
|
|
@racket["long-dash"], @racket['long-dash],
|
|
@racket["short-dash"], @racket['short-dash],
|
|
@racket["dot-dash"], or @racket['dot-dash].
|
|
}
|
|
|
|
@defproc[(pen-cap? [x any/c]) boolean?]{
|
|
Determines if @racket[x] is a valid pen cap.
|
|
It can be one of
|
|
@racket["round"], @racket['round],
|
|
@racket["projecting"], @racket['projecting],
|
|
@racket["butt"], or @racket['butt].
|
|
}
|
|
|
|
@defproc[(pen-join? [x any/c]) boolean?]{
|
|
Determines if @racket[x] is a valid pen join.
|
|
It can be one of
|
|
@racket["round"], @racket['round],
|
|
@racket["bevel"], @racket['bevel],
|
|
@racket["miter"], or @racket['miter].
|
|
}
|
|
|
|
@section{Equality Testing of Images}
|
|
|
|
Two images are equal if they draw exactly the same way, at their current size
|
|
(not neccessarily at all sizes).
|
|
|
|
@section[#:tag "nitty-gritty"]{The nitty gritty of pixels, pens, and lines}
|
|
|
|
The image library treats coordinates as if they are in the upper-left corner
|
|
of each pixel, and infinitesimally small.
|
|
|
|
Thus, when drawing a solid @racket[square] of whose side-length is 10, the image library
|
|
colors in all of the pixels enclosed by the @racket[square] starting at the upper
|
|
left corner of (0,0) and going down to the upper left corner of (10,10),
|
|
so the pixel whose upper left at (9,9) is colored in, but the pixel
|
|
at (10,10) is not. All told, 100 pixels get colored in, just as expected for
|
|
a @racket[square] with a side length of 10.
|
|
|
|
When drawing lines, however, things get a bit more complex. Specifically,
|
|
imagine drawing the outline of that rectangle. Since the border is
|
|
between the pixels, there really isn't a natural pixel to draw to indicate
|
|
the border. Accordingly, when drawing an outline @racket[square] (without a
|
|
@racket[pen] specification, but just a color as the last argument),
|
|
the image library uses a pen whose width is 1 pixel, but draws a line
|
|
centered at the point (0.5,0.5) that goes down and around to the point (10.5,10.5).
|
|
This means that the outline slightly exceeds the bounding box of the shape.
|
|
Specifically, the upper and left-hand lines around the square are within
|
|
the bounding box, but the lower and right-hand lines are just outside.
|
|
|
|
The special case of adding 0.5 to each coordinate when drawing the square
|
|
applies to all polygon-based shapes, but does not apply when a @racket[pen]
|
|
is passed as the last argument to create the shape.
|
|
In that case, not adjustment of the pixels is performed and using a one
|
|
pixel wide pen draws the pixels above and below the line, but each with
|
|
a color that is half of the intensity of the given color. Using a
|
|
@racket[pen] with with two, colors the pixels above and below the line
|
|
with the full intensity.
|
|
|
|
|
|
@;-----------------------------------------------------------------------------
|
|
@section{Exporting Images to Disk}
|
|
|
|
In order to use an image as an input to another program (Photoshop, e.g., or
|
|
a web browser), it is necessary to represent it in a format that these programs
|
|
can understand. The @racket[save-image] function provides this functionality,
|
|
writing an image to disk using the @tt{PNG} format. Since this
|
|
format represents an image using a set of pixel values, an image written to disk
|
|
generally contains less information than the image that was written, and cannot be scaled
|
|
or manipulated as cleanly (by any image program).
|
|
|
|
@defproc[(save-image [image image?] [filename path-string?]) boolean?]{
|
|
writes an image to the path specified by @racket[filename], using the
|
|
@tt{PNG} format.}
|
|
|
|
|