by Vladimir Nikishkin (lockywolf gmail.com)
This SRFI is currently in final status. Here is an explanation of each status that a SRFI can hold. To provide input on this SRFI, please send email to srfi-203@nospamsrfi.schemers.org
. To subscribe to the list, follow these instructions. You can access previous messages via the mailing list archive.
This SRFI proposes a simple library for programmatic drawing of pictures compatible with Section 2.2.4 of Structure and Interpretation of Computer Programs.
It aims to close the gap between the Scheme suggested for study in the book and portable Scheme.
Structure and Interpretation of Computer Programs (SICP), by Harold Abelson and Gerald Jay Sussman with Julie Sussman, is one of the world's most famous programming textbooks. The code examples in the book are given in Scheme, and the exercises are mostly expected to be done in Scheme. The examples and exercises are best executed with a Scheme system that implements a reasonable subset of the Scheme language. Furthermore, the textbook assumes the existence of several primitives not included in any of the Scheme reports. Most of these primitives are already either covered by other relevant SRFIs, or can be implemented on top of those. The picture language of Section 2.2.4 cannot, however, be portably implemented using any of the portable Scheme libraries. This SRFI aims to fill this gap.
Potentially, this SRFI may serve as one of the building blocks on which another SRFI, dedicated to providing in full all the language facilities assumed by SICP, may be implemented.
This SRFI is not a complete implementation of the picture language as it is presented in Section 2.2.4. This is intentional. The scope of this SRFI is not to implement the whole drawing library presented, but only to implement a minimal subset on top of which the code from the book can be run. This leads to procedures accepting as arguments certain data structures for which constructors are not provided within this SRFI. Those should be sufficiently easy to implement using the code from the book. Nevertheless, the code from the sample implementation test file can be reused.
This SRFI can be compared to SRFI 96, which is to SLIB as this SRFI is to the SICP drawing language. SRFI 96 makes no attempt to document SLIB (which has over 200 modules), much less to extend it. Instead, it documents the constants, variables, procedures, and syntax forms that a Scheme must provide in order to fully host SLIB, which amount to less than forty.
A "canvas" is anything that the drawing procedures draw on. It may be a window, or a file, or some other drawing device. Due to the great variety of available Scheme implementations and hardware on which they run, it is hard to specify what is a canvas precisely, but it should be a certain location where the result of the drawing procedures is stored. It may be a file, a buffer, a window, or a certain Scheme object dedicated to keep a list of instructions to be flushed to a real graphics system later.
As far as the code of SICP is concerned, it is legitimate to call any drawing routine at any time, without prior initialization of a canvas. So, each of the drawing routines has to create a canvas if it does not exist. They should, however, draw on an existing one if it does exist.
Many systems are likely to use a so-called "double-buffering"
or "delayed drawing" technique, in which drawing and displaying what has been
drawn are two different operations.
On the other hand, some systems are expected to try and implement this SRFI
in a "value-based" way, that is to change the state of the display by
using some display operation on a Scheme
value. (This is the approach
used by the Kawa sample implementation, which displays the "picture
value" returned by canvas-refresh
in a graphical REPL.)
Other systems may use other routines not specified by this SRFI to
display the "picture value", if pictures are represented as values.
(canvas-reset)
Explanation: Graphics systems differ, and giving a precise definition
to (canvas-reset)
is hard. If the graphics system only supports
a single graphical display (as the DOS systems used to), this procedure
is expected to make this display empty.
If the system is window-based, it will probably create a
new window.
If the only drawing is done at the moment that the "picture value" is
output into the REPL, this procedure is expected to do some off-screen
operations that will ensure that subsequent calls to the drawing
procedures will be drawing on an empty canvas.
(canvas-refresh)
Explanation:
(canvas-refresh)
is an attempt to reconcile as many drawing
approaches as possible.
After a call to (canvas-refresh)
the state of the display
(whatever it may be) is expected to be a faithful representation of the
image drawn by a sequence of calls to the drawing routines, regardless of
the underlying approach that a system is using.
If the system "displays" the return value in some sort of a
graphical REPL (like the Kawa sample implementation does), (canvas-refresh)
returns a
"picture value", that is expected to be displayed by the REPL.
If the system has a separate windowing subsystem, not connected to the
REPL in any meaningful way, the call to (canvas-refresh)
should guarantee that the window on which the canvas is displayed
is presenting the final result of the drawing, and displaying it to the user.
If (canvas-refresh)
is called and no canvas exists, the implementations are expected to
do something reasonable. In the case of the sample file-based implementation,
(canvas-refresh)
returns a file name that could have been
used for drawing, which may or may not exist.
In case of a window-based implementation, it is reasonable to return
a value that could serve as a valid window identifier.
If an implementation displays images in the REPL,
(canvas-refresh)
might return an empty picture value.
(canvas-refresh)
thus has both "pure" and side-effecting
semantics: it may change the display, or it may simply return a value
which can be displayed, or it may do nothing.
(canvas-cleanup)
(draw-line start end)
(car start)
, (car
(cdr start))
and ending at (car end)
, (car
(cdr end))
.
It is an error if start
is not a list of at least two numbers.
It is an error if end
is not a list of at least two numbers.
If the canvas does not exist, it is created.
(rogers v-list)
Draws an image of MIT's founder, William Barton Rogers, as shown in
Figure 2.11 of SICP, on the canvas so that it fits the frame defined
by the vectors (car v-list)
, (car (cdr v-list))
and
(car (cdr (cdr v-list)))
in a natural linear algebraic way.
It is an error if v-list
is not a list of at least three elements,
each of which is a list of at least two numbers.
If the canvas does not exist, it is created.
v-list
may be one of the possible implementations of a frame,
in the SICP terminology. However, in order to avoid nudging the potential
users of the library into a particular implementation of frames, we
opted to specify one of the possible underlying data structures directly.
Converting between this representation, as well as any other representation,
should be a relatively simple exercise.
These procedures, although they are not strictly needed for SICP, may make programming with the picture language less mundane.
(jpeg-file->painter file-name)
If file-name
exists and is a JPEG file,
jpeg-file->painter
returns
a painter similar to rogers
, that is a procedure that
accepts a frame and draws the image located at file-name
shifted, rotated, and skewed to fit into the frame.
Otherwise, the result is unspecified.
(image-file->painter file-name)
If image-name
exists, and is a file that can be
interpreted as containing a representation of an image, and
the implementation supports loading such a kind of files,
image-file->painter
returns
a painter similar to rogers
, that is a procedure that
accepts a frame and draws the image located at file-name
shifted, rotated, and skewed to fit into the frame.
Otherwise, the result is unspecified.
In the simplest case this procedure
can be a synonym to jpeg-file->painter
.
The exemplar use of this SRFI can be found in the
attached srfi-sicp-pictures-test.org
file, which exploits
the org-display-inline-images
feature of Emacs' org-mode
.
(import (scheme red)) (import (srfi 203)) (define (make-vect xcor ycor . o) (append (list xcor) (list ycor) o)) (define (make-frame origin edge1 edge2) (list origin edge1 edge2)) (canvas-reset) (landau (make-frame (make-vect 0 0) (make-vect 0.5 0.0) (make-vect 0.0 0.5))) (rogers (make-frame (make-vect 0.5 0.5) (make-vect 0.5 0.0) (make-vect 0.0 0.5))) (draw-line (make-vect 0.5 0.5) (make-vect 0 1.0)) (define testpainter (jpeg-file->painter "lambda.jpg")) (testpainter (make-frame (make-vect 0.5 0.0) (make-vect 0.5 0.1) (make-vect 0.1 0.5))) (display (canvas-refresh))
The 203.sld
and 203.scm
files constitute
a simple file-based implementation, in which the "system-dependent
identifier" corresponds to a file name.
canvas-name
and canvas-size
should be
parameterised by the same parameterize
form.
The sample implementation litters the file system with bogus files. This is a consequence of the generality. Scheme system specific implementations are encouraged to provide a method of garbage collection.
The extra
directory provides an additional implementation
for Kawa scheme, as well as a test file kawatest.scm
and
additional resources that may be found helpful when implementing this
SRFI.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.