Introduction to Programming in Java: A Multimedia Approach Mark Guzdial and Barbara Ericson

advertisement
i
i
“MAIN”
2004/5/11
page i
i
Introduction to Programming in
Java:
A Multimedia Approach
Mark Guzdial and Barbara Ericson
College of Computing/GVU
Georgia Institute of Technology
PRENTICE HALL, Upper Saddle River, New Jersey 07458
i
i
i
i
i
“MAIN”
2004/5/11
page ii
i
ii
Copyright held by Mark Guzdial and Barbara Ericson, 2004.
i
i
i
i
i
“MAIN”
2004/5/11
page iii
i
iii
Dedicated to our children Matthew, Katherine, and Jennifer
i
i
i
i
i
“MAIN”
2004/5/11
page iv
i
Contents
Contents
iv
Preface
I
1
Introduction
5
1 Introduction to Media Computation
1.1 What is computer science about? . . . . . . . .
1.2 What Computers Understand . . . . . . . . . .
1.3 Media Computation: Why digitize media? . . .
1.4 Computer Science for Non-Computer Scientists
1.4.1 It’s about communication . . . . . . . .
1.4.2 It’s about process . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6
6
9
11
13
13
13
2 Introduction to Programming
2.1 Programming is about Naming . . . . . . . . . . . . . .
2.1.1 Files and their Names . . . . . . . . . . . . . . .
2.2 Programming in Java . . . . . . . . . . . . . . . . . . .
2.2.1 History of Java . . . . . . . . . . . . . . . . . . .
2.2.2 Introduction to Objects and Classes . . . . . . .
2.2.3 Introduction to DrJava . . . . . . . . . . . . . .
2.3 Programming in DrJava . . . . . . . . . . . . . . . . . .
2.4 Media Computation in DrJava . . . . . . . . . . . . . .
2.4.1 Showing a Picture . . . . . . . . . . . . . . . . .
2.4.2 Playing a Sound . . . . . . . . . . . . . . . . . .
2.4.3 Naming your Media (and other Values) . . . . .
2.5 Making a Recipe . . . . . . . . . . . . . . . . . . . . . .
2.5.1 Variable Recipes: Real functions that Take Input
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
16
16
18
19
19
19
20
21
24
27
30
31
35
40
II
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Pictures
3 Encoding and Manipulating Pictures
3.1 How Pictures are Encoded . . . . . . . . . . .
3.2 Manipulating Pictures . . . . . . . . . . . . .
3.2.1 Exploring pictures . . . . . . . . . . .
3.3 Changing color values . . . . . . . . . . . . .
3.3.1 Using loops in pictures . . . . . . . . .
3.3.2 Increasing/decreasing red (green, blue)
3.3.3 Creating a sunset . . . . . . . . . . . .
3.3.4 Making sense of methods . . . . . . .
3.3.5 Lightening and darkening . . . . . . .
45
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
46
46
52
58
58
59
61
70
71
79
iv
i
i
i
i
i
“MAIN”
2004/5/11
page v
i
v
3.4
3.5
3.6
3.7
3.8
3.3.6 Creating a negative . . . . . . . . . . . . . . . . . . . . . . .
3.3.7 Converting to grayscale . . . . . . . . . . . . . . . . . . . . .
Copying pixels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.4.1 Looping across the pixels with a nested loop . . . . . . . . .
3.4.2 Mirroring a picture . . . . . . . . . . . . . . . . . . . . . . . .
Copying and transforming pictures . . . . . . . . . . . . . . . . . . .
3.5.1 Copying . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.5.2 Creating a Collage . . . . . . . . . . . . . . . . . . . . . . . .
3.5.3 Blending Pictures . . . . . . . . . . . . . . . . . . . . . . . .
3.5.4 Rotation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.5.5 Scaling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Replacing Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.6.1 Reducing red eye . . . . . . . . . . . . . . . . . . . . . . . . .
3.6.2 Sepia toned and posterized pictures: Using conditionals to
choose the color . . . . . . . . . . . . . . . . . . . . . . . . .
Combining pixels: Blurring . . . . . . . . . . . . . . . . . . . . . . .
Color Figures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4 Advanced Pictures
4.1 Background subtraction . . . . . . . . . . .
4.2 Chromakey . . . . . . . . . . . . . . . . . .
4.3 Drawing on images with pixels . . . . . . .
4.4 Drawing with drawing commands . . . . . .
4.4.1 Vector and Bitmap Representations
4.5 Programs as Specifying Drawing Process . .
4.5.1 Why do we write programs? . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
81
82
85
85
87
96
96
102
108
111
113
117
120
122
128
134
143
143
147
152
154
156
158
161
5 Advanced Sounds
165
6 Design and Debugging
166
i
i
i
i
i
“MAIN”
2004/5/11
page vi
i
List of Figures
1.1
1.2
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
3.1
3.2
3.3
3.4
3.5
3.6
3.7
3.8
3.9
3.10
3.11
3.12
3.13
3.14
3.15
3.16
3.17
3.18
3.19
3.20
3.21
Eight wires with a pattern of voltages is a byte, which gets interpreted as a pattern of eight 0’s and 1’s, which gets interpreted as a
decimal number. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Alan Perlis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
DrJava Preferences Window . . . . . . . . . . . . . . . . . . . . . . .
DrJava Splash Screen . . . . . . . . . . . . . . . . . . . . . . . . . .
DrJava (with annotations) . . . . . . . . . . . . . . . . . . . . . . . .
The File Chooser . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
File chooser with media types identified . . . . . . . . . . . . . . . .
Picking, making, and showing a picture, using the result of each
method in the next method . . . . . . . . . . . . . . . . . . . . . . .
Picking, making, and showing a picture, when naming the pieces . .
Defining and executing pickAndShow() . . . . . . . . . . . . . . . .
An example matrix . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Upper left corner of DrJava window with part magnified 600% . . .
Image shown in the picture explorer: 100% image on left and 500%
on right . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Merging red, green, and blue to make new colors . . . . . . . . . . .
The ends of this figure are the same colors of gray, but the middle
two quarters contrast sharply so the left looks darker than the right
The Macintosh OS X RGB color picker . . . . . . . . . . . . . . . .
Picking a color using RGB sliders from Java . . . . . . . . . . . . . .
RGB triplets in a matrix representation . . . . . . . . . . . . . . . .
Directly modifying the pixel colors via commands: Note the small
black line on the left under the leaf . . . . . . . . . . . . . . . . . . .
Using the MediaTools image exploration tools . . . . . . . . . . . . .
The original picture (left) and red-reduced version (right) . . . . . .
Using the picture explorer to convince ourselves that the red was
decreased . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Overly blue (left) and red increased by 30% (right) . . . . . . . . . .
Original (left) and blue erased (right) . . . . . . . . . . . . . . . . .
Original beach scene (left) and at (fake) sunset (right) . . . . . . . .
Lightening and darkening of original picture . . . . . . . . . . . . . .
Negative of the image . . . . . . . . . . . . . . . . . . . . . . . . . .
Color picture converted to grayscale . . . . . . . . . . . . . . . . . .
Once we pick a mirror point, we can just walk x halfway and subtract/add to the mirror point . . . . . . . . . . . . . . . . . . . . . .
Original picture (left) and mirrored along the vertical axis (right) . .
Santa mirrored horizontally, bottom to top (left) and top to bottom
(right) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
14
21
22
23
26
28
29
31
37
47
48
48
49
50
51
51
52
57
59
63
68
69
70
71
81
82
84
88
89
91
vi
i
i
i
i
i
“MAIN”
2004/5/11
page vii
i
3.22
3.23
3.24
3.25
3.26
3.27
3.28
3.29
3.30
3.31
3.32
3.33
3.34
3.35
3.36
3.37
3.38
3.39
3.40
3.41
3.42
3.43
3.44
3.45
3.46
3.47
3.48
3.49
3.50
3.51
3.52
3.53
3.54
3.55
3.56
3.57
3.58
3.59
3.60
4.1
4.2
4.3
4.4
4.5
LIST OF FIGURES
vii
Temple of Zeus from the ancient agora in Athens, Greece . . . . . .
Coordinates where we need to do the mirroring . . . . . . . . . . . .
The manipulated temple . . . . . . . . . . . . . . . . . . . . . . . . .
Copying a picture to a canvas . . . . . . . . . . . . . . . . . . . . . .
Copying a picture midway into a canvas . . . . . . . . . . . . . . . .
Copying part of a picture onto a canvas . . . . . . . . . . . . . . . .
Flowers in the mediasources folder . . . . . . . . . . . . . . . . . .
Collage of flowers . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Blending the picture of Katie and Jenny . . . . . . . . . . . . . . .
Copying a picture to a canvas rotated to the left 90 degrees . . . . .
Scaling the picture down . . . . . . . . . . . . . . . . . . . . . . . . .
Scaling up a picture . . . . . . . . . . . . . . . . . . . . . . . . . . .
Increasing reds in the browns . . . . . . . . . . . . . . . . . . . . . .
Increasing reds in the browns, within a certain range . . . . . . . . .
Finding the range of where Jenny’s eyes are red . . . . . . . . . . . .
After fixing red-eye. . . . . . . . . . . . . . . . . . . . . . . . . . . .
Original scene (left) and using our sepia-tone recipe . . . . . . . . .
Reducing the colors (right) from the original (left) . . . . . . . . . .
Pictures posterized to two levels (left) and four levels (right) . . . .
Making the flower bigger, then blurring to reduce pixellation . . . .
Merging red, green, and blue to make new colors . . . . . . . . . . .
Color: RGB triplets in a matrix representation . . . . . . . . . . . .
Color: The original picture (left) and red-reduced version (right) . .
Color: Overly blue (left) and red increased by 30% (right) . . . . . .
Color: Original (left) and blue erased (right) . . . . . . . . . . . . .
Original beach scene (left) and at (fake) sunset (right) . . . . . . . .
Color: Lightening and darkening the original picture . . . . . . . . .
Color: Negative of the image . . . . . . . . . . . . . . . . . . . . . .
Color: Color picture converted to grayscale . . . . . . . . . . . . . .
Color: Increasing reds in the browns . . . . . . . . . . . . . . . . . .
Color: Increasing reds in the browns, within a certain range . . . . .
Finding the range where Jenny’s eyes are red, then changing them
to black . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Frames from the slow sunset movie . . . . . . . . . . . . . . . . . . .
Frames from the slow fade-out movie . . . . . . . . . . . . . . . . . .
Frames from the Mommy watching Katie movie . . . . . . . . . . . .
Frames from the original too dark movie . . . . . . . . . . . . . . . .
Frames from the modified lighter movie . . . . . . . . . . . . . . . .
Frames from the original movie with kids crawling in front of a blue
screen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Frames from the kids on the moon movie . . . . . . . . . . . . . . .
A picture of a child (Katie), and her background without her . . . .
A new background, the moon . . . . . . . . . . . . . . . . . . . . . .
Katie on the moon . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Two people in front of a wall, and a picture of the wall . . . . . . .
Swapping a jungle for the wall, using background subtraction, with
a threshold of 50 . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
92
92
93
98
99
101
103
106
110
112
115
116
119
120
121
122
123
124
127
129
134
134
135
135
135
135
136
136
136
137
138
138
139
139
140
140
141
141
142
143
144
145
147
147
i
i
i
i
i
“MAIN”
2004/5/11
page viii
i
viii
LIST OF FIGURES
4.6
4.7
4.8
4.9
4.10
4.11
4.12
4.13
4.14
4.15
Mark in front of a blue sheet . . . . . . . . . . . . . . .
Mark on the moon . . . . . . . . . . . . . . . . . . . . .
Mark in the jungle . . . . . . . . . . . . . . . . . . . . .
Student in front of a red background, and with flash on
Using chromakey recipe with red background . . . . . .
Santa with a grid of drawn lines . . . . . . . . . . . . .
A small, drawn picture . . . . . . . . . . . . . . . . . . .
A programmed gray scale effect . . . . . . . . . . . . . .
Nested filled rectangles image . . . . . . . . . . . . . . .
Nested rectangles image . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
148
149
150
151
151
153
156
158
161
162
i
i
i
i
i
“MAIN”
2004/5/11
page 1
i
Preface
This book is based on the proposition that the best way to learn to program
is to have something interesting to program. Most educated people want to use a
computer, and the task that they most want to do with a computer is communicate.
Alan Perlis first made the claim in 1961 that computer science, and programming
explicitly, should be part of a liberal education [8]. What we’ve learned since then is
that one doesn’t just “learn to program.” One learns to program something [3, 9],
and the motivation to do that something can make the difference between learning
to program or not [4].
The philosophies which drive the structure of this book include:
• People learn from concrete examples to abstract ideas, driven by need. Teaching structure before content is painful and results in brittle knowledge that
can’t be used elsewhere [5]. Certainly, one can introduce structure (and theory and design), but students won’t really understand the structure until they
have the content to fill it with – and a reason to need the structure. Thus,
this book doesn’t introduce debugging or design (or complexity or most of
computer science) until the students are doing complex enough software to
make it worthwhile learning.
• Repetition is good. Variety is good. Marvin Minsky once said, “If you know
something only one way, you don’t know it at all.” The same ideas come back
frequently in this book. The same idea is framed in multiple ways. I will use
metaphor, visualizations, mathematics, and even computer science to express
ideas in enough different ways that hopefully one of the ways will ring true
for the individual student.
• The computer is the most amazingly creative device that humans have ever
conceived of. It is literally completely made up of mind-stuff. The notion
“Don’t just dream it, be it” is really possible on a computer. If you can imagine it, you can make it “real” on the computer. Playing with programming
can be and should be enormous fun.
TYPOGRAPHICAL NOTATIONS
Examples of Java code look like this: x = x + 1;. Longer examples look look like
this:
public class Greeter {
public static void main(String[] argv)
{
// show the string "Hello World" on the console
System.out.println("Hello World");
}
}
1
i
i
i
i
i
“MAIN”
2004/5/11
page 2
i
2
LIST OF FIGURES
When showing something that the user types in the interactions pane with
DrJava’s response, it will have a similar font and style, but the user’s typing will
appear after a DrJava prompt (>):
> 3 + 4
7
User interface components of DrJava will be specified using a smallcaps font,
like File menu item and the Compile All button.
There are several special kinds of sidebars that you’ll find in the book.
Recipe 1: An Example Recipe
Recipes (programs) appear like this:
public static void main(String[] argv)
{
// show the string "Hello World" on the console
System.out.println("Hello World");
}
End of Recipe 1
Computer Science Idea: An Example Idea
Key computer science concepts appear like this.
Common Bug: An Example Common Bug
Common things that can cause your recipe to fail appear
like this.
Debugging Tip: An Example Debugging Tip
If there’s a good way to keep those bugs from creeping into
your recipes in the first place, they’re highlighted here.
i
i
i
i
i
“MAIN”
2004/5/11
page 3
i
LIST OF FIGURES
3
Making it Work Tip: An Example How To Make
It Work
Best practices or techniques that really help are highlighted
like this.
FOR THE TEACHER
The programming language used in this book is Java. Java is a high-level objectoriented programming language that runs on most computers and many small electronic devices. It is widely used in industry and in universities.
The development environment used in this book is DrJava. It is a free and
easy to use development environment. DrJava lets the student focus on learning to
program in Java and not on how to use the development environment. An advantage
of DrJava is that you can try out Java code in the interactions pane without having
to write a ”main” method. You don’t have to use this development environment.
There are many development environments that are available for use with Java.
If you use another development environment just include the book classes in the
classpath.
It’s possible to teach a class where students learn the algorithms from this
book, but apply them in another language. The media manipulations described in
this book can easily be used in other languages. Examples from this book have
been successfully used in classes using Scheme1 , and Squeak2 .
ACKNOWLEDGEMENTS
Our sincere thanks go out to the following:
• Adam Wilson built the MediaTools that are so useful for exploring sounds
and images and processing video.
• Jeff Pierce reviewed and advised us on the design of the media language used
in the book.
• Picture of Alan Perlis from http://www.cs.cmu.edu/afs/cs.cmu.edu/Web/
csd/perlis.html. Most of the clip art is used with permission from the Art
Explosion package by Nova Development.
• Thanks for permission to use their snapshots from class in examples are former Media Computation students Constantino Kombosch, Joseph Clark, and
Shannon Joiner.
The cover image was created by Rachel Cobb who was a first year Architecture
student at Georgia Institute of Technology in Spring 2003 when she created the
image for a homework assignment to build a collage. The original arch image came
from the National Park Service gallery at http://www.nps.gov/arch/gallery/
index.htm. The original image and the collage are both used with permission, and
my thanks!
1 JScheme,
http://jscheme.sf.net
2 http://www.squeak.org
i
i
i
i
i
“MAIN”
2004/5/11
page 4
i
i
i
i
i
i
“MAIN”
2004/5/11
page 5
i
P A R T
O N E
INTRODUCTION
Chapter 1
Introduction to Media Computation
Chapter 2
Introduction to Programming
5
i
i
i
i
i
“MAIN”
2004/5/11
page 6
i
C H A P T E R
1
Introduction to Media
Computation
1.1
1.2
1.3
1.4
1.1
WHAT IS COMPUTER SCIENCE ABOUT?
WHAT COMPUTERS UNDERSTAND
MEDIA COMPUTATION: WHY DIGITIZE MEDIA?
COMPUTER SCIENCE FOR NON-COMPUTER SCIENTISTS
WHAT IS COMPUTER SCIENCE ABOUT?
Computer science is the study of process: How we do things, how we specify what
we do, how we specify what the stuff is that you’re processing. But that’s a pretty
dry definition. Let’s try a metaphorical one.
Computer Science Idea: Computer science is the
study of recipes
They’re a special kind of recipe—one that can be executed
by a computational device, but that point is only of importance to computer scientists. The important point overall
is that a computer science recipe defines exactly what’s to
be done.
If you’re a biologist who wants to describe how migration works or how DNA
replicates, or if you’re a chemist who wants to explain how an equilibrium is reached
in a reaction, or if you’re a factory manager who wants to define a machine-andbelt layout and even test how it works before physically moving heavy things into
position, then being able to write a recipe that specifies exactly what happens, in
terms that can be completely defined and understood, is very useful. This exactness
is part of why computers have radically changed so much of how science is done
and understood.
It may sound funny to call programs or algorithms a recipe, but the analogy
goes a long way. Much of what computer scientists study can be defined in terms
of recipes:
• Some computer scientists study how recipes are written: Are there better or
worse ways of doing something? If you’ve ever had to separate whites from
yolks in eggs, you know that knowing the right way to do it makes a world
of difference. Computer science theoreticians worry about the fastest and
shortest recipes, and the ones that take up the least amount of space (you can
6
i
i
i
i
i
“MAIN”
2004/5/11
page 7
i
Section 1.1
What is computer science about?
7
think about it as counter space — the analogy works). How a recipe works,
completely apart from how it’s written, is called the study of algorithms.
Software engineers worry about how large groups can put together recipes
that still work. (The recipe for some programs, like the one that keeps track
of Visa/MasterCard records has literally millions of steps!)
• Other computer scientists study the units used in recipes. Does it matter
whether a recipe uses metric or English measurements? The recipe may work
in either case, but if you have the read the recipe and you don’t know what
a pound or a cup is, the recipe is a lot less understandable to you. There are
also units that make sense for some tasks and not others, but if you can fit the
units to the tasks well, you can explain yourself more easily and get things
done faster—and avoid errors. Ever wonder why ships at sea measure their
speed in knots? Why not use things like meters per second? There are places,
like at sea, where more common terms aren’t appropriate or don’t work as
well. The study of computer science units is referred to as data structures.
Computer scientists who study ways of keeping track of lots of data in lots of
different kinds of units are studying databases.
• Can recipes be written for anything? Are there some recipes that can’t be
written? Computer scientists actually do know that there are recipes that
can’t be written. For example, you can’t write a recipe that can absolutely
tell, for any other recipe, if the other recipe will actually work. How about
intelligence? Can we write a recipe that, when a computer followed it, the
computer would actually be thinking (and how would you tell if you got it
right)? Computer scientsts in theory, intelligent systems, artificial intelligence, and systems worry about things like this.
• There are even computer scientists who worry about whether people like what
the recipes produce, like the restauraunt critics for the newspaper. Some
of these are human-computer interface specialists who worry about whether
people like how the recipes work (those “recipes” that produce an interface
that people use, like windows, buttons, scrollbars, and other elements of what
we think about as a running program).
• Just as some chefs specialize in certain kinds of recipes, like crepes or barbeque, computer scientists also specialize in special kinds of recipes. Computer scientists who work in graphics are mostly concerned with recipes that
produce pictures, animations, and even movies. Computer scientists who work
in computer music are mostly concerned with recipes that produce sounds (often melodic ones, but not always).
• Still other computer scientists study the emergent properties of recipes. Think
about the World Wide Web. It’s really a collection of millions of recipes
(programs) talking to one another. Why would one section of the Web get
slower at some point? It’s a phenomena that emerges from these millions
of programs, certainly not something that was planned. That’s something
that networking computer scientists study. What’s really amazing is that
these emergent properties (that things just start to happen when you have
i
i
i
i
i
“MAIN”
2004/5/11
page 8
i
8
Chapter 1
Introduction to Media Computation
many, many recipes interacting at once) can also be used to explain noncomputational things. For example, how ants forage for food or how termites
make mounds can also be described as something that just happens when you
have lots of little programs doing something simple and interacting.
The recipe metaphor also works on another level. Everyone knows that some
things in recipe can be changed without changing the result dramatically. You
can always increase all the units by a multiplier to make more. You can always
add more garlic or oregano to the spaghetti sauce. But there are some things that
you cannot change in a recipe. If the recipe calls for baking powder, you may not
substitute baking soda. If you’re supposed to boil the dumplings then saute’ them,
the reverse order will probably not work well.
Similarly, for software recipes. There are usually things you can easily change:
The actual names of things (though you should change names consistently), some
of the constants (numbers that appear as plain old numbers, not as variables), and
maybe even some of the data ranges (sections of the data) being manipulated. But
the order of the commands to the computer, however, almost always has to stay
exactly as stated. As we go on, you’ll learn what can be changed safely, and what
can’t.
Computer scientists specify their recipes with programming languages. Different programming languages are used for different purposes. Some of them are
wildly popular, like Java and C++. Others are more obscure, like Squeak and T.
Others are designed to make computer science ideas very easy to learn, like Scheme
or Python, but the fact that they’re easy to learn doesn’t always make them very
popular nor the best choice for experts building larger or more complicated recipes.
It’s a hard balance in teaching computer science to pick a language that is easy to
learn and is popular and useful enough that students are motivated to learn it.
Why don’t computer scientists just use natural languages, like English or
Spanish? The problem is that natural languages evolved the way that they did
to enhance communications between very smart beings, humans. As we’ll go into
more in the next section, computers are exceptionally dumb. They need a level of
specificity that natural language isn’t good at. Further, what we say to one another
in natural communication is not exactly what you’re saying in a computational
recipe. When was the last time you told someone how a videogame like Doom
or Quake or Super Mario Brothers worked in such minute detail that they could
actually replicate the game (say, on paper)? English isn’t good for that kind of
task.
There are so many different kinds of programming languages because there are
so many different kinds of recipes to write. Programs written in the programming
language C tend to be very fast and efficient, but they also tend to be hard to
read, hard to write, and require units that are more about computers than about
bird migrations or DNA or whatever else you want to write your recipe about. The
programming language Lisp (and its related languages like Scheme, T, and Common
Lisp) is very flexible and is well suited to exploring how to write recipes that have
never been written before, but Lisp looks so strange compared to languages like
C that many people avoid it and there are (natural consequence) few people who
know it. If you want to hire a hundred programmers to work on your project, you’re
i
i
i
i
i
“MAIN”
2004/5/11
page 9
i
Section 1.2
What Computers Understand
9
going to find it easier to find a hundred programmers who know a popular language
than a less popular one—but that doesn’t mean that the popular language is the
best one for your task!
The programming language that we’re using in this book is Java (http:
//java.sun.com for more information on Java). Java is a very popular programming language. Delta uses it to handle its web site (http://www.delta.
com). NASA used it on the Mars Rover ”Spirit” (http://www.sun.com/aboutsun/
media/features/mars.html). It has been used in touchscreen kiosks for Super
Bowl fans (http://java.sun.com/features/1998/01/superbowl.html).
Java is known for being object-oriented, platform neutral (runs on many computers and electronic devices), robust, and secure. An early drawback to Java was
that programs written in Java often had a slower execution time than ones written
in C or C++. However, current Java compilers and interpreters have essentially
eliminated this problem.
1.2
WHAT COMPUTERS UNDERSTAND
Computational recipes are written to run on computers. What does a computer
know how to do? What can we tell the computer to do in the recipe? The answer
is “Very, very little.” Computers are exceedingly stupid. They really only know
about numbers.
Actually, even to say that computers know numbers is a myth, or more appropriately, an encoding. Computers are electronic devices that react to voltages on
wires. We group these wires into sets (like eight of these wires are called a byte and
one of them is called a bit ). If a wire has a voltage on it, we say that it encodes a 1.
If it has no voltage on it, we say that it encodes a 0. So, from a set of eight wires
(a byte), we interpret a pattern of eight 0’s and 1’s, e.g., 01001010. To calculate
the decimal number (10 based) that 01001010 represents we add up the values of
the digits using the binary number (2 based) system starting from right to left as
follows: 20 * 0 + 21 * 1 + 22 * 0 + 23 * 1 + 24 * 0 + 25 * 0 + 26 * 1 + 27 * 0 = 74
(Figure 1.1). We can represent the numbers 0 (00000000) to 255 (11111111) using
eight wires (a byte). That’s where we come up with the claim that a computer
knows about numbers1 .
The computer has a memory made up of bytes. Everything that a computer is
working with at a given instant is stored in its memory. That means that everything
that a computer is working with is encoded in its bytes: JPEG pictures, Excel
spreadsheets, Word documents, annoying Web pop-up ads, and the latest spam
email.
A computer can do lots of things with numbers. It can add them, subtract
them, multiply them, divide them, sort them, collect them, duplicate them, filter
them (e.g., “make a copy of these numbers, but only the even ones”), and compare
them and do things based on the comparison. For example, a computer can be told
in a recipe “Compare these two numbers. If the first one is less than the second
one, jump to step 5 in this recipe. Otherwise, continue on to the next step.”
So far, the computer is an incredible calculator, and that’s certainly why it
was invented. The first use of the computer was during World War II for calculating
1 We’ll
talk more about this level of the computer in Chapter ??
i
i
i
i
i
“MAIN”
2004/5/11
page 10
i
10
Chapter 1
Introduction to Media Computation
FIGURE 1.1: Eight wires with a pattern of voltages is a byte, which gets interpreted
as a pattern of eight 0’s and 1’s, which gets interpreted as a decimal number.
trajectories of projectiles (“If the wind is coming from the SE at 15 MPH, and you
want to hit a target 0.5 miles away at an angle of 30 degrees East of North, then
incline your launcher to . . .”). The computer is an amazing calculator. But what
makes it useful for general recipes is the concept of encodings.
Computer Science Idea: Computers can layer encodings
Computers can layer encodings to virtually any level of
complexity. Numbers can be interpreted as characters,
which can be interpreted in sets as Web pages, which can
be interpreted to appear as multiple fonts and styles. But
at the bottommost level, the computer only “knows” voltages which we intepret as numbers.
If one of these bytes is interpreted as the number 65, it could just be the
number 65. Or it could be the letter A using a standard encoding of numbers-toletters called the American Standard Code for Information Interchange (ASCII). It
could also be the letter A in Unicode which is a more recent standard encoding of
number to characters which supports a wide range of languages . If that 65 appears
in a collection of other numbers that we’re interpreting as text, and that’s in a file
that ends in “.html” it might be part of something that looks like this <a href=. . .,
which a Web browser will interpret as the definition of a link. Down at the level
of the computer, that A is just a pattern of voltages. Many layers of recipes up, at
the level of a Web browser, it defines something that you can click on to get more
information.
If the computer understands only numbers (and that’s a stretch already), how
does it manipulate these encodings? Sure, it knows how to compare numbers, but
i
i
i
i
i
“MAIN”
2004/5/11
page 11
i
Section 1.3
Media Computation: Why digitize media?
11
how does that extend to being able to alphabetize a class list. Typically, each layer
of encoding is implemented as a piece or layer of software. There’s software that
understands how to manipulate characters. The character software knows how to
do things like compare names because it has encoded that a comes before b and
so on, and that the numeric comparison of the order of numbers in the encoding
of the letters leads to alphabetical comparisons. The character software is used by
other software that manipulates text in files. That’s the layer that something like
Microsoft Word or Notepad or TextEdit would use. Still another piece of software
knows how to interpret HTML (the language of the Web), and another layer of
that software knows how to take HTML and display the right text, fonts, styles,
and colors.
We can similarly create layers of encodings in the computer for our specific
tasks. We can teach a computer that cells contain mitochondria and DNA, and that
DNA has four kinds of nucleotides, and that factories have these kinds of presses
and these kinds of stamps. Creating layers of encoding and interpretation so that
the computer is working with the right units (recall back to our recipe analogy)
for a given problem is the task of data representation or defining the right data
structures.
If this sounds like a lot of software, it is. When software is layered like this,
it slows the computer down some. But the amazing thing about computers is that
they’re amazingly fast—and getting faster all the time!
Computer Science Idea: Moore’s Law
Gordon Moore, one of the founders of Intel (maker of computer processing chips used by computers running Windows operating systems), made the claim that the number
of transistors (a key component of computers) would double at the same price every 18 months, effectively meaning
that the same amount of money would buy twice as much
computing power every 18 months. This Law has continued to hold true for decades.
Computers today can execute literally BILLIONS of recipe steps per second!
They can hold in memory literally encyclopediae of data! They never get tired nor
bored. Search a million customers for a particular card holder? No problem! Find
the right set of numbers to get the best value out of an equation? Piece of cake!
Process millions of picture elements or sound fragments or movie frames?
That’s media computation.
1.3
MEDIA COMPUTATION: WHY DIGITIZE MEDIA?
Let’s consider an encoding that would be appropriate for pictures. Imagine that
pictures were made up of little dots. That’s not hard to imagine: Look really closely
at your monitor or at a TV screen and see that your images are already made up of
little dots. Each of these dots is a distinct color. You may know from physics that
colors can be described as the sum of red , green, and blue. Add the red and green
to get yellow. Mix all three together to get white. Turn them all off, and you get
a black dot.
i
i
i
i
i
“MAIN”
2004/5/11
page 12
i
12
Chapter 1
Introduction to Media Computation
What if we encoded each dot in a picture as collection of three bytes, one each
for the amount of red, green, and blue at that dot on the screen? And we collect a
bunch of these three-byte-sets to determine all the dots of a given picture? That’s a
pretty reasonable way of representing pictures, and it’s essentially how we’re going
to do it in Chapter 3.
Manipulating these dots (each referred to as a pixel or picture element ) can
take a lot of processing. There are thousands or even millions of them in a picture
that you might want to work with on your computer or on the Web. But the
computer doesn’t get bored and it’s mighty fast.
The encoding that we will be using for sound involves 44,100 two-byte-sets
(called a sample) for each second of time. A three minute song requires 158,760,000
bytes. Doing any processing on this takes a lot of operations. But at a billion
operations per second, you can do lots of operations to every one of those bytes in
just a few moments.
Creating these kinds of encodings for media requires a change to the media.
Look at the real world: It isn’t made up of lots of little dots that you can see.
Listen to a sound: Do you hear thousands of little bits of sound per second? The
fact that you can’t hear little bits of sound per second is what makes it possible
to create these encodings. Our eyes and ears are limited: We can only perceive so
much, and only things that are just so small. If you break up an image into small
enough dots, your eyes can’t tell that it’s not a continuous flow of color. If you
break up a sound into small enough pieces, your ears can’t tell that the sound isn’t
a continuous flow of auditory energy.
The process of encoding media into little bits is called digitization, sometimes
referred to as “going digital .” Digital means (according to the American Heritage
Dictionary) “Of, relating to, or resembling a digit, especially a finger.” Making
things digital is about turning things from continuous, uncountable, to something
that we can count, as if with our fingers.
Digital media, done well, feel the same to our limited human sensory apparatus as the original. Phonograph recordings (ever seen one of those?) capture
sound continuously, as an analogue signal. Photographs capture light as a continuous flow. Some people say that they can hear a difference between phonograph
recordings and CD recordings, but to my ear and most measurements, a CD (which
is digitized sound) sounds just the same—maybe clearer. Digital cameras at high
enough resolutions produce photograph-quality pictures.
Why would you want to digitize media? Because it’s easier to manipulate,
to replicate exactly, to compress, and to transmit. For example, it’s hard to manipulate images that are in photographs, but it’s very easy when the same images
are digitized. This book is about using the increasingly digital world of media and
manipulating it—and learning computation in the process.
Moore’s Law has made media computation feasible as an introductory topic.
Media computation relies on the computer doing lots and lots of operations on lots
and lots of bytes. Modern computers can do this easily. Even with slower (but
easy to understand) languages, even with inefficient (but easy to read and write)
recipes, we can learn about computation by manipulating media.
i
i
i
i
i
“MAIN”
2004/5/11
page 13
i
Section 1.4
1.4
Computer Science for Non-Computer Scientists
13
COMPUTER SCIENCE FOR NON-COMPUTER SCIENTISTS
But why should you? Why should anyone who doesn’t want to be a computer
scientist learn about computer science? Why should you be interested in learning
about computation through manipulating media?
Most professionals today do manipulate media: Papers, videos, tape recordings, photographs, drawings. Increasingly, this manipulation is done with a computer. Media are very often in a digitized form today.
We use software to manipulate these media. We use Adobe Photoshop for
manipulating our images, and Macromedia SoundEdit to manipulate our sounds,
and perhaps Microsoft PowerPoint for assembling our media into slideshows. We
use Microsoft Word for manipulating our text, and Netscape Navigator or Microsoft
Internet Explorer for browsing media on the Internet.
So why should anyone who does not want to be a computer scientist study
computer science? Why should you learn to program? Isn’t it enough to learn to
use all this great software? The following two sections provide two answers to these
questions.
1.4.1
It’s about communication
Digital media are manipulated with software. If you can only manipulate media
with software that someone else made for you, you are limiting your ability to
communicate. What if you want to say something or say it in some way that
Adobe, Microsoft, Apple, and the rest don’t support you in saying? If you know
how to program, even if it would take you longer to do it yourself, you have that
freedom.
What about learning those tools in the first place? In my years in computers,
I’ve seen a variety of software come and go as the package for drawing, painting,
word-processing, video editing, and beyond. You can’t learn just a single tool and
expect to be able to use that your entire career. If you know how the tools work,
you have a core understanding that can transfer from tool to tool. You can think
about your media work in terms of the algorithms, not the tools.
Finally, if you’re going to prepare media for the Web, for marketing, for print,
for broadcast, for any use whatsoever, it’s worthwhile for you to have a sense of
what’s possible, what can be done with media. It’s even more important as a
consumer of media that you know how the media can be manipulated, to know
what’s true and what could be just a trick. If you know the basics of media
computation, you have an understanding that goes beyond what any individual
tool provides.
1.4.2
It’s about process
In 1961, Alan Perlis gave a talk at MIT where he made the argument that computer science, and programming explicitly, should be part of a general, liberal
education [8]. Perlis is an important figure in the field of computer science (Figure 1.2). The highest award that a computer scientist can be honored with is the
ACM Turing Award. Perlis was the first recipient of that award. He’s an important
figure in software engineering, and he started several of the first computer science
i
i
i
i
i
“MAIN”
2004/5/11
page 14
i
14
Chapter 1
Introduction to Media Computation
FIGURE 1.2: Alan Perlis
departments in the United States.
Perlis’ argument can be made in comparison with calculus. Calculus is generally considered part of a liberal education: Not everyone takes calculus, but if
you want to be well-educated, you will typically take at least a term of calculus.
Calculus is the study of rates, which is important in many fields. Computer science,
as we said before (page 6), is the study of process. Process is important to nearly
every field, from business to science to medicine to law. Knowing process formally
is important to everyone.
PROBLEMS
1.1. Find an ASCII table on the Web: A table listing every character and its corresponding numeric representation. Write down the sequence of numbers whose
ASCII values make up your name.
1.2. Find a Unicode table on the Web. What’s the difference between ASCII and
Unicode?
1.3. Consider the representation for pictures described in Section 1.3, where each
“dot” (pixel) in the picture is represented by three bytes, for the red, green,
and blue components of the color at that dot. How many bytes does it take
to represent a 640x480 picture, a common picture size on the Web? How many
bytes does it take to represent a 1024x768 picture, a common screen size? (What
do you think is meant now by a “3 megapixel” camera?)
1.4. How many different numbers can be represented by one byte? In other words,
eight bits can represent from zero to what number? What if you have two bytes?
Four bytes?
*1.5. How might you represent a floating point number in terms of bytes?
1.6. Look up Alan Kay and the Dynabook on the Web. Who is he, and what does he
have to do with media computation?
i
i
i
i
i
“MAIN”
2004/5/11
page 15
i
Section 1.4
Computer Science for Non-Computer Scientists
15
1.7. Look up Alan Turing on the Web. Who was he, and what does he have to do
with our notion of what a computer can do and how encodings work?
1.8. Look up Kurt Goedel on the Web. Who was he, and what amazing things did
he do with encodings?
TO DIG DEEPER
James Gleick’s book Chaos describes more on emergent properties–how small changes
can lead to dramatic effects, and the unintended impacts of designs because of
difficult-to-foresee interactions.
Mitchel Resnick’s book Turtles, Termites, and Traffic Jams: Explorations in
Massively Parallel Microworlds [12] describes how ants, termites, and even traffic
jams and slime molds can be described pretty accurately with hundreds or thousands of very small programs running and interacting all at once.
Beyond the Digital Domain [2] is a wonderful introductory book to computation with lots of good information about digital media.
i
i
i
i
i
“MAIN”
2004/5/11
page 16
i
C H A P T E R
2
Introduction to Programming
2.1
2.2
2.3
2.4
2.5
2.1
PROGRAMMING IS ABOUT NAMING
PROGRAMMING IN JAVA
PROGRAMMING IN DRJAVA
MEDIA COMPUTATION IN DRJAVA
MAKING A RECIPE
PROGRAMMING IS ABOUT NAMING
Computer Science Idea: Much of programming is
about naming
A computer can associate names, or symbols, with just
about anything: With a particular byte; with a collection
of bytes making up a numeric variable or a bunch of letters; with a media element like a file, sound, or picture; or
even with more abstract concepts, like a named recipe (a
program or method or a named encoding (a type or class).
A computer scientist sees a choice of names as being high
quality in the same way that a philosopher or mathematician might: If the naming scheme (the names and what
they name) are elegant, parsimonious, and usable.
Obviously, the computer itself doesn’t care about names. Names are for the
humans. If the computer were just a calculator, then remembering words and the
words’ association with values would be just a waste of the computer’s memory.
But for humans, it’s very powerful. It allows us to work with the computer in
a natural way, even a way that extends how we think about recipes (processes)
entirely.
A programming language is really a set of names that a computer has encodings for, such that those names make the computer do expected actions and
interpret our data in expected ways. Some of the programming language’s names
allow us to define new namings—which allows us to create our own layers of encoding. Assigning a variable to a value is one way of defining a name for the computer.
Defining a method (function) is giving a name to a recipe. In Java you can also
assign a name to a group of related data and methods (functions) when you define
a class (type).
16
i
i
i
i
i
“MAIN”
2004/5/11
page 17
i
Section 2.1
Programming is about Naming
17
Computer Science Idea: Programs are for people,
not computers.
Remember names are only meaningful for people, not computers. Computers just take instructions. A good program
is meaningful (understandable and useful) for humans.
A program is a set of names and their values, where some of these names have
values of instructions to the computer (“code”). Our instructions will be in the
Java programming language. Combining these two definitions means that the Java
programming language gives us a set of useful names that have a meaning to the
computer, and our programs are then made up of Java’s useful names as a way of
specifying what we want the computer to do.
'
$
Making it Work Tip: Java Keywords, Operators,
and Classes
In Java the useful names that the computer understands
are keywords, operators, and classes. All of the keywords
defined in Java are completely lowercase. Some example keywords are public, class, static, main, new, and
instanceof. Operators in Java include the standard math
operators like addition (+), multiplication (*), division (/),
subtraction (-) and others. There are also classes that have
been defined and are included with a version of Java for
you to use and build on. Some of the classes included with
Java are String, System, Math, and JFrame. Notice that
class names start with an uppercase letter. This is a Java
convention (usual way something is done).
&
%
There are good names and bad names. Bad names aren’t curse words, or
TLA’s (Three Letter Acronyms), but names that aren’t understandable or easy to
use. A good set of encodings and names allow one to describe recipes in a way that’s
natural, without having to say too much. The variety of different programming
languages can be thought of as a collection of sets of namings-and-encodings. Some
are better for some tasks than others. Some languages require you to write more to
describe the same recipe than others—but sometimes that “more” leads to a much
more (human) readable recipe that helps others to understand what you’re saying.
Philosophers and mathematicians look for very similar senses of quality. They
try to describe the world in few words, but an elegant selection of words that cover
many situations, while remaining understandable to their fellow philosophers and
mathematicians. That’s exactly what computer scientists do as well.
How the units and values (data) of a recipe can be interpreted is often also
named. Remember how we said in Section 1.2 (page 9) that everything is in bytes,
but we can interpret those bytes as numbers? In some programming languages, you
can say explicitly that some value is a byte, and later tell the language to treat it as
a number, an integer (or sometimes int ). Similarly, you can tell the computer that
these series of bytes is a collection of numbers (an array of integers), or a collection
of characters (a String), or even as a more complex encoding of a single floating
i
i
i
i
i
“MAIN”
2004/5/11
page 18
i
18
Chapter 2
Introduction to Programming
point number (a floating point number —any number with a decimal point in it).
In Java, we will explicitly tell the computer how to interpret our values.
Languages such as Java, C++, and C# are strongly typed . Their names are strongly
associated with certain types or encodings. They require you to say that this name
will only be associated with integers, and that one will only be a floating point
number. In Java, C++, and C# you can also create your own types which is
part of what makes object-oriented languages so powerful. We do this in Java by
defining classes such as Picture which represents a simple digital picture. An object
of the Picture class has a width and height and you can get and set the pixels of
the Picture object. This isn’t a class that is part of the Java language but a class
that we have defined using Java to make it easier for students to work with digital
pictures.
2.1.1
Files and their Names
A programming language isn’t the only place where computers associate names and
values. Your computer’s operating system takes care of the files on your disk, and
it associates names with those files. Operating systems you may be familiar with
or use include Windows 95, Windows 98 (Windows ME, NT, XP. . .), MacOS, and
Linux. A file is a collection of values (bytes) on your hard disk (the part of your
computer that stores things after the power gets turned off). If you know the name
of a file, you can tell it to the operating system, and it can give you the values
associated with that name.
You may be thinking, “I’ve been using the computer for years, and I’ve never
’given a file name to the operating system.’ ” Maybe you didn’t realize that you
were doing it, but when you pick a file from a file choosing dialog in Photoshop,
or double-click a file in a directory window (or Explorer or Finder), you are asking
some software somewhere to give the name you’re picking or double-clicking to
the operating system, and get the values back. When you write your own recipes,
though, you’ll be explicitly getting file names and asking for their values.
Files are very important for media computation. Disks can store acres and
acres of information on them. Remember our discussion of Moore’s Law (page 11)?
Disk capacity per dollar is increasing faster than computer speed per dollar! Computer disks today can store whole movies, hours (days?) of sounds, and the equivalent of hundreds of film rolls of pictures.
These media are not small. Even in a compressed form, screen size pictures
can be over a million bytes large, and songs can be three million bytes or more. You
need to keep them someplace where they’ll last past the computer being turned off
and where there’s lots of space.
In contrast, your computer’s memory is impermanent (disappears when the
power does) and is relatively small. Computer memory is getting larger all the
time, but it’s still just a fraction of the amount of space on your disk. When you’re
working with media, you will load the media from the disk into memory so you can
work with it, but you wouldn’t want it to stay in memory after you’re done. It’s
too big.
Think about your computer’s memory as a dorm room. You can get to things
easily in a dorm room—they’re right at hand, easy to reach, easy to use. But you
i
i
i
i
i
“MAIN”
2004/5/11
page 19
i
Section 2.2
Programming in Java
19
wouldn’t want to put everything you own (or everything you hope to own) in that
one dorm room. All your belongings? Your skis? Your car? Your boat? That’s
silly. Instead, you store large things in places designed to store large things. You
know how to get them when you need them (and maybe take them back to your
dorm room if you need to or can).
When you bring things into memory, you usually will name the value, so that
you can retrieve it and use it later. In that sense, programming is something like
algebra. To write generalizable equations and functions (those that work for any
number or value), you wrote equations and functions with variables, like P V = nRT
or e = M c2 or f (x) = sin(x). Those P’s, V’s, R’s, T’s, e’s, M’s, c’s, and x’s were
names for values. When you evaluated f (30), you knew that the x was the name
for 30 when computing f . We’ll be naming media (as values) in the same way when
using them when programming.
2.2
PROGRAMMING IN JAVA
The programming language that we’re going to be using in this book is called Java.
It’s a language invented by James Gosling (http://java.sun.com/people/jag/)
at Sun Microsystems.
2.2.1
History of Java
Back in 1990 Sun created project Green to try and predict the next big thing in
computers. The goal of the project was to try and develop something to position
Sun ahead of its competitors. They thought that the next big thing would be
networked consumer electronics devices like set-top boxes for downloading video on
demand. They tried to develop a prototype using C++ but after many problems
decided to develop a new object-oriented language which they originally named
Oak, after a tree outside James Gosling’s office. They created a demonstration but
the cable companies weren’t really interested and the future of the project was in
doubt.
At a brainstorming session they decided to try to reposition the language
for use with the internet. They created a web browser that had Java programs
(applets) embedded in HTML pages to do 3D rotation of a molecule and animation
of a sorting algorithm. They showed this at a conference. At that time web pages
didn’t respond to user action. They simply displayed text and unchanging graphics.
The audience was amazed to see the user rotate the 3d molecule on a web page.
Later they renamed Oak to Java and released it for free in 1995. Since then it has
become one of the fastest adopted technologies of all times. It is now used for more
than just web pages. It is used in many devices from cell phones to web servers.
For more on the history of Java see http://java.sun.com/features/1998/05/
birthday.html.
2.2.2
Introduction to Objects and Classes
Java is an object-oriented programming language. This means that the focus for
programmers is on objects (who) as well as procedures (what). Objects are persons,
places, or things that are doing the action in a situation or being acted upon.
i
i
i
i
i
“MAIN”
2004/5/11
page 20
i
20
Chapter 2
Introduction to Programming
An example might help you to understand what focusing on the objects means.
When customers enter a restaurant a greeter will welcome them to the restaurant
and show them to their table. A waiter will take the order and bring the drinks
and food. One or more chefs will cook the food. The waiter will create the bill and
give it to the customers. The customers will pay the bill.
How many people does it take to get a customer fed in a restaurant? Well,
you need at least a customer, greeter, waiter, and a chef. What other things are
doing action or being acted upon? We mentioned order, table, drink, food, and
bill. Each of these are objects. The objects in this situation are working together
to feed the customer.
What types of objects are they? We have given names to each thing we
mentioned: customer, waiter, food, etc. The names we gave are how we classify
these objects. You probably know what I mean by a customer or food. But the
computer doesn’t know what we mean by these things. The way that we get the
computer to understand what we mean is by defining a class. A class in Java tells
the computer what data we expect objects of the class to have and what things it
can do. We would expect that food will have a name, a price, and a way to prepare
it. We would expect that a customer would know what they can afford to pay and
how to pay a bill.
Each object of a class will have the same skills or operations (things it can
do) and data (things it knows about). For example, each object of the order class
should know which customer placed that order and what food is in the order. An
object of the chef class should know how to prepare the food.
There can be many objects of a class. A restaurant might have 3 chefs, 10
waiters, 2 greeters, and 100 food objects on its menu. On a given day and time it
might have 100 customers.
Why don’t restaurants just have one type of employee? One person could
greet the customers, take the orders, cook the food and deliver the food. That
might be okay if there is only one customer but what about when there are many
customers? You can imagine that one person wouldn’t be able to handle so many
tasks and food would get burnt, orders would take too long to fill, and customers
wouldn’t be happy. Restaurants break the tasks into different jobs so that they can
be efficient and effective. Object-oriented programs also try to distribute the tasks
to be done so that no one object does all the work.
2.2.3
Introduction to DrJava
You’ll actually be programming using a tool called DrJava. DrJava is a simple
editor (tool for entering program text) and interaction space so that you can try
things out in DrJava and create new recipes within it. DrJava is available for free
under the DrJava Open Source License, and it is under active development by the
JavaPLT group at Rice University.
To install DrJava, you’ll have to do these things:
1. Make sure that you have Java 1.4 or above installed on your computer. If
you don’t have it load it from the CD or you can get it from the Sun site at
http://www.java.sun.com.
i
i
i
i
i
“MAIN”
2004/5/11
page 21
i
Section 2.3
Programming in DrJava
21
2. You’ll need to install DrJava. You can either load it from the CD or get it
from http://drjava.org/.
3. Add the Java classes that come with the book to the extra classpaths for
DrJava. Start DrJava (see the next section for how to do this), click on Edit
and then Preferences. This will show the Preferences window. Click on
the Add button below the Extra Classpath textarea and add the following
path: c:/intro-prog-java/bookClasses.
FIGURE 2.1: DrJava Preferences Window
2.3
PROGRAMMING IN DRJAVA
How you start DrJava depends on your platform. In Linux, you’ll probably cd into
your DrJava directory and type a command like java -jar drjava-DATE-TIME.jar
where DATE-TIME are values for the release of DrJava that you are using. In Windows, you’ll have a DrJava icon that you’ll simply double-click. On the Macintosh,
you’ll probably have to type commands in your Terminal application where you cd
to the correct directory then type ./DrJava. See the instructions on the CD for
what will work for your kind of computer.
Common Bug: DrJava is slow to start
DrJava will take a while to load on all platforms. Don’t
worry—you’ll see the splash screen for a long time, but if
you see the splash screen (Figure 2.2), it will load.
i
i
i
i
i
“MAIN”
2004/5/11
page 22
i
22
Chapter 2
Introduction to Programming
FIGURE 2.2: DrJava Splash Screen
'
Common Bug: Making DrJava run faster
As we’ll talk more about later, when you’re running DrJava, you’re actually running Java. Java needs memory. If
you’re finding DrJava running slowly, give it more memory.
You can do that by quitting out of other applications that
you’re running. Your email program, your instant messenger, and your digital music player all take up memory
(sometimes lots of it!). Quit out of those and DrJava will
run faster.
$
&
%
Once you start DrJava, it will look something like Figure 2.3. There are three
main areas in DrJava (the bars between them move so that you can resize the
areas):
• The top left window pane is the files pane. It has a list of the open files
in DrJava. In Java each class that you create is usually stored in its own
file. Java programs often consist of more than one file. You can click on a
file name in the Files pane to view the contents of that file in the top right
window pane (definitions pane).
• The top right part is the definitions pane. This where you write your classes:
The collection of related data and methods. This area is simply a text editor—
think of it as Microsoft Word for your programs. The computer doesn’t
actually try to interpret the names that you type up in the program area
until you compile it. You can compile all the current files open in the files
pane by clicking on the Compile All button near the top of the DrJava
window.
Don’t worry if you hit Compile All before you save changes to a file. DrJava
won’t compile files until they are saved, so it will give you the chance to save
the changes then.
• The bottom part is the interactions pane. This is where you literally command
the computer to do something. You type your commands at the > prompt,
and when you hit return, the computer will interpret your words (i.e., apply
the meanings and encodings of the Java programming language) and do what
you have told it to do. This interpretation will include whatever you typed
and compiled in the definitions pane as well. In English you end sentences
with a period. In Java you typically end a programming statement with a
semicolon. However, in the interactions pane you can leave off the semicolon
and it will print the result of whatever you have typed. If you do add the
i
i
i
i
i
“MAIN”
2004/5/11
page 23
i
Section 2.3
Programming in DrJava
23
semicolon at the end of a Java statement in the interations pane it will do the
statement but not automatically print the result in the interactions pane.
FIGURE 2.3: DrJava (with annotations)
There are other features of DrJava visible in Figure 2.3. The Open button
will let you open a file and will add the file name to the files pane and show the
code in that file in the definitions pane. The Save button will save the file that
is currently displayed in the definitions pane. The Javadoc button creates the
HTML documentation from the Javadoc comments in your files (comments that
start with ’/**’ and end with ’*/’.
$
'
&
Making it Work Tip: Get to know your Help!
An important feature to already start exploring is the
Help. If you click on Help and then click on Help again
when a menu is displayed you will see a help window. Start
exploring it now so that you have a sense for what’s there
when you start writing your own programs.
%
i
i
i
i
i
“MAIN”
2004/5/11
page 24
i
24
2.4
Chapter 2
Introduction to Programming
MEDIA COMPUTATION IN DRJAVA
We’re going to start out by simply typing commands in the interactions pane—not
defining new names yet, but simply using the names that the computer already
knows from within Java (keywords, operators, and classes that come with a release
of Java).
The phrase System.out.println() is an important one to know. The meaning for System.out.println() is “Use the PrintStream object known as out on
the System class to display a readable representation of whatever is in the parentheses on the console window, followed by an end-of-line character.” You can have
nothing in the parentheses which will just move the output to a new line, or it can
be a name that the computer knows, or an expression (literally, in the algebraic
sense). Try typing System.out.println(34 + 56) by clicking in the interactions
area, typing the command, and hitting return—like this:
> System.out.println(34 + 56)
90
34 + 56 is a numeric expression that Java understands. Obviously, it’s composed of two numbers and an operation (in our sense, a name) that Java knows
how to do, + meaning “add.” Java understands other kinds of expressions, not all
numeric. In Java we call math symbols like ’+’ and ’-’ operators.
> System.out.println(34.1/46.5)
0.7333333333333334
> System.out.println(22 * 33)
726
> System.out.println(14 - 15)
-1
> System.out.println(5 % 2)
1
> System.out.println("Hello")
Hello
> System.out.println("Hello" + "Mark")
HelloMark
Java understands a bunch of standard math operations. As you might expect
’/’ is divide, ’*’ is multiply, ’-’ is subtract. Java also uses ’%’ for remainder as in
5 divided by 2 has a remainder of 1. This is also called the modulo operator. Java
knows how to recognize different kinds of numbers, both integer and floating point.
It also knows how to recognize strings (lists of characters) that are started and
ended with " (double quotes). It even knows what it means to “add” two strings
together: It simply puts one right after the other (appends them).
i
i
i
i
i
“MAIN”
2004/5/11
page 25
i
'
Section 2.4
Media Computation in DrJava
25
Common Bug: Java’s types can produce odd results
Java takes types seriously. If it sees you using integers, it
thinks you want an integer result from your expressions. If
it sees you use floating point numbers, it thinks you want
a floating point result. Sounds reasonable, no? But how
about:
$
> System.out.println(1.0/2.0)
0.5
> System.out.println(1/2)
0
1/2 is 0? Well, sure! 1 and 2 are integers. There is no
integer equal to 1/2, so the answer must be 0! Simply
by adding “.0” to an integer convinces Java that we’re
talking about floating point numbers (specifically the Java
primitive type double), so the result is in floating point
form.
&
%
Java also understands about functions. Remember functions from algebra?
They’re a “machine or box” into which you put one value, and out comes another.
Java calls these methods.
However, you can’t just call a function or method in Java like you can in
procedural languages. Every method or function must be defined in a class. There
are two types of methods in Java: class methods or object methods. Class methods
can be invoked (executed) by using the class name followed by a period and then
the method name. By convention class names in Java start with an uppercase
letter: like Character.
One of the class methods for the Character class takes a character as the input
value (the value that goes into the box) and returns (the value that comes out of
the box) the number that is the Unicode mapping for that character. Characters
in Java are specified between single quotes: ’A’. The name of that function is
getNumericValue() and you can use System.out.println to display the value
that the method getNumericValue() returns:
> System.out.println(Character.getNumericValue(’A’))
10
Another class method that’s built in to the Math class in Java is named
abs—it’s the absolute value function. It returns the absolute value of the input
value.
> System.out.println(Math.abs(1))
1
> System.out.println(Math.abs(-1))
1
i
i
i
i
i
“MAIN”
2004/5/11
page 26
i
26
Chapter 2
Introduction to Programming
FIGURE 2.4: The File Chooser
Debugging Tip: Common typos
If you type a class name and Java can’t figure out what
class you are taking about you will get an undefined class
error.
> Mat.abs(-3)
Error: Undefined class ’Mat’
If you mistype a method (function) name you will get the
following error:
> Math.ab(-3)
Error: No ’ab’ method in ’java.lang.Math’
FileChooser.pickAFile() is a class method on the FileChooser class. This is
a class that we created to make it easy for you to pick a file name and return a string
which represents the full path name of that file. The name of the function (method)
is pickAFile(). Java is very picky about capitalization—neither pickafile nor
Pickafile will work! Try it like this System.out.println(FileChooser.pickAFile()).
When you do, you will get something that looks like Figure 2.4.
You’re probably already familiar with how to use a file chooser or file dialog
like this:
• Double-click on folders/directories to open them.
• Click to select and then click Open, or double-click, to select a file.
Once you select a file, what gets returned is the full file name as a string (a
sequence of characters). (If you click Cancel, pickAFile() returns null which is a
i
i
i
i
i
“MAIN”
2004/5/11
page 27
i
Section 2.4
Media Computation in DrJava
27
Java keyword that means nothing. Try it: Do System.out.println(FileChooser.pickAFile())
and Open a file.
> System.out.println(FileChooser.pickAFile())
C:\intro-prog-java\mediasources\cat.jpg
What you get when you finally select a file will depend on your operating
system. On Windows, your file name will probably start with C: and will have
backslashes in it (e.g., “). On Linux or MacOS, it will probably look something like
the above. There are really two parts to this file name:
• The character between words (e.g., the \ between “intro-prog-java” and “mediasources”) is called the path separator . Everything from the beginning of
the file name to the last path separator is called the path to the file. That
describes exactly where on the hard disk (in which directory) a file exists.
• The last part of the file (e.g. “cat.jpg”) is called the base file name. When you
look at the file in the Finder/Explorer/Directory window (depending on your
operating system), that’s the part that you see. Those last three characters
(after the period) is called the file extension. It identifies the encoding of the
file.
Files that have an extension of “.jpg” are JPEG files. They contain pictures.
(To be picky, they contain data that can be interpreted to be a representation of a
picture – but that’s close enough to “they contain pictures.”) JPEG is a standard
encoding (a representation) for any kind of images. The other kind of media files
that we’ll be using frequently are “.wav” files (Figure 2.5). The “.wav” extension
means that these are WAV files. They contain sounds. WAV is a standard encoding
for sounds. There are many other kinds of extensions for files, and there are even
many other kinds of media extensions. For example, there are also GIF (“.gif”)
files for images and AIFF (“.aif” or “.aiff”) files for sounds. We’ll stick to JPEG
and WAV in this text, just to avoid too much complexity.
2.4.1
Showing a Picture
So now we know how to get a complete file name: Path and base name. This doesn’t
mean that we have the file itself loaded into memory. To get the file into memory, we
have to tell Java how to interpret this file. We know that JPEG files are pictures,
but we have to tell Java explicitly to read the file and make a Picture object from
it (an object of the Picture class). The way we create new objects in Java is to ask
the class to create a new object by new ClassName(parameters). So, to create
a new object of the Picture class from a file name use new Picture(fileName).
The fileName is the name of a file as a string. We know how to get a file name
using FileChooser.pickAFile().
> System.out.println(new Picture(FileChooser.pickAFile()))
Picture, filename
C:\intro-prog-java\mediasources\partFlagSmall.jpg height 217 width
139
i
i
i
i
i
“MAIN”
2004/5/11
page 28
i
28
Chapter 2
Introduction to Programming
FIGURE 2.5: File chooser with media types identified
The result from System.out.println suggests that we did in fact make a
picture object, from a given filename and with a given height and width. Success!
Oh, you wanted to actually see the picture? We’ll need another method! (Did I
mention somewhere that computers are stupid?) The method to show the picture
is named show().
You ask a picture object to show itself using the method show(). It may
seem strange to say that a picture knows how to show itself but in object-oriented
programming we treat objects as intelligent beings that know how to do the things
that we would expect an object to be able to do or that someone would want to do
to it. We typically show pictures so in object-oriented programming picture objects
know how to show themselves (make themselves visible).
We can now pick a file, make a picture, and show it in a couple of different
ways.
• We can do it all at once because the result from one method can be used in the
next method: new Picture(FileChooser.pickAFile()).show(). That’s
what we see in figure 2.6. This code will first invoke the pickAFile() class
method of the class FileChooser and that will return the selected file as a
string. Next it will create a new picture object with the selected file name.
And finally it will ask the created picture object to show itself.
• The second way is to name each of the pieces by using =. However, in Java
we can’t just use new names without saying what type of thing we expect the
name to represent. We call this declaring a variable. To declare a variable (a
name for data) use Type name; or Type name=something;.
i
i
i
i
i
“MAIN”
2004/5/11
page 29
i
Section 2.4
Media Computation in DrJava
29
FIGURE 2.6: Picking, making, and showing a picture, using the result of each method
in the next method
'
Making it Work Tip: Types in Java
A type in Java can be any of the predefined primitive types
(char, byte, int, short, long, float, double, or boolean)
or the name of a class. Java is not a completely objectoriented language in that the primitive types are not objects. Why are there so many primitive types? The answer
has to do with how many bits you want to use to represent
a value. The more bits you use the larger the number that
you can store. We will typically use only int, double, and
boolean in this book. The type int is for integer numbers
and takes up 32 bits. The type double is for floating point
numbers and takes up 64 bits. The type boolean is for
things that are just true or false so it takes up 1 bit. Java
uses primitive types to speed calculations.
A class name can be either a class defined as part of the
Java language like (String, JFrame, or BufferedImage) or
a class that you or someone else created (like the Picture
class we created).
$
&
%
We can name the file ( String fileName =) that we get from FileChooser.pickAFile().
i
i
i
i
i
“MAIN”
2004/5/11
page 30
i
30
Chapter 2
Introduction to Programming
This says that the name “fileName” will be of type String (will represent an object of
the String class) and that the String object that it will refer to will be returned from
FileChooser.pickAFile(). In a similar fashion we can create a name picture
that will represent an object of the Picture class that we get from creating a new
Picture object with the fileName Picture picture = new Picture(fileName).
We can then ask that Picture object to show itself by sending it the show() message using picture.show(). That’s what we see in figure 2.7.
'
$
&
Making it Work Tip: Java Conventions
By convention all class names in Java begin with an uppercase letter, all variable and method names begin with
a lowercase letter. This will help you tell the difference
between a class name and a variable or method name. So,
Picture is a class name since it starts with a uppercase
letter and picture is a variable name since it starts with a
lowercase letter. If a name has several words in it the convention is to uppercase the first letter of each additional
word like pickAFile(). A convention is the usual way of doing something which means that the compiler won’t care
if you don’t do it this way but other programmers will be
upset with you because it will make your programs harder
to understand.
Debugging Tip: Methods names must be followed
by parentheses!
In Java all methods (functions) have to have parentheses
after the method name both when you declare the method
and when you use it. You can’t leave off the parentheses
even if the method doesn’t take any parameters. So, you
must type picture.show() not picture.show.
%
If you try picture.show(), you’ll notice that there is no output from this
method. Methods in Java don’t have to return a value, unlike real mathematical
functions. A method may just do something (like opening up a picture in a window).
2.4.2
Playing a Sound
We can replicate this entire process with sounds.
• We still use FileChooser.pickAFile() to find the file we want and get its
file name.
• We now use new Sound(fileName ) to make a Sound object. new Sound(fileName),
as you might imagine, takes a name of a file as input.
• We will use play() to play the sound. The method play() is an object
method (invoked on a sound object). It plays the sound one time. It doesn’t
return anything.
i
i
i
i
i
“MAIN”
2004/5/11
page 31
i
Section 2.4
Media Computation in DrJava
31
FIGURE 2.7: Picking, making, and showing a picture, when naming the pieces
Here are the same steps we saw previously with pictures:
> System.out.println(FileChooser.pickAFile())
C:\intro-prog-java\mediasources\croak.wav
> System.out.println(new Sound(FileChooser.pickAFile()))
Sound file: croak.wav length: 17616
> new Sound(FileChooser.pickAFile()).play()
We’ll explain what the length of the sound means in the next chapter. Please
do try this on your own, using WAV files that you have on your own computer,
that you make yourself, or that came on your CD. (We talk more about where to
get the media and how to create it in future chapters.)
Congratulations! You’ve just worked your first media computation!
2.4.3
Naming your Media (and other Values)
The code new Sound(FileChooser.pickAFile()).play() looks awfully complicated and long to type. You may be wondering if there are ways to simplify it. We
can actually do it just the way that mathematicians have for centuries: We name
the pieces! The results from methods (functions) can be named, and these names
i
i
i
i
i
“MAIN”
2004/5/11
page 32
i
32
Chapter 2
Introduction to Programming
can be used as the inputs to other functions.
Since we have already mentioned naming so often, it probably doesn’t come
as any surprise that you can create your own names. Later, we’ll show how to name
your own methods (functions). Right now, let’s name our data. We call our names
for data variables
We name data using =. We can check our namings using System.out.println(),
just as we have been doing.
> int myVariable=12;
> System.out.println(myVariable);
12
> double anotherVariable=34.5;
> System.out.println(anotherVariable);
34.5
> String myName="Mark";
> System.out.println(myName);
Mark
Don’t read = as “equals.” That’s what it means in mathematics, but that’s not
at all what we’re doing here. Read = as “becomes a name for.” myVariable=12 thus
means “myVariable becomes a name for 12.” The reverse (putting the expression
on the left and the name on the right) thus makes no sense: 12 = myVariable
would then mean “12 becomes a name for myVariable.”
> int x = 2 * 8;
> System.out.println(x);
16
> 2 * 8 = x;
Syntax Error: ";"
We can easily reuse names.
> String myName = "Mark";
> System.out.println(myName);
Mark
> myName = "Barb";
> System.out.println(myName);
Barb
You can’t declare the same variable name twice. Declare the name one time
(by specifying the type and name) and then you can use it many times.
> String myName = "Mark";
> System.out.println(myName);
Mark
> String myName = "Sue";
Error: Redefinition of ’myName’
i
i
i
i
i
“MAIN”
2004/5/11
page 33
i
Section 2.4
Media Computation in DrJava
33
The binding between the name and the data only exists (a) until the name gets
assigned to something else or (b) you quit DrJava or (c) you reset the interactions
pane. The relationship between names and data (or even names and functions)
only exist during a session of DrJava.
Remember that data do have encodings or types. How the data act in expressions depends in part of their types. Notice how the integer : the primitive
type int 12 and the string: an object of the String class “12” act differently for
addition below. Both are doing something reasonable for their type, but they are
very different actions.
> int myVariable=12;
> System.out.println(myVariable+4);
16
> String myOtherVariable="12";
> System.out.println(myOtherVariable+4);
124
We can assign names to the results of methods (functions). If we name the
result from FileChooser.pickAFile(), each time we print the name, we get the
same result. We don’t re-run FileChooser.pickAFile(). Naming code in order to
re-execute it is what we’re doing when we define methods (functions), which comes
up in Section ??
> String fileName = FileChooser.pickAFile();
> System.out.println(fileName);
C:\intro-prog-java\mediasources\beach-smaller.jpg
> System.out.println(fileName);
C:\intro-prog-java\mediasources\beach-smaller.jpg
In the below example, we assign names to the file name and picture.
> String myFileName = FileChooser.pickAFile();
> System.out.println(myFileName);
C:\intro-prog-java\mediasources\katie.jpg
> Picture myPicture = new Picture(myFileName);
> System.out.println(myPicture);
Picture, filename C:\intro-prog-java\mediasources\katie.jpg height
360 width 381
Notice that the algebraic notions of subsitution and evaluation work here
as well. Picture myPicture = new Picture(myFileName) causes the exact same
picture to be created as if we had executed Picture myPicture = new Picture(FileChooser.pickAFile())1,
because we set myFileName to be equal to the result of FileChooser.pickAFile().
The values get substituted for the names when the expression is evaluated. new
Picture(myFileName) is an expression which, at evaluation time, gets expanded
into
new Picture ("C:\intro-prog-java\mediasources\katie.jpg")
1 Assuming,
of course, that you picked the same file.
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 34
i
34
Chapter 2
Introduction to Programming
because “C:“intro-prog-java“mediasources“katie.jpg” is the name of the file that
was picked when FileChooser.pickAFile() was evaluated and the returned value
was named myFileName.
We can also replace the method (function) invocations (“function calls”) with
the value returned. FileChooser.pickAFile() returns a String object—a bunch
of characters enclosed inside of double quotes. We can make the last example work
like this, too.
$
'
Common Bug: Backslashes and Slashes
You
have
seen
the
names
of
files
displayed
with
backslashes in
them,
such
as
C:\intro-prog-java\mediasources\beach-smaller.jpg.
However, when you create an object of the String class
in Java you can’t use backslashes for they are used to
create special characters like tab. You can use slashes ’/’
instead as a path separator. Java can still figure out the
path name when you use slashes. Actually, you can use
backslashes in the full path name but you would need to
double each one.
&
%
> String myFileName =
"C:/intro-prog-java/mediasources/katie.jpg";
> System.out.println(myFileName);
C:/intro-prog-java/mediasources/katie.jpg
> Picture myPicture = new Picture(myFileName);
> System.out.println(myPicture);
Picture, filename C:/intro-prog-java/mediasources/katie.jpg height
360 width 381
Or even substitute for the name.
> Picture aPicture = new
Picture("C:/intro-prog-java/mediasources/katie.jpg");
> System.out.println(aPicture);
Picture, filename C:/intro-prog-java/mediasources/katie.jpg height
360 width 381
Computer Science Idea: We can substitute names,
values, and methods.
We can substitute a value, a name assigned to that value,
and the method returning that value interchangeably. The
computer cares about the values, not if it comes from a
string, a name, or a method (function) call.
We actually don’t need to use System.out.println() every time we ask
the computer to do something. If we want to call a function that doesn’t return
anything (and so is pretty useless to System.out.println()), we can just call the
i
i
i
i
i
“MAIN”
2004/5/11
page 35
i
Section 2.5
Making a Recipe
35
method (function) by typing its name and its input (if any) in parentheses and
hitting return.
> aPicture.show();
We tend to call these statements to the computer that are telling it to do
things commands. System.out.println(aPicture) is a command. So is String
myFileName = FileChooser.pickAFile(), and aPicture.show(). These are more
than expressions: They’re telling the computer to do something.
2.5
MAKING A RECIPE
We have now used names to stand for values. The values get substituted for the
names when the expression is evaluated. We can do the same for recipes. We can
name a series of commands, so that we can just use the name whenever we want
the commands to be executed. This is exactly what defining a recipe or program
is about.
Remember when we said earlier that just about anything can be named in
computers? We’ve seen naming values. Now we’ll see naming recipes.
'
$
Making it Work Tip: Try every recipe!
To really understand what’s going on, type in, compile, and
execute every recipe in the book. EVERY one. None are
long, and the practice will go a long way towards convincing you that the programs work, developing your programming skill, and helping you understand why they work.
&
%
The way that Java defines the name of a new recipe is by declaring a method
inside a class definition. In object-oriented programming we need to decide who
(what class) is going to do the recipe as well as what are the steps to take in
doing the recipe. An object-oriented program is more like a large restaurant where
certain chefs specialize in the types of recipes they create. You might have a desert
chef and a French chef. Each class in an object-oriented program understands the
recipes defined inside of it.
You have seen how you declare variables in Java Type name; or Type name =
value;. To declare a method in Java use public Type methodName(parameterList).
Here the ’Type’ is the type of value being returned from the method. Remember
that a type can be any of the primitive types (char, byte, short, int, long, float,
double, boolean) or a class name.
The structure of how you declare a method is referred to as the syntax —the
words and characters that have to be there for Java to understand what’s going on,
and the order of those things.
A method declaration usually has a visibility (usually the keyword public
or private), the type of the thing being returned from the method, the method
name, and the parameter list in parentheses. This is followed by a block which has
curly braces around the series of commands you want to have executed when the
method is invoked.
i
i
i
i
i
“MAIN”
2004/5/11
page 36
i
36
Chapter 2
Introduction to Programming
Visibility means who can invoke the method (ask for the method to be done).
If the keyword public is used this method can be invoked by any code in any class
definition. If the keyword private is used then the method can only be accessed
from inside the class definition. You can think of this as a security feature. If your
phone number is public (listed) then anyone can look it up and call you. If your
phone number is private (unlisted) then only the people that live at the same house
will be able to call you.
There are two types of methods in Java. One is a class method and the other
an object method. Class methods operate on class fields and object methods operate
on class and object fields. Object methods are implicitly passed the current object
(accessed by the this keyword). To declare a class method you add the keyword
static to the method declaration. To declare an object method you leave off the
static keyword. The static keyword is usually given after the visibility.
The code to declare an object method such as show() for the Picture class
which doesn’t return a value and has no input parameters would be public void
show(). The class method pickAFile which is a class method in the FileChooser
class and returns a String object is declared as public static String pickAFile().
The return type is required and is given before the method name. If you leave
off a return type you will get a compiler error. If your method returns a value the
return type must match the type of the value returned. Remember that types can
be any of the primitive types (char, byte, int, short, long, float, double, or boolean)
or a class name. Methods that don’t return any value use the Java keyword void
for the return type.
By convention method names start with a lowercase letter and the first letter
of each additional word is uppercase: FileChooser.pickAFile(). The name of
this method is pickAFile. The first word is all lowercase and the first letter of each
additional word is capitalized.
A method must have parentheses following the method name. If any parameters are passed to the method then they will be declared inside the parentheses
separated by commas. To declare a parameter you must give a type and name.
We create a collection of commands by defining a block . A block is code
between an open curly brace ’’and a close curly brace ’}’. The block of commands
that follow a method declaration are the ones associated with the name of the
method (function).
Most real programs that do useful things, especially those that create user
interfaces, require the definition of more than one method (function). Imagine that
in the definitions pane you have several method declarations. How do you think
Java will figure out that one function has ended and a new one begun? Java needs
some way of figuring out where the method body ends: Which statements are part
of this method and which are part of the next? Java uses curly braces to do this.
All statements between the open curly brace and close curly brace are part of the
method body.
We can now define our first recipe! Open Picture.java by clicking on the Open
button near the top of the window and using the file chooser to pick Picture.java.
Type the following code into the definitions pane of DrJava before the last closing
curly brace (which ends the class definition). When you’re done, save the file and
i
i
i
i
i
“MAIN”
2004/5/11
page 37
i
Section 2.5
Making a Recipe
37
FIGURE 2.8: Defining and executing pickAndShow()
click the Compile All button near the top of the window (Figure 2.8).
Recipe 2: Pick and show a picture
public static void pickAndShow()
{
String fileName = FileChooser.pickAFile();
Picture picture = new Picture(fileName);
picture.show();
}
End of Recipe 2
Now you can execute your recipe (Figure ??). Click on the Interactions
tab in the interactions pane (near the bottom of the window). Since this is a class
method (because of the keyword static in the method declaration) you can execute
the method by using the class name (Picture) followed by a dot (period) and then
i
i
i
i
i
“MAIN”
2004/5/11
page 38
i
38
Chapter 2
Introduction to Programming
the method name. This method doesn’t take any parameters so just finish with the
open and close parenthesis.
> Picture.pickAndShow()
>
We can similarly define our second recipe, to pick and play a sound. Open the
Sound class definition file and type the following before the last close curly brace
’’ in the file. Then click the Compile All button to compile the file. You can
test this new class method (because of the static keyword) using the class name
Sound followed by dot (period) and then the method name. This method doesn’t
have any parameters so use Sound.pickAndPlay(); to test the new method.
Recipe 3: Pick and play a sound
public static void pickAndPlay()
{
String fileName = FileChooser.pickAFile();
Sound sound = new Sound(fileName);
sound.play();
}
End of Recipe 3
'
Making it Work Tip: Name the names you like
You’ll notice that, in the last section, we were using the
names myFileName and myPicture. In this recipe, I used
fileName and picture. Does it matter? Absolutely not!
Well, to the computer, at any rate. The computer doesn’t
care what names you use—they’re entirely for your benefit.
Pick names that (a) are meaningful to you (so that you can
read and understand your program), (b) are meaningful to
others (so that others you show your program to can understand it), and (c) are easy to type. 25-character names,
like,
myPictureThatIAmGoingToOpenAfterThis
are meaningful, easy-to-read, but are a pain to type.
$
&
%
While cool, this probably isn’t the most useful thing for you. Having to pick
the file over-and-over again is just annoying. But now that we have the power of
recipes, we can define new ones however we like! Let’s define one that will just
open a specific picture we want, and another that opens a specific sound we want.
Use FileChooser.pickAFile() to get the file name of the sound or picture
that you want. We’re going to need that in defining the recipe to play that specific
i
i
i
i
i
“MAIN”
2004/5/11
page 39
i
Section 2.5
Making a Recipe
39
sound or show that specific picture. We’ll just set the value of fileName directly,
instead of as a result of FileChooser.pickAFile(), by putting the string between
quotes directly in the recipe.
Recipe 4: Show a specific picture
Type in the following code before the last ’}’ in the Picture.java file. Be sure to
replace FILENAME below with the complete path to your own picture file, e.g.,
”C:/intro-prog-java/mediasources/katie.jpg”. Remember to use slashes instead of
backslashes in your file name.
public static void showPicture()
{
String myFile = "FILENAME";
Picture myPicture = new Picture(myFile);
myPicture.show();
}
End of Recipe 4
Recipe 5: Play a specific sound
Type in the following code before the last ’}’ in the Sound.java file. Be sure to
replace FILENAME below with the complete path to your own sound file, e.g.,
”C:/intro-prog-java/mediasources/thisisatest.wav”. Remember to use slashes instead of backslashes in the file name.
public static void playSound()
{
String myFile = "FILENAME";
Sound mySound = new Sound(myFile);
mySound.play();
}
End of Recipe 5
i
i
i
i
i
“MAIN”
2004/5/11
page 40
i
40
2.5.1
'
Chapter 2
&
Introduction to Programming
Making it Work Tip: Copying and pasting
Text can be copied and pasted between the interactions pane and definitions pane.
You can use
System.out.println(FileChooser.pickAFile())
to print a filename, then select it and copy it (from
the Edit menu), then click in the definitions pane and
paste it. Similarly, you can copy whole commands from
the interactions pane up to the definitions pane: That’s
an easy way to test the individual commands, and then
put them all in a recipe once you have the order right
and they’re working. You can also copy text within the
definitions pane. Instead of re-typing a command, select
it, copy it, paste it into the bottom line (make sure
the cursor is at the end of the line!), and hit return to
execute it.
Variable Recipes: Real functions that Take Input
$
%
How do we create a method (function) with inputs out of our stored recipe, like
Math.abs(-1) or new Picture(fileName)? Why would you want to?
An important reason for using input variables is to make a program more
general. Consider Recipe 4, Picture.showPicture(). That’s for a specific file
name. Would it be useful to have a function that could take any file name, then
make and show the picture? That kind of function handles the general case of
making and showing pictures. We call that kind of generalization abstraction.
Abstraction leads to general solutions that work in lots of situations.
Defining a recipe that takes input is very easy. It continues to be a matter of
substitution and evaluation. We’ll put a name inside those parentheses on the def
line. That name is sometimes called the parameter or input variable.
When you evaluate the function, by specifying its name with an input value
(also called the argument ) inside parentheses (like new Picture(myFileName) or
new Sound(aFileName)), the input value is assigned to the input variable. We say
that the input variable “takes on” the input value. During the execution of the
function (recipe), the input value will be substituted for the value.
Here’s what a recipe would look like that takes the file name as an input
variable:
Recipe 6: Show the picture file whose file name is input
public static void showNamed(String fileName)
{
Picture myPicture = new Picture(fileName);
myPicture.show();
}
i
i
i
i
i
“MAIN”
2004/5/11
page 41
i
Section 2.5
Making a Recipe
41
End of Recipe 6
When I type
Picture.showNamed("C:/intro-prog-java/mediasources/katie.jpg")
and hit return, the variable fileName takes on the value
"C:/intro-prog-java/mediasources/katie.jpg".
myPicture will then be assigned to the picture resulting from reading and interpreting the file at
‘‘C:/intro-prog-java/mediasources/katie.jpg’’
Then the picture is shown.
We can do a sound in the same way.
Recipe 7: Play the sound file whose file name is input
public static void playNamed(String fileName)
{
Sound mySound = new Sound(fileName);
mySound.play();
}
End of Recipe 7
We can also write recipes that take pictures or sounds in as the input values.
Here’s a recipe that shows a picture but takes the picture object as the input value,
instead of the filename.
Recipe 8: Show the picture provided as input
public static void showPicture(Picture myPicture)
{
myPicture.show();
}
End of Recipe 8
Now, what’s the difference between the method (function) showPicture()
and the provided method show()? Nothing at all. We can certainly create a
function that provides a new name to another function. If that makes your code
easier for you to understand, than it’s a great idea.
What’s the right input value for a function? Is it better to input a filename or
a picture? And what does “better” mean here, anyway? You’ll read more about all
i
i
i
i
i
“MAIN”
2004/5/11
page 42
i
42
Chapter 2
Introduction to Programming
of these later, but here’s a short answer: Write the function that is most useful to
you. If defining showPicture() is more readable for you than show(), then that’s
useful. If what you really want is a method that takes care of making the picture
and showing it to you, then that’s more useful and you might find the showNamed()
method the most useful.
OBJECTS AND FUNCTIONS SUMMARY
In this chapter, we talk about several kinds of encodings of data (or objects).
Integers
Floating
numbers
Strings
Java primitive type int e.g., 3
point
Java primitive type double e.g.,
5.2, 3.01
Java String object e.g., ”Hello!”
File name
Java String object
Pictures
object of our Picture class
Sounds
object of our Sound class
Numbers without a decimal
point—they
can’t
represent
fractions.
Numbers with a fractional piece
to them.
A sequence of characters (including spaces, punctuation, etc.) delimited on either end with a double quote character.
A filename is just a string whose
characters represent a path, path
separators, and a base file name.
Pictures are encodings of images,
typically coming from a JPEG
file.
Sounds are encodings of sounds,
typically coming from a WAV file.
Here are the functions introduced in this chapter:
i
i
i
i
i
“MAIN”
2004/5/11
page 43
i
Section 2.5
Character.getNumericValue(character)
Math.abs(number)
FileChooser.pickAFile()
new Picture(fileName)
picture.show()
new Sound(fileName)
sound.play()
Making a Recipe
43
Returns the equivalent numeric
value in Unicode for the input
character.
Takes a number and returns the
absolute value of it.
Lets the user pick a file and returns the complete path name as
a string.
Takes a name of a file as input,
reads the file, and creates a picture from it. Returns the created
picture object.
Shows the picture object that it
is invoked on. No return value.
Takes a filename as input, reads
the file, and creates a sound from
it. Returns the sound object.
Plays the sound object that it is
invoked on.
PROBLEMS
2.1. Try some other operations with strings in Java. What happens if you add a
number to a string, like 3 + "Hello"?
2.2. You can combine the sound playing and picture showing commands in the same
recipe. Trying playing a sound and then show a picture while a sound is playing.
Try playing a sound and opening several pictures while the sound is still playing.
The hardest decision is where to put this method. It could go on the Sound or
Picture class or perhaps it would go on a new MixedMedia class. Where does it
make sense to put it?
2.3. We evaluated the expression FileChooser.pickAFile() when we wanted to execute the function named pickAFile(). But what is the name pickAFile()
anyway? You could open the FileChooser class and find that method declaration.
2.4. Try the Sound.playNamed() method. You weren’t given any examples of its use,
but you should be able to figure it out from Picture.showNamed().
TO DIG DEEPER
The best (deepest, most material, most elegant) computer science textbook is Structure and Interpretation of Computer Programs [1], by Abelson, Sussman, and Sussman. It’s a hard book to get through, though. Somewhat easier, but in the same
spirit is the new book How to Design Programs [6].
Neither of these books are really aimed at students who want to program
because it’s fun or because they have something small that they want to do. They’re
really aimed at future professional software developers. The best books aimed at
the less hardcore user are by Brian Harvey. His book Simply Scheme uses the
i
i
i
i
i
“MAIN”
2004/5/11
page 44
i
44
Chapter 2
Introduction to Programming
same programming language as the earlier two, Scheme, but is more approachable.
My favorite of this class of books, though, is Brian’s three volume set Computer
Science Logo Style [10] which combine good computer science with creative and fun
projects.
There is a wealth of material for Java on Sun’s Java web site http://java.
sun.com including tutorials, papers, and APIs. To learn more about DrJava see
the web site http://www.drjava.org/. Thinking in Java by Bruce Eckel is a great
book for those who have some coding experience and like to understand a language
deeply. Beginners might want to start with Beginning Java by Ivor Horton, or
Headfirst Java by Kathy Sierra and Bert Bates.
i
i
i
i
i
“MAIN”
2004/5/11
page 45
i
P A R T
T W O
PICTURES
Chapter 3
Encoding and Manipulating Pictures
Chapter 4
Advanced Pictures
Chapter 5
Advanced Sounds
Chapter 6
Design and Debugging
45
i
i
i
i
i
“MAIN”
2004/5/11
page 46
i
C H A P T E R
3
Encoding and Manipulating
Pictures
3.1
3.2
3.3
3.4
3.5
3.6
3.7
3.8
HOW PICTURES ARE ENCODED
MANIPULATING PICTURES
CHANGING COLOR VALUES
COPYING PIXELS
COPYING AND TRANSFORMING PICTURES
REPLACING COLORS
COMBINING PIXELS: BLURRING
COLOR FIGURES
Pictures (images, graphics) are an important part of any media communication. In this chapter, we discuss how pictures are represented on a computer
(mostly as bitmap images—each dot or pixel is represented separately) and how
they can be manipulated. The next chapter will discuss more about other kinds of
representations, such as vector images.
3.1
HOW PICTURES ARE ENCODED
Pictures are two-dimensional arrays of pixels. In this section, each of those terms
will be described.
For our purposes, a picture is an image stored in a JPEG file. JPEG is an
international standard for how to store images with high quality but in little space.
JPEG is a lossy compression format. That means that it is compressed , made
smaller, but not with 100% of the quality of the original format. Typically, though,
what gets thrown away is stuff that you don’t see or don’t notice anyway. For most
purposes, a JPEG image works fine.
An array is a sequence of elements, each with an index number associated
with it. The first element in an array is at index 0, the second at index 1, the third
at index 2, and so on. The last element of the array will always be at the length of
the array minus one. An array with 5 elements will have its last element at index
4. It may sound strange to say that the first element of an array is at index 0 but
the index is based on the distance from the beginning of the array to the element.
Since the first item of the array is at the beginning of the array the distance is 0.
You can access elements of an array in Java using arrayName[index]. For
example, to access the first element in an array named pixels use pixels[0]. You
can get the number of items in an array using arrayName.length.
46
i
i
i
i
i
“MAIN”
2004/5/11
page 47
i
'
Section 3.1
How Pictures are Encoded
47
Making it Work Tip: Using dot notation for public
fields
Notice that there are no parenthesis following
arrayName.length. This is because length is not a
method but a public field (data). Public fields can be
accessed using dot notation objectName.fieldName.
Methods always have parenthesis after the method
name even if there are no input parameters, such as
FileChooser.pickAFile().
$
&
%
A two-dimensional array is a matrix . A matrix is a collection of elements
arranged in both a horizontal and vertical sequence. For one dimensional arrays
you would talk about an element at index i, that is array[i]. For two-dimensional
arrays you talk about an element at column i and row j, that is, matrix[i][j].
In Figure 3.1, you see an example matrix. At coordinates (0, 0) (horizontal,
vertical), you’ll find the matrix element whose value is 15. The element at(1, 1) is
7, (2, 1) is 43, and (3, 1) is 23. We will often refer to these coordinates as (x, y)
((horizontal, vertical).
FIGURE 3.1: An example matrix
What’s stored at each element in the picture is a pixel . The word “pixel” is
short for “picture element.” It’s literally a dot, and the overall picture is made up
of lots of these dots. Have you ever taken a magnifying glass to pictures in the
newspaper or magazines, or to a television or even your own computer monitor?
(Figure 3.2 was generated by capturing as an image the of the top left part of the
DrJava window and then magnifying it 600%. It’s made up of many, many dots.
When you look at the picture in the magazine or on the television, it doesn’t look
like it’s broken up into millions of discrete spots, but it is.
You can get a similar view of individual pixels using the picture explorer,
which is discussed later in this chapter. The picture explorer allows you to zoom a
picture up to 500% where each individual pixel is visible (Figure 3.3).
Our human sensor apparatus can’t distinguish (without magnification or other
special equipment) the small bits in the whole. Humans have low visual acuity—we
don’t see as much detail as, say, an eagle. We actually have more than one kind
i
i
i
i
i
“MAIN”
2004/5/11
page 48
i
48
Chapter 3
Encoding and Manipulating Pictures
FIGURE 3.2: Upper left corner of DrJava window with part magnified 600%
FIGURE 3.3: Image shown in the picture explorer: 100% image on left and 500% on
right
of vision system in use in our brain and our eyes. Our system for processing color
is different than our system for processing black-and-white (or luminance). We
actually pick up luminance detail better with the sides of our eyes than the center
of our eye. That’s an evolutionary advantage since it allows you to pick out the
sabertooth sneaking up on your side.
That lack of resolution in human vision is what makes it possible to digitize
pictures. Animals that perceive greater details than humans (e.g., eagles or cats)
may actually see the individual pixels. We break up the picture into smaller elements (pixels), but there are enough of them and they are small enough that the
picture doesn’t look choppy when looked at it overall. If you can see the effects
of the digitization (e.g., lines have sharp edges, you see little rectangles in some
spots), we call that pixelization—the effect when the digitization process becomes
obvious.
Picture encoding is actually more complex than sound encoding. A sound is
inherently linear—it progresses forward in time. A picture has two dimensions, a
width and a height.
Visible light in continuous—visible light is any wavelength between 370 and
730 nanometers (0.00000037 and 0.00000073 meters). But our perception of light
is limited by how our color sensors work. Our eyes have sensors that trigger (peak)
around 425 nanometers (blue), 550 nanometers (green), and 560 nanometers (red).
Our brain determines what a particular color based on the feedback from these
i
i
i
i
i
“MAIN”
2004/5/11
page 49
i
Section 3.1
How Pictures are Encoded
49
three sensors in our eyes. There are some animals with only two kinds of sensors,
like dogs. Those animals still do perceive color, but not the same colors nor in
the same way as humans do. One of the interesting implications of our limited
visual sensory apparatus is that we actually perceive two kinds of orange. There is
a spectral vision—a particular wavelength that is natural orange. There is also a
mixture of red and yellow that hits our color sensors just right that we perceive as
the same orange.
Based on how we perceive color, as long as we encode what hits our three
kinds of color sensors, we’re recording our human perception of color. Thus, we
will encode each pixel as a triplet of numbers. The first number represents the
amount of red in the pixel. The second is the amount of green, and the third is
the amount of blue. We can make up any human-visible color by combining red,
green, and blue light (Figure 3.4) (replicated at Figure 3.42 (page 134). Combining
all three gives us pure white. Turning off all three gives us black. We call this the
RGB model .
FIGURE 3.4: Merging red, green, and blue to make new colors
There are other models for defining and encoding colors besides the RGB color
model. There’s the HSV color model which encodes Hue, Saturation, and Value.
The nice thing about the HSV model is that some notions, like making a color
“lighter” or “darker” map cleanly to it (e.g., you simply change the saturation).
Another model is the CMYK color model , which encodes Cyan, Magenta, Yellow,
and blacK (“B” could be confused with Blue). The CMYK model is what printers
use—those are the inks they combine to make colors. However, the four elements
means more to encode on a computer, so it’s less popular for media computation.
RGB is probably the most popular model on computers.
Each color component (sometimes called a channel ) in a pixel is typically
represented with a single byte, eight bits. Eight bits can represent 256 values (28 ),
which we typically use to represent the values 0 to 255. Each pixel, then, uses 24
bits to represent colors. Using the same formula (22 4), we know that the standard
encoding for color using the RGB model can represent 16,777,216 colors. There are
certainly more than 16 million colors in all of creation, but it turns out that it just
doesn’t matter—humans have no technology that comes even close to being able
i
i
i
i
i
“MAIN”
2004/5/11
page 50
i
50
Chapter 3
Encoding and Manipulating Pictures
to replicate 16 million distinct colors. Printing technology, color pictures, color
monitors—none of these technologies can represent anything close to 16 million
colors. So, the 24 bit RGB model is just fine for most purposes.
There are computer models that use more bits per pixel. For example, there
are 32 bit models which use the extra 8 bits to represent transparency—how much
of the color “below” the given image should be blended with this color? These
additional 8 bits are sometimes called the alpha channel . There are other models
that actually use more than 8 bits for the red, green, and blue channels, and while
they do capture (encode) more color information, we don’t usually need that much
information.
We actually perceive borders of objects, motion, and depth through a separate vision system. We perceive color through one system, and luminance (how
light/dark things are) through another system. Luminance is not actually the
amount of light, but our perception of the amount of light. We can measure the
amount of light (e.g., the number of photons reflected off the color) and show that
a red and a blue spot each are reflecting the same amount of light, but we’ll perceive the blue as darker. Our sense of luminance is based on comparisons with
the surroundings—the optical illusion in Figure 3.5 highlights this. The two end
quarters are actually the same level of gray, but because the two mid quarters end
in a sharp contrast of lightness and darkness, we perceive that one end is darker
than the other.
FIGURE 3.5: The ends of this figure are the same colors of gray, but the middle two
quarters contrast sharply so the left looks darker than the right
Most tools for allowing users to pick out colors let the users specify the color
as RGB components. The Macintosh offers RGB sliders in its basic color picker
(Figure 3.6). The color chooser in Java offers a similar set of sliders (Figure 3.7).
As mentioned a triplet of (0, 0, 0) (red, green, blue components) is black,
and (255, 255, 255) is white. (255, 0, 0) is pure red, but (100, 0, 0) is red, too—just
darker. (0, 100, 0) is a dark green, and (0, 0, 100) is a dark blue.
When the red component is the same as the green and as the blue, the resultant color is gray. (50, 50, 50) would be a fairly dark gray, and (150, 150, 150) is a
lighter gray.
The Figure 3.8 (replicated at Figure 3.43 (page 134) in the color pages at the
end of this chapter) is a representation of pixel RGB triplets in a matrix representation. Thus, the pixel at (1, 0) has color (30, 30, 255) which means that it has a
red value of 30, a green value of 30, and a blue value of 255—it’s a mostly blue
color, but not pure blue. Pixel at (2, 1) has pure green but also more red and blue
i
i
i
i
i
“MAIN”
2004/5/11
page 51
i
Section 3.1
How Pictures are Encoded
51
FIGURE 3.6: The Macintosh OS X RGB color picker
FIGURE 3.7: Picking a color using RGB sliders from Java
((150, 255, 150)), so it’s a fairly light green.
Images on disk and even in computer memory are usually stored in some kind
of compressed form. The amount of memory needed to represent every pixel of
even small images is pretty large (Table 3.1). A fairly small image of 320 pixels
across by 240 pixels wide, with 24-bits per pixel, takes up nearly 2 million bits. A
computer monitor with 1024 pixels across and 768 pixels vertically with 32-bits per
pixel takes up a whopping 25 million bits of data or over 3 million bytes of data (A
byte is 8 bits).
TABLE 3.1: Number of bits needed to store pixels at various sizes and formats
24-bit color
32-bit color
320x240 image
1, 843, 200 bits
2, 457, 600 bits
640x480
7, 372, 800 bits
9, 830, 400 bits
1024x768
18, 874, 368 bits
25, 165, 824 bits
i
i
i
i
i
“MAIN”
2004/5/11
page 52
i
52
Chapter 3
Encoding and Manipulating Pictures
FIGURE 3.8: RGB triplets in a matrix representation
3.2
MANIPULATING PICTURES
We manipulate pictures in DrJava by making a picture object out of a JPEG file,
then changing the pixels in that picture. We change the pixels by changing the color
associated with the pixel—by manipulating the red, green, and blue components.
We make pictures using new Picture(fileName ). We make the picture appear with the Picture method show(). We can also explore a picture with the
method explore().
> String fileName = FileChooser.pickAFile();
> System.out.println(fileName);
C:\intro-prog-java\mediasources\catapillarClipart.jpg
> Picture picture=new Picture(fileName);
> picture.show();
> System.out.println(picture);
Picture, filename
C:\intro-prog-java\mediasources\catapillarClipart.jpg height 181
width 360
What new Picture(fileName) does is to scoop up all the bytes at the input filename, bring them in to memory, reformat them slightly, and place a sign
on them “This is a picture object!” When you execute Picture picture = new
Picture(fileName), you are saying “The name picture is referring to a Picture
object created from the contents of the file.”
Picture objects know their width and their height. You can query them with
the methods getWidth() and getHeight().
> System.out.println(picture.getWidth());
360
> System.out.println(picture.getHeight());
181
i
i
i
i
i
“MAIN”
2004/5/11
page 53
i
Section 3.2
Manipulating Pictures
53
We can get any particular pixel from a picture using getPixel(x,y)where x
and y are the coordinates of the pixel desired. The x coordinate starts at 0 at the top
left of the picture and increasing horizontally. The y coordinate starts at 0 at the
top left of the picture and increases vertically. We can also get a one-dimensional
array containing all the pixels in the picture using the method getPixels().
> Pixel pixel = picture.getPixel(0,0);
> System.out.println(pixel);
Pixel red=255 green=255 blue=255
> Pixel[] pixels=picture.getPixels();
> System.out.println(pixels[0]);
Pixel red=255 green=255 blue=255
Pixels know where they came from. You can ask them their x and y coordinates with getX() and getY().
> System.out.println(pixel.getX());
0
> System.out.println(pixel.getY());
0
Each pixel knows how to getRed() and setRed(redValue). (Green and blue
work similarly.)
> System.out.println(pixel.getRed());
255
> pixel.setRed(0);
> System.out.println(pixel.getRed());
0
You can ask a pixel for its color with getColor(), and you can ask the pixel to
set the color with setColor(color). Color objects know their red, green, and blue
components. You can also create new color objects with new Color(redValue,greenValue,blueValue).
The Color class also has several colors predefined that you can use. If you need a
color object that represents the color black you can use Color.black, for yellow
use Color.yellow. Other colors that are predefined are: Color.blue, Color.green,
Color.red, Color.gray, Color.orange, Color.pink, Color.cyan, Color.magenta, and
Color.white.
i
i
i
i
i
“MAIN”
2004/5/11
page 54
i
54
'
Chapter 3
&
Encoding and Manipulating Pictures
Making it Work Tip: Importing Classes from Packages
Color is a Java class in the package java.awt. A package is
a group of related classes. To use classes in packages other
than java.lang (which contains System and Math) you will
need to import them. Importing a class or all classes in
a package allows you to use the name of a class without
fully qualifying it by using the package name followed by a
period (dot) and the class name. The fully qualified name
for the Color class is java.awt.Color. You can always
use the fully qualified name instead of importing but people don’t usually want to type that much. To import all
classes in the package java.awt use import java.awt.*;.
To import just the Color class from the package java.awt
use import java.awt.Color;.
Debugging Tip: Undefined Class Error
If you get the message Error: Undefined class ’Color’
it means that you didn’t import the class Color. You
must either import classes that are in packages other than
java.lang or fully qualify them. To import just the class
Color so that you can refer to it using just the class name
use import java.awt.Color;. If you are using several
classes from the same package you can import all classes
in a package using import java.awt.*;. You can type
the import statement in the interactions pane. When you
write class files the import statements go before the class
definition at the beginning of the file.
$
%
> import java.awt.Color;
> Color color=pixel.getColor();
> System.out.println(color);
java.awt.Color[r=255,g=255,b=255]
> Color newColor=new Color(0,100,0);
> System.out.println(newColor);
java.awt.Color[r=0,g=100,b=0]
> pixel.setColor(newColor);
> System.out.println(pixel.getColor());
java.awt.Color[r=0,g=100,b=0]
If you change the color of a pixel, the picture that the pixel is from does get
changed. However you won’t see the change until the picture repaints.
> System.out.println(picture.getPixel(0,0));
Pixel red=0 green=100 blue=0
i
i
i
i
i
“MAIN”
2004/5/11
page 55
i
Section 3.2
'
Manipulating Pictures
55
Common Bug: Seeing changes in the picture
If you show your picture, and then change the pixels, you
might be wondering, “Where are the changes?!?” Picture
displays don’t automatically update. If you ask the picture to repaint using picture.repaint(), the picture will
update.
$
&
%
One of the important things that you can do with colors is to compare them.
Some recipes for manipulating pictures will do different things with pixels depending on the color of the pixel. There are several ways of comparing pictures.
One way of comparing colors is the same way that one would compare numbers. We can subtract the red, green, and blue values of two colors. If we do
that, we can create a new color whose red, green, and blue components are the
amount of difference between the colors for those components. We can also use
color1.equals(color2) to compare colors to see if they have the same red, green,
and blue values. We would use the operator == to test if they are the same color
object.
Debugging Tip: == and .equals
The operator ’==’ tests to see if two objects are the same
object or if two primitive types have the same value. Use
object1.equals(object2) to test if two objects have the same
data. To test if two String objects have the same characters
in them use string1.equals(string2) not (string1 ==
string2). The test string1 == string2 will only be true
if both variables refer to the same String object.
> Color color1 = new Color(10,10,10);
> System.out.println(color1);
java.awt.Color[r=10,g=10,b=10]
> Color color2 = new Color(20,20,20);
> System.out.println(color2);
java.awt.Color[r=20,g=20,b=20]
> int diffRed = Math.abs(color1.getRed() - color2.getRed());
> int diffGreen = Math.abs(color1.getGreen() - color2.getGreen());
> int diffBlue = Math.abs(color1.getBlue() - color2.getBlue());
> Color colorDiff = new Color(diffRed,diffGreen,diffBlue);
> System.out.println(colorDiff);
java.awt.Color[r=10,g=10,b=10]
> System.out.println(color1.equals(color2));
false
> System.out.println(color1.equals(colorDiff));
true
> System.out.println(color1 == colorDiff);
false
Another method of comparing pictures is with a notion of color distance.
i
i
i
i
i
“MAIN”
2004/5/11
page 56
i
56
Chapter 3
Encoding and Manipulating Pictures
You often won’t care about an exact match of colors—two shades of blue might be
close enough for your purposes.
The distance between two colors is the Cartesian distance between the colors
as points in a three-dimensional space, where red, green, and blue are the three
dimensions.
Recall that the distance between two points (x1 , y1 ) and (x2 , y2 ) is:
p
(x1 − x2 )2 + (y1 − y2 )2
The similar measure for two colors (red1 , green1 , blue1) and (red2 , green2 , blue2)
is: p
(red1 − red2 )2 + (green1 − green2 )2 + (blue1 − blue2 )2
You can automatically get a darker or lighter color from a current color object
with color.darker() or color.brighter(). (Remember that this was easy in
HSV, but not so easy in RGB. These functions do it for you.)
> Color testColor = new Color(168,131,105);
> System.out.println(testColor);
java.awt.Color[r=168,g=131,b=105]
> testColor = testColor.darker();
> System.out.println(testColor);
java.awt.Color[r=117,g=91,b=73]
> testColor = testColor.brighter();
> System.out.println(testColor);
java.awt.Color[r=167,g=130,b=104]
Notice that even though we darken the color and then brighten it the final
color doesn’t exactly match the original color. This is due to rounding errors. A
rounding error is when calculations are done in floating point but the answer is
stored in an integer. The floating point result can’t fit in the type of the result
(integer) and so some of the detail is lost .
You can also get a color using ColorChooser.pickAColor(), which gives you
a variety of ways of picking a color. ColorChooser is a class that we have created
to make it easy for you to pick colors using the Java class JColorChooser.
> import java.awt.Color;
> Color pickedColor = ColorChooser.pickAColor();
> System.out.println(pickedColor);
java.awt.Color[r=51,g=255,b=102]
When you have finished manipulating a picture, you can write it out to a file
with picture.write(fileName).
> picture.write("newPicture.jpg");
Common Bug: End with .jpg
Be sure to end your filename with “.jpg” in order to get
your operating system to recognize it as a JPEG file.
i
i
i
i
i
“MAIN”
2004/5/11
page 57
i
'
Section 3.2
Manipulating Pictures
57
Common Bug: Saving a file quickly—and how to
find it again!
What if you don’t know the whole path to a directory of
your choosing? You don’t have to specify anything more
than the base name. The problem is finding the file again!
In what directory did it get saved? This is a pretty simple
bug to resolve. The default directory (the one you get if
you don’t specify a path) is wherever DrJava is.
$
&
%
We don’t have to write new functions to manipulate pictures. We can do it
from the command area using the functions just described.
>
>
>
>
>
>
>
>
>
>
>
>
>
>
String fileName = "C:/intro-prog-java/mediasources/catapillarClipart.jpg";
Picture picture = new Picture(fileName);
picture.show();
picture.getPixel(10,100).setColor(Color.black);
picture.getPixel(11,100).setColor(Color.black);
picture.getPixel(12,100).setColor(Color.black);
picture.getPixel(13,100).setColor(Color.black);
picture.getPixel(14,100).setColor(Color.black);
picture.getPixel(15,100).setColor(Color.black);
picture.getPixel(16,100).setColor(Color.black);
picture.getPixel(17,100).setColor(Color.black);
picture.getPixel(18,100).setColor(Color.black);
picture.getPixel(19,100).setColor(Color.black);
picture.repaint();
The result showing a small black line on the left side appears in Figure 3.9.
The black line is 100 pixels down, and the pixels 10 though 19 from the left edge
have been turned black.
FIGURE 3.9: Directly modifying the pixel colors via commands: Note the small black
line on the left under the leaf
i
i
i
i
i
“MAIN”
2004/5/11
page 58
i
58
3.2.1
Chapter 3
Encoding and Manipulating Pictures
Exploring pictures
On your CD, you will find the MediaTools application with documentation for
how to get it started. You can also open a picture explorer in DrJava. Both the
MediaTools application and the picture explorer will let you get pixel information
from a picture. You saw the picture explorer in Figure 3.3 and the MediaTools
application appears in Figure 3.10. Both of these will display the x, y, red, green,
and blue values for a pixel. They will also both let you zoom in or out.
The picture explorer can be opened on a picture object. Picture p = new
Picture(FileChooser.pickAFile()); will allow you to define a picture and name
it p. You can open a picture explorer on the picture using p.explore(). The picture
explorer will make a copy of the current picture and show it. The copy will not
be affected by any changes you make to the picture.
The picture explorer allows you to zoom at various levels of magnification, by
choosing one in the Zoom menu. As you move your cursor around in the picture,
press down with the mouse button. You’ll be shown the (x, y) (horizontal, vertical)
coordinates of the pixel your mouse cursor is currently over, and the red, green,
and blue values at that pixel.
The MediaTools application works from files on the disk. If you want to check
out a file before loading into DrJava, use the MediaTools application. Click on the
Picture Tools box in MediaTools, and the tools will open. Use the Open button
to bring up a file selection box—you click on directories you want to explore on the
left, and images you want on the right, then click OK. When the image appears,
you have several different tools available. Move your cursor over the picture and
press down with the mouse button.
• The red, green, and blue values will be displayed for the pixel you’re pointing
at. This is useful when you want to get a sense of how the colors in your
picture map to numeric red, green, and blue values. It’s also helpful if you’re
going to be doing some computation on the pixels and want to check the
values.
• The x and y position will be display for the pixel you’re point at. This is
useful when you want to figure out regions of the screen, e.g., if you want to
process only part of the picture. If you know the range of x and y coordinates
where you want to process, you can tune your program to reach just those
sections.
• Finally, a magnifier is available to let you see the pixels magnified. (The
magnifier can be clicked and dragged around.)
3.3
CHANGING COLOR VALUES
The easiest thing to do with pictures is to change the color values of their pixels
by changing the red, green, and blue components. You can get radically different
effects by simply tweaking those values. Many of Adobe Photoshop’s filters do just
what we’re going to be doing in this section.
The way that we’re going to be manipulating colors is by computing a percentage of the original color. If we want 50% of the amount of red in the picture,
i
i
i
i
i
“MAIN”
2004/5/11
page 59
i
Section 3.3
Changing color values
59
FIGURE 3.10: Using the MediaTools image exploration tools
we’re going to set the red channel to 0.50 times whatever it is right now. If we want
to increase the red by 25%, we’re going to set the red to 1.25 times whatever it is
right now. Recall that the asterisk (*) is the operator for multiplication in Java.
3.3.1
Using loops in pictures
What we could do is to get each pixel in the picture and change its red value. Let’s
say that we want to decrease the red by 50%. We can always write code like this:
>
>
>
>
>
>
>
>
>
>
>
>
>
String fileName = "C:/intro-prog-java/mediasources/catapillarClipart.jpg";
Picture pict = new Picture(fileName);
pict.show();
Pixel currPixel = pict.getPixel(11,100);
int redValue = currPixel.getRed();
currPixel.setRed((int) (redValue * 0.5));
currPixel = pict.getPixel(11,101);
redValue = currPixel.getRed();
currPixel.setRed((int) (redValue * 0.5));
currPixel = pict.getPixel(11,102);
redValue = currPixel.getRed();
currPixel.setRed((int) (redValue * 0.5));
pict.repaint();
That’s pretty tedious to write, especially for all the pixels in even a small
image. What we need is way of telling the computer to do the same thing over and
over again. Well, not exactly the same thing—we want to change what’s going on
in a well-defined way. We want to take one step each time, or process one additional
pixel.
We can do that with a for loop. A for loop executes a command or group
of commands in a block. A for loop continues executing until a continuation test
i
i
i
i
i
“MAIN”
2004/5/11
page 60
i
60
Chapter 3
Encoding and Manipulating Pictures
is false. Each time through the loop one or more variables can be changed.
The syntax for a for loop is:
for (initialization area; continuation test; change area)
Let’s talk through the pieces here.
• First comes the required Java keyword for.
• Next we have a required opening parenthesis
• Next is the initialization area. You can declare and initialize variables here.
For example, you can have int i=0 which declares a variable i of the primitive
type int and initializes it to 0. You can initialize more than one variable here
by separating the initializations with commas.
• Next comes the required semicolon.
• Next is the continuation test. This holds an expression that returns true or
false. When this expression is true the loop will continue to be executed.
When this test is false the loop will finish and the statement following the
loop will be executed.
• Next comes the required semicolon.
• Next is the change area. Here you usually increment or decrement variables,
such as i++ to increment i. i++ is a shorthand way of saying i = i + 1. You
can use either i++ or i=i+1, they both will increment the value in i by 1. The
statements in the change area actually take place after each execution of the
body of the loop.
• Next is the required closing parenthesis.
If you just want to execute one statement (command) in the body of the loop
it can just follow on the next line. It is normally indented to show that it is part of
the for loop. If you want to execute more than one statements in the body of the
for loop you will need to enclose the statements in a block (a set of open and close
curly braces).
For example, here is the for loop that simply sets each pixel’s color to black
in a picture.
> import java.awt.Color;
> Pixel[] pixels = pict.getPixels();
> for (int i=0; i<pixels.length; i++)
pixels[i].setColor(Color.black);
>pict.repaint();
Let’s talk through this code.
• We are using the Color class so we need to either use the fully qualified name
(java.awt.Color) or import the Color class using import java.awt.Color;.
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 61
i
Section 3.3
Changing color values
61
• Next we declare a variable pixels that references an array of Pixel objects
(Pixel[]). We get the array of Pixel objects by asking the picture object
for them using the getPixels() method.
• Next we have a for loop. In the for loop initialization area a variable i is
declared of type int and the value of it is set to 0. The continuation test will
be true as long as variable i is less than the length of the pixels array. Since
arrays are indexed starting at 0 the last element that we want to process is
at index (length - 1). The change area will increment the value of i each time
we finish executing the body of the loop.
• The body of the for loop simply tells the current pixel (element of the pixel
array at index i) to set its color to the color black.
• The statement after the body of the for loop will ask the picture object to
repaint so that we can see the color change.
Debugging Tip: Loops and Variable Declarations
Remember that you can’t declare a variable more than
once so you shouldn’t put variable declarations inside
loops. Declare any variables that you will need before you
start the loop or in the initialization area of the for loop.
You don’t actually have to put loops into functions to use them. You can
type them into the command area of DrJava. However, you will need to put the
whole loop on one line.
> for (int i=0; i<pixels.length; i++) pixels[i].setColor(Color.black);
Now that we see how to get the computer to do thousands of commands
without writing thousands of individual lines, let’s do something useful with this.
3.3.2
Increasing/decreasing red (green, blue)
A common desire when working with digital pictures is to shift the redness (or
greenness or blueness—but most often, redness) of a picture. You might shift it
higher to “warm” the picture, or to reduce it to “cool” the picture or deal with
overly-red digital cameras.
The below recipe reduces the amount of red 50% in the current picture. It
uses the variable p to stand for the pixel (where we used the variable pixel before).
It doesn’t matter—the names are merely our choices.
Recipe 9: Reduce the amount of red in a picture by 50%
/**
* Method to decrease the red by half in the current picture
*/
i
i
i
i
i
“MAIN”
2004/5/11
page 62
i
62
Chapter 3
Encoding and Manipulating Pictures
public void decreaseRed()
{
Pixel[] pixels = this.getPixels();
Pixel p = null;
int value = 0;
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
p = pixels[i];
// get the value
value = p.getRed();
// set the red value to half what it was
p.setRed((int) (value * 0.5));
}
}
End of Recipe 9
Go ahead and type the above into your DrJava definitions pane before the last
curly brace in the Picture.java file. Click Compile All to get DrJava to compile
the new method.
'
$
Making it Work Tip: Comments in Java
You may notice that there are some interesting characters
in the reduceRed recipe. The ’/**’ and ’//’ are comments
in Java. Comments are descriptions of what your code
is doing. Use comments to make the code easier to read
and understand (not only for yourself but also for others).
There are actually three kinds of comments in Java. The
’//’ starts a comment and tells the computer to ignore everything following till the end of the line. You can use
’/*’ followed at some point by ’*/’ for a multi-line comment. The ’/**’ followed at some point by ’*/’ creates
a JavaDoc comment. JavaDoc is a utility that pulls the
JavaDoc comments from your class files and creates hyperlinked documentation from them. All of the Java class
files written by Sun have JavaDoc comments in them and
that is how the API documentation was created.
&
%
This recipe works on a picture object—the one that we’ll use to get the pixels
from. To get a picture, we need a filename then we need to make a picture from
it. After we ask the picture to decreaseRed(), we’ll want to repaint the picture to
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 63
i
Section 3.3
Changing color values
63
FIGURE 3.11: The original picture (left) and red-reduced version (right)
see the effect. Therefore, the decreaseRed recipe can be used like this:
>
>
>
>
>
String fileName = "C:/intro-prog-java/mediasources/catapillarClipart.jpg";
Picture picture = new Picture(fileName);
picture.show();
picture.decreaseRed();
picture.repaint();
'
Common Bug: Patience: for loops can take a long
time
The most common bug with this kind of code is to give up
and quit because you don’t think the loop is working. It
might take a full minute (or two!) for some of the manipulations we’ll do—especially if your source image is large.
$
&
%
The original picture and its red-reduced version appear in Figure 3.11 (and
at Figure 3.44 on page 135). 50% is obviously a lot of red to reduce! The picture
looks like it was taken through a blue filter.
Tracing the program: How did that work?.
Computer Science Idea: The most important skill
is tracing
The most important skill that you can develop in programming is the ability to trace your program. (This is sometimes also called stepping or walking through your program.
To trace your program is to walk through it, line-by-line,
and figure out what happens. Looking at a program, can
you predict what it’s going to do? You should be able to
by thinking through what it does.
Let’s trace the method to reduce red and see how it worked. We want to
break in at the point where we just called decreaseRed()
> String fileName = "C:/intro-prog-java/mediasources/catapillarClipart.jpg";
> Picture picture = new Picture(fileName);
> picture.show();
i
i
i
i
i
“MAIN”
2004/5/11
page 64
i
64
Chapter 3
Encoding and Manipulating Pictures
> picture.decreaseRed();
What happens now? picture.decreaseRed() really means invoking the decreaseRed method which you have just added to the Picture.java file on the Picture
object referred to by the variable picture.
/**
* Method to decrease the red by half in the current picture
*/
public void decreaseRed()
{
Pixel[] pixels = this.getPixels();
Pixel p = null;
int value = 0;
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
p = pixels[i];
// get the value
value = p.getRed();
// set the red value to half what it was
p.setRed((int) (value * 0.5));
}
}
The first line we execute is Pixel[] pixels = this.getPixels(). Let’s
break this down.
• The Pixel[] pixels = is a declaration of a variable ’pixels’ that references
an array of Pixel objects. The ’=’ means that the variable pixels will be initialized to the result of the right side expression which is this.getPixels().
• The this is a keyword that represents the current object. Since the method
declaration doesn’t have the keyword static in it this is an object method.
Object methods are always implicitly passed the current object (the object
the method was invoked on). In this case the method decreaseRed() was
invoked by picture.decreaseRed(); so the Picture object referenced by the
variable picture is the current object. We could leave off the this and get
the same result. If you don’t reference any object when invoking a method
the compiler will assume you mean the current object (referenced by the this
keyword).
• The this.getPixels() invokes the method getPixels() on the current object. This method returns a one-dimensional array of Pixel objects which are
the pixels in the current Picture object.
i
i
i
i
i
“MAIN”
2004/5/11
page 65
i
Section 3.3
Changing color values
65
So at the end of the first line we have a variable pixels that is referring to
an array of Pixel objects. The pixel objects came from the Picture object which
was referred to as picture in the interaction pane and as this in the method
reduceRed().
Next is a declaration of a couple of variables that we will need in the for loop.
We will need something to represent the current Pixel object Pixel p = null;.
We start it off referring to nothing by using the keyword null. We also will need
a variable to hold the current red value and we declare that as int value = 0;.
We initialize the variable ’value’ to be 0. Variables that you declare inside methods
are not automatically initialized for you so you should initialize them when you
declare them.
Computer Science Idea: Scope
The names inside a method like p and value are completely
different than the names in the Command Area or any
other method. We say that they have a different scope.
The scope of a variable is the area of a program in which
the variable is known. The variables that we declare inside
of a method are only known from where they are declared
until the end of the method. Variables declared in the
initialization area of a for loop are only known until the
end of the body of the for loop.
Next comes the for loop for (int i = 0; i < pixels.length; i++). This
declares a variable i of the type int and initializes it to 0. It tests that the value
of i is less that the length of the pixels array and if so will execute the statements
in the body of the loop.
In the body of the loop we have p = pixels[i];. This will set the p variable
to point to a Pixel object in the pixels array with an index equal to the current
i
i
i
i
i
“MAIN”
2004/5/11
page 66
i
66
Chapter 3
Encoding and Manipulating Pictures
value of i. Since i is initialized to 0 in the for loop the first time through this loop
the pixel variable will point to the first Pixel object in the pixels array.
Next in the body of the loop is value = p.getRed();. This sets the variable
value to the amount of red in the current pixel.
Next in the body of the loop is p.setRed((int) (value * 0.5));. This
changes the amount of red in the pixel to half of its original value. The (int)
(value * 0.5) is needed because the variable value is declared of type int and
yet the calculation of (value * 0.5) contains a floating point number and so will
automatically be done in floating point. However, a floating point result (say of 1.5)
won’t fit into a variable of type int. So, the compiler won’t let us do this without
telling it that we really want it to by including the (int). This is called casting
and is required whenever a larger value is being placed into a smaller variable. So
if the result of the multiplication has a fractional part that fractional part will just
be thrown away so that the result can fit in an int.
After the statements in the body of the loop are executed the i++ will be
executed which will add one to the current value of i. The value of i will change to
1.
What happens next is very important. The loop starts over again. The
continuation test will check that the value in i is less than the length of the pixels
array and since the value of i is less the statements in the body of the loop will be
executed again. The variable p will be set to the pixel object in the pixels array at
index 1.
i
i
i
i
i
“MAIN”
2004/5/11
page 67
i
Section 3.3
Changing color values
67
The value variable is updated to get the red value for the pixel pointed to
by p (this happens to have the same value as the previous pixel but it could have
changed).
The red value for the pixel pointed to by p will be changed to 50% the original
value.
At the end of each loop body the commands in the change area will be executed
again (so the value in i will increment). Next, the continuation test will be evaluated
and if the result is true the commands in the loop body will be executed again.
If the continuation test evaluates to false execution will continue with the first
statement after the body of the loop.
Eventually, we get Figure 3.11 (and at Figure 3.44 on page 135). We keep
going through all the pixels in the sequence and changing all the red values.
Testing the program: Did that really work?.
How do we know that that really worked? Sure, something happened to the
picture, but did we really decrease the red? By 50%?
$
'
Making it Work Tip: Don’t just trust your programs!
It’s easy to mislead yourself that your programs worked.
After all, you told the computer to do a particular thing,
you shouldn’t be surprised if the computer did what you
wanted. But computers are really stupid—they can’t figure out what you want. They only do what you tell them.
It’s pretty easy to get it almost right. Actually check.
&
%
We can check it several ways. One way is with the picture explorer. Create two
picture objects: Picture p = new Picture(FileChooser.pickAFile()); and Picture
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 68
i
68
Chapter 3
Encoding and Manipulating Pictures
FIGURE 3.12: Using the picture explorer to convince ourselves that the red was
decreased
p2 = new Picture(FileChooser.pickAFile()); and pick the same picture each
time. Decrease red in one of them. Then open a picture explorer on each of the
picture objects using p.explore(); and p2.explore();.
We can also use the functions that we know in the Command Area to check
the red values of individual pixels.
> String fileName = "C:/intro-prog-java/mediasources/catapillarClipart.jpg";
> Picture pict = new Picture(fileName);
> Pixel pixel = pict.getPixel(0,0);
> System.out.println(pixel);
Pixel red=255 green=255 blue=255
> pict.decreaseRed();
> Pixel newPixel = pict.getPixel(0,0);
> System.out.println(newPixel);
Pixel red=127 green=255 blue=255
> System.out.println( 255 * 0.5);
127.5
Increasing red.
Let’s increase the red in the picture now. If multiplying the red component
by 0.5 reduced it, multiplying it by something over 1.0 should increase it. I’m going
to apply the increase to the exact same picture, to see if we can reduce the blue
(Figure 3.13 and Figure 3.45).
Recipe 10: Increase the red component by 30%
/**
* Method to increase the amount of red by 1.3
*/
public void increaseRed()
{
Pixel[] pixels = this.getPixels();
Pixel pixel = null;
int value = 0;
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 69
i
Section 3.3
Changing color values
69
FIGURE 3.13: Overly blue (left) and red increased by 30% (right)
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// get the value
value = pixel.getRed();
// set the red value to 1.3 times what it was
pixel.setRed((int) (value * 1.3));
}
}
End of Recipe 10
We can even get rid of a color completely. The below recipe erases the blue
component from a picture by setting the blue value to 0 in all pixels(Figure 3.14
and Figure 3.46).
Recipe 11: Clear the blue component from a picture
/**
* Method to clear the blue from the picture (set
* the blue to 0 for all pixels)
*/
public void clearBlue()
{
Pixel[] pixels = this.getPixels();
Pixel pixel = null;
// loop through all the pixels
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 70
i
70
Chapter 3
Encoding and Manipulating Pictures
FIGURE 3.14: Original (left) and blue erased (right)
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// set the blue on the pixel to 0
pixel.setBlue(0);
}
}
End of Recipe 11
3.3.3
Creating a sunset
We can certainly do more than one picture manipulation at once. One that I wanted
to do was to try to generate a sunset out of a beach scene. My first attempt was to
increase the red, but that doesn’t work. Some of the red values in a given picture
are pretty high. If you go past 255 for a channel value, you wrap-around. If you
setRed of a pixel to 256, you’ll actually get zero! So, increasing red created bright
blue-green (no red) spots.
My second thought was that maybe what happens in a sunset is that there is
less blue and green, thus emphasizing the red, without actually increasing it. Here
was the program that I wrote for that:
Recipe 12: Making a sunset
/**
* Method to simulate a sunset by reducing the green and blue
*/
public
public void makeSunset()
{
i
i
i
i
i
“MAIN”
2004/5/11
page 71
i
Section 3.3
Changing color values
71
FIGURE 3.15: Original beach scene (left) and at (fake) sunset (right)
Pixel[] pixels = this.getPixels();
Pixel pixel = null;
int value = 0;
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// change the blue value
value = pixel.getBlue();
pixel.setBlue((int) (value * 0.7));
// change the green value
value = pixel.getGreen();
pixel.setGreen((int) (value * 0.7));
}
}
End of Recipe 12
What we see happening in Recipe 12 is that we’re changing both the blue
and green channels—reducing each by 30%. The effect works pretty well, as seen
in Figure 3.15 (and in the color section at Figure 3.47).
3.3.4
Making sense of methods
You probably have lots of questions about methods at this point. Why did we
write these methods in this way? How is that we’re reusing variable names like
pixel in both the method and Command Area? Are there other ways to write
these methods? Is there such a thing as a better or worse method?
Since we’re always picking a file (or typing in a filename) then making a picture, before calling one of our picture manipulation functions, and then showing or
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 72
i
72
Chapter 3
Encoding and Manipulating Pictures
repainting the picture, it’s a natural question why we’re not building those in. Why
doesn’t every method have String fileName = FileChooser.pickAFile(); and
new Picture(fileName); in it?
We actually want to write the methods to make them more general and
reusable. We want our methods to do one and only one thing, so that we can
use the method again in a new context where we need that one thing done. An example might make that clearer. Consider the recipe to make a sunset (Recipe 12).
That works by reducing the green and blue, each by 30%. What if we rewrote that
method so that it called two smaller methods that just did the two pieces of the
manipulation? We’d end up with something like Recipe 13.
Recipe 13: Making a sunset as three methods
/**
* Method to reduce the green in the picture by 30%
*/
public void reduceGreen()
{
Pixel[] pixels = this.getPixels();
Pixel pixel = null;
int value = 0;
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// get the value
value = pixel.getGreen();
// set the green value to 70% of what it was
pixel.setGreen((int) (value * 0.7));
}
}
/**
* Method to reduce the blue in the picture by 30%
*/
public void reduceBlue()
{
Pixel[] pixels = this.getPixels();
Pixel pixel = null;
int value = 0;
i
i
i
i
i
“MAIN”
2004/5/11
page 73
i
Section 3.3
Changing color values
73
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// get the value
value = pixel.getBlue();
// set the blue value to 70% of what it was
pixel.setBlue((int) (value * 0.7));
}
}
/**
* Method to make a picture look like it was taken at sunset
* by reducing the blue and green to make it look more red
*/
public void makeSunset()
{
reduceGreen();
reduceBlue();
}
End of Recipe 13
The first thing to note is that this actually does work. makeSunset() does the
same thing here as in the previous recipe. It’s perfectly okay to have one method
(makeSunset() in this case) use other methods in the same class (reduceBlue()
and reduceGreen()). You use makeSunset() just as you had before. It’s the same
recipe (it tells the computer to do the same thing), but with different methods.
The earlier recipe did everything in one method, and this one does it in three.
In fact, you can also use reduceBlue() and reduceGreen()—make a picture in
the Command Area and pass it as input to either of them. They work just like
decreaseRed().
What’s different is that the function makeSunset() is much simpler to read.
That’s very important.
i
i
i
i
i
“MAIN”
2004/5/11
page 74
i
74
Chapter 3
Encoding and Manipulating Pictures
Computer Science Idea: Programs are for people.
Computers don’t care about how a program looks. Programs are written to communicate with people. Making
programs easy to read and understand means that they are
more easily changed and reused, and they more effectively
communicate process to other humans. Notice that first
we had a method called decreaseRed() that reduced the
red in the picture by 50% Later we added reduceBlue()
that reduced the blue in the picture by 30%. Wouldn’t it
be better to use similar names for methods that do similar things? We could rename the method that reduced
the red as reduceRed(). What about the differences in
the amount of reduction? Should we call the method that
reduces the red 50% reduceRed50Percent?
What if we had written reduceBlue() and reduceGreen() so that each asked
you to pick a file and created the picture before changing the color. We would be
asked for the picture twice—once in each function. Because we wrote these functions
to only reduce the blue and reduce the green (“one and only one thing”), we can
use them in new functions like makeSunset()1
Now, let’s say that we asked you to pick a picture and created the picture in
makeSunset() before calling the other methods. The methods reduceBlue() and
reduceGreen() are completely flexible and reusable again. But makeSunset() is
now less flexible and reusable. Is that a big deal? No, not if you only care about
having the ability to give a sunset look to a single picked picture. But what if you
later want to build a movie with a few hundred frames, to each of which you want
to add a sunset look? Do you really want to pick out each of those few hundred
frames? Or would you rather write a method to go through each of the frames
(which we’ll learn how to do in a few chapters) and send each of these pictures the
message makeSunset(). That’s why we make methods general and reusable—you
never know when you’re going to want to use that method again, in a larger context.
1 There is an issue that the new makeSunset() will take twice as long to finish as the original
one, since every pixel gets changed twice. We address that issue in a later chapter on speed and
complexity. The important issue is still to write the code readably first, and worry about efficiency
later.
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 75
i
'
Section 3.3
Changing color values
75
Making it Work Tip: Don’t start by trying to write
applications
There’s a tendency for new programmers to want to write
complete applications that a non-technical user can use.
You might want to write a makeSunset() application that
goes out and fetches a picture for a user and generates a
sunset for them. Building good user interfaces that anyone
can use is hard work. Start out more slowly. It’s hard
enough to make a method just operates on a picture. You
can work on user interfaces later.
$
&
%
We could also write these functions with explicit filenames, by saying at the
beginning of one of the programs:
String fileName = "C:/intro-prog-java/mediasources/catapillarClipart.jpg";)
That way, we wouldn’t get prompted for a file each time. But then the
methods only work for the one file, and if we want them to work for some other file,
we have to modify the function. Do you really want to change the method each
time you use it? It’s easier to leave the method alone, and change the picture that
you use to invoke the method.
Of course, we could change any of our methods to be handed a filename rather
than a picture. For example, we could write:
/**
* Method to create a picture from the passed file name and
* reduce the green in it
* @param fileName the name of the file to create the picture from
* @return the created picture
*/
public static void reduceGreen(String fileName)
{
Picture picture = new Picture(fileName);
Pixel[] pixels = picture.getPixels();
Pixel pixel = null;
int value = 0;
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// get the value
value = pixel.getGreen();
// set the green value to 70% of what it was
pixel.setGreen((int) (value * 0.7));
}
i
i
i
i
i
“MAIN”
2004/5/11
page 76
i
76
Chapter 3
Encoding and Manipulating Pictures
}
/**
* Method to create a picture and reduce the blue in it
* @param fileName the name of the file to use to create the picture
* @return the created picture
*/
public static void reduceBlue(String fileName)
{
Picture picture = new Picture(fileName);
Pixel[] pixels = picture.getPixels();
Pixel pixel = null;
int value = 0;
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// get the value
value = pixel.getBlue();
// set the blue value to 70% of what it was
pixel.setBlue((int) (value * 0.7));
}
}
/**
* Method to simulate a sunset by reducing the green and blue
* @param fileName the name of the file to use
*/
public static void makeSunset(String fileName)
{
reduceGreen(fileName);
reduceBlue(fileName);
}
Notice that the methods are now class methods (because they have the static
keyword in the method declarations). They are class methods because they no
longer operate on the current picture object. Instead they create a picture object
inside the method and work on that.
Is this better or worse than the code we saw before? At some level, it doesn’t
matter – we can work with pictures or filenames, whichever makes more sense to
us. The filename version does have several disadvantages, though. For one, it
doesn’t work—the picture object gets made in each of reduceGreen(fileName)
and reduceBlue(fileName), but then it doesn’t get saved, so it gets lost at the
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 77
i
Section 3.3
Changing color values
77
end of the function. We could fix that by saving the file out to disk after we’re done
with each method, but then the functions are doing more than “one and only one
thing.” There’s also the inefficiency of making the picture twice, and if we were to
add in the saving, saving the picture twice. Again, the best functions do “one and
only one thing.” Also in doing object-oriented programming the idea is to create
objects and have the objects do the work. It isn’t a good idea put most of the work
into class methods.
Even larger methods, like makeSunset(), do “one and only one thing.” makeSunset()
makes a sunset-looking picture. It does that by reducing green and reducing blue.
It calls two other methods to do that. What we end up with is a hierarchy of
goals—the “one and only one thing” that is being done. makeSunset() does its
one thing, by asking two other methods to do their one thing. We call this hierarchical decomposition (breaking down a problem into smaller parts, and then
breaking down those smaller parts until you get something that you can easily program), and it’s very powerful for creating complex programs out of pieces that you
understand.
Names in methods are completely separate from names in the interactions
pane. The only way to get any data (pictures, sounds, filenames, numbers) from
the interactions pane into a function is by passing it in as input to the function.
Within the function, you can use any names you want–names that you first define
within the method (like pixel in the last example) or names that you use to stand
for the input data (like fileName) only exist while the method is running. When
the method is done, those variable names literally do not exist anymore.
This is really an advantage. Earlier, we said that naming is very important
to computer scientists: We name everything, from data to methods to classes. But
if each name could mean one and only one thing ever, we’d run out of names. In
natural language, words mean different things in different contexts (e.g., “What do
you mean?” and “You are being mean!”.) A method is a different context—names
can mean something different than they do outside of that method.
Sometimes, you will compute something inside a method that you want to
return to the interactions pane or to a calling method. We’ve already seen methods
that output a value, like FileChooser.pickAFile() which outputs a filename. If
you did a new Picture(fileName) inside a method, you might want to output the
picture object that you created inside the function. You can do that by using the
return keyword, which we’ll talk more about later.
The name that you give to a method’s input can be thought of as a placeholder .
Whenever the placeholder appears, imagine the input data appearing instead. So,
in a method like:
/**
* Method to simulate a sunset by reducing the green and blue
* @param fileName the name of the file to use
*/
public static void makeSunset(String fileName)
{
reduceGreen(fileName);
reduceBlue(fileName);
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 78
i
78
Chapter 3
Encoding and Manipulating Pictures
}
We are going to call makeSunset() with a statement like // makeSunset("C:/intro-prog-java/mediasources/cat
Whatever string is in // makeSunset("C:/intro-prog-java/mediasources/catapillarClipart.jpg")
becomes known as fileName while makeSunset() is running.
We’ve now talked about different ways of writing the same method—some
better, some worse. There are others that are pretty much equivalent, and others
that are much better. Let’s consider a few more ways that we can write methods.
We can pass in more than input at a time. Consider this version of decreaseRed:
/**
* Method to decrease the red by an amount
* @param amount the amount to change the red by
*/
public void decreaseRed(double amount)
{
Pixel[] pixels = this.getPixels();
Pixel pixel = null;
int value = 0;
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// get the value
value = pixel.getRed();
// set the red value to the original value times the passed amount
pixel.setRed((int) (value * amount));
}
}
We would use this one by saying something like myPicture.decreaseRed(0.25).
That particular use would reduce the red by 75%. We could say myPicture.decreaseRed(1.25)
and increase red by 25%. Perhaps this function should be better named changeRed,
because that’s what it is now—a general way of changing the amount of red for
every pixel in a picture. That’s a pretty useful and powerful function.
Recall seeing in Recipe 11 this code:
/**
* Method to clear the blue from the picture (set
* the blue to 0 for all pixels)
*/
public void clearBlue()
{
Pixel[] pixels = this.getPixels();
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 79
i
Section 3.3
Changing color values
79
Pixel pixel = null;
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// set the blue on the pixel to 0
pixel.setBlue(0);
}
}
We could also write that same recipe like this:
/**
* Method to clear the blue from the picture (set
* the blue to 0 for all pixels)
*/
public void clearBlue()
{
Pixel[] pixels = this.getPixels();
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
pixels[i].setBlue(0);
}
It’s important to note that this function achieves the exact same thing as the
earlier recipe did. Both set the blue channel of all pixels to zero. An advantage of
the second method is that it is shorter and doesn’t require a variable declaration
for a pixel. However, it may be harder for someone to understand. A shorter recipe
isn’t necessarily better.
3.3.5
Lightening and darkening
To lighten or darken a picture is pretty simple. It’s the same pattern as we saw
previously, but instead of changing a color component, you change the overall color.
Here’s lightening and then darkening as recipes. Figure 3.16 (Figure 3.48) shows
the lighter and darker versions of the original picture seen earlier.
Recipe 14: Lighten the picture
/**
* Method to lighten the colors in the picture
*/
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 80
i
80
Chapter 3
Encoding and Manipulating Pictures
public void lighten()
{
Pixel[] pixels = this.getPixels();
Color color = null;
Pixel pixel = null;
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// get the current color
color = pixel.getColor();
// get a lighter color
color = color.brighter();
// set the pixel color to the lighter color
pixel.setColor(color);
}
}
End of Recipe 14
Recipe 15: Darken the picture
/**
* Method to darken the color in the picture
*/
public void darken()
{
Pixel[] pixels = this.getPixels();
Color color = null;
Pixel pixel = null;
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// get the current color
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 81
i
Section 3.3
Changing color values
81
color = pixel.getColor();
// get a darker color
color = color.darker();
// set the pixel color to the darker color
pixel.setColor(color);
}
}
End of Recipe 15
FIGURE 3.16: Lightening and darkening of original picture
3.3.6
Creating a negative
Creating a negative image of a picture is much easier than you might think at first.
Let’s think it through. What we want is the opposite of each of the current values
for red, green, and blue. It’s easiest to understand at the extremes. If we have a
red component of 0, we want 255 instead. If we have 255, we want the negative to
have a zero.
Now let’s consider the middle ground. If the red component is slightly red
(say, 50), we want something that is almost completely red—where the “almost”
is the same amount of redness in the original picture. We want the maximum red
(255), but 50 less than that. We want a red component of 255 − 50 = 205. In
general, the negative should be 255 − original. We need to compute the negative
of each of the red, green, and blue components, then create a new negative color,
and set the pixel to the negative color.
Here’s the recipe that does it, and you can see even from the grayscale image
that it really does work (Figure 3.17 and Figure 3.49).
Recipe 16: Create the negative of the original picture
/**
* Method to negate the picture
i
i
i
i
i
“MAIN”
2004/5/11
page 82
i
82
Chapter 3
Encoding and Manipulating Pictures
*/
public void negative()
{
Pixel[] pixels = this.getPixels();
Pixel pixel = null;
int redValue, blueValue, greenValue = 0;
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// get the current red, green, and blue values
redValue = pixel.getRed();
greenValue = pixel.getGreen();
blueValue = pixel.getBlue();
// set the pixel’s color to the new color
pixel.setColor(new Color(255 - redValue, 255 - greenValue, 255 - blueValue));
}
}
End of Recipe 16
FIGURE 3.17: Negative of the image
3.3.7
Converting to grayscale
Converting to grayscale is a fun recipe. It’s short, not hard to understand, and yet
has such a nice visual effect. It’s a really nice example of what one can do easily
yet powerfully by manipulating pixel color values.
Recall that the resultant color is gray whenever the red component, green
component, and blue component have the same value. That means that our RGB
encoding supports 256 levels of gray from, (0, 0, 0) (black) to (1, 1, 1) through
(100, 100, 100) and finally (255, 255, 255). The tricky part is figuring out what
the replicated value should be.
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 83
i
Section 3.3
Changing color values
83
What we want is a sense of the intensity of the color. It turns out that it’s
pretty easy to compute: We average the three component colors. Since there are
three components, the formula for intensity is:
(red+green+blue)
3
This leads us to the following simple recipe and Figure 3.18 (and Figure 3.50
on page 136).
Recipe 17: Convert to grayscale
/**
* Method to change the picture to gray scale
*/
public void grayscale()
{
Pixel[] pixels = this.getPixels();
Pixel pixel = null;
int intensity = 0;
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// compute the intensity of the pixel (average value)
intensity = (int) ((pixel.getRed() + pixel.getGreen() +
pixel.getBlue()) / 3);
// set the pixel color to the new color
pixel.setColor(new Color(intensity,intensity,intensity));
}
}
End of Recipe 17
This is an overly simply notion of grayscale. Below is a recipe that takes into
account how the human eye perceives luminance. Remember that we consider blue
to be darker than red, even if there’s the same amount of light reflected off. So, we
weight blue lower, and red more, when computing the average.
Recipe 18: Convert to grayscale with more careful control of luminance
i
i
i
i
i
“MAIN”
2004/5/11
page 84
i
84
Chapter 3
Encoding and Manipulating Pictures
FIGURE 3.18: Color picture converted to grayscale
/**
* Method to change the picture to gray scale with luminance
*/
public void grayscaleWithLuminance()
{
Pixel[] pixels = this.getPixels();
Pixel pixel = null;
int luminance = 0;
double redValue = 0;
double greenValue = 0;
double blueValue = 0;
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// get the corrected red, green, and blue values
redValue = pixel.getRed() * 0.299;
greenValue = pixel.getGreen() * 0.587;
blueValue = pixel.getBlue() * 0.114;
// compute the intensity of the pixel (average value)
luminance = (int) (redValue + greenValue + blueValue);
// set the pixel color to the new color
pixel.setColor(new Color(luminance,luminance,luminance));
}
}
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 85
i
Section 3.4
Copying pixels
85
End of Recipe 18
3.4
COPYING PIXELS
We can only get so far in our image processing with getPixels() before we need
to know where a pixel is. For example, if we want to process only some of the pixels
in a picture (say, just the red in someone’s eyes, but not the red in her dress), we
need to control which pixels we’re manipulating.
3.4.1
Looping across the pixels with a nested loop
Unlike sounds and samples (as we’ll see later), we can’t use just a single for loop
if we want to address every pixel. We have to use two for loops—one to move
horizontally across the pixels, and the other to move vertically to get every pixel.
The function getPixels() did this inside itself, to make it easier to write simple
picture manipulations. But if you want to access each individual pixel, you’ll need
to use two loops, one for each dimension of the picture. The inner loop will be
nested inside the outer loop, literally, inside its block.
Your loops will look something like this:
// loop through the columns (x direction)
for (int x = 0; x < getWidth(); x++)
{
// loop through the rows (y direction)
for (int y = 0; y < getHeight(); y++)
{
// get the current pixel
pixel = getPixel(x,y);
// do something to the color
// set the new color
pixel.setColor(aColor);
}
}
For example, here’s Recipe 14 (page 79), but using explicit pixel references.
Recipe 19: Lighten the picture using nested loops
/**
* Method to lighten the colors in the picture
*/
public void lighten()
{
i
i
i
i
i
“MAIN”
2004/5/11
page 86
i
86
Chapter 3
Encoding and Manipulating Pictures
Color color = null;
Pixel pixel = null;
// loop through the columns (x direction)
for (int x = 0; x < getWidth(); x++)
{
// loop through the rows (y direction)
for (int y = 0; y < getHeight(); y++)
{
// get pixel at the x and y location
pixel = getPixel(x,y);
// get the current color
color = pixel.getColor();
// get a lighter color
color = color.brighter();
// set the pixel color to the lighter color
pixel.setColor(color);
}
}
}
End of Recipe 19
Let’s walk through (trace) how it would work. Imagine that we just executed
picture.lighten().
1. picture.lighten() maps to the object method in the Picture class public
void lighten(). The method is implicitly passed the current picture object
(you can refer to the current picture object using the keyword this).
2. java.awt.Color color = null; and Pixel pixel = null; declare the variables color (an object of the Color class) and pixel (an object of the Pixel
class). Both of these are initialized to null (not referring to any object yet).
These variables will be needed when we are looping through the pixels. We
could declare these in the for loop but then they would be redeclared each
time through the loop. We can declare them once before the loop and reuse
them each time through the loop.
3. for (int x = 0; x < getWidth(); x++) declares a variable x of type int
which will be initialized to 0 and then a check will be made to see if x is less
than the width of the current picture object. If x is less than the width then
the body of this for loop will be executed. After the body of the loop has
been executed one time the value in x will be incremented and the continuation
condition will be tested again.
4. for (int y = 0; y < getHeight(); y++) This declares a variable y of type
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 87
i
Section 3.4
5.
6.
7.
8.
9.
10.
3.4.2
Copying pixels
87
int which will be initialized to 0. The continuation condition checks that y
is less than the height of the current picture object. If y is less than the
height then the body of this for loop will be executed. After the body has
executed the value in y will be incremented and the continuation condition
will be tested again.
pixel = getPixel(x,y); This sets the variable pixel to refer to the Pixel
object at the given x and y location in the picture.
color = pixel.getColor(); This sets the variable color to refer to the
Color object at the current pixel.
color = color.brighter(); This creates a new lighter (brighter) color object based on the original color object and sets the variable color to refer to
that new color object.
pixel.setColor(color); This sets the current pixel’s color to be the lighter
color.
Each time we reach the end of the inner for loop the y value will be incremented
by 1 and then the value of y will be compared to the height of the picture. If
the value of y is less than the height the statements in the body of the loop
will be executed again. If the value of y is equal or greater than the height
then execution will move to the next statement (the outer loop).
Each time we reach the end of the outer for loop the x value will be incremented by 1 and then the value of x will be compared to the width of the
picture. If the x value is less than the width of the picture the commands in
the loop body will be executed. If the value of x is equal or greater than the
width of the picture then execution will continue at the statement following
the body of the loop.
Mirroring a picture
Let’s start out with an interesting effect that is only occasionally useful, but it is
fun. Let’s mirror a picture along its vertical axis. In other words, imagine that
you have a mirror, and you place it on a picture so that the left side of the picture
shows up in the mirror. That’s the effect that we’re going to implement. We’ll do
it in a couple of different ways.
First, let’s think through what we’re going to do. We’ll pick a horizontal
mirrorPoint—halfway across the picture, (int) (picture.getWidth()/2). (We
want this to be an integer, a whole number, so we’ll apply (int) to it.) We’ll have
the x value increment from 1 to the mirrorPoint. At each value of x, we want to
copy the color at the pixel x pixels to the left of the mirrorPoint to the pixel x
pixels to the right of the mirrorPoint. The left would be mirrorPoint-x and the
right would be mirrorPoint+x. Take a look at Figure 3.19 to convince yourself
that we’ll actually reach every pixel using this scheme. Here’s the actual recipe.
Recipe 20: Mirror pixels in a picture along a vertical line
/**
i
i
i
i
i
“MAIN”
2004/5/11
page 88
i
88
Chapter 3
Encoding and Manipulating Pictures
mirrorpoint-1
a
b
mirrorpoint
c
mirrorpoint+1
d
e
FIGURE 3.19: Once we pick a mirror point, we can just walk x halfway and subtract/add to the mirror point
* Method to mirror around a vertical line in the middle of the picture
* based on the width
*/
public void mirrorVertical()
{
int mirrorPoint = (int) (getWidth() / 2);
Pixel leftPixel = null;
Pixel rightPixel = null;
// loop through the rows
for (int y = 0; y < getHeight(); y++)
{
// loop from 1 to just before the mirror point
for (int x = 1; x < mirrorPoint; x++)
{
leftPixel = getPixel((mirrorPoint - x), y);
rightPixel = getPixel((mirrorPoint + x), y);
rightPixel.setColor(leftPixel.getColor());
}
}
}
End of Recipe 20
We’d use it like this, and the result appears in Figure 3.20.
> String fileName = "C:/intro-prog-java/mediasources/santa.jpg";
> System.out.println(fileName);
C:/intro-prog-java/mediasources/santa.jpg
> Picture picture = new Picture(fileName);
> picture.mirrorVertical();
> picture.show();
Another way to code this would be to copy the colors for the pixels starting
with the left-most x (x=0) into the right-most pixel (width - 1). To do this copy
have x range from 0 to less than the mirrorPoint and copy it to (width - 1 - x).
i
i
i
i
i
“MAIN”
2004/5/11
page 89
i
Section 3.4
Copying pixels
89
FIGURE 3.20: Original picture (left) and mirrored along the vertical axis (right)
Can we mirror horizontally? Sure!
Recipe 21: Mirror pixels horizontally, top-to-bottom
/**
* Method to mirror around a horizontal line in the middle based
* on the height. It copies the top mirrored to the bottom
*/
public void mirrorHorizontal()
{
int mirrorPoint = (int) (getHeight() / 2);
Pixel topPixel = null;
Pixel bottomPixel = null;
// loop through the columns
for (int x=0; x < getWidth(); x++)
{
// loop from 1 to just before the mirror point
for (int y=1; y < mirrorPoint; y++)
{
topPixel = getPixel(x,(mirrorPoint - y));
bottomPixel = getPixel(x,(mirrorPoint + y));
bottomPixel.setColor(topPixel.getColor());
}
}
}
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 90
i
90
Chapter 3
Encoding and Manipulating Pictures
End of Recipe 21
Now this last recipe copies from the top of the picture onto the bottom (see
Figure 3.21). You can see that we’re getting the color from topPixel which is from
mirrorPoint - y–that will always be above mirrorPoint since smaller values of y
are nearer the top of the picture. To copy from the bottom up, simply change the
color at the top pixel to the color of the bottom pixel. (Figure 3.21).
Recipe 22: Mirror pixels horizontally, bottom-to-top
/**
* Method to mirror around a horiztonal line in the middle
* based on the height of the picture. It copies the bottom
* to the top.
*/
public void mirrorHorizontalBottomToTop()
{
int mirrorPoint = (int) (getHeight() / 2);
Pixel topPixel = null;
Pixel bottomPixel = null;
// loop through the columns
for (int x=0; x < getWidth(); x++)
{
// loop from 1 to just before the mirror point
for (int y=1; y < mirrorPoint; y++)
{
topPixel = getPixel(x,(mirrorPoint - y));
bottomPixel = getPixel(x,(mirrorPoint + y));
topPixel.setColor(bottomPixel.getColor());
}
}
}
public void mirrorHorizontalBottomToTop()
{
int mirrorPoint = (int) (getHeight() / 2);
Pixel topPixel = null;
Pixel bottomPixel = null;
// loop through the columns
for (int x=0; x < getWidth(); x++)
{
// loop from 1 to just before the mirror point
for (int y=1; y < mirrorPoint; y++)
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 91
i
Section 3.4
Copying pixels
91
{
topPixel = getPixel(x,(mirrorPoint - y));
bottomPixel = getPixel(x,(mirrorPoint + y));
topPixel.setColor(bottomPixel.getColor());
}
}
}
End of Recipe 22
FIGURE 3.21: Santa mirrored horizontally, bottom to top (left) and top to bottom
(right)
Mirroring usefully.
While mirroring is probably mostly used for interesting effects, occasionally
it has some more serious (but still fun!) purposes. I took a picture of the Temple
of Zeus in the ancient agora in Athens, Greece, when traveling to a conference
(Figure 3.22). By sheer luck, I got the pediment dead horizontal. The Temple of
Zeus had its pediment damaged. I wondered if I could “fix” it by mirroring the
good part onto the broken part.
I used the picture explorer to figure out the range of values where I would
need to do the mirroring and the point where I should mirror (Figure 3.23). The
function I wrote to do the repair is below, and the final picture is in (Figure 3.24)–it
worked pretty well! Of course, it is possible to tell that it was digitally manipulated.
For example, if you check the shadows, you can see that the sun must have been
on the left and the right at the same time.
Recipe 23: Mirror the Temple of Zeus
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 92
i
92
Chapter 3
Encoding and Manipulating Pictures
FIGURE 3.22: Temple of Zeus from the ancient agora in Athens, Greece
FIGURE 3.23: Coordinates where we need to do the mirroring
/**
* Method to mirror the piedmont of the temple
* @return the corrected picture
*/
public static Picture mirrorTemple()
{
Picture picture = new Picture(getMediaPath("temple.jpg"));
int mirrorPoint = 276;
int lengthToCopy = mirrorPoint - 13;
Pixel leftPixel = null;
Pixel rightPixel = null;
// loop through the columns
for (int x = 1; x < lengthToCopy; x++)
{
// loop through the rows
i
i
i
i
i
“MAIN”
2004/5/11
page 93
i
Section 3.4
Copying pixels
93
for (int y = 27; y < 97; y++)
{
leftPixel = picture.getPixel(mirrorPoint - x,y);
rightPixel = picture.getPixel(mirrorPoint + x, y);
rightPixel.setColor(leftPixel.getColor());
}
}
// show the picture
picture.show();
return picture;
}
End of Recipe 23
In this recipe, we’re using Picture.getMediaPath(fileName). The function Picture.getMediaPath(fileName) is a shorthand. If you keep your media
in one place, and you’d like to refer to it just by its base name, you can use
Picture.getMediaPath(fileName), which actually just generates a complete path
for you. However, before you use it you should Picture.setMediaPath(directory)
first!. Picture.setMediaPath(directory) lets you specify that place (directory)
where you store your media. Picture.setMediaPath(directory) tells Picture.getMediaPath(fileName)
what directory to use to construct the full path name.
FIGURE 3.24: The manipulated temple
The temple example is a good one to ask ourselves about. If you really
understand, you can answer questions like “What’s the first pixel to be mirrored
in this function?” and “How many pixels get copied anyway?” You should be able
to figure these out by thinking through the program–pretend you’re the computer
and execute the program in your mind.
i
i
i
i
i
“MAIN”
2004/5/11
page 94
i
94
Chapter 3
Encoding and Manipulating Pictures
If that’s too hard, you can insert System.out.println() statements, like
this:
/**
* Method to mirror the piedmont of the temple
* @return the corrected picture
*/
public static Picture mirrorTemple()
{
Picture picture = new Picture(getMediaPath("temple.jpg"));
int mirrorPoint = 276;
int lengthToCopy = mirrorPoint - 13;
Pixel leftPixel = null;
Pixel rightPixel = null;
// loop through the columns
for (int x = 1; x < lengthToCopy; x++)
{
// loop through the rows
for (int y = 27; y < 97; y++)
{
System.out.print("Copying color from " + (mirrorPoint - x) + "," + y);
System.out.println(" to " + (mirrorPoint + x) + "," + y);
leftPixel = picture.getPixel(mirrorPoint - x,y);
rightPixel = picture.getPixel(mirrorPoint + x, y);
rightPixel.setColor(leftPixel.getColor());
}
}
// show the picture
picture.show();
return picture;
}
When we run this version, it takes a long time to finish. Hit Reset after a
little bit since we only really care about the first few pixels. Here’s what I got:
> Picture.mirrorTemple();
Copying color from 275,27 to 277,27
Copying color from 275,28 to 277,28
Copying color from 275,29 to 277,29
Copying color from 275,30 to 277,30
It copies from just to the left of the mirror point (276), since x is 1 at first,
and we copy from mirrorpoint-x to mirrorpoint+x. Thus, we copy down the
i
i
i
i
i
“MAIN”
2004/5/11
page 95
i
Section 3.4
Copying pixels
95
column before the mirror point to the column of pixels to the right of the mirror
point. Then we move back one column to the left, and copy one column further to
the right.
How many pixels did we process? We can have the computer figure that one
out, too.
/**
* Method to mirror the piedmont of the temple
* @return the corrected picture
*/
public static Picture mirrorTemple()
{
Picture picture = new Picture(getMediaPath("temple.jpg"));
int mirrorPoint = 276;
int lengthToCopy = mirrorPoint - 13;
Pixel leftPixel = null;
Pixel rightPixel = null;
int count = 0;
// loop through the columns
for (int x = 1; x < lengthToCopy; x++)
{
// loop through the rows
for (int y = 27; y < 97; y++)
{
count = count + 1;
leftPixel = picture.getPixel(mirrorPoint - x,y);
rightPixel = picture.getPixel(mirrorPoint + x, y);
rightPixel.setColor(leftPixel.getColor());
}
}
// tell how many pixels were copied
System.out.println("We copied " + count + " pixels");
// show the picture
picture.show();
return picture;
}
This one comes back with We copied 18340 pixels. Where did that number
come from? You can calculate how many times you execute the commands in a for
loop with end - start + 1. We copy 70 rows of pixels (y goes from 27 to 96 (because
of the ¡ 97) which is 96 - 27 + 1). We copy 262 columns of pixels (x goes from 1 to
¡ 263 (276 - 13) which is 262 - 1 + 1 = 262). 70 ∗ 262 is 18, 340.
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 96
i
96
3.5
Chapter 3
Encoding and Manipulating Pictures
COPYING AND TRANSFORMING PICTURES
We can create wholly new pictures when we copy pixels across pictures. We’re
going to end up keeping track of a source picture that we take pixels from and
a target picture that we’re going to set pixels in. Actually, we don’t copy the
pixels–we simply make the pixels in the target the same color as the pixels in the
source. Copying pixels requires us keep track of multiple index variables: The (x, y)
positions in the source and the (x, y) in the target.
What’s exciting about copying pixels is that making some small changes in
how we deal with the index variables leads to not only copying the image but transforming it. In this section, we’re going to talk about copying, cropping, rotating,
and scaling pictures.
We’re going to make use of the utility function Picture.getMediaPath(fileName)
to make our coding of methods with several files easier. We’ve seen it before.
It’s particularly helpful when you want to deal with several pieces of media in
the same directory but don’t want to spell out the whole directory name. You
just have to remember to use Picture.setMediaPath(directory) first! All that
Picture.getMediaPath(fileName) does is to prepend the directory found in Picture.setMediaPathdirectory)
to the input filename.
> Picture.setMediaPath("C:/intro-prog-java/mediasources/");
> Picture.getMediaPath("temple.jpg")
"C:/intro-prog-java/mediasources/temple.jpg"
> Picture temple = new Picture(Picture.getMediaPath("temple.jpg"));
Our target will be the paper-sized JPEG file in the mediasources directory,
which is 7x9.5 inches, which will fit on a 9x11.5 inch lettersize piece of paper with
one inch margins.
> String paperFile = Picture.getMediaPath("7inx95in.jpg");
> Picture paperPicture = new Picture(paperFile);
> System.out.println(paperPicture.getWidth());
504
> System.out.println(paperPicture.getHeight());
684
3.5.1
Copying
To copy a picture from one file to another, we simply make sure that we increment
sourceX and targetX variables (the source and target index variables for the X
axis) together, and the sourceY and targetY variables together. We can initialize
more than one variable in the initialization area of a for loop and change more than
one variable in the change area.
Here’s a recipe for copying a picture of Katie to the canvas.
Recipe 24: Copying a picture to a canvas
i
i
i
i
i
“MAIN”
2004/5/11
page 97
i
Section 3.5
Copying and transforming pictures
97
/**
* Method to copy the picture of Katie to the canvas
* @return the canvas after the picture of Katie has been copied
*/
public static Picture copyKatie()
{
String sourceFile = Picture.getMediaPath("KatieFancy.jpg");
Picture sourcePicture = new Picture(sourceFile);
String targetFile = Picture.getMediaPath("7inx95in.jpg");
Picture targetPicture = new Picture(targetFile);
Pixel sourcePixel = null;
Pixel targetPixel = null;
// loop through the columns
for (int sourceX = 0, targetX=0;
sourceX < sourcePicture.getWidth();
sourceX++, targetX++)
{
// loop through the rows
for (int sourceY = 0, targetY =0;
sourceY < sourcePicture.getHeight();
sourceY++, targetY++)
{
// set the target pixel color to the source pixel color
sourcePixel = sourcePicture.getPixel(sourceX,sourceY);
targetPixel = targetPicture.getPixel(targetX,targetY);
targetPixel.setColor(sourcePixel.getColor());
}
}
// show the source and target pictures
sourcePicture.show();
targetPicture.show();
return targetPicture;
}
End of Recipe 24
This program copies a picture of Katie to the canvas (blank picture) (Figure 3.25). Here’s how it works:
• The first few lines are just setting up the source (sourcePicture) and target
(targetPicture) pictures.
• Next comes the loop for managing the x index variables, sourceX for the
source picture and targetX for the target picture. The for loop declares both
i
i
i
i
i
“MAIN”
2004/5/11
page 98
i
98
Chapter 3
Encoding and Manipulating Pictures
FIGURE 3.25: Copying a picture to a canvas
variables and initializes them to 0. You can have more than one variable
declared and initialized in the initialization area of a for loop, if you separate
them with commas. Next the continuation test checks if the sourceX is less
than the width of the source picture. Finally in the change area we increment
both the sourceX and targetX variables each time after the statements in
the body of the loop have been executed. You can change more than one
variable in the change area as long as you separate the changes with commas.
The for loop for looping through the columns is:
for (int sourceX = 0, targetX=0;
sourceX < sourcePicture.getWidth();
sourceX++, targetX++)
• Inside the loop for the X variables is the loop for the Y variables. It has a
very similar structure, since it’s goal is to keep targetY and sourceY in synch
in exactly the same way.
for (int sourceY = 0, targetY =0;
sourceY < sourcePicture.getHeight();
sourceY++, targetY++)
It’s inside the Y loop that we actually get the color from the source pixel and
set the corresponding pixel in the target to the same color.
Of course, we don’t have to copy from (0, 0) in the source to (0, 0) in the
target. We can easily copy somewhere else in the canvas, too. All we have to do is
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 99
i
Section 3.5
Copying and transforming pictures
99
FIGURE 3.26: Copying a picture midway into a canvas
to change where the target X and Y coordinates start. The rest stays exactly the
same (Figure 3.26).
Recipe 25: Copy elsewhere into the canvas
/**
* Method to copy the picture of Katie to 100, 100 in the canvas
* @return the picture of Katie copied to 100,100
*/
public static Picture copyKatieMidway()
{
String sourceFile = Picture.getMediaPath("KatieFancy.jpg");
Picture sourcePicture = new Picture(sourceFile);
String targetFile = Picture.getMediaPath("7inx95in.jpg");
Picture targetPicture = new Picture(targetFile);
Pixel sourcePixel = null;
Pixel targetPixel = null;
// loop through the columns
for (int sourceX = 0, targetX=100;
sourceX < sourcePicture.getWidth();
sourceX++, targetX++)
{
// loop through the rows
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 100
i
100
Chapter 3
Encoding and Manipulating Pictures
for (int sourceY = 0, targetY =100;
sourceY < sourcePicture.getHeight();
sourceY++, targetY++)
{
// set the target pixel color to the source pixel color
sourcePixel = sourcePicture.getPixel(sourceX,sourceY);
targetPixel = targetPicture.getPixel(targetX,targetY);
targetPixel.setColor(sourcePixel.getColor());
}
}
// show the source and target pictures
sourcePicture.show();
targetPicture.show();
return targetPicture;
}
End of Recipe 25
Similarly, we don’t have to copy a whole picture. Cropping is taking only part
of a picture out of the whole picture. Digitally, that’s just a matter of changing
your start and end coordinates. To grab just Katie’s face out of the picture, we
only have to figure out what the coordinates are where her face is located, then
use those on the dimensions of sourceX and sourceY (Figure 3.27). The face is at
(70, 3) to (136, 81).
Recipe 26: Cropping a picture onto a canvas
/**
* Method to copy just Katie’s face to the canvas
* @return the canvas after the copying the face
*/
public static Picture copyKatiesFace()
{
String sourceFile = Picture.getMediaPath("KatieFancy.jpg");
Picture sourcePicture = new Picture(sourceFile);
String targetFile = Picture.getMediaPath("7inx95in.jpg");
Picture targetPicture = new Picture(targetFile);
Pixel sourcePixel = null;
Pixel targetPixel = null;
// loop through the columns
i
i
i
i
i
“MAIN”
2004/5/11
page 101
i
Section 3.5
Copying and transforming pictures
101
FIGURE 3.27: Copying part of a picture onto a canvas
for (int sourceX = 70, targetX = 100;
sourceX < 135; sourceX++, targetX++)
{
// loop through the rows
for (int sourceY = 3, targetY = 100;
sourceY < 80; sourceY++, targetY++)
{
// set the target pixel color to the source pixel color
sourcePixel = sourcePicture.getPixel(sourceX,sourceY);
targetPixel = targetPicture.getPixel(targetX,targetY);
targetPixel.setColor(sourcePixel.getColor());
}
}
// show the source and target pictures
sourcePicture.show();
targetPicture.show();
return targetPicture;
}
i
i
i
i
i
“MAIN”
2004/5/11
page 102
i
102
Chapter 3
Encoding and Manipulating Pictures
End of Recipe 26
How does that work?.
Let’s look at a small example to see what’s going on in the copying recipe.
We start out with a source and a target, and copy from x=0,y=0 to x=3 y=1.
We then increment both the sourceY and targetY, and copy again.
We continue down the column, incrementing both Y index variables.
When done with that column, we increment the X index variables and move
on to the next column, until we copy every pixel.
3.5.2
Creating a Collage
In the mediasources folder are a couple images of flowers (Figure 3.28), each 100
pixels wide. Let’s make a collage of them, by combining several of our effects to
create different flowers. We’ll copy them all into the blank image 640x480.jpg. All
we really have to do is to copy the pixel colors to the right places.
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 103
i
Section 3.5
Copying and transforming pictures
103
FIGURE 3.28: Flowers in the mediasources folder
Recipe 27: Creating a collage
/**
* Method to create a collage from the flower pictures. All the flower pictures
* will be lined up near the bottom of the canvas (5 pixels from the bottom)
* @return the collage as a picture object
*/
public static Picture createCollage()
{
// create the three pictures
Picture flower1Picture = new Picture(Picture.getMediaPath("flower1.jpg"));
Picture flower2Picture = new Picture(Picture.getMediaPath("flower2.jpg"));
Picture canvasPicture = new Picture(Picture.getMediaPath("640x480.jpg"));
// declare the source and target pixel variables
Pixel sourcePixel = null;
Pixel targetPixel = null;
// print out the picture information
System.out.println(flower1Picture);
System.out.println(flower2Picture);
System.out.println(canvasPicture);
/* copy the first flower picture to 5 pixels from the bottom
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 104
i
104
Chapter 3
Encoding and Manipulating Pictures
* left corner of the canvas
*/
for (int sourceX = 0, targetX = 0;
sourceX < flower1Picture.getWidth();
sourceX++, targetX++)
{
for (int sourceY = 0,
targetY = canvasPicture.getHeight() - flower1Picture.getHeight() - 5;
sourceY < flower1Picture.getHeight();
sourceY++, targetY++)
{
sourcePixel = flower1Picture.getPixel(sourceX,sourceY);
targetPixel = canvasPicture.getPixel(targetX,targetY);
targetPixel.setColor(sourcePixel.getColor());
}
}
// copy the flower2 picture starting with x = 100 in the canvas
for (int sourceX = 0, targetX = 100;
sourceX < flower2Picture.getWidth();
sourceX++, targetX++)
{
for (int sourceY = 0,
targetY = canvasPicture.getHeight() - flower2Picture.getHeight() - 5;
sourceY < flower2Picture.getHeight();
sourceY++, targetY++)
{
sourcePixel = flower2Picture.getPixel(sourceX,sourceY);
targetPixel = canvasPicture.getPixel(targetX,targetY);
targetPixel.setColor(sourcePixel.getColor());
}
}
// copy the flower1 negated to x = 200 in the canvas
flower1Picture.negative();
for (int sourceX = 0, targetX = 200;
sourceX < flower1Picture.getWidth();
sourceX++, targetX++)
{
for (int sourceY = 0,
targetY = canvasPicture.getHeight() - flower1Picture.getHeight() - 5;
sourceY < flower1Picture.getHeight();
sourceY++, targetY++)
{
sourcePixel = flower1Picture.getPixel(sourceX,sourceY);
targetPixel = canvasPicture.getPixel(targetX,targetY);
targetPixel.setColor(sourcePixel.getColor());
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 105
i
Section 3.5
Copying and transforming pictures
105
}
}
// clear the blue in flower 2 picture and add at x=300 in the canvas
flower2Picture.clearBlue();
for (int sourceX = 0, targetX = 300;
sourceX < flower2Picture.getWidth();
sourceX++, targetX++)
{
for (int sourceY = 0,
targetY = canvasPicture.getHeight() - flower2Picture.getHeight() - 5;
sourceY < flower2Picture.getHeight();
sourceY++, targetY++)
{
sourcePixel = flower2Picture.getPixel(sourceX,sourceY);
targetPixel = canvasPicture.getPixel(targetX,targetY);
targetPixel.setColor(sourcePixel.getColor());
}
}
// copy the negated flower 1 to x=400
for (int sourceX = 0, targetX = 400;
sourceX < flower1Picture.getWidth();
sourceX++, targetX++)
{
for (int sourceY = 0,
targetY = canvasPicture.getHeight() - flower1Picture.getHeight() - 5;
sourceY < flower1Picture.getHeight();
sourceY++, targetY++)
{
sourcePixel = flower1Picture.getPixel(sourceX,sourceY);
targetPixel = canvasPicture.getPixel(targetX,targetY);
targetPixel.setColor(sourcePixel.getColor());
}
}
// show the resulting picture
canvasPicture.show();
return canvasPicture;
}
End of Recipe 27
Here’s how we run the collage(Figure 3.29):
> Picture flowerCollage = Picture.createCollage();
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 106
i
106
Chapter 3
Encoding and Manipulating Pictures
Picture, filename C:/intro-prog-java/mediasources/flower1.jpg
height 138 width 100
Picture, filename C:/intro-prog-java/mediasources/flower2.jpg
height 227 width 100
Picture, filename C:/intro-prog-java/mediasources/640x480.jpg
height 480 width 640
FIGURE 3.29: Collage of flowers
This method is long and repetitive which makes it hard to read. One of the
ways to improve it is to pull out pieces of code that are basically the same and make
them new methods. Each time we add a new picture to our canvas the only things
changing are the picture to be added and the targetX. The targetY is always
calculated the same way as the height of the canvas minus the height of the picture
being copied minus 5. We can make a new method which copies a passed picture
object into the current picture object starting at a passed x value.
/**
* Method that will copy all of the passed source picture into
* the current picture object starting with the left corner
* given by xStart
* @param sourcePicture the picture object to copy
* @param xStart the x position to start the copy into
*/
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 107
i
Section 3.5
Copying and transforming pictures
107
public void copyPictureTo(Picture sourcePicture, int xStart)
{
Pixel sourcePixel = null;
Pixel targetPixel = null;
// loop through the columns
for (int sourceX = 0, targetX = xStart;
sourceX < sourcePicture.getWidth();
sourceX++, targetX++)
{
// loop through the rows
for (int sourceY = 0,
targetY = this.getHeight() - sourcePicture.getHeight() - 5;
sourceY < sourcePicture.getHeight();
sourceY++, targetY++)
{
sourcePixel = sourcePicture.getPixel(sourceX,sourceY);
targetPixel = this.getPixel(targetX,targetY);
targetPixel.setColor(sourcePixel.getColor());
}
}
}
/**
* Method to create a collage of flowers
* @return the flower collage as a picture object
*/
public static Picture createCollageBetter()
{
// create the three pictures
Picture flower1Picture = new Picture(Picture.getMediaPath("flower1.jpg"));
Picture flower2Picture = new Picture(Picture.getMediaPath("flower2.jpg"));
Picture canvasPicture = new Picture(Picture.getMediaPath("640x480.jpg"));
// print out the picture information
System.out.println(flower1Picture);
System.out.println(flower2Picture);
System.out.println(canvasPicture);
// copy the first flower picture to near the
// bottom left corner of the canvas
canvasPicture.copyPictureTo(flower1Picture,0);
// copy the flower2 picture starting with x = 100 in the canvas
canvasPicture.copyPictureTo(flower2Picture,100);
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 108
i
108
Chapter 3
Encoding and Manipulating Pictures
// copy the flower1 negated to x = 200 in the canvas
flower1Picture.negative();
canvasPicture.copyPictureTo(flower1Picture,200);
// clear the blue in flower 2 picture and add at x=300 in the canvas
flower2Picture.clearBlue();
canvasPicture.copyPictureTo(flower2Picture,300);
// copy the negated flower 1 to x=400
canvasPicture.copyPictureTo(flower1Picture,400);
// show the resulting picture
canvasPicture.show();
return canvasPicture;
}
3.5.3
Blending Pictures
When we create collages by copying, any overlap typically means that one picture
shows over another. The last picture painted on is the one that appears. But it
doesn’t have to be that way. We can blend pictures by multiplying their colors and
adding them. This gives us the effect of transparency.
We know that 100% of something is the whole thing. 50% of one and 50% of
another would also add up to 100%. In the recipe below, we blend a picture of the
two sisters with an overlap of some 70 (the width of Barbara minus 150) columns
of pixels (Figure 3.30).
Recipe 28: Blending two pictures
/**
* Method to blend pictures of Katie and Jenny
* @return the blended picture
*/
public static Picture blendPictures()
{
// create the three pictures
Picture katiePicture = new Picture(Picture.getMediaPath("KatieFancy.jpg"));
Picture jennyPicture = new Picture(Picture.getMediaPath("JenParty.jpg"));
Picture canvasPicture = new Picture(Picture.getMediaPath("640x480.jpg"));
// declare the source and target pixel variables
Pixel katiePixel = null;
Pixel jennyPixel = null;
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 109
i
Section 3.5
Copying and transforming pictures
109
Pixel targetPixel = null;
// declare the target x and source x since we will need the values after the
// for loop
int sourceX = 0;
int targetX = 0;
// copy the first 150 pixels of katie to the canvas
for (; sourceX < 150; sourceX++, targetX++)
{
for (int sourceY=0, targetY=0;
sourceY < katiePicture.getHeight();
sourceY++, targetY++)
{
katiePixel = katiePicture.getPixel(sourceX,sourceY);
targetPixel = canvasPicture.getPixel(targetX,targetY);
targetPixel.setColor(katiePixel.getColor());
}
}
// copy 50% of katie and 50% of jenny till the end of katie’s width
for (; sourceX < katiePicture.getWidth(); sourceX++, targetX++)
{
for (int sourceY=0,targetY=0;
sourceY < katiePicture.getHeight();
sourceY++, targetY++)
{
katiePixel = katiePicture.getPixel(sourceX,sourceY);
jennyPixel = jennyPicture.getPixel(sourceX - 150,sourceY);
targetPixel = canvasPicture.getPixel(targetX,targetY);
targetPixel.setColor(new Color((int) (katiePixel.getRed() * 0.5 +
jennyPixel.getRed() * 0.5),
(int) (katiePixel.getGreen() * 0.5 +
jennyPixel.getGreen() * 0.5),
(int) (katiePixel.getBlue() * 0.5 +
jennyPixel.getBlue() * 0.5)));
}
}
// copy the rest of Jenny
sourceX = sourceX - 150;
for (; sourceX < jennyPicture.getWidth(); sourceX++, targetX++)
{
for (int sourceY = 0, targetY = 0;
sourceY < jennyPicture.getHeight();
sourceY++, targetY++)
{
i
i
i
i
i
“MAIN”
2004/5/11
page 110
i
110
Chapter 3
Encoding and Manipulating Pictures
FIGURE 3.30: Blending the picture of Katie and Jenny
jennyPixel = jennyPicture.getPixel(sourceX,sourceY);
targetPixel = canvasPicture.getPixel(targetX,targetY);
targetPixel.setColor(jennyPixel.getColor());
}
}
// show the canvas
canvasPicture.show();
// return the canvas
return canvasPicture;
}
End of Recipe 28
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 111
i
'
3.5.4
&
Section 3.5
Copying and transforming pictures
111
Making it Work Tip: Optional parts of the for loop
Notice that we are missing the initialization area in the
for loops in the method blendPictures(). Also notice that
we moved the declaration of sourceX and sourceY outside
the for loops. This is because we want to keep the values
around after the first for loop ends. The initialization area
of a for loop is optional (the ; is not optional). In fact, the
initialization area, continuation test, and change area are
all optional. You could code a for loop as for (;;;) but
that isn’t terribly useful. It would execute the body of the
for loop forever. This is also known as an infinite loop.
Rotation
$
%
Transformations to the image occur by using the index variables differently or
incrementing them differently, but otherwise keeping the same recipe. Let’s rotate
Katie 90 degrees. We’ll do that by simply swapping the X and Y variables in the
target–we increment them the exact same way, but we’ll use them X for Y and Y
for X (Figure 3.31).
Recipe 29: Rotating a picture
/**
* Method to copy Katie rotated to the left 90 degrees
* @return the picture after Katie has been copied and rotated to the left 90
*/
public static Picture copyKatieSideways()
{
String sourceFile = Picture.getMediaPath("KatieFancy.jpg");
Picture sourcePicture = new Picture(sourceFile);
String targetFile = Picture.getMediaPath("7inx95in.jpg");
Picture targetPicture = new Picture(targetFile);
Pixel sourcePixel = null;
Pixel targetPixel = null;
// loop through the columns
for (int sourceX = 0, targetX=0;
sourceX < sourcePicture.getWidth();
sourceX++, targetX++)
{
// loop through the rows
for (int sourceY = 0, targetY =0;
sourceY < sourcePicture.getHeight();
sourceY++, targetY++)
i
i
i
i
i
“MAIN”
2004/5/11
page 112
i
112
Chapter 3
Encoding and Manipulating Pictures
{
// set the target pixel color to the source pixel color
sourcePixel = sourcePicture.getPixel(sourceX,sourceY);
targetPixel = targetPicture.getPixel(targetY,targetX);
targetPixel.setColor(sourcePixel.getColor());
}
}
// show the source and target pictures
sourcePicture.show();
targetPicture.show();
return targetPicture;
}
End of Recipe 29
FIGURE 3.31: Copying a picture to a canvas rotated to the left 90 degrees
How does that work?.
Rotating starts with the same source and target, and even the same variable
values, but since we use the target X and Y differently, we get a different effect.
i
i
i
i
i
“MAIN”
2004/5/11
page 113
i
Section 3.5
Copying and transforming pictures
113
Now, as we increment the Y variables, we’re moving down the source, but
across the target. As we increment the X variables we’re moving across the source
but down the target.
When we’re done, we’ve done the same copy, but the result is completely
different.
3.5.5
Scaling
A very common transformation for pictures is to scale them. Scaling up means to
make them larger, and scaling them down makes them smaller. It’s common to
scale a 1-megapixel or 3-megapixel picture down to a smaller size to make it easier
to place on the Web. Smaller pictures require less disk space, and thus less network
bandwidth, and thus are easier and faster to download.
Scaling a picture requires the use of sampling which we’ll also use with sounds
later. To scale a picture smaller we are going to take every other pixel when copying
from the source to the target. To scale a picture larger we are going to take every
pixel twice.
Scaling the picture down is the easier function. We will use the daisyMed.jpg
picture which is 302 (width) by 202 (height). Instead of incrementing the source X
and Y variables by 1, we simply increment by 2. We divide the amount of space by
2, since we’ll fill half as much room–our width will be 302/2 and the height will be
i
i
i
i
i
“MAIN”
2004/5/11
page 114
i
114
Chapter 3
Encoding and Manipulating Pictures
202/2. The result is a smaller flower in the canvas (Figure 3.32).
Recipe 30: Scaling a picture down (smaller)
/**
* Method to copy the flower but smaller (half as big)
* @return the smaller flower picture
*/
public static Picture copyFlowerSmaller()
{
Picture flowerPicture = new Picture(Picture.getMediaPath("daisyMed.jpg"));
Picture canvasPicture = new Picture(Picture.getMediaPath("640x480.jpg"));
Pixel sourcePixel = null;
Pixel targetPixel = null;
// loop through the columns
for (int sourceX = 0, targetX=0;
sourceX < flowerPicture.getWidth();
sourceX+=2, targetX++)
{
// loop through the rows
for (int sourceY=0, targetY=0;
sourceY < flowerPicture.getHeight();
sourceY+=2, targetY++)
{
sourcePixel = flowerPicture.getPixel(sourceX,sourceY);
targetPixel = canvasPicture.getPixel(targetX,targetY);
targetPixel.setColor(sourcePixel.getColor());
}
}
// show the resulting picture
canvasPicture.show();
return canvasPicture;
}
End of Recipe 30
Scaling up the picture (making it larger) is a little trickier. We want to take
every pixel twice. What we’re going to do is to increment the source index variables
by 0.5. Now, we can’t reference pixel 1.5. But if we reference (int) 1.5 we’ll get
1 again, and that’ll work. The sequence of 1, 1.5, 2, 2.5... will become 1,1,2,2...
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 115
i
Section 3.5
Copying and transforming pictures
115
FIGURE 3.32: Scaling the picture down
The result is a larger form of the picture (Figure 3.33).
Recipe 31: Scaling the picture up (larger)
/**
* Method to copy a flower but scaled to 2x normal size
* @return the larger flower
*/
public static Picture copyFlowerLarger()
{
Picture flowerPicture = new Picture(Picture.getMediaPath("daisyMed.jpg"));
Picture canvasPicture = new Picture(Picture.getMediaPath("640x480.jpg"));
Pixel sourcePixel = null;
Pixel targetPixel = null;
// loop through the columns
for (double sourceX = 0, targetX=0;
sourceX < flowerPicture.getWidth();
sourceX = sourceX + 0.5, targetX++)
{
// loop through the rows
for (double sourceY=0, targetY=0; sourceY < flowerPicture.getHeight();
sourceY = sourceY + 0.5, targetY++)
{
sourcePixel = flowerPicture.getPixel((int) sourceX,(int) sourceY);
targetPixel = canvasPicture.getPixel((int) targetX,(int) targetY);
targetPixel.setColor(sourcePixel.getColor());
}
}
// show the resulting picture
i
i
i
i
i
“MAIN”
2004/5/11
page 116
i
116
Chapter 3
Encoding and Manipulating Pictures
canvasPicture.show();
return canvasPicture;
}
End of Recipe 31
FIGURE 3.33: Scaling up a picture
You might want to be able to scale a picture to a particular size, instead of
always using the canvas pictures. There is a constructor that takes a width and
height new Picture(width,height ) and creates a picture of a desired width and
height (both specified in pixels). new Picture(640,480) would create a picture
object that is 640 pixels wide by 480 pixels tall—just like the canvas.
How did that work?.
We start from the same place as the original copy.
When we increment sourceY by 0.5, we end up referring to the same pixel in
the source, but the target has moved on to the next pixel.
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 117
i
Section 3.6
Replacing Colors
117
When we increment sourceY a second time by 0.5, we now move on to the
next pixel, which we’ll end up copying the same pixel twice.
And eventually, we cover every pixel. Notice that the end result is degraded–
it’s choppier than the original.
3.6
REPLACING COLORS
Replacing colors with another color is pretty easy. We can do it broadly, or just
within a range.
Here’s a recipe that tries to replace the brown color in Katie’s hair with red. I
used the picture explorer to figure out roughly what the RGB values were for Katie’s
brown hair, then wrote a program to look for colors close to that, and increase the
redness of those pixels. I played a lot with the value that I used for distance (here,
50.0) and the amount of redness increase (here, 100% increase). However, it turned
part of the couch and carpet red too. (Figure 3.34 and Figure 3.51).
Recipe 32: Color replacement: Turn Katie into a redhead
/**
* Method to turn to turn Katie into a red head
*/
public static Picture turnKatieRedHead()
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 118
i
118
Chapter 3
Encoding and Manipulating Pictures
{
Color brown = new Color(42,25,15);
Color currentColor = null;
Picture katiePicture = new Picture(Picture.getMediaPath("KatieFancy.jpg"));
Pixel[] pixels = katiePicture.getPixels();
Pixel pixel = null;
// loop through the pixels
for (int i=0; i<pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// check if in distance to brown and if so reduce blue and green
if (pixel.colorDistance(brown) < 50.0)
pixel.setColor(new Color((int) (currentColor.getRed() * 2.0),
currentColor.getGreen(),
currentColor.getBlue()));
}
// show the result
katiePicture.show();
return katiePicture;
}
End of Recipe 32
With the picture explorer we can also figure out the coordinates just around
Katie’s face, and then just do the browns near her face. The effect isn’t too good,
though it’s clear that it worked. The line of redness is too sharp and rectangular
(Figure 3.35 and Figure 3.52).
Recipe 33: Color replacement in a range
/**
* Method to turn to turn Katie into a red head using a range
*/
public static Picture turnKatieRedHeadInRange()
{
Color brown = new Color(42,25,15);
Color currentColor = null;
Picture katiePicture = new Picture(Picture.getMediaPath("KatieFancy.jpg"));
Pixel pixel = null;
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 119
i
Section 3.6
Replacing Colors
119
FIGURE 3.34: Increasing reds in the browns
// loop through the x values
for (int x=63; x < 125; x++)
{
for (int y=6; y < 76; y++)
{
// get the current pixel
pixel = katiePicture.getPixel(x,y);
// check if in distance to brown and if so reduce blue and green
if (pixel.colorDistance(brown) < 50.0)
pixel.setColor(new Color((int) (currentColor.getRed() * 2.0),
currentColor.getGreen(),
currentColor.getBlue()));
}
}
// show the result
katiePicture.show();
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 120
i
120
Chapter 3
Encoding and Manipulating Pictures
return katiePicture;
}
End of Recipe 33
FIGURE 3.35: Increasing reds in the browns, within a certain range
3.6.1
Reducing red eye
“Red eye” is the effect where the flash from the camera bounces off the back of the
subject’s eyes. Reducing red eye is a really simple matter. We find the pixels that
are “pretty close” (we use a distance from red of 165 works well) to red, then insert
a replacement color.
We probably don’t want to change the whole picture. In the Figure 3.36, we
can see that Jenny is wearing a red dress—we don’t want to wipe out that red,
too. We’ll fix that by only changing the area where Jenny’s eyes are. Using the
MediaTools, we find the upper left and lower right corners of her eyes. Those points
were (109, 91) and (202, 107).
Recipe 34: Remove red eye
i
i
i
i
i
“MAIN”
2004/5/11
page 121
i
Section 3.6
Replacing Colors
121
FIGURE 3.36: Finding the range of where Jenny’s eyes are red
/**
* Method to remove red eye from the current picture object in the rectange
* define by startX, startY, endX, endY. The red will be replaced with the
* passed newColor
* @param startX the top left corner x value of a rectangle
* @param startY the top left corner y value of a rectangle
* @param endX
the bottom right corner x value of a rectangle
* @param endY
the bottom right corner y value of a rectangle
* @param newColor the new color to use
*/
public void removeRedEye(int startX, int startY, int endX,
int endY, Color newColor)
{
Pixel pixel = null;
// loop through the pixels in the rectangle defined by the startX, startY, and
// endX and endY
for (int x = startX; x < endX; x++)
{
for (int y = startY; y < endY; y++)
{
// get the current pixel
pixel = getPixel(x,y);
// if the color is near red then change it
if (pixel.colorDistance(Color.red) < 167)
pixel.setColor(newColor);
}
}
}
i
i
i
i
i
“MAIN”
2004/5/11
page 122
i
122
Chapter 3
Encoding and Manipulating Pictures
End of Recipe 34
We call this function with:
> Picture jennyPicture = new Picture("c:/intro-prog-java/mediasources/jenny-red.jpg");
> jennyPicture.removeRedEye(109,91,202,107,java.awt.Color.black);
> jennyPicture.show();
to replace the red with black—certainly other colors could be used for the
replacement color. The result was good, and we can check that the eye really does
now have all-black pixels (Figure 3.37). (See also Figure 3.53.)
FIGURE 3.37: After fixing red-eye.
3.6.2
Sepia toned and posterized pictures: Using conditionals to choose the color
So far, we’ve done color modification by simply saying “This color replaces that
color.” We can be more sophisticated in our color swapping. We can look for a
range of colors, by using if, and choosing to replace with some function of the
original color or by changing to a specific color. The results are quite interesting.
For example, we might want to generate sepia-toned prints. Older prints
sometimes have a yellow-ish tint to them. We could just do an overall color change,
but the end result isn’t aesthetically pleasing. By looking for different kinds of
color–highlights, shadows–and treating them differently, we can get a better effect
(Figure 3.38).
The way we do this is to first convert everything to grayscale, both because
older prints were in a gray scale, and because it makes it a little easier to work
with. We then look for high and low ranges of color, and change them separately.
We want to make the shadows (darkest grays) a bit darker. We want to make most
of the picture (middle grays) into a brownish color. We want to the highlights
(lightest grays) a bit yellow. Recall that yellow is a mixture of red and green so
one way to make things yellow is to increase the red and green. Another way is to
reduce the amount of blue. The advantage to reducing the blue is that you don’t
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 123
i
Section 3.6
Replacing Colors
123
FIGURE 3.38: Original scene (left) and using our sepia-tone recipe
have to worry about increasing a value past 255.
Recipe 35: Convert a picture to sepia-tones
/**
* Method to change the current picture to a sepia
* tint (modify the middle colors to a light brown and
* the light colors to a light yellow and make the shadows darker
*/
public void sepiaTint()
{
Pixel pixel = null;
double redValue = 0;
double greenValue = 0;
double blueValue = 0;
// first change the current picture to grayscale
this.grayscale();
// loop through the pixels
for (int x = 0; x < this.getWidth(); x++)
{
for (int y = 0; y < this.getHeight(); y++)
{
// get the current pixel and color values
pixel = this.getPixel(x,y);
redValue = pixel.getRed();
greenValue = pixel.getGreen();
blueValue = pixel.getBlue();
// tint the shadows darker
if (redValue < 60)
i
i
i
i
i
“MAIN”
2004/5/11
page 124
i
124
Chapter 3
Encoding and Manipulating Pictures
{
redValue = redValue * 0.9;
greenValue = greenValue * 0.9;
blueValue = blueValue * 0.9;
}
// tint the midtones a light brown
// by reducing the blue
else if (redValue < 190)
{
blueValue = blueValue * 0.8;
}
// tint the highlights a light yellow
// by reducing the blue
else
{
blueValue = blueValue * 0.9;
}
// set the colors
pixel.setRed((int) redValue);
pixel.setGreen((int) greenValue);
pixel.setBlue((int) blueValue);
}
}
}
End of Recipe 35
Posterizing is a process of converting a picture to a smaller number of colors.
We’re going to do that by looking for specific ranges of color, then setting the color
to one value in that range. The result is that we reduce the number of colors in
the picture (Figure 3.39).
FIGURE 3.39: Reducing the colors (right) from the original (left)
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 125
i
Section 3.6
Replacing Colors
125
Recipe 36: Posterizing a picture
/**
* Method to posterize (reduce the number of colors) in the picture
* The number of reds, greens, and blues will be 4
*/
public void posterize()
{
Pixel pixel = null;
int redValue = 0;
int greenValue = 0;
int blueValue = 0;
// loop through the pixels
for (int x = 0; x < this.getWidth(); x++) {
for (int y = 0; y < this.getHeight(); y++) {
// get the current pixel and colors
pixel = this.getPixel(x,y);
redValue = pixel.getRed();
greenValue = pixel.getGreen();
blueValue = pixel.getBlue();
// check for red range and change color
if (redValue < 64)
redValue = 31;
else if (redValue < 128)
redValue = 95;
else if (redValue < 192)
redValue = 159;
else
redValue = 223;
// check for green range
if (greenValue < 64)
greenValue = 31;
else if (greenValue < 128)
greenValue = 95;
else if (greenValue < 192)
greenValue = 159;
else
greenValue = 223;
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 126
i
126
Chapter 3
Encoding and Manipulating Pictures
// check for blue range
if (blueValue < 64)
blueValue = 31;
else if (blueValue < 128)
blueValue = 95;
else if (blueValue < 192)
blueValue = 159;
else
blueValue = 223;
// set the colors
pixel.setRed(redValue);
pixel.setGreen(greenValue);
pixel.setBlue(blueValue);
}
}
}
End of Recipe 36
What’s really going on here, though, is setting up (a) a bunch of levels then
(b) setting the value of red, green, or blue to the midpoint of that level. We can do
this more generally using mathematics to compute the ranges for a desired number
of levels and picking the midpoint. Below is the recipe for a flexible number of
levels, and Figure 3.40 shows a couple of examples.
Recipe 37: Posterize by levels
/**
* Method to posterize (reduce the number of colors) in the picture
* @param numLevels the number of color levels to use
*/
public void posterize(int numLevels)
{
Pixel pixel = null;
int redValue = 0;
int greenValue = 0;
int blueValue = 0;
int increment = (int) (256.0 / numLevels);
int bottomValue, topValue, middleValue = 0;
// loop through the pixels
for (int x = 0; x < this.getWidth(); x++) {
for (int y = 0; y < this.getHeight(); y++) {
i
i
i
i
i
“MAIN”
2004/5/11
page 127
i
Section 3.6
Replacing Colors
127
// get the current pixel and colors
pixel = this.getPixel(x,y);
redValue = pixel.getRed();
greenValue = pixel.getGreen();
blueValue = pixel.getBlue();
// loop through the number of levels
for (int i = 0; i < numLevels; i++)
{
// compute the bottom, top, and middle values
bottomValue = i * increment;
topValue = (i + 1) * increment;
middleValue = (int) ((bottomValue + topValue - 1) / 2.0);
// check if current values are in current range and if so
// set them to the middle value
if (bottomValue <= redValue && redValue < topValue)
pixel.setRed(middleValue);
if (bottomValue <= greenValue && greenValue < topValue)
pixel.setGreen(middleValue);
if (bottomValue <= blueValue && blueValue < topValue)
pixel.setBlue(middleValue);
}
}
}
}
End of Recipe 37
FIGURE 3.40: Pictures posterized to two levels (left) and four levels (right)
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 128
i
128
3.7
Chapter 3
Encoding and Manipulating Pictures
COMBINING PIXELS: BLURRING
When we make pictures larger (scaling them up), we usually get rough edges: Sharp
steps to lines, which we call pixelation. We can reduce pixelation by blurring the
image. What we do is set each pixel to an average of pixels around it. In this
example, we go through all pixels (note the large loop that surrounds everything)
and then in the X and Y dimensions, compute the average of the pixels to either
side of the pixel. It takes a picture, and a number (size) of pixels to compute the
average.
Recipe 38: A simple blur
/**
* Method to blur the pixels
* @param numPixels the number of pixels to average in all directions so if the
* numPixels is 2 then we will average all pixels in the rectange defined by 2 before
* the current pixel to 2 after the current pixel
*/
public void blur(int numPixels)
{
Pixel pixel = null;
Pixel samplePixel = null;
int redValue = 0;
int greenValue = 0;
int blueValue = 0;
int count = 0;
// loop through the pixels
for (int x=0; x < this.getWidth(); x++) {
for (int y=0; y < this.getHeight(); y++) {
// get the current pixel
pixel = this.getPixel(x,y);
// reset the count and red, green, and blue values
count = 0;
redValue = greenValue = blueValue = 0;
// loop through pixel numPixels before x to numPixels after x
for (int xSample = x - numPixels; xSample <= x + numPixels; xSample++) {
for (int ySample = y - numPixels; ySample <= y + numPixels; ySample++) {
// check that we are in the range of acceptable pixels
if (xSample >= 0 && xSample < this.getWidth() &&
ySample >= 0 && ySample < this.getHeight()) {
samplePixel = this.getPixel(xSample,ySample);
i
i
i
i
i
“MAIN”
2004/5/11
page 129
i
Section 3.7
Combining pixels: Blurring
129
redValue = redValue + samplePixel.getRed();
greenValue = greenValue + samplePixel.getGreen();
blueValue = blueValue + samplePixel.getBlue();
count = count + 1;
}
}
}
// use average color of surrounding pixels
Color newColor = new Color(redValue / count,
greenValue / count,
blueValue / count);
pixel.setColor(newColor);
}
}
}
End of Recipe 38
Figure 3.41 shows the flower from the collage made bigger, then blurrred.
You can see the pixellation in the bigger version—the sharp, blocky edges. With
the blur, some of that pixellation goes away. More careful blurs take into account
regions of colors (so that edges between colors are kept sharp), and thus are able
to reduce pixellation without removing sharpness.
FIGURE 3.41: Making the flower bigger, then blurring to reduce pixellation
i
i
i
i
i
“MAIN”
2004/5/11
page 130
i
130
Chapter 3
Encoding and Manipulating Pictures
FUNCTIONS AND OBJECTS SUMMARY
In this chapter, we talk about several kinds of encodings of data (or objects).
Picture
Pixel
Color
Pictures are encodings of images, typically coming
from a JPEG file.
A pixel is a dot in the Picture. It has a color (red,
green, and blue) and an (x, y) position associated
with it. It remembers its own Picture so that a
change to the pixel changes the real dot in the
picture.
It’s a mixture of red, green, and blue values, each
between 0 and 255.
Here are the functions used or introduced in this chapter:
FileChooser.pickAFile()
new Picture(fileName)
picture.show()
picture.getPixels()
picture.getPixel()
picture.getWidth()
picture.getHeight()
picture.writePictureTo(fileName)
Lets the user pick a file and returns the complete
path name as a string. Takes no input.
Takes a filename as input, reads the file, and creates a picture object from it. Returns the picture
object.
Must be called on a Picture object. Shows the
picture object. No return value.
Must be called on a Picture object. Returns an
array of Pixel objects in the picture.
Must be called on a Picture object. It takes an x
position and a y position (two numbers), and returns the Pixel object at that point in the picture.
Must be called on a picture object. Returns the
width of the picture in pixels.
Must be called on a picture object. It returns the
height in pixels.
Must be called on a picture object. It takses a file
name (string) as input, then writes the picture to
the file as a JPEG. (Be sure to end the filename
in “.jpg” for the operating system to understand
it well.)
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 131
i
Section 3.7
Combining pixels: Blurring
pixel.getRed(), pixel.getGreen(), pixel.getBlue()
pixel.setRed(), pixel.setGreen(), pixel.setBlue()
pixel.getColor()
pixel.setColor()
pixel.getX(), pixel.getY()
131
Each of these methods must be called on a Pixel
object. Each method returns the value (between 0
and 255) of the amount of redness, greenness, and
blueness (respectively) in that pixel.
Each of these methods must be called on a Pixel
object. Each method takes a value (between 0 and
255) and sets the redness, greenness, or blueness
(respectively) of that pixel to the given value.
Must be called on a Pixel object. Returns the
Color object at that pixel.
Must be called on a Pixel object. Takes a Color
object and sets the color for that pixel.
Must be called on a Pixel object. Returns the x
or y (respectively) position of where that Pixel is
at in the picture.
new Color(red,green,blue)
Takes three inputs: For the red, green, and blue
components (in order), then creates and returns a
color object.
ColorChooser.pickAColor()
Takes no input, but puts up a color picker. Find
the color you want, and the function will return
the Color object of what you picked.
pixel.colorDistance(color)
Takes a Color object and returns a single number
representing the distance between the color and
the current pixel’s color. The red, green, and blue
values of the colors are taken as a point in (x, y, z)
space, and the cartesian distance is computed.
color.darker(),color.brighter() Must be called on a Color object. The methods
return a slightly darker or lighter (respectively)
version of the color.
There are a bunch of constants that are useful in this chapter. These are variables with pre-defined values. These values are colors: Color.black, Color.white,
Color.blue, Color.red, Color.green, Color.gray, Color.darkGray, Color.lightGray,
Color.yellow, Color.orange, Color.pink, Color.magenta, Color.cyan.
PROBLEMS
3.1. Recipe 9 (page 61) is obviously too much color reduction. Write a version that
only reduces the red by 10%, then one by 20%. Which seems to be more useful?
Note that you can always repeatedly reduce the redness in a picture, but you
don’t want to have to do it too many times, either.
3.2. Write the blue and green versions of Recipe 9 (page 61).
3.3. Each of the below is equivalent to Recipe 10 (page 68). Test them and convince
yourself that they are equivalent. Which do you prefer and why?
/**
* Method to increase the amount of red by 1.3
*/
public void increaseRed2()
{
i
i
i
i
i
“MAIN”
2004/5/11
page 132
i
132
Chapter 3
Encoding and Manipulating Pictures
Pixel[] pixels = this.getPixels();
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// set the red value to 1.3 times what it was
pixels[i].setRed((int) (pixels[i].getRed() * 1.3));
}
}
/**
* Method to increase the amount of red by 1.3
*/
public void increaseRed3()
{
Pixel[] pixels = this.getPixels();
Pixel pixel = null;
int red = 0;
int green = 0;
int blue = 0;
int newRed = 0;
// loop through all the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
pixel = pixels[i];
// get the color values
red = pixel.getRed();
green = pixel.getGreen();
blue = pixel.getBlue();
// calculate the new red value
newRed = (int) (red * 1.3);
// set the pixel color to the new color
pixel.setColor(new Color(newRed,green,blue));
}
}
3.4. If you keep increasing the red, eventually the red looks like it disappears, and
you eventually get errors about illegal arguments. What you do think is going
on?
3.5. Write new methods like Recipe 11 (page 69) to clear red and green. For each of
these, which would be the most useful in actual practice? How about combinations of these?
3.6. Write a new method to maximize blue (i.e., setting it to 255) instead of clearing
it use Recipe 11 (page 69) as a starting point. Is this useful? Would the red or
green versions be useful?
3.7. There is more than one way to compute the right grayscale value for a color
value. The simple recipe that we use in Recipe 17 (page 83) may not be what
your grayscale printer uses when printing a color picture. Compare the color (rel-
i
i
i
i
i
“MAIN”
2004/5/11
page 133
i
Section 3.7
Combining pixels: Blurring
133
atively unconverted by the printer) grayscale image using our simple algorithm
in Figure 3.50 with the original color picture that the printer has converted to
grayscale (left of Figure 3.11). How do the two pictures differ?
3.8. Write a method to do mirroring along the diagonal (from (0, 0) to (width −
1, height − 1)?
3.9. Think about how the grayscale algorithm works. Basically, if you know the
luminance of anything visual (e.g., a small image, a letter), you can replace a
pixel with that visual element in a similar way to create a collage image. Try
implementing that. You’ll need 256 visual elements of increasing lightness, all
of the same size. You’ll create a collage by replacing each pixel in the original
image with one of these visual elements.
TO DIG DEEPER
The bible of computer graphics is Introduction to Computer Graphics [7]. It’s highly
recommended.
A wonderful new book on how vision works, and how artists have learned
to manipulate it, is Vision and art: The biology of Seeing by Margaret Livingstone [11].
i
i
i
i
i
“MAIN”
2004/5/11
page 134
i
134
3.8
Chapter 3
Encoding and Manipulating Pictures
COLOR FIGURES
FIGURE 3.42: Merging red, green, and blue to make new colors
FIGURE 3.43: Color: RGB triplets in a matrix representation
i
i
i
i
i
“MAIN”
2004/5/11
page 135
i
Section 3.8
Color Figures
135
FIGURE 3.44: Color: The original picture (left) and red-reduced version (right)
FIGURE 3.45: Color: Overly blue (left) and red increased by 30% (right)
FIGURE 3.46: Color: Original (left) and blue erased (right)
FIGURE 3.47: Original beach scene (left) and at (fake) sunset (right)
i
i
i
i
i
“MAIN”
2004/5/11
page 136
i
136
Chapter 3
Encoding and Manipulating Pictures
FIGURE 3.48: Color: Lightening and darkening the original picture
FIGURE 3.49: Color: Negative of the image
FIGURE 3.50: Color: Color picture converted to grayscale
i
i
i
i
i
“MAIN”
2004/5/11
page 137
i
Section 3.8
Color Figures
137
FIGURE 3.51: Color: Increasing reds in the browns
i
i
i
i
i
“MAIN”
2004/5/11
page 138
i
138
Chapter 3
Encoding and Manipulating Pictures
FIGURE 3.52: Color: Increasing reds in the browns, within a certain range
FIGURE 3.53: Finding the range where Jenny’s eyes are red, then changing them to
black
i
i
i
i
i
“MAIN”
2004/5/11
page 139
i
Section 3.8
Color Figures
139
FIGURE 3.54: Frames from the slow sunset movie
FIGURE 3.55: Frames from the slow fade-out movie
i
i
i
i
i
“MAIN”
2004/5/11
page 140
i
140
Chapter 3
Encoding and Manipulating Pictures
FIGURE 3.56: Frames from the Mommy watching Katie movie
FIGURE 3.57: Frames from the original too dark movie
i
i
i
i
i
“MAIN”
2004/5/11
page 141
i
Section 3.8
Color Figures
141
FIGURE 3.58: Frames from the modified lighter movie
FIGURE 3.59: Frames from the original movie with kids crawling in front of a blue
screen
i
i
i
i
i
“MAIN”
2004/5/11
page 142
i
142
Chapter 3
Encoding and Manipulating Pictures
FIGURE 3.60: Frames from the kids on the moon movie
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 143
i
C H A P T E R
4
Advanced Pictures
4.1
4.2
4.3
4.4
4.5
BACKGROUND SUBTRACTION
CHROMAKEY
DRAWING ON IMAGES WITH PIXELS
DRAWING WITH DRAWING COMMANDS
PROGRAMS AS SPECIFYING DRAWING PROCESS
In this chapter, we’ll talk about techniques for creating pictures. We’ll compose pictures in new ways (essentially, pulling someone out and putting them in a
new setting) and create pictures from scratch without explicitly setting every pixel.
4.1
BACKGROUND SUBTRACTION
Let’s imagine that you have a picture of someone, and a picture of where they stood
without them there (Figure 4.1). Could you subtract the background of the person
(i.e., figure out where the colors are close), and then replace another background?
Say, of the moon (Figure 4.2)?
FIGURE 4.1: A picture of a child (Katie), and her background without her
Recipe 39: Subtract the background and replace it with a new one
/**
* Method to replace the background in the current picture with the background
* from another picture
* @param oldBackground a picture with the old background to replace
143
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 144
i
144
Chapter 4
Advanced Pictures
FIGURE 4.2: A new background, the moon
* @param newBackground a picture with the new background to use
*/
public void swapBackground(Picture oldBackground, Picture newBackground)
{
Pixel currPixel = null;
Pixel oldPixel = null;
Pixel newPixel = null;
// loop through the columns
for (int x=0; x<getWidth(); x++)
{
// loop through the rows
for (int y=0; y<getHeight(); y++)
{
// get the current pixel and old background pixel
currPixel = this.getPixel(x,y);
oldPixel = oldBackground.getPixel(x,y);
/* if the color at the current pixel is within 15.0 of the old background pixel
* then swap in the new background pixel
*/
if (currPixel.colorDistance(oldPixel.getColor()) < 15.0)
{
newPixel = newBackground.getPixel(x,y);
currPixel.setColor(newPixel.getColor());
}
}
i
i
i
i
i
“MAIN”
2004/5/11
page 145
i
Section 4.1
Background subtraction
145
}
}
End of Recipe 39
To test if we can replace an old background with a new background try:
>
>
>
>
>
Picture p = new Picture(Picture.getMediaPath("kid-in-frame.jpg"));
Picture oldBg = new Picture(Picture.getMediaPath("bgframe.jpg"));
Picture newBg = new Picture(Picture.getMediaPath("moon-surface.jpg"));
p.swapBackground(oldBg,newBg);
p.show();
We can, but the effect isn’t as good as we would like (Figure 4.3). Our
daughter’s shirt color was too close to the color of the wall. And though the light
was dim, the shadow is definitely having an effect here.
FIGURE 4.3: Katie on the moon
Mark tried the same thing with a picture of two students in front of a tiled
wall. While Mark did use a tripod (really critical to get the pixels to line up), Mark
unfortunately left autofocus on, so the two original pictures (Figure 4.4) weren’t
all that comparable. The background swap (again with the jungle scene) hardly
did anything at all! We changed the threshold value to 50, and finally got some
swapping (Figure 4.5).
>
>
>
>
>
Picture p = new Picture(Picture.getMediaPath("wall-two-people.jpg"));
Picture oldBg = new Picture(Picture.getMediaPath("wall.jpg"));
Picture newBg = new Picture(Picture.getMediaPath("jungle3.jpg"));
p.swapBackground(oldBg,newBg);
p.show();
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 146
i
146
Chapter 4
'
&
Advanced Pictures
Making it Work Tip: Add an input parameter to
generalize a method
Notice that we changed the threshold from 15.0 to 50.0
for the second test of the swapBackground(oldBG,newBG)
method. A better thing to do would be to change the
method to take the threshold distance as another input
parameter swapBackground(oldBG,newBG,threshold).
This means we won’t have to keep changing the method
each time we want to change the threshold, which means
the method can be used in more situations.
$
%
Recipe 40: Better Swap Background
/**
* Method to replace the background in the current picture with the background
* from another picture for pixels that have a color distance to the old
* background of under the passed threshold
* @param oldBackground a picture with the old background to replace
* @param newBackground a picture with the new background to use
* @param threshold the distance from the old background color to use
* to figure out which pixels to swap with the new background
*/
public void swapBackgroundForThreshold(Picture oldBackground,
Picture newBackground,
double threshold)
{
Pixel currPixel = null;
Pixel oldPixel = null;
Pixel newPixel = null;
// loop through the columns
for (int x=0; x<getWidth(); x++)
{
// loop through the rows
for (int y=0; y<getHeight(); y++)
{
// get the current pixel and old background pixel
currPixel = this.getPixel(x,y);
oldPixel = oldBackground.getPixel(x,y);
i
i
i
i
i
“MAIN”
2004/5/11
page 147
i
Section 4.2
Chromakey
147
/* if the color at the current pixel is within 15.0 of the old background pixel
* then swap in the new background pixel
*/
if (currPixel.colorDistance(oldPixel.getColor()) < threshold)
{
newPixel = newBackground.getPixel(x,y);
currPixel.setColor(newPixel.getColor());
}
}
}
}
End of Recipe 40
FIGURE 4.4: Two people in front of a wall, and a picture of the wall
FIGURE 4.5: Swapping a jungle for the wall, using background subtraction, with a
threshold of 50
4.2
CHROMAKEY
The way that weatherpersons do it is to stand before a background of a fixed color
(usually blue or green), then subtract that color. This is called chromakey. Mark
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 148
i
148
Chapter 4
Advanced Pictures
took our son’s blue sheet, attached it to the entertainment center, then took a
picture of himself in front of it using a timer on a camera (Figure 4.6).
FIGURE 4.6: Mark in front of a blue sheet
Recipe 41: Chromakey: Replace all blue with the new background
/**
* Method to do chromakey using a blue background
* @param newBg the new background image to use to replace
* the blue from the current picture
*/
public void chromakey(Picture newBg)
{
Pixel currPixel = null;
Pixel newPixel = null;
// loop through the columns
for (int x=0; x<getWidth(); x++)
{
// loop through the rows
for (int y=0; y<getHeight(); y++)
{
// get the current pixel
currPixel = this.getPixel(x,y);
/* if the color at the current pixel mostly blue (blue value is
i
i
i
i
i
“MAIN”
2004/5/11
page 149
i
Section 4.2
Chromakey
149
* greater than red and green combined, then use new background color
*/
if (currPixel.getRed() + currPixel.getGreen() < currPixel.getBlue())
{
newPixel = newBg.getPixel(x,y);
currPixel.setColor(newPixel.getColor());
}
}
}
}
End of Recipe 41
The effect is really quite striking (Figure 4.7). Do note the “folds” in the lunar
surface, though. The really cool thing is that this recipe works for any background
that’s the same size as the image (Figure 4.8). To put Mark on the moon and in
the jungle try this:
>
>
>
>
>
>
>
>
Picture mark = new Picture(Picture.getMediaPath("blue-mark.jpg"));
Picture newBg = new Picture(Picture.getMediaPath("moon-surface.jpg"));
mark.chromakey(newBg);
mark.show();
mark = new Picture(Picture.getMediaPath("blue-mark.jpg"));
newBg = new Picture(Picture.getMediaPath("jungle3.jpg"));
mark.chromakey(newBg);
mark.show();
FIGURE 4.7: Mark on the moon
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 150
i
150
Chapter 4
Advanced Pictures
FIGURE 4.8: Mark in the jungle
There’s another way of writing this code, which is shorter but does the same
thing.
Recipe 42: Chromakey, shorter
/**
* Method to do chromakey using a blue background
* @param newBg the new background image to use to replace
* the blue from the current picture
*/
public void chromakeyBlue(Picture newBg)
{
Pixel[] pixels = this.getPixels();
Pixel currPixel = null;
Pixel newPixel = null;
// loop through the pixels
for (int i = 0; i < pixels.length; i++)
{
// get the current pixel
currPixel = pixels[i];
/* if the color at the current pixel mostly red (red value is
* greater than green and blue combined, then use new background color
*/
if (currPixel.getRed() + currPixel.getGreen() < currPixel.getBlue())
{
i
i
i
i
i
“MAIN”
2004/5/11
page 151
i
Section 4.2
Chromakey
151
newPixel = newBg.getPixel(currPixel.getX(),currPixel.getY());
currPixel.setColor(newPixel.getColor());
}
}
}
End of Recipe 42
You don’t really want to do chromakey with a common color, like red—
something that there’s a lot of in your face. Mark tried it with the two pictures in
Figure 4.9—one with the flash on, and one with it off. We changed the test to if
(currPixel.getRed() > currPixel.getGreen() + currPixel.getBlue()). The
one without a flash was terrible—the student’s face was jungle-ified. The one with
the flash was better, but the flash is still clear after the swap (Figure 4.10). It’s
clear why moviemakers and weather people use blue or green backgrounds.
FIGURE 4.9: Student in front of a red background, and with flash on
FIGURE 4.10: Using chromakey recipe with red background
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 152
i
152
4.3
Chapter 4
Advanced Pictures
DRAWING ON IMAGES WITH PIXELS
Sometimes you want to create your own images from scratch. We know that this
is just a matter of setting pixel values to whatever we want, but setting individual
pixel values to draw a line or a circle or some letters is hard. One way of drawing
on images is to simply set the pixels appropriately. Here’s an example that we can
use to create a grid on the picture of Santa (Figure 4.11).
Recipe 43: Draw lines by setting pixels
/**
* Method to add vertical and horizontal lines to the current picture
*/
public void addLines()
{
addHorizontalLines();
addVerticalLines();
}
/**
* Method to add a horizontal line every 5 pixels in the current picture
*/
public void addHorizontalLines()
{
// loop through rows
for (int y = 0; y < getHeight(); y+=5)
{
// loop through the columns
for (int x = 0; x < getWidth(); x++)
{
// set the pixel to black
this.getPixel(x,y).setColor(Color.black);
}
}
}
/**
* Method to add a vertical line every 5 pixels in the current picture
*/
public void addVerticalLines()
{
// loop through the columns
for (int x = 0; x < getWidth(); x+=5)
{
// loop through the rows
i
i
i
i
i
“MAIN”
2004/5/11
page 153
i
Section 4.3
Drawing on images with pixels
153
FIGURE 4.11: Santa with a grid of drawn lines
for (int y=0; y < getHeight(); y++)
{
// set the pixel to black
this.getPixel(x,y).setColor(Color.black);
}
}
}
End of Recipe 43
To run this try:
> Picture santa = new Picture(Picture.getMediaPath("santa.jpg"));
> santa.addLines();
> santa.show();
You’ll notice that this program is using the color name Color.black. Java
pre-defines for you a bunch of colors: Color.black, Color.white, Color.blue,
Color.red, Color.green, Color.gray, Color.lightGray, Color.darkGray, Color.yellow,
Color.orange, Color.pink, Color.magenta, and Color.cyan. You can use any
of these when you need a color. Each of these is a class field of the Color class which
is why you can use them using the Class ’dot’ field notation (Color.black).
We can imagine drawing anything we want like this. We could draw rectangles
or circles, simply by figuring out what pixels need to be what color. We could even
draw letters—by setting the appropriate pixels to the appropriate colors, we could
make any letter we want.
i
i
i
i
i
“MAIN”
2004/5/11
page 154
i
154
4.4
Chapter 4
Advanced Pictures
DRAWING WITH DRAWING COMMANDS
Actually, drawing lines and other shapes by changing the colors of individual pixels
is amazingly painful to even imagine. Fortunately, there’s a much easier way.
Java (like most modern programming languages) provides methods for drawing a variety of shapes and text. There are actually two different classes that
you can use for drawing java.awt.Graphics and java.awt.Graphics2D. The Graphics
class contains methods for doing simple drawing while the Graphics2D class can be
used for more sophisticated drawing. Here are some of the methods in the Graphics
class:
• drawString(string,x,y) draws the string starting at position (x, y) in the
current font and color.
• drawLine(x1,y1,x2,y2) draws a line from position (x1, y1) to (x2, y2) in the
current color.
• drawRect(x1,y1,width,height) draws a rectangle with the upper left hand
corner at (x1, y1), a width of width, and a height of height in the current
color.
• fillRect(x1,y1,width,height) draws a rectangle with the upper left hand
corner at (x1, y1), a width of width, and a height of height and filled with
the current color.
• drawOval(x1,y1,width,height) draws an oval that is enclosed by a rectangle with the upper left hand corner of the rectangle at (x1, y1) a width of
width and a height of height in the current color.
• fillOval(x1,y1,width,height) draws a filled oval that is enclosed by a
rectangle with the upper left hand corner of the rectangle at (x1, y1) a width
of width and a height of height in the current color. The oval is filled with
the current drawing color.
• drawArc(x1,y1,width,height,startAngle,arcAngle) draws an arc which
is part of the oval specified by the enclosing rectangle with a upper left hand
corner of the rectangle at (x1, y1) a width of width and a height of height in
the current color. The arc starts at the given start angle and has an angle of
arcAngle. A start angle of 0 means the 3 o’clock position. A negative value
is clockwise rotation and a positive value is counter-clockwise rotation.
• fillArc(x1,y1,width,height,startAngle,arcAngle) draws a filled arc which
is part of the oval specified by the enclosing rectangle with a upper left hand
corner of the rectangle at (x1, y1) a width of width and a height of height in
the current color. The arc is filled with the current drawing color.
• setColor(color) sets the current drawing color.
You can get an object of the Graphics class from a Picture object using
getGraphics(). Then you can do the drawing using the graphics object and repaint
the picture to see the changes.
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 155
i
Section 4.4
Drawing with drawing commands
155
Below is an example of using these drawing commands (Figure 4.12).
Recipe 44: An example of using drawing commands
/**
* Method to show using drawing on a picture
* @return the example picture
*/
public static Picture drawExample()
{
// start with a white 640 by 480 picture
Picture p = new Picture(Picture.getMediaPath("640x480.jpg"));
// get the graphics object to use for drawing
Graphics graphics = p.getGraphics();
// start with a black color
graphics.setColor(Color.black);
// draw the string with a upper left corner at x=10, y=75
graphics.drawString("This is a test of drawing a string on a picture",10,75);
// draw a line from (10,20) to (300,50)
graphics.drawLine(10,20,300,50);
// set the color to yellow
graphics.setColor(Color.yellow);
// draw a filled rectangle (filled with yellow) at upper left (0,200) with
// a width of 300 and height 250
graphics.fillRect(0,200,300,250);
// set the color back to black
graphics.setColor(Color.black);
// draw the outline of a rectangle with the upper left at (10,210) and
// a width of 200 and a height of 100
graphics.drawRect(10,210,200,100);
/* draw an oval enclosed by a rectangle with the top left corner at
* (400,10) and a width of 200 and a height of 100
*/
graphics.drawOval(400,10,200,100);
/* draw an arc which is part of an oval enclosed by a rectangle with the
i
i
i
i
i
“MAIN”
2004/5/11
page 156
i
156
Chapter 4
Advanced Pictures
FIGURE 4.12: A small, drawn picture
* top left corner at (400,300) a width of 200, and a height of 150. The
* arc starts at 0 (3 o’clock position) and goes 180 degrees counter-clockwise
* to the 9 o’clock position
*/
graphics.fillArc(400,300,200,150,0,180);
// show the picture
p.show();
// return the picture
return p;
}
End of Recipe 44
4.4.1
Vector and Bitmap Representations
Here’s a thought: Which of these is smaller–the picture (Figure 4.12) or the
Recipe 44 (page 155)? The picture, on my disk, is about 24 kilobytes (a kilobyte is about a thousand bytes). The recipe is about 1 kilobyte (calculated by
comparing the Picture.java file size before and after adding the method). But for
many purposes, they are equivalent. What if you just saved the program and not
the pixels? That’s what a vector representation for graphics is about.
i
i
i
i
i
“MAIN”
2004/5/11
page 157
i
Section 4.4
Drawing with drawing commands
157
Vector-based graphical representations are basically executable programs that
generate the picture when desired. Vector-based representations are used in Postscript,
Flash, and AutoCAD. When you make a change to an image in Flash or AutoCAD,
you are actually making a change to the underlying representation—essentially,
you’re changing the program, like the one in Recipe 4.12 (page 156). The program
is then executed again to make the image appear. But thanks to Moore’s Law,
that execution-and-new-display occurs so fast that it feels like you’re changing the
picture.
Font definitions languages like Postscript and TrueType actually define miniature programs (or equations) for each and every letter or symbol. When you want
the letter or symbol at a particular size, the program is run to figure out which
pixels should be set to what values. (Some actually specify more than one color to
create the effect of smoother curves.) Because the programs are written to handle
desired font size as an input, the letters and symbols can be generated at any size.
Bitmap graphical representations, on the other hand, store every individual
pixel, or some compressed representation of the pixels. Formats like BMP, GIF,
and JPEG are essentially bitmap representations. GIF and JPEG are compressed
representations—they don’t represent each and every pixel with 24 bits. Instead,
they use some techniques to represent the same information but with fewer bits.
There are several benefits to vector-based representations over bitmap representations. If you can represent the picture you want to send (say, over the Internet)
using a vector-based representation, it’s much smaller than sending all the pixels.
Essentially, you’re sending the instructions for how to make the picture, rather than
sending the picture itself. For very complex images, however, the instructions can
be as long as the image itself (imagine sending all the directions on how to paint
the Mona Lisa!), so there is no benefit. But when the images are simple enough,
representations like those used in Flash make for faster upload and download times
than sending the same JPEG images.
The real benefit of vector-based notations come when you want to change the
image. Let’s say that you’re working on an architectural drawing, and you extend
a line in your drawing tool. If your drawing tool is only working with bitmapped
images (sometimes called a painting tool ) then all you have are more pixels on the
screen that are adjacent to the other pixels on the screen representing the line.
There’s nothing in the computer that says that all those pixels represent a line of
any kind—they’re just pixels. But if your drawing tool is working with vector-based
representations (sometimes called a drawing tool ) then extending a line means that
you’re changing an underlying representation of a line.
Why is that important? The underlying representation is actually a specification of the drawing, and it can be used anywhere that a specification is needed.
Imagine taking the drawing of a part, then actually running the cutting and stamping machines based on that drawing. This happens regularly in many shops, and it’s
possible because the drawing isn’t just pixels—it’s a specification of the lines and
their relationships, which can then be scaled and used to determine the behavior
of machines.
You might be wondering, ”But how could we change the program? Can
we write a program that would essentially re-type the program or parts of the
program?” Yes, we can, and we’ll do that in the chapter on text.
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 158
i
158
Chapter 4
Advanced Pictures
FIGURE 4.13: A programmed gray scale effect
4.5
PROGRAMS AS SPECIFYING DRAWING PROCESS
What we can do with drawing functions like these is create pictures that are exactly specified—things that might be too hard to do by hand. Take, for example,
Figure 4.13.
This doesn’t work quite as well as a professionally done picture, but it’s simple
to understand how it works. Our eyes tell us that the left half of the picture is lighter
than the right half, even though the end quarters are exactly the same shade of
gray. The effect is caused by the sharp boundary between the middle quarters,
where one moves (left-to-right) from gray to white, and the other moves black to
gray.
The image in Figure 4.13 is a carefully defined and created picture. It would
be very hard to do with pencil and paper. It would be possible to do with something like Photoshop, but it wouldn’t be easy. Using the graphics functions in this
chapter, however, we can easily specific exactly what that picture should be.
Recipe 45: Draw the gray effect picture
/**
* Method to draw a gray effect picture
* @return the picture that shows the gray effect
*/
public static Picture drawGrayEffect()
{
// create a picture to draw on
Picture pic = new Picture(400,100);
// create a medium gray color to use
Color medGray = new Color(100,100,100);
// Do 100 columns of medium gray
for (int x = 0; x < 100; x++)
for (int y = 0; y < 100; y++)
pic.getPixel(x,y).setColor(medGray);
// Do 100 columns of gray starting at medium gray and getting lighter
for (int x=100, grayLevel=100; x < 200; x++,grayLevel++)
i
i
i
i
i
“MAIN”
2004/5/11
page 159
i
Section 4.5
Programs as Specifying Drawing Process
159
for (int y=0; y < 100; y++)
pic.getPixel(x,y).setColor(new Color(grayLevel,grayLevel,grayLevel));
// Do 100 columns starting at black and getting lighter
for (int x=200, grayLevel=0; x < 300; x++, grayLevel++)
for (int y=0; y < 100; y++)
pic.getPixel(x,y).setColor(new Color(grayLevel,grayLevel,grayLevel));
// Do 100 columns of medium gray
for (int x=300; x < 400; x++)
for (int y=0; y < 100; y++)
pic.getPixel(x,y).setColor(medGray);
// show the picture
pic.show();
// return the picture
return pic;
}
End of Recipe 45
'
&
Making it Work Tip: Class Methods versus Object
Methods
Notice that both of the methods that create and return pictures are declared as static. This makes them
class methods and means that they can be called (invoked) using the class name followed by a dot and
then the method name: Picture.drawExample() and
Picture.drawGrayEffect(). Why are they class methods instead of object methods (a method called on an object of the class)? When we call these methods do we have
a current picture object to work on? No, these methods
create a picture object so there is no picture object to call
the methods on. So, when there is no current object to
call the method on use a class method and when there is
a current object to call the method on use an object
method.
Graphics functions are particularly good at drawings that are repeated where
the positions of lines and shapes and the selection of colors can be made by math-
$
%
i
i
i
i
i
‘‘MAIN’’
2004/5/11
page 160
i
160
Chapter 4
Advanced Pictures
ematical relationships.
Recipe 46: Draw the picture in Figure 4.14
/**
* Method to draw a picture with a succession of filled rectangles
* with the top left corner the darkest and the bottom right the
* lightest
* @return the picture with the filled rectangles
*/
public static Picture drawFilledRectangles()
{
Picture p = new Picture(250,250);
Graphics g = p.getGraphics();
Color color = null;
// loop 25 times
for (int i = 25; i > 0; i--)
{
color = new Color(i * 10, i * 5, i);
g.setColor(color);
g.fillRect(0,0,i*10,i*10);
}
// show the picture
p.show();
// return the picture
return p;
}
End of Recipe 46
Recipe 47: Draw the picture in Figure 4.15
/**
* Method to draw a picture with a succession of rectangles
* @return the picture with the filled rectangles
*/
public static Picture drawRectangles()
{
i
i
i
i
i
“MAIN”
2004/5/11
page 161
i
Section 4.5
Programs as Specifying Drawing Process
161
FIGURE 4.14: Nested filled rectangles image
Picture p = new Picture(Picture.getMediaPath("640x480.jpg"));
Graphics g = p.getGraphics();
Color color = null;
// loop 25 times
for (int i = 25; i > 0; i--)
{
g.setColor(Color.black);
g.drawRect(i,i,i*3,i*4);
g.drawRect(100+i*4,100+i*3,i*8,i*10);
}
// show the picture
p.show();
// return the picture
return p;
}
End of Recipe 47
4.5.1
Why do we write programs?
Why do we write programs, especially to draw pictures like this? Could we draw
pictures like these in Photoshop? Certainly we can, but we’d have to know how,
and that’s not easy knowledge to come by. Could I teach you how to do this in
Photoshop? Probably, but that may take a lot of effort?
But if I give you these programs, you can create the picture anytime you want.
What’s more, by giving you the program, I’m giving you the exact definition that
i
i
i
i
i
“MAIN”
2004/5/11
page 162
i
162
Chapter 4
Advanced Pictures
FIGURE 4.15: Nested rectangles image
you can go and change for yourself.
Computer Science Idea: We write programs to
encapsulate and communicate process
The reason why we write programs is to exactly specify a
process and to communicate it to others.
Imagine that you have some process to communicate. It doesn’t have to
be drawing—imagine that it’s a financial process (such that you could do it in a
spreadsheet or in a program like Quicken) or something that you do with text (such
as laying out text for a book or a brochure). If you can do something by hand,
you should just do it. If you need to teach someone else to do it, consider writing
a program to do it. If you need to explain to lots of people how to do it, definitely
use a program. If you want lots of people to be able to do the process themselves,
without someone having to teach them something first, definitely write a program
and give the people the program.
FUNCTIONS AND OBJECTS SUMMARY
Here are the functions introduced in this chapter:
i
i
i
i
i
“MAIN”
2004/5/11
page 163
i
Section 4.5
Programs as Specifying Drawing Process
163
graphics.drawString(string,x,y)
draws the string starting at position (x, y) in the
picture using the graphics object.
graphics.drawLine(x1,y1,x2,y2)
draws a line from position (x1, y1) to (x2, y2) using the graphics object.
graphics.drawRect(x1,y1,width,height)
draws a rectangle with the upper left hand corner at (x1, y1), a width of width, and a height of
height using the graphics object.
graphics.fillRect(x1,y1,width,height)draws a rectangle filled with the current color with
the upper left hand corner at (x1, y1), a width of
width, and a height of height.
graphics.drawOval(x1,y1,width,height)
draws a oval enclosed by the rectangle with the upper left hand corner at (x1, y1), a width of width,
and a height of height using the graphics object.
graphics.fillOval(x1,y1,width,height)draws a filled oval enclosed by the rectangle with
the upper left hand corner at (x1, y1), a width of
width, and a height of height using the graphics
object.
graphics.drawArc(x1,y1,width,height,startAngle,arcAngle)
draws a arc which is part of an oval enclosed by
the rectangle with the upper left hand corner at
(x1, y1), a width of width, and a height of height
using the graphics object. The startAngle says
at what angle to start drawing the arc and the
arcAngle is what is the total angle of the arc.
graphics.fillArc(x1,y1,width,height,startAngle,arcAngle)
draws a filled arc which is part of an oval enclosed
by the rectangle with the upper left hand corner at
(x1, y1), a width of width, and a height of height
using the graphics object. The startAngle says
at what angle to start drawing the arc and the
arcAngle is what is the total angle of the arc.
graphics.setColor(color)
changes the drawing color to the passed in color
object.
PROBLEMS
4.1. Try doing chromakey in a range—grab something out of its background where
the something is only in one part of a picture. Now, composite the something
into a new picture (new background).
4.2. Using the drawing tools presented here, draw a house—just go for the simple
i
i
i
i
i
“MAIN”
2004/5/11
page 164
i
164
Chapter 4
Advanced Pictures
child’s house with one door, two windows, walls, and a roof.
4.3. Using the house tool from the last exercise, draw a town with dozens of houses
at different sizes.
4.4. Using the drawing tools presented here, draw a face with two eyes, a nose, and
a smile.
4.5. Draw a rainbow.
i
i
i
i
i
“MAIN”
2004/5/11
page 165
i
C H A P T E R
5
Advanced Sounds:
Synthesizing Sounds
165
i
i
i
i
i
“MAIN”
2004/5/11
page 166
i
C H A P T E R
6
Design and Debugging
166
i
i
i
i
i
“MAIN”
2004/5/11
page 167
i
Bibliography
1. Harold Abelson, Gerald Jay Sussman, and Julie Sussman, Structure and intepretation of computer programs – 2nd edition, MIT Press, Cambridge, MA, 1996.
2. Ken Abernethy and Tom Allen, Exploring the digital domain: An introduction to
computing with multimedia and networking, PWS Publishing, Boston, 1998.
3. Beth Adelson and Elliot Soloway, The role of domain experience in software
design., IEEE Transactions on Software Engineering SE-11 (1985), no. 11, 1351–
1360.
4. Amy Bruckman, Situated support for learning: Storm’s weekend with rachael, Journal of the Learning Sciences 9 (2000), no. 3, 329–372.
5. John T. Bruer, Schools for thought: A science of learning in the classroom, MIT
Press, Cambridge, MA, 1993.
6. Matthias Felleisen, Robert Bruce Findler, Matthew Flatt, and Shriram
Krishnamurthi, How to design programs: An introduction to programming and computing, MIT Press, Cambridge, MA, 2001.
7. James D. Foley, Andries Van Dam, and Steven K. Feiner, Introduction to
computer graphics, Addison Wesley, Reading, MA, 1993.
8. Martin Greenberger, Computers and the world of the future, Transcribed recordings of lectures held at the Sloan School of Business Administration, April, 1961, MIT
Press, Cambridge, MA, 1962.
9. Idit Harel and Seymour Papert, Software design as a learning environment, Interactive Learning Environments 1 (1990), no. 1, 1–32.
10. Brian Harvey, Computer science logo style 2/e vol. 1: Symbolic computing, MIT
Press, Cambridge, MA, 1997.
11. Margaret Livingstone, Vision and art: The biology of seeing, Harry N. Abrams,
Inc., New York, 2002.
12. M. Resnick, Turtles, termites, and traffic jams: Explorations in massively parallel
microworlds, MIT Press, Cambridge, MA, 1997.
167
i
i
i
i
i
“MAIN”
2004/5/11
page 168
i
Index
=, 32
==, 55
abstraction, 40
ACM Turing Award, 14
acuity, 47
algebra, 19
algorithm, 6
algorithms, 7
alpha channel, 50
American Standard Code for Information Interchange (ASCII), 10
analogue, 12
applets, 19
argument, 40
array, 17
artificial intelligence, 7
ASCII, 10
assignment, 32
AutoCAD, 157
background subtraction, 143
base file name, 27
binary number, 9
binding, 32, 33
bit, 9
bitmap, 46
bitmap graphical representations, 157
blend, 108
blending
pictures, 108
block, 36
blue, 11
blurring, 128
BMP, 157
body of method, 36
byte, 9, 17
C, 8
calculus, 14
capitalization, 26
casting, 66
changeRed, 78
channel, 49
168
i
i
i
i
i
“MAIN”
2004/5/11
page 169
i
Index
169
chromakey, 147
class, 16, 20
fully qualified name, 54
class methods, 25
CMYK color model, 49
code, 17
collage, 102
color
comparing, 55
sepia, 122
color replacement, 117
color.brighter(), 56
color.darker(), 56
ColorChooser.pickAColor(), 56
commands, 35
common bug
An Example Common Bug, 2
Backslashes and Slashes, 34
DrJava is slow to start, 21
End with .jpg, 56
Java’s types can produce odd results, 24
Making DrJava run faster, 21
Patience: for loops can take a long time, 63
Saving a file quickly—and how to find it again, 56
Seeing changes in the picture, 55
comparing colors, 55
compressed, 18, 46, 51
computational recipe, 6
computer, 9
computer music, 7
computer science idea
An Example Idea, 2
Computer science is the study of recipes, 6
Computers can layer encodings, 10
Moore’s Law, 11
Much of programming is about naming, 16
Programs are for people, not computers., 16
Programs are for people., 73
Scope, 65
The most important skill is tracing, 63
We can substitute names, values, and methods., 34
We write programs to encapsulate and communicate process, 162
constants, 8, 131
convention, 17
coordinates, 47
copying, 96
cropping, 100
i
i
i
i
i
“MAIN”
2004/5/11
page 170
i
170
Index
data, 17
data representation, 11
data structures, 7, 11
databases, 7
debuggging
using print statements, 94
debugging
using print statements, 93
debugging tip
== and .equals, 55
An Example Debugging Tip, 2
Common typos, 25
Loops and Variable Declarations, 61
Methods names must be followed by parentheses, 30
Undefined Class Error, 54
decimal number, 9
def, 40
definitions pane, 22
Digital, 12
Digital media, 12
digitization, 12
digitizing media
pictures, 48
why?, 12
directory, 18, 27
disk, 18
distance, 55
double quote, 24
drawArc(x1,y1,width,height,startAngle,arcAngle), 154
drawing tool, 157
drawLine(x1,y1,x2,y2), 154
drawOval(x1,y1,width,height), 154
drawRect(x1,y1,width,height), 154
drawString(string,x,y), 154
DrJava, 20
definitions pane, 22
interactions pane, 22
files pane, 22
installing, 20
running slowly, 22
starting, 21
Dynabook, 14
editor, 20
emergent properties, 7
encoding, 9, 27
equals(), 55
i
i
i
i
i
“MAIN”
2004/5/11
page 171
i
Index
171
evaluation, 33, 40
explore(), 52
expression, 24, 32
file, 18
file extension, 27
files pane, 22
fillArc(x1,y1,width,height,startAngle,arcAngle), 154
fillOval(x1,y1,width,height), 154
fillRect(x1,y1,width,height), 154
Flash, 157
floating point
typing, 25
floating point number, 14, 18
font
how defined, 157
for, 59
for loop, 59
in command area, 61
full file name, 26
fully qualified name, 54
function
arguments, 40
input values, 40
input variables, 40
parameters, 40
when to make one, 41
function calls, 34
functions, 25
general, 72
getColor(), 53
getHeight(), 52
getPixel(x,y), 53
getPixels(), 53
getRed(), 53
getWidth(), 52
getX(), 53
getY(), 53
GIF, 157
going digital, 12
graphics, 7
grayscale, 82
green, 11
hard disk, 18
hierarchical decomposition, 77
i
i
i
i
i
“MAIN”
2004/5/11
page 172
i
172
Index
hierarchy, 77
HSV color model, 49
HTML, 11
human-computer interface, 7
import, 54
how to, 54
why, 54
infinite loop, 111
input, 25
input value, 40
input variable, 40
integer, 17, 33
typing, 25
Intel, 11
intelligence, 7
intelligent systems, 7
intensity, 83
interactions pane, 22
interface, 7
Java, 9, 19
capitalization, 26
installing, 20
JPEG, 27, 157
kilobyte, 156
knots, 7
liberal education, 14
Lisp, 8
lossy compression, 46
luminance, 48, 50, 83
making it work
Add an input parameter to generalize a method, 146
An Example How To Make It Work, 2
Class Methods versus Object Methods, 159
Comments in Java, 62
Copying and pasting, 39
Don’t just trust your programs, 67
Don’t start by trying to write applications, 74
Get to know your Help, 23
Importing Classes from Packages, 53
Java Conventions, 30
Java Keywords, Operators, and Classes, 17
Name the names you like, 38
Optional parts of the for loop, 110
i
i
i
i
i
“MAIN”
2004/5/11
page 173
i
Index
173
Try every recipe, 35
Types in Java, 28
Using dot notation for public fields, 46
matrix, 47
definition, 47
media computation, 11
MediaTools, 58
picture tools, 58
memory, 9, 18, 22
method, 16, 25
method body, 36
methods, 25
methods vs. recipes, 73
modulus, 24
Moore’s Law, 11
Moore, Gordon, 11
negative image, 81
nested, 85
networking, 7
new Color(redValue,greenValue,blueValue), 53
new Picture(fileName), 52
new Picture(width,height ), 116
new Sound(fileName), 30
null, 26
object
definition, 19
object methods, 25
object-oriented, 19
operating system, 18
operators, 24
package
definition, 54
painting tool, 157
parameter, 40
path, 27
path separator, 27
percentage, 58
Perlis, Alan, 13
physics
color, 11
pickAFile(), 26
picture
show(), 28
picture element, 12
i
i
i
i
i
“MAIN”
2004/5/11
page 174
i
174
Index
picture objects, 46
picture tool, 58
Picture.getMediaPath(fileName), 93, 96
picture.repaint(), 55
picture.write(fileName), 56
pixel, 12, 46, 47
definition, 47
pixelation, 128
pixelization, 48
pixels, 46
placeholder, 77
play(), 30
posterizing, 124
Postscript, 157
primitive, 29
primitive type, 29
process, 14
program, 6, 16, 17
defined, 17
programming language, 16
programming languages, 8
ranges, 8
recipe, 6
A simple blur, 128
An example of using drawing commands, 155
An Example Recipe, 2
Better Swap Background, 146
Blending two pictures, 108
Chromakey, shorter, 150
Chromakey: Replace all blue with the new background, 148
Clear the blue component from a picture, 69
Color replacement in a range, 118
Color replacement: Turn Katie into a redhead, 117
Convert a picture to sepia-tones, 123
Convert to grayscale, 83
Convert to grayscale with more careful control of luminance, 83
Copy elsewhere into the canvas, 99
Copying a picture to a canvas, 96
Create the negative of the original picture, 81
Creating a collage, 103
Cropping a picture onto a canvas, 100
Darken the picture, 80
Draw lines by setting pixels, 152
Draw the gray effect picture, 158
Draw the picture in Figure 4.14, 160
Draw the picture in Figure 4.15, 160
i
i
i
i
i
“MAIN”
2004/5/11
page 175
i
Index
175
Increase the red component by 30%, 68
Lighten the picture, 79
Lighten the picture using nested loops, 85
Making a sunset, 70
Making a sunset as three methods, 72
Mirror pixels horizontally, bottom-to-top, 90
Mirror pixels horizontally, top-to-bottom, 89
Mirror pixels in a picture along a vertical line, 87
Mirror the Temple of Zeus, 91
Pick and play a sound, 38
Pick and show a picture, 37
Play a specific sound, 39
Play the sound file whose file name is input, 41
Posterize by levels, 126
Posterizing a picture, 125
Reduce the amount of red in a picture by 50%, 61
Remove red eye, 120
Rotating a picture, 111
Scaling a picture down (smaller), 114
Scaling the picture up (larger), 115
Show a specific picture, 39
Show the picture file whose file name is input, 40
Show the picture provided as input, 41
Subtract the background and replace it with a new one, 143
recipes vs. methods, 73
red, 11
return, 77
reusable, 72
RGB model, 49
rounding errors, 56
sample, 12
sampling, 113
scope, 65
sepia-toned, 122
setColor(color), 53, 154
setRed(redValue), 53
show(), 28, 52
software engineering, 7, 13
sound
new Sound(fileName), 30
play(), 30
source, 96
specification, 157
stepping, 63
String, 17, 34
string, 33
i
i
i
i
i
“MAIN”
2004/5/11
page 176
i
176
Index
strings, 24
strongly typed, 18
subsitution, 33
substitution, 40
Sun, 20
symbols, 16
syntax, 35
systems, 7
takes on, 40
target, 96
testing
using print statements, 93
theory, 7
trace, 63
tracing
using print statements, 94
transforming, 96
transistor, 11
transparency, 50, 108
TrueType, 157
type, 16
types
byte, 17
double, 18
float, 18
int, 17
integer array, 17
String, 17
Unicode, 10
getting the mapping, 25
utility function, 96
variable, 28
declaration, 28
variables, 19, 32
reusing, 32
vector, 46
vector representation, 156
visibility, 35
walking through, 63
WAV, 27
i
i
i
Download