607 lines
24 KiB
Racket
607 lines
24 KiB
Racket
#lang scribble/doc
|
|
|
|
@(require (for-label (only-in scheme/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
|
|
scheme/gui/base)
|
|
lang/posn
|
|
"shared.ss"
|
|
"image-util.ss"
|
|
scribble/manual)
|
|
|
|
@teachpack["image"]{Images}
|
|
|
|
@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 DrScheme).
|
|
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 color?])
|
|
image?]{
|
|
Constructs a circle with the given radius, height, mode, and color.
|
|
|
|
@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 color?]) image?]{
|
|
Constructs an ellipsis with the given width, height, mode, and color.
|
|
|
|
@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 color?])
|
|
image?]{
|
|
Constructs a upward-pointing equilateral triangle.
|
|
The @scheme[side-length] argument
|
|
determines the
|
|
length of the side of the triangle.
|
|
|
|
@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 color?])
|
|
image?]{
|
|
|
|
Constructs a triangle with a right angle where the two sides adjacent
|
|
to the right angle have lengths @scheme[side-length1] and @scheme[side-length2].
|
|
|
|
@image-examples[(right-triangle 36 48 "solid" "black")]
|
|
}
|
|
|
|
@defproc[(isosceles-triangle [side-length (and/c real? (not/c negative?))]
|
|
[angle angle?]
|
|
[mode mode?]
|
|
[color color?])
|
|
image?]{
|
|
|
|
Creates a triangle with two equal-length sides, of length @scheme[side-length]
|
|
where the angle between those sides is @scheme[angle]. The third
|
|
leg is straight, horizontally. If the angle is less than
|
|
@scheme[180], then the triangle will point up and if the @scheme[angle]
|
|
is more, then the triangle will point down.
|
|
|
|
@image-examples[(isosceles-triangle 200 170 "solid" "seagreen")
|
|
(isosceles-triangle 60 30 "solid" "aquamarine")
|
|
(isosceles-triangle 60 330 "solid" "lightseagreen")]
|
|
}
|
|
|
|
|
|
@defproc[(square [side-length (and/c real? (not/c negative?))]
|
|
[mode mode?]
|
|
[color color?])
|
|
image?]{
|
|
|
|
Constructs a square.
|
|
|
|
@image-examples[(square 40 "solid" "slateblue")
|
|
(square 50 "outline" "darkmagenta")]
|
|
|
|
}
|
|
|
|
@defproc[(rectangle [width real?] [height real?] [mode mode?] [color color?]) image?]{
|
|
Constructs a rectangle with the given width, height, mode, and color.
|
|
@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 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 @scheme[angle] and the left and right are @scheme[(- 180 angle)].
|
|
|
|
@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 color?])
|
|
image?]{
|
|
Constructs a regular polygon with @scheme[side-count] sides.
|
|
|
|
@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 color?])
|
|
image?]{
|
|
Constructs a star with five points. The @scheme[side-length] argument
|
|
determines the side length of the enclosing pentagon.
|
|
|
|
@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 color?])
|
|
image?]{
|
|
|
|
Constructs an arbitrary regular star polygon (a generalization of the regular polygons).
|
|
The polygon is enclosed by a regular polygon with @scheme[side-count] sides each
|
|
@scheme[side-length] long. The polygon is actually constructed by going from vertex to
|
|
vertex around the regular polgon, but skipping over every @scheme[step-count] verticies.
|
|
|
|
For examples, if @scheme[side-count] is @scheme[5] and @scheme[step-count] is @scheme[2],
|
|
then this function produces a shape just like @scheme[star].
|
|
|
|
@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 [verticies (listof posn?)]
|
|
[mode mode?]
|
|
[color color?])
|
|
image?]{
|
|
Constructs a polygon connecting the given verticies.
|
|
|
|
@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")]
|
|
}
|
|
|
|
@defproc[(line [x1 real?] [y1 real?] [color 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?]
|
|
[color color?])
|
|
image?]{
|
|
|
|
Adds a line to the image @scheme[image], starting from the point (@scheme[x1],@scheme[y1])
|
|
and going to the point (@scheme[x2],@scheme[y2]).
|
|
|
|
@image-examples[(add-line (ellipse 40 40 "outline" "maroon")
|
|
0 40 40 0 "maroon")
|
|
(add-line (ellipse 80 60 "outline" "darkolivegreen")
|
|
(+ 40 (* 40 (cos (* pi 1/4))))
|
|
(+ 30 (* 30 (sin (* pi 1/4))))
|
|
(+ 40 (* 40 (cos (* pi 5/4))))
|
|
(+ 30 (* 30 (sin (* pi 5/4))))
|
|
"darkolivegreen")]
|
|
}
|
|
|
|
@defproc[(text [string string?] [font-size (and/c integer? (<=/c 1 255))] [color 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 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 @scheme[face] and the @scheme[family] combine to give the complete typeface. If
|
|
@scheme[face] is available on the system, it is used, but if not then a default typeface
|
|
based on the @scheme[family] is chosen. The @scheme[style] controls if the face is italic
|
|
or not (under Windows and Mac OS X, @scheme['slant] and @scheme['italic] are the same),
|
|
the @scheme[weight] controls if it is boldface (or light), and @scheme[underline?]
|
|
determines if the face is underlined. For more details on these arguments, see @scheme[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)]
|
|
}
|
|
|
|
|
|
@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 upper-left corners.
|
|
|
|
@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"))]
|
|
|
|
}
|
|
|
|
@defproc[(overlay/places [x-place x-place?] [y-place y-place?] [i1 image?] [i2 image?] [is image?] ...) image?]{
|
|
Overlays all of its image arguments, much like the @scheme[overlay] function, but using
|
|
@scheme[x-place] and @scheme[y-place] to determine where the images are lined up. For example, if
|
|
@scheme[x-place] and @scheme[y-place] are both @scheme["middle"], then the images are lined up
|
|
on their centers.
|
|
|
|
@image-examples[(overlay/places "middle" "middle"
|
|
(rectangle 30 60 "solid" "orange")
|
|
(ellipse 60 30 "solid" "purple"))
|
|
(overlay/places "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 @scheme[i1] on top of @scheme[i2] after
|
|
shifting @scheme[i2] over by @scheme[x] pixels to the right and @scheme[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[(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 top edges.
|
|
|
|
@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/places [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 @scheme[y-place] argument. For example, if @scheme[y-place]
|
|
is @scheme["middle"], then the images are placed side by side with their centers
|
|
lined up with each other.
|
|
|
|
@image-examples[(beside/places "bottom"
|
|
(ellipse 20 70 "solid" "lightsteelblue")
|
|
(ellipse 20 50 "solid" "mediumslateblue")
|
|
(ellipse 20 30 "solid" "slateblue")
|
|
(ellipse 20 10 "solid" "navy"))
|
|
|
|
(beside/places "center"
|
|
(ellipse 20 70 "solid" "mediumorchid")
|
|
(ellipse 20 50 "solid" "darkorchid")
|
|
(ellipse 20 30 "solid" "purple")
|
|
(ellipse 20 10 "solid" "indigo"))
|
|
|
|
(beside/places "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 left edges.
|
|
|
|
@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/places [y-place y-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 @scheme[x-place] argument. For example, if @scheme[x-place]
|
|
is @scheme["middle"], then the images are placed above each other with their centers
|
|
lined up.
|
|
|
|
@image-examples[(above/places "right"
|
|
(ellipse 70 20 "solid" "gold")
|
|
(ellipse 50 20 "solid" "goldenrod")
|
|
(ellipse 30 20 "solid" "darkgoldenrod")
|
|
(ellipse 10 20 "solid" "sienna"))
|
|
|
|
(above/places "center"
|
|
(ellipse 70 20 "solid" "yellowgreen")
|
|
(ellipse 50 20 "solid" "olivedrab")
|
|
(ellipse 30 20 "solid" "darkolivegreen")
|
|
(ellipse 10 20 "solid" "darkgreen"))]
|
|
|
|
|
|
}
|
|
|
|
@section{Rotating, Scaling, and Framing Images}
|
|
|
|
@defproc[(rotate [angle angle?] [image image?]) image?]{
|
|
Rotates @scheme[image] by @scheme[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/places
|
|
"center"
|
|
(rectangle 40 20 "solid" "darkseagreen")
|
|
(rectangle 20 100 "solid" "darkseagreen")))]
|
|
|
|
}
|
|
|
|
@defproc[(scale [factor real?] [image image?]) image?]{
|
|
Scales @scheme[image] by @scheme[factor].
|
|
|
|
@image-examples[(scale 2 (ellipse 20 30 "solid" "blue"))
|
|
(ellipse 40 60 "solid" "blue")]
|
|
|
|
|
|
|
|
}
|
|
|
|
@defproc[(scale/xy [x-factor real?] [y-factor real?] [image image?]) image?]{
|
|
Scales @scheme[image] by @scheme[x-factor] horizontally and by
|
|
@scheme[y-factor] vertically.
|
|
|
|
@image-examples[(scale/xy 3
|
|
2
|
|
(ellipse 20 30 "solid" "blue"))
|
|
(ellipse 60 60 "solid" "blue")]
|
|
}
|
|
|
|
|
|
@defproc[(frame [image image?]) image?]{
|
|
Returns an image just like @scheme[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/places "bottom"
|
|
(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 number? positive?)]{
|
|
Returns the width of @scheme[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")))]
|
|
}
|
|
|
|
@defproc[(image-height [i image?]) (and/c number? positive?)]{
|
|
Returns the height of @scheme[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")))]
|
|
}
|
|
|
|
@defproc[(image-baseline [i image?]) (and/c number? positive?)]{
|
|
Returns the distance from the top of the image to its baseline.
|
|
Unless the image was constructed with @scheme[text] or @scheme[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 @scheme[x] is an image. Images are returned by functions
|
|
like @scheme[ellipse] and @scheme[rectangle] and
|
|
accepted by functions like @scheme[overlay] and @scheme[beside].
|
|
|
|
Additionally, images inserted into a DrScheme window are treated as
|
|
bitmap images, as are instances of @scheme[image-snip%] and @scheme[bitmap%].
|
|
}
|
|
|
|
@defproc[(mode? [x any/c]) boolean?]{
|
|
Determines if @scheme[x] is a mode suitable for
|
|
constructing images. It can be one of
|
|
@scheme['solid], @scheme["solid"], @scheme['outline],
|
|
or @scheme["outline"], indicating if the shape is
|
|
filled in or not.
|
|
}
|
|
|
|
@defproc[(color? [x any/c]) boolean?]{
|
|
|
|
Determines if @scheme[x] represents a color. Both strings and symbols are allowed as colors.
|
|
For example,
|
|
@scheme["magenta"], @scheme["black"], @scheme['orange], and @scheme['purple]
|
|
are allowed. Colors are not case-sensitive, so
|
|
@scheme["Magenta"], @scheme["Black"], @scheme['Orange], and @scheme['Purple]
|
|
are also allowed, and are the same colors as in the previous sentence.
|
|
|
|
If a color is not recognized, black is used in its place.
|
|
|
|
The complete list of colors is available in the documentation for
|
|
@scheme[color-database<%>].
|
|
|
|
}
|
|
|
|
@defproc[(y-place? [x any/c]) boolean?]{
|
|
Determines if @scheme[x] is a placement option
|
|
for the vertical direction. It can be one
|
|
of
|
|
@scheme["top"],
|
|
@scheme['top],
|
|
@scheme["bottom"],
|
|
@scheme['bottom],
|
|
@scheme["middle"],
|
|
@scheme['middle],
|
|
@scheme["center"],
|
|
@scheme['center],
|
|
@scheme["baseline"], or
|
|
@scheme['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 @scheme[x] is a placement option
|
|
for the horizontal direction. It can be one
|
|
of @scheme["left"],
|
|
@scheme['left],
|
|
@scheme["right"],
|
|
@scheme['right],
|
|
@scheme["middle"],
|
|
@scheme['middle],
|
|
@scheme["center"], or
|
|
@scheme['center].
|
|
}
|
|
|
|
@defproc[(angle? [x any/c]) boolean?]{
|
|
Determines if @scheme[x] is an angle, namely
|
|
a real number between @scheme[0] (inclusive)
|
|
and @scheme[360] (exclusive).
|
|
}
|
|
|
|
@defproc[(side-count? [x any/c]) boolean?]{
|
|
Determines if @scheme[x] is an integer
|
|
greater than or equal to @scheme[3].
|
|
}
|
|
|
|
@section{Equality Testing of Images}
|
|
|
|
Image equality testing is done structurally, i.e., based on
|
|
the construction of the image,
|
|
although with certain, expected equivalences. For example,
|
|
two rectangles with the same width, height, color, and mode
|
|
are equal. Similarly, constructing a 20x10 rectangle and
|
|
then rotating it by 90 degress is equal to a 10x20 rectangle
|
|
(provided they have the same color and mode).
|
|
|
|
Equality testing may contain a few nuances, though:
|
|
@itemize[
|
|
@item{Overlaying two images in opposite orders is never equal. For example,
|
|
these two images are not @scheme[equal]:
|
|
@schemeblock[(overlay/xy (rectangle 30 10 "solid" "blue")
|
|
0
|
|
10
|
|
(rectangle 30 10 "solid" "red"))]
|
|
@schemeblock[(overlay/xy (rectangle 30 10 "solid" "red")
|
|
0
|
|
-10
|
|
(rectangle 30 10 "solid" "blue"))]
|
|
even thought they may appear to be the same when drawn.
|
|
|
|
The rationale for them being different is that, at some scale factor,
|
|
they will draw differently; specifically when they are scaled down
|
|
far enough, the first will appear to be a single red pixel and the second will appear to
|
|
be a single blue pixel.}
|
|
@item{When rotating images, the internal calculations involve real numbers, not just
|
|
rationals and thus must be approximated with Scheme's inexact numbers, causing
|
|
small roundoff errors that make the images draw slightly differently.
|
|
|
|
To combat this problem, use @scheme[equal~?] to compare the images,
|
|
or @scheme[check-within] for test suites involving images.}
|
|
|
|
@item{Combining a series of line segments to form a polygon produces
|
|
an image that is different than the polygon.}
|
|
|
|
@item{In order to make equality on images created with
|
|
@scheme[text] and @scheme[text/font]
|
|
work well, each string passed to either of those functions results
|
|
in a number of horizontally aligned images, one for each letter in the
|
|
string. This means that, for example
|
|
@schemeblock[(equal? (beside/places "baseline"
|
|
(text "a" 18 "black")
|
|
(text "b" 18 "black"))
|
|
(text "ab" 18 "black"))]
|
|
is true, but that subtle aspects of font drawing may be wrong, since
|
|
the underlying toolkit only gets a single letter at a time, instead
|
|
of the entire word (or sentence).
|
|
|
|
The most obvious way that this shows up is in the handling of ligatures.
|
|
For example, the letter combinations ``ff'' and ``fi'' and ``fl'' are
|
|
generally drawn intertwined when they appear together, and thus an ``f''
|
|
drawn separately from an ``i'' looks different than the ligature ``fi''.
|
|
For example, here is how 24 point Times font looks when the word ``refill''
|
|
is drawn, first with ligatures and then without:
|
|
@centerline{@image["2htdp/scribblings/ligature.png"]}.
|
|
}
|
|
]
|