Fundamentals of Computer Science I: Media Computing (CS151.01 2008S)
Primary: [Front Door] [Syllabus] - [Academic Honesty] [Instructions]
Current: [Outline] [EBoard] [Reading] [Lab] [Assignment]
Groupings: [Assignments] [EBoards] [Examples] [Exams] [Handouts] [Labs] [Outlines] [Projects] [Readings]
References: [A-Z] [Primary] [Scheme Report (R5RS)] [Scheme Reference] [DrScheme Manual]
Related Courses: [CSC151.02 2008S (Davis)] [CSC151 2007F (Rebelsky)] [CSC151 2007S (Rebelsky)] [CSCS151 2005S (Stone)]
Summary: In this laboratory, you will explore ways to store images more efficiently by representing the data in an encoded form rather than in a human-readable form.
a. Review the lab from the previous day.
b. Add to your definitions pane the revised procedures created
during that lab, image-write-pixmap
and
image-read-pixmap
. If you don't have that code,
or your don't trust your code, you can find sample solutions
at the end of this lab.
c. Add to your definitions pane the file-size
and
image-random-fill!
procedures, also available
at the end of this lab.
d. Add to your definitions pane the first versions of
rgb-write
and rgb-read
.
;;; Procedure: ;;; rgb-write ;;; Parameters: ;;; color, an rgb color ;;; port, the port to which to write the color ;;; Purpose: ;;; Write the color to the specified port ;;; Preconditions: ;;; port is open for writing. ;;; Postconditions: ;;; When read with rgb-read, the data just appended to the file ;;; will give color. (define rgb-write (lambda (color port) (write color port) (newline port))) ;;; Procedure: ;;; rgb-read ;;; Parameters: ;;; port, the name of an input port ;;; Purpose: ;;; Reads an RGB color from the file. ;;; Produces: ;;; color, an RGB color (or <eof>, if the port is at the end of ;;; the file) ;;; Preconditions: ;;; port is open for reading. ;;; port is at the place in a file after which the next data was ;;; written by rgb-write. ;;; Postconditions: ;;; color is the color written by the call to rgb-write mentioned ;;; in the preconditions. (define rgb-read (lambda (port) (read port)))
a. Create a new 10x10 image named all-white
,
all of whose pixels are white.
b. Using image-write-pixmap
, save that
image to a file named all-white.pixmap
.
c. How many characters do you expect to be in that file?
d. Check your answer experimentally, using
file-size
. If you're not sure about
why you got the number you did, you may want to open
all-white.pixmap
to look at what form it has.
(That is, in DrScheme, select
from the menu, navigate to the file you
just created, and select it.)
e. Make a new 10x10 image, all-black
, in which all of the
pixels are black. (An easy way to do this is to first set the
background color to black, and then create the new image.)
f. Using image-write-pixmap
, save that new image
to all-black.pixmap
.
g. How many characters do you expect to be in that file?
h. Check your answer experimentally, using
file-size
. If you're not sure about
why you got the number you did, you may want to open
all-black.pixmap
to look at what form it has.
i. Create another 10x10 image and name it random-colors
.
Fill the image with random colors, using
image-random-fill!
.
j. Using image-write-pixmap
, save that image
to random-colors.pixmap
.
k. How many characters do you expect to be in that file?
l. Check your answer experimentally, using
file-size
. If you're not sure about
why you got the number you did, you may want to open
random-colors.pixmap
to look at what form it has.
m. If you got different file sizes for the three files, explain why.
a. Replace the definitions of rgb-write
and
rgb-read
with the component-based human-readable
versions below.
(define rgb-write (lambda (color port) (write (rgb-red color) port) (display " " port) (write (rgb-green color) port) (display " " port) (write (rgb-blue color) port) (newline port))) (define rgb-read (lambda (port) (let* ((red (read port)) (green (read port)) (blue (read port))) (if (eof-object? blue) blue (rgb-new red green blue)))))
b. Write the three images you created in Exercise 1 to three files,
new-all-white.pixmap
,
new-all-black.pixmap
, and
new-random-colors.pixmap
.
c. Predict the size of each file.
d. Check your predictions using file-size
.
e. Using these results, predict the size of a file for a 10x20 image of random pixels.
f. Check your answer experimentally.
a. Add the definitions of int-write
, int-read
,
and int-peek
to your definitions pane.
(define int-write (lambda (int port) (write-char (integer->char (+ int 1)) port))) (define int-read (lambda (port) (let ((ch (read-char port))) (if (eof-object? ch) ch (- (char->integer ch) 1))))) (define int-peek (lambda (port) (let ((ch (peek-char port))) (if (eof-object? ch) ch (- (char->integer ch) 1)))))
b. Using int-write
, write five bytes of your choice to
a file named data
. For example,
>
(define dataport (open-output-file "data"))
>
(int-write 6 dataport)
>
(int-write 17 dataport)
>
(int-write 64 dataport)
>
(int-write 32 dataport)
>
(int-write 42 dataport)
>
(close-output-port dataport)
c. Predict the size of that file.
d. Using file-size
, determine the size of the file.
e. Read the data back from the file using int-read
.
>
(define inport (open-input-file "data"))
>
(int-read inport)
6
...>
(int-read inport)
<eof>
>
(close-input-port inport)
f. What do you expect to have happen if you read the data back from
the file using read-char
?
g. Check your answer experimentally.
>
(define inport (open-input-file "data"))
>
(read-char inport)
...>
(read-char inport)
<eof>
>
(close-input-port inport)
h. What do you expect to have happen if you read the data back from
the file using read
?
i. Check your answer experimentally.
>
(define inport (open-input-file "data"))
>
(read inport)
...>
(read inport)
<eof>
>
(close-input-port inport)
j. What do your results suggest about reading values from a file
created by int-write
?
a. As you may recall, the file
/home/rebelsky/glimmer/samples/hi.txt
contains
the text Hi There!
. What do you expect to have happen if
you use int-read
to read from that file?
b. Check your answer experimentally.
>
(define inport (open-input-file "/home/rebelsky/glimmer/samples/hi.txt"))
>
(int-read inport)
...>
(int-read inport)
<eof>
>
(close-input-port inport)
We suggested in the reading that it is useful to represent colors as byte sequences, rather than in human-readable form. To do so, we need to make some changes to our code.
a. List the changes you expect to have to make in order to use bytes, rather than text, for storing our images.
b. Replace the definitions of rgb-write
and rgb-read
to the ones that use
int-write
and int-read
.
(define rgb-write (lambda (color port) (int-write (rgb-red color) port) (int-write (rgb-green color) port) (int-write (rgb-blue color) port))) (define rgb-read (lambda (port) (let* ((red (int-read port)) (green (int-read port)) (blue (int-read port))) (if (eof-object? blue) blue (rgb-new red green blue)))))
c. Update the definition of image-write-pixmap
to (i) drop any calls to newline
and (ii) use
int-write
to write the width and height.
d. Update the definition of image-read-pixmap
to use int-read
to read the width and
height.
e. Using these updated versions, write and then read a small sample image. (Note that your old saved files won't work, because we changed the method for storing the data.)
In case you've forgotten, the point of all of this work was to write our images using smaller files. Let's see if our strategy worked, using the same examples we used before.
a. Create three images, each 10x10, the first filled with all white pixels, the second with all black pixels, the third with random pixels.
b. Write the three images to three files,
newer-all-white.pixmap
,
newer-all-black.pixmap
, and
newer-random-colors.pixmap
.
c. Predict the size of each file.
d. Check your predictions using file-size
.
e. Using these results, predict the size of a file for a random 10x20 image.
f. Check your answer experimentally.
g. Reflect on what you learned from all of today's work.
The following extra exercises are repeated from the laboratory on pixmaps, as it is not likely that many students had the opportunity to do them in the first lab.
Right now, when you read a pixmap into a larger image, it fills in the larger image, row-by-row, until you run out of colors. Instead, we could specify the section of the larger image to fill in. What should we specify? Presumably, the left edge, top edge, width, and height of the region to fill in.
Write a procedure, (
,
that reads from a pixmap into a rectangular region in an image.
image-read-pixmap-region!
image
filename
left
top
width
height
)
For example, to read from a recently created image file into the 4x3 section starting at 5,7, we might write
>
(region-read-pixmap! big-canvas "image3.pixmap" 5 7 4 3)
Your procedure should verify that the width and height stored in the pixmap file match the width and height of the region. Your procedure should also verify that the region is completely contained in the image.
If we're willing to read pixmaps into sections of images, we might as well provide the converse operations: Writing pixmaps from sections of images.
Write a procedure, (
,
that writes a region of an image to the specified file.
image-write-pixmap-region
image
file
left
top
width
height
)
As you've seen, the computer is willing to treat almost any file as data. That is, even if you've written text, you can read that text back as numbers.
Here's a version of image-read-pixmap
(renamed appropriately), that reads an image without paying
attention to the size.
;;; Problems: ;;; This procedure throws an inappropriate error when end-of-file is ;;; reached before the end of the image. Can you fix this bug? (define image-read-pixels! (lambda (image filename) (let ((width (image-width image)) (height (image-height image)) (port (open-input-file filename))) (let kernel ((col 0) (row 0)) (cond ((> (+ col row) (+ (- width 1) (- height 1))) (close-input-port port) image) ((eof-object? (peek-char port)) (close-input-port port) (throw "image-read-pixels!: Premature end of file.")) ((>= col width) (kernel 0 (+ row 1))) (else (image-set-pixel! image col row (rgb-read port)) (kernel (+ col 1) row)))))))
Pick a few interesting text files (e.g., papers you've written, programs you've written for this class, assorted Web pages ) and turn them into images.
;;; Procedure: ;;; image-write-pixmap ;;; Parameters: ;;; image, an image ;;; filename, a string ;;; Purpose: ;;; Writes the pixmap information on image to the file. ;;; Produces: ;;; [Nothing; Called for the side effect.] ;;; Preconditions: ;;; filename is a valid file name. ;;; Postconditions: ;;; The file named by filename now contains a sequence of integers, ;;; one for each RGB color in image. (define image-write-pixmap (lambda (image filename) (let ((width (image-width image)) (height (image-height image)) (port (open-output-file filename))) (write width port) (newline port) (write height port) (newline port) (let kernel ((col 0) (row 0)) (cond ((>= row height) (close-output-port port) image) ((>= col width) (kernel 0 (+ row 1))) (else (rgb-write (image-get-pixel image col row) port) (kernel (+ col 1) row))))))) ;;; Procedure: ;;; image-read-pixmap ;;; Parameters: ;;; filename, a string ;;; Purpose: ;;; Read pixmap data from the specified file, returning a new ;;; image from that data. ;;; Produces: ;;; image, an image. ;;; Preconditions: ;;; filename names a file. ;;; That file was created by image-write-pixmap. ;;; Postconditions: ;;; image contains teh same colors in the same positions as the image ;;; previously written with image-write-pixmap. (define image-read-pixmap (lambda (filename) (let* ((port (open-input-file filename)) (width (read port)) (height (read port)) (image (image-new width height))) (let kernel ((col 0) (row 0)) (cond ((> (+ col row) (+ (- width 1) (- height 1))) (let ((next-color (rgb-read port))) (close-input-port port) (if (not (eof-object? next-color)) (throw "image-read-pixmap!: Data remain in file after image was competely read"))) image) ((eof-object? (peek-char port)) (close-input-port port) (throw "image-read-pixmap!: Premature end of file.")) ((>= col width) (kernel 0 (+ row 1))) (else (let ((next-color (rgb-read port))) (cond ((eof-object? next-color) (close-input-port port) (throw "image-read-pixmap!: Premature end of file.")) (else (image-set-pixel! image col row next-color) (kernel (+ col 1) row)))))))))) ;;; Procedure: ;;; image-random-fill! ;;; Parameters: ;;; image, an image ;;; Purpose: ;;; Fills the image with a random set of colors. ;;; Produces: ;;; [Nothing; called for the side effect] ;;; Preconditions: ;;; image identifies a valid image. ;;; Postconditions: ;;; Every pixel in the image has an unpredictable color. (define image-random-fill! (lambda (image) (image-compute-pixels! image 0 0 (- (image-width image) 1) (- (image-height image) 1) (lambda (pos) (rgb-new (random 255) (random 255) (random 255)))))) ;;; Procedure: ;;; file-size ;;; Parameters: ;;; filename, a string ;;; Purpose: ;;; Determines the number of characters in the file. ;;; Produces: ;;; s, an integer. ;;; Preconditions: ;;; filename names a valid file. ;;; Postconditions: ;;; s is the size of file. That is, ;;; s read-char commands from file will succeed. ;;; The s+1st read from file will fail. (define file-size (lambda (fname) (file-size-kernel (open-input-file fname) 0))) (define file-size-kernel (lambda (source size) (cond ((eof-object? (read-char source)) (close-input-port source) size) (else (file-size-kernel source (+ size 1))))))
Primary: [Front Door] [Syllabus] - [Academic Honesty] [Instructions]
Current: [Outline] [EBoard] [Reading] [Lab] [Assignment]
Groupings: [Assignments] [EBoards] [Examples] [Exams] [Handouts] [Labs] [Outlines] [Projects] [Readings]
References: [A-Z] [Primary] [Scheme Report (R5RS)] [Scheme Reference] [DrScheme Manual]
Related Courses: [CSC151.02 2008S (Davis)] [CSC151 2007F (Rebelsky)] [CSC151 2007S (Rebelsky)] [CSCS151 2005S (Stone)]
Copyright (c) 2007-8 Janet Davis, Matthew Kluber, and Samuel A. Rebelsky. (Selected materials copyright by John David Stone and Henry Walker and used by permission.)
This material is based upon work partially supported by the National Science Foundation under Grant No. CCLI-0633090. Any opinions, findings, and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the National Science Foundation.
This work is licensed under a Creative Commons
Attribution-NonCommercial 2.5 License. To view a copy of this
license, visit http://creativecommons.org/licenses/by-nc/2.5/
or send a letter to Creative Commons, 543 Howard Street, 5th Floor,
San Francisco, California, 94105, USA.