java program
META-INF/MANIFEST.MF
Manifest-Version: 1.0 Created-By: 1.8.0_191 (Oracle Corporation)
BinaryIn.java
BinaryIn.java
/******************************************************************************
* Compilation: javac BinaryIn.java
* Execution: java BinaryIn input output
* Dependencies: none
*
* This library is for reading binary data from an input stream.
*
* % java BinaryIn https://introcs.cs.princeton.edu/java/cover.png output.png
*
******************************************************************************/
import
java
.
io
.
BufferedInputStream
;
import
java
.
io
.
File
;
import
java
.
io
.
FileInputStream
;
import
java
.
io
.
IOException
;
import
java
.
io
.
InputStream
;
import
java
.
net
.
Socket
;
import
java
.
net
.
URL
;
import
java
.
net
.
URLConnection
;
import
java
.
util
.
NoSuchElementException
;
/**
* <i>Binary input</i>. This class provides methods for reading
* in bits from a binary input stream, either
* one bit at a time (as a {
@code
boolean}),
* 8 bits at a time (as a {
@code
byte} or {
@code
char}),
* 16 bits at a time (as a {
@code
short}),
* 32 bits at a time (as an {
@code
int} or {
@code
float}), or
* 64 bits at a time (as a {
@code
double} or {
@code
long}).
* <p>
* The binary input stream can be from standard input, a filename,
* a URL name, a Socket, or an InputStream.
* <p>
* All primitive types are assumed to be represented using their
* standard Java representations, in big-endian (most significant
* byte first) order.
* <p>
* The client should not intermix calls to {
@code
BinaryIn} with calls
* to {
@code
In}; otherwise unexpected behavior will result.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
BinaryIn
{
private
static
final
int
EOF
=
-
1
;
// end of file
private
BufferedInputStream
in
;
// the input stream
private
int
buffer
;
// one character buffer
private
int
n
;
// number of bits left in buffer
/**
* Initializes a binary input stream from standard input.
*/
public
BinaryIn
()
{
in
=
new
BufferedInputStream
(
System
.
in
);
fillBuffer
();
}
/**
* Initializes a binary input stream from an {
@code
InputStream}.
*
*
@param
is the {
@code
InputStream} object
*/
public
BinaryIn
(
InputStream
is
)
{
in
=
new
BufferedInputStream
(
is
);
fillBuffer
();
}
/**
* Initializes a binary input stream from a socket.
*
*
@param
socket the socket
*/
public
BinaryIn
(
Socket
socket
)
{
try
{
InputStream
is
=
socket
.
getInputStream
();
in
=
new
BufferedInputStream
(
is
);
fillBuffer
();
}
catch
(
IOException
ioe
)
{
System
.
err
.
println
(
"Could not open "
+
socket
);
}
}
/**
* Initializes a binary input stream from a URL.
*
*
@param
url the URL
*/
public
BinaryIn
(
URL url
)
{
try
{
URLConnection
site
=
url
.
openConnection
();
InputStream
is
=
site
.
getInputStream
();
in
=
new
BufferedInputStream
(
is
);
fillBuffer
();
}
catch
(
IOException
ioe
)
{
System
.
err
.
println
(
"Could not open "
+
url
);
}
}
/**
* Initializes a binary input stream from a filename or URL name.
*
*
@param
name the name of the file or URL
*/
public
BinaryIn
(
String
name
)
{
try
{
// first try to read file from local file system
File
file
=
new
File
(
name
);
if
(
file
.
exists
())
{
FileInputStream
fis
=
new
FileInputStream
(
file
);
in
=
new
BufferedInputStream
(
fis
);
fillBuffer
();
return
;
}
// next try for files included in jar
URL url
=
getClass
().
getResource
(
name
);
// or URL from web
if
(
url
==
null
)
{
url
=
new
URL
(
name
);
}
URLConnection
site
=
url
.
openConnection
();
InputStream
is
=
site
.
getInputStream
();
in
=
new
BufferedInputStream
(
is
);
fillBuffer
();
}
catch
(
IOException
ioe
)
{
System
.
err
.
println
(
"Could not open "
+
name
);
}
}
private
void
fillBuffer
()
{
try
{
buffer
=
in
.
read
();
n
=
8
;
}
catch
(
IOException
e
)
{
System
.
err
.
println
(
"EOF"
);
buffer
=
EOF
;
n
=
-
1
;
}
}
/**
* Returns true if this binary input stream exists.
*
*
@return
{
@code
true} if this binary input stream exists;
* {
@code
false} otherwise
*/
public
boolean
exists
()
{
return
in
!=
null
;
}
/**
* Returns true if this binary input stream is empty.
*
*
@return
{
@code
true} if this binary input stream is empty;
* {
@code
false} otherwise
*/
public
boolean
isEmpty
()
{
return
buffer
==
EOF
;
}
/**
* Reads the next bit of data from this binary input stream and return as a boolean.
*
*
@return
the next bit of data from this binary input stream as a {
@code
boolean}
*
@throws
NoSuchElementException if this binary input stream is empty
*/
public
boolean
readBoolean
()
{
if
(
isEmpty
())
throw
new
NoSuchElementException
(
"Reading from empty input stream"
);
n
--
;
boolean
bit
=
((
buffer
>>
n
)
&
1
)
==
1
;
if
(
n
==
0
)
fillBuffer
();
return
bit
;
}
/**
* Reads the next 8 bits from this binary input stream and return as an 8-bit char.
*
*
@return
the next 8 bits of data from this binary input stream as a {
@code
char}
*
@throws
NoSuchElementException if there are fewer than 8 bits available
*/
public
char
readChar
()
{
if
(
isEmpty
())
throw
new
NoSuchElementException
(
"Reading from empty input stream"
);
// special case when aligned byte
if
(
n
==
8
)
{
int
x
=
buffer
;
fillBuffer
();
return
(
char
)
(
x
&
0xff
);
}
// combine last N bits of current buffer with first 8-N bits of new buffer
int
x
=
buffer
;
x
<<=
(
8
-
n
);
int
oldN
=
n
;
fillBuffer
();
if
(
isEmpty
())
throw
new
NoSuchElementException
(
"Reading from empty input stream"
);
n
=
oldN
;
x
|=
(
buffer
>>>
n
);
return
(
char
)
(
x
&
0xff
);
// the above code doesn't quite work for the last character if N = 8
// because buffer will be -1
}
/**
* Reads the next r bits from this binary input stream and return as an r-bit character.
*
*
@param
r number of bits to read
*
@return
the next {
@code
r} bits of data from this binary input streamt as a {
@code
char}
*
@throws
NoSuchElementException if there are fewer than {
@code
r} bits available
*
@throws
IllegalArgumentException unless {
@code
1 <= r <= 16}
*/
public
char
readChar
(
int
r
)
{
if
(
r
<
1
||
r
>
16
)
throw
new
IllegalArgumentException
(
"Illegal value of r = "
+
r
);
// optimize r = 8 case
if
(
r
==
8
)
return
readChar
();
char
x
=
0
;
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
x
<<=
1
;
boolean
bit
=
readBoolean
();
if
(
bit
)
x
|=
1
;
}
return
x
;
}
/**
* Reads the remaining bytes of data from this binary input stream and return as a string.
*
*
@return
the remaining bytes of data from this binary input stream as a {
@code
String}
*
@throws
NoSuchElementException if this binary input stream is empty or if the number of bits
* available is not a multiple of 8 (byte-aligned)
*/
public
String
readString
()
{
if
(
isEmpty
())
throw
new
NoSuchElementException
(
"Reading from empty input stream"
);
StringBuilder
sb
=
new
StringBuilder
();
while
(
!
isEmpty
())
{
char
c
=
readChar
();
sb
.
append
(
c
);
}
return
sb
.
toString
();
}
/**
* Reads the next 16 bits from this binary input stream and return as a 16-bit short.
*
*
@return
the next 16 bits of data from this binary input stream as a {
@code
short}
*
@throws
NoSuchElementException if there are fewer than 16 bits available
*/
public
short
readShort
()
{
short
x
=
0
;
for
(
int
i
=
0
;
i
<
2
;
i
++
)
{
char
c
=
readChar
();
x
<<=
8
;
x
|=
c
;
}
return
x
;
}
/**
* Reads the next 32 bits from this binary input stream and return as a 32-bit int.
*
*
@return
the next 32 bits of data from this binary input stream as a {
@code
int}
*
@throws
NoSuchElementException if there are fewer than 32 bits available
*/
public
int
readInt
()
{
int
x
=
0
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
char
c
=
readChar
();
x
<<=
8
;
x
|=
c
;
}
return
x
;
}
/**
* Reads the next r bits from this binary input stream return as an r-bit int.
*
*
@param
r number of bits to read
*
@return
the next {
@code
r} bits of data from this binary input stream as a {
@code
int}
*
@throws
NoSuchElementException if there are fewer than r bits available
*
@throws
IllegalArgumentException unless {
@code
1 <= r <= 32}
*/
public
int
readInt
(
int
r
)
{
if
(
r
<
1
||
r
>
32
)
throw
new
IllegalArgumentException
(
"Illegal value of r = "
+
r
);
// optimize r = 32 case
if
(
r
==
32
)
return
readInt
();
int
x
=
0
;
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
x
<<=
1
;
boolean
bit
=
readBoolean
();
if
(
bit
)
x
|=
1
;
}
return
x
;
}
/**
* Reads the next 64 bits from this binary input stream and return as a 64-bit long.
*
*
@return
the next 64 bits of data from this binary input stream as a {
@code
long}
*
@throws
NoSuchElementException if there are fewer than 64 bits available
*/
public
long
readLong
()
{
long
x
=
0
;
for
(
int
i
=
0
;
i
<
8
;
i
++
)
{
char
c
=
readChar
();
x
<<=
8
;
x
|=
c
;
}
return
x
;
}
/**
* Reads the next 64 bits from this binary input stream and return as a 64-bit double.
*
*
@return
the next 64 bits of data from this binary input stream as a {
@code
double}
*
@throws
NoSuchElementException if there are fewer than 64 bits available
*/
public
double
readDouble
()
{
return
Double
.
longBitsToDouble
(
readLong
());
}
/**
* Reads the next 32 bits from this binary input stream and return as a 32-bit float.
*
*
@return
the next 32 bits of data from this binary input stream as a {
@code
float}
*
@throws
NoSuchElementException if there are fewer than 32 bits available
*/
public
float
readFloat
()
{
return
Float
.
intBitsToFloat
(
readInt
());
}
/**
* Reads the next 8 bits from this binary input stream and return as an 8-bit byte.
*
*
@return
the next 8 bits of data from this binary input stream as a {
@code
byte}
*
@throws
NoSuchElementException if there are fewer than 8 bits available
*/
public
byte
readByte
()
{
char
c
=
readChar
();
return
(
byte
)
(
c
&
0xff
);
}
/**
* Unit tests the {
@code
BinaryIn} data type.
* Reads the name of a file or URL (first command-line argument)
* and writes it to a file (second command-line argument).
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
BinaryIn
in
=
new
BinaryIn
(
args
[
0
]);
BinaryOut
out
=
new
BinaryOut
(
args
[
1
]);
// read one 8-bit char at a time
while
(
!
in
.
isEmpty
())
{
char
c
=
in
.
readChar
();
out
.
write
(
c
);
}
out
.
flush
();
}
}
BinaryOut.java
BinaryOut.java
/******************************************************************************
* Compilation: javac BinaryOut.java
* Execution: java BinaryOut
* Dependencies: none
*
* Write binary data to an output stream, either one 1-bit boolean,
* one 8-bit char, one 32-bit int, one 64-bit double, one 32-bit float,
* or one 64-bit long at a time. The output stream can be standard
* output, a file, an OutputStream or a Socket.
*
* The bytes written are not aligned.
*
******************************************************************************/
import
java
.
io
.
BufferedOutputStream
;
import
java
.
io
.
FileOutputStream
;
import
java
.
io
.
IOException
;
import
java
.
io
.
OutputStream
;
import
java
.
net
.
Socket
;
/**
* <i>Binary output</i>. This class provides methods for converting
* primtive type variables ({
@code
boolean}, {
@code
byte}, {
@code
char},
* {
@code
int}, {
@code
long}, {
@code
float}, and {
@code
double})
* to sequences of bits and writing them to an output stream.
* The output stream can be standard output, a file, an OutputStream or a Socket.
* Uses big-endian (most-significant byte first).
* <p>
* The client must {
@code
flush()} the output stream when finished writing bits.
* <p>
* The client should not intermix calls to {
@code
BinaryOut} with calls
* to {
@code
Out}; otherwise unexpected behavior will result.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
BinaryOut
{
private
BufferedOutputStream
out
;
// the output stream
private
int
buffer
;
// 8-bit buffer of bits to write out
private
int
n
;
// number of bits remaining in buffer
/**
* Initializes a binary output stream from standard output.
*/
public
BinaryOut
()
{
out
=
new
BufferedOutputStream
(
System
.
out
);
}
/**
* Initializes a binary output stream from an {
@code
OutputStream}.
*
@param
os the {
@code
OutputStream}
*/
public
BinaryOut
(
OutputStream
os
)
{
out
=
new
BufferedOutputStream
(
os
);
}
/**
* Initializes a binary output stream from a file.
*
@param
filename the name of the file
*/
public
BinaryOut
(
String
filename
)
{
try
{
OutputStream
os
=
new
FileOutputStream
(
filename
);
out
=
new
BufferedOutputStream
(
os
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Initializes a binary output stream from a socket.
*
@param
socket the socket
*/
public
BinaryOut
(
Socket
socket
)
{
try
{
OutputStream
os
=
socket
.
getOutputStream
();
out
=
new
BufferedOutputStream
(
os
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Writes the specified bit to the binary output stream.
*
@param
x the bit
*/
private
void
writeBit
(
boolean
x
)
{
// add bit to buffer
buffer
<<=
1
;
if
(
x
)
buffer
|=
1
;
// if buffer is full (8 bits), write out as a single byte
n
++
;
if
(
n
==
8
)
clearBuffer
();
}
/**
* Writes the 8-bit byte to the binary output stream.
*
@param
x the byte
*/
private
void
writeByte
(
int
x
)
{
assert
x
>=
0
&&
x
<
256
;
// optimized if byte-aligned
if
(
n
==
0
)
{
try
{
out
.
write
(
x
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
return
;
}
// otherwise write one bit at a time
for
(
int
i
=
0
;
i
<
8
;
i
++
)
{
boolean
bit
=
((
x
>>>
(
8
-
i
-
1
))
&
1
)
==
1
;
writeBit
(
bit
);
}
}
// write out any remaining bits in buffer to the binary output stream, padding with 0s
private
void
clearBuffer
()
{
if
(
n
==
0
)
return
;
if
(
n
>
0
)
buffer
<<=
(
8
-
n
);
try
{
out
.
write
(
buffer
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
n
=
0
;
buffer
=
0
;
}
/**
* Flushes the binary output stream, padding 0s if number of bits written so far
* is not a multiple of 8.
*/
public
void
flush
()
{
clearBuffer
();
try
{
out
.
flush
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Flushes and closes the binary output stream.
* Once it is closed, bits can no longer be written.
*/
public
void
close
()
{
flush
();
try
{
out
.
close
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Writes the specified bit to the binary output stream.
*
@param
x the {
@code
boolean} to write
*/
public
void
write
(
boolean
x
)
{
writeBit
(
x
);
}
/**
* Writes the 8-bit byte to the binary output stream.
*
@param
x the {
@code
byte} to write.
*/
public
void
write
(
byte
x
)
{
writeByte
(
x
&
0xff
);
}
/**
* Writes the 32-bit int to the binary output stream.
*
@param
x the {
@code
int} to write
*/
public
void
write
(
int
x
)
{
writeByte
((
x
>>>
24
)
&
0xff
);
writeByte
((
x
>>>
16
)
&
0xff
);
writeByte
((
x
>>>
8
)
&
0xff
);
writeByte
((
x
>>>
0
)
&
0xff
);
}
/**
* Writes the r-bit int to the binary output stream.
*
*
@param
x the {
@code
int} to write
*
@param
r the number of relevant bits in the char
*
@throws
IllegalArgumentException unless {
@code
r} is between 1 and 32
*
@throws
IllegalArgumentException unless {
@code
x} is between 0 and 2<sup>r</sup> - 1
*/
public
void
write
(
int
x
,
int
r
)
{
if
(
r
==
32
)
{
write
(
x
);
return
;
}
if
(
r
<
1
||
r
>
32
)
throw
new
IllegalArgumentException
(
"Illegal value for r = "
+
r
);
if
(
x
>=
(
1
<<
r
))
throw
new
IllegalArgumentException
(
"Illegal "
+
r
+
"-bit char = "
+
x
);
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
boolean
bit
=
((
x
>>>
(
r
-
i
-
1
))
&
1
)
==
1
;
writeBit
(
bit
);
}
}
/**
* Writes the 64-bit double to the binary output stream.
*
@param
x the {
@code
double} to write
*/
public
void
write
(
double
x
)
{
write
(
Double
.
doubleToRawLongBits
(
x
));
}
/**
* Writes the 64-bit long to the binary output stream.
*
@param
x the {
@code
long} to write
*/
public
void
write
(
long
x
)
{
writeByte
((
int
)
((
x
>>>
56
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
48
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
40
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
32
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
24
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
16
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
8
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
0
)
&
0xff
));
}
/**
* Writes the 32-bit float to the binary output stream.
*
@param
x the {
@code
float} to write
*/
public
void
write
(
float
x
)
{
write
(
Float
.
floatToRawIntBits
(
x
));
}
/**
* Write the 16-bit int to the binary output stream.
*
@param
x the {
@code
short} to write.
*/
public
void
write
(
short
x
)
{
writeByte
((
x
>>>
8
)
&
0xff
);
writeByte
((
x
>>>
0
)
&
0xff
);
}
/**
* Writes the 8-bit char to the binary output stream.
*
*
@param
x the {
@code
char} to write
*
@throws
IllegalArgumentException unless {
@code
x} is betwen 0 and 255
*/
public
void
write
(
char
x
)
{
if
(
x
<
0
||
x
>=
256
)
throw
new
IllegalArgumentException
(
"Illegal 8-bit char = "
+
x
);
writeByte
(
x
);
}
/**
* Writes the r-bit char to the binary output stream.
*
*
@param
x the {
@code
char} to write
*
@param
r the number of relevant bits in the char
*
@throws
IllegalArgumentException unless {
@code
r} is between 1 and 16
*
@throws
IllegalArgumentException unless {
@code
x} is between 0 and 2<sup>r</sup> - 1
*/
public
void
write
(
char
x
,
int
r
)
{
if
(
r
==
8
)
{
write
(
x
);
return
;
}
if
(
r
<
1
||
r
>
16
)
throw
new
IllegalArgumentException
(
"Illegal value for r = "
+
r
);
if
(
x
>=
(
1
<<
r
))
throw
new
IllegalArgumentException
(
"Illegal "
+
r
+
"-bit char = "
+
x
);
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
boolean
bit
=
((
x
>>>
(
r
-
i
-
1
))
&
1
)
==
1
;
writeBit
(
bit
);
}
}
/**
* Writes the string of 8-bit characters to the binary output stream.
*
*
@param
s the {
@code
String} to write
*
@throws
IllegalArgumentException if any character in the string is not
* between 0 and 255
*/
public
void
write
(
String
s
)
{
for
(
int
i
=
0
;
i
<
s
.
length
();
i
++
)
write
(
s
.
charAt
(
i
));
}
/**
* Writes the string of r-bit characters to the binary output stream.
*
@param
s the {
@code
String} to write
*
@param
r the number of relevants bits in each character
*
@throws
IllegalArgumentException unless r is between 1 and 16
*
@throws
IllegalArgumentException if any character in the string is not
* between 0 and 2<sup>r</sup> - 1
*/
public
void
write
(
String
s
,
int
r
)
{
for
(
int
i
=
0
;
i
<
s
.
length
();
i
++
)
write
(
s
.
charAt
(
i
),
r
);
}
/**
* Test client. Read bits from standard input and write to the file
* specified on command line.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
// create binary output stream to write to file
String
filename
=
args
[
0
];
BinaryOut
out
=
new
BinaryOut
(
filename
);
BinaryIn
in
=
new
BinaryIn
();
// read from standard input and write to file
while
(
!
in
.
isEmpty
())
{
char
c
=
in
.
readChar
();
out
.
write
(
c
);
}
out
.
flush
();
}
}
BinaryStdIn.java
BinaryStdIn.java
/******************************************************************************
* Compilation: javac BinaryStdIn.java
* Execution: java BinaryStdIn < input > output
* Dependencies: none
*
* Supports reading binary data from standard input.
*
* % java BinaryStdIn < input.jpg > output.jpg
* % diff input.jpg output.jpg
*
******************************************************************************/
import
java
.
io
.
BufferedInputStream
;
import
java
.
io
.
IOException
;
import
java
.
util
.
NoSuchElementException
;
/**
* <i>Binary standard input</i>. This class provides methods for reading
* in bits from standard input, either one bit at a time (as a {
@code
boolean}),
* 8 bits at a time (as a {
@code
byte} or {
@code
char}),
* 16 bits at a time (as a {
@code
short}), 32 bits at a time
* (as an {
@code
int} or {
@code
float}), or 64 bits at a time (as a
* {
@code
double} or {
@code
long}).
* <p>
* All primitive types are assumed to be represented using their
* standard Java representations, in big-endian (most significant
* byte first) order.
* <p>
* The client should not intermix calls to {
@code
BinaryStdIn} with calls
* to {
@code
StdIn} or {
@code
System.in};
* otherwise unexpected behavior will result.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
BinaryStdIn
{
private
static
final
int
EOF
=
-
1
;
// end of file
private
static
BufferedInputStream
in
;
// input stream
private
static
int
buffer
;
// one character buffer
private
static
int
n
;
// number of bits left in buffer
private
static
boolean
isInitialized
;
// has BinaryStdIn been called for first time?
// don't instantiate
private
BinaryStdIn
()
{
}
// fill buffer
private
static
void
initialize
()
{
in
=
new
BufferedInputStream
(
System
.
in
);
buffer
=
0
;
n
=
0
;
fillBuffer
();
isInitialized
=
true
;
}
private
static
void
fillBuffer
()
{
try
{
buffer
=
in
.
read
();
n
=
8
;
}
catch
(
IOException
e
)
{
System
.
out
.
println
(
"EOF"
);
buffer
=
EOF
;
n
=
-
1
;
}
}
/**
* Close this input stream and release any associated system resources.
*/
public
static
void
close
()
{
if
(
!
isInitialized
)
initialize
();
try
{
in
.
close
();
isInitialized
=
false
;
}
catch
(
IOException
ioe
)
{
throw
new
IllegalStateException
(
"Could not close BinaryStdIn"
,
ioe
);
}
}
/**
* Returns true if standard input is empty.
*
@return
true if and only if standard input is empty
*/
public
static
boolean
isEmpty
()
{
if
(
!
isInitialized
)
initialize
();
return
buffer
==
EOF
;
}
/**
* Reads the next bit of data from standard input and return as a boolean.
*
*
@return
the next bit of data from standard input as a {
@code
boolean}
*
@throws
NoSuchElementException if standard input is empty
*/
public
static
boolean
readBoolean
()
{
if
(
isEmpty
())
throw
new
NoSuchElementException
(
"Reading from empty input stream"
);
n
--
;
boolean
bit
=
((
buffer
>>
n
)
&
1
)
==
1
;
if
(
n
==
0
)
fillBuffer
();
return
bit
;
}
/**
* Reads the next 8 bits from standard input and return as an 8-bit char.
* Note that {
@code
char} is a 16-bit type;
* to read the next 16 bits as a char, use {
@code
readChar(16)}.
*
*
@return
the next 8 bits of data from standard input as a {
@code
char}
*
@throws
NoSuchElementException if there are fewer than 8 bits available on standard input
*/
public
static
char
readChar
()
{
if
(
isEmpty
())
throw
new
NoSuchElementException
(
"Reading from empty input stream"
);
// special case when aligned byte
if
(
n
==
8
)
{
int
x
=
buffer
;
fillBuffer
();
return
(
char
)
(
x
&
0xff
);
}
// combine last n bits of current buffer with first 8-n bits of new buffer
int
x
=
buffer
;
x
<<=
(
8
-
n
);
int
oldN
=
n
;
fillBuffer
();
if
(
isEmpty
())
throw
new
NoSuchElementException
(
"Reading from empty input stream"
);
n
=
oldN
;
x
|=
(
buffer
>>>
n
);
return
(
char
)
(
x
&
0xff
);
// the above code doesn't quite work for the last character if n = 8
// because buffer will be -1, so there is a special case for aligned byte
}
/**
* Reads the next r bits from standard input and return as an r-bit character.
*
*
@param
r number of bits to read.
*
@return
the next r bits of data from standard input as a {
@code
char}
*
@throws
NoSuchElementException if there are fewer than {
@code
r} bits available on standard input
*
@throws
IllegalArgumentException unless {
@code
1 <= r <= 16}
*/
public
static
char
readChar
(
int
r
)
{
if
(
r
<
1
||
r
>
16
)
throw
new
IllegalArgumentException
(
"Illegal value of r = "
+
r
);
// optimize r = 8 case
if
(
r
==
8
)
return
readChar
();
char
x
=
0
;
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
x
<<=
1
;
boolean
bit
=
readBoolean
();
if
(
bit
)
x
|=
1
;
}
return
x
;
}
/**
* Reads the remaining bytes of data from standard input and return as a string.
*
*
@return
the remaining bytes of data from standard input as a {
@code
String}
*
@throws
NoSuchElementException if standard input is empty or if the number of bits
* available on standard input is not a multiple of 8 (byte-aligned)
*/
public
static
String
readString
()
{
if
(
isEmpty
())
throw
new
NoSuchElementException
(
"Reading from empty input stream"
);
StringBuilder
sb
=
new
StringBuilder
();
while
(
!
isEmpty
())
{
char
c
=
readChar
();
sb
.
append
(
c
);
}
return
sb
.
toString
();
}
/**
* Reads the next 16 bits from standard input and return as a 16-bit short.
*
*
@return
the next 16 bits of data from standard input as a {
@code
short}
*
@throws
NoSuchElementException if there are fewer than 16 bits available on standard input
*/
public
static
short
readShort
()
{
short
x
=
0
;
for
(
int
i
=
0
;
i
<
2
;
i
++
)
{
char
c
=
readChar
();
x
<<=
8
;
x
|=
c
;
}
return
x
;
}
/**
* Reads the next 32 bits from standard input and return as a 32-bit int.
*
*
@return
the next 32 bits of data from standard input as a {
@code
int}
*
@throws
NoSuchElementException if there are fewer than 32 bits available on standard input
*/
public
static
int
readInt
()
{
int
x
=
0
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
char
c
=
readChar
();
x
<<=
8
;
x
|=
c
;
}
return
x
;
}
/**
* Reads the next r bits from standard input and return as an r-bit int.
*
*
@param
r number of bits to read.
*
@return
the next r bits of data from standard input as a {
@code
int}
*
@throws
NoSuchElementException if there are fewer than {
@code
r} bits available on standard input
*
@throws
IllegalArgumentException unless {
@code
1 <= r <= 32}
*/
public
static
int
readInt
(
int
r
)
{
if
(
r
<
1
||
r
>
32
)
throw
new
IllegalArgumentException
(
"Illegal value of r = "
+
r
);
// optimize r = 32 case
if
(
r
==
32
)
return
readInt
();
int
x
=
0
;
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
x
<<=
1
;
boolean
bit
=
readBoolean
();
if
(
bit
)
x
|=
1
;
}
return
x
;
}
/**
* Reads the next 64 bits from standard input and return as a 64-bit long.
*
*
@return
the next 64 bits of data from standard input as a {
@code
long}
*
@throws
NoSuchElementException if there are fewer than 64 bits available on standard input
*/
public
static
long
readLong
()
{
long
x
=
0
;
for
(
int
i
=
0
;
i
<
8
;
i
++
)
{
char
c
=
readChar
();
x
<<=
8
;
x
|=
c
;
}
return
x
;
}
/**
* Reads the next 64 bits from standard input and return as a 64-bit double.
*
*
@return
the next 64 bits of data from standard input as a {
@code
double}
*
@throws
NoSuchElementException if there are fewer than 64 bits available on standard input
*/
public
static
double
readDouble
()
{
return
Double
.
longBitsToDouble
(
readLong
());
}
/**
* Reads the next 32 bits from standard input and return as a 32-bit float.
*
*
@return
the next 32 bits of data from standard input as a {
@code
float}
*
@throws
NoSuchElementException if there are fewer than 32 bits available on standard input
*/
public
static
float
readFloat
()
{
return
Float
.
intBitsToFloat
(
readInt
());
}
/**
* Reads the next 8 bits from standard input and return as an 8-bit byte.
*
*
@return
the next 8 bits of data from standard input as a {
@code
byte}
*
@throws
NoSuchElementException if there are fewer than 8 bits available on standard input
*/
public
static
byte
readByte
()
{
char
c
=
readChar
();
return
(
byte
)
(
c
&
0xff
);
}
/**
* Test client. Reads in a binary input file from standard input and writes
* it to standard output.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
// read one 8-bit char at a time
while
(
!
BinaryStdIn
.
isEmpty
())
{
char
c
=
BinaryStdIn
.
readChar
();
BinaryStdOut
.
write
(
c
);
}
BinaryStdOut
.
flush
();
}
}
BinaryStdOut.java
BinaryStdOut.java
/******************************************************************************
* Compilation: javac BinaryStdOut.java
* Execution: java BinaryStdOut
* Dependencies: none
*
* Write binary data to standard output, either one 1-bit boolean,
* one 8-bit char, one 32-bit int, one 64-bit double, one 32-bit float,
* or one 64-bit long at a time.
*
* The bytes written are not aligned.
*
******************************************************************************/
import
java
.
io
.
BufferedOutputStream
;
import
java
.
io
.
IOException
;
/**
* <i>Binary standard output</i>. This class provides methods for converting
* primtive type variables ({
@code
boolean}, {
@code
byte}, {
@code
char},
* {
@code
int}, {
@code
long}, {
@code
float}, and {
@code
double})
* to sequences of bits and writing them to standard output.
* Uses big-endian (most-significant byte first).
* <p>
* The client must {
@code
flush()} the output stream when finished writing bits.
* <p>
* The client should not intermix calls to {
@code
BinaryStdOut} with calls
* to {
@code
StdOut} or {
@code
System.out}; otherwise unexpected behavior
* will result.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
BinaryStdOut
{
private
static
BufferedOutputStream
out
;
// output stream (standard output)
private
static
int
buffer
;
// 8-bit buffer of bits to write
private
static
int
n
;
// number of bits remaining in buffer
private
static
boolean
isInitialized
;
// has BinaryStdOut been called for first time?
// don't instantiate
private
BinaryStdOut
()
{
}
// initialize BinaryStdOut
private
static
void
initialize
()
{
out
=
new
BufferedOutputStream
(
System
.
out
);
buffer
=
0
;
n
=
0
;
isInitialized
=
true
;
}
/**
* Writes the specified bit to standard output.
*/
private
static
void
writeBit
(
boolean
bit
)
{
if
(
!
isInitialized
)
initialize
();
// add bit to buffer
buffer
<<=
1
;
if
(
bit
)
buffer
|=
1
;
// if buffer is full (8 bits), write out as a single byte
n
++
;
if
(
n
==
8
)
clearBuffer
();
}
/**
* Writes the 8-bit byte to standard output.
*/
private
static
void
writeByte
(
int
x
)
{
if
(
!
isInitialized
)
initialize
();
assert
x
>=
0
&&
x
<
256
;
// optimized if byte-aligned
if
(
n
==
0
)
{
try
{
out
.
write
(
x
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
return
;
}
// otherwise write one bit at a time
for
(
int
i
=
0
;
i
<
8
;
i
++
)
{
boolean
bit
=
((
x
>>>
(
8
-
i
-
1
))
&
1
)
==
1
;
writeBit
(
bit
);
}
}
// write out any remaining bits in buffer to standard output, padding with 0s
private
static
void
clearBuffer
()
{
if
(
!
isInitialized
)
initialize
();
if
(
n
==
0
)
return
;
if
(
n
>
0
)
buffer
<<=
(
8
-
n
);
try
{
out
.
write
(
buffer
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
n
=
0
;
buffer
=
0
;
}
/**
* Flushes standard output, padding 0s if number of bits written so far
* is not a multiple of 8.
*/
public
static
void
flush
()
{
clearBuffer
();
try
{
out
.
flush
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Flushes and closes standard output. Once standard output is closed, you can no
* longer write bits to it.
*/
public
static
void
close
()
{
flush
();
try
{
out
.
close
();
isInitialized
=
false
;
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Writes the specified bit to standard output.
*
@param
x the {
@code
boolean} to write.
*/
public
static
void
write
(
boolean
x
)
{
writeBit
(
x
);
}
/**
* Writes the 8-bit byte to standard output.
*
@param
x the {
@code
byte} to write.
*/
public
static
void
write
(
byte
x
)
{
writeByte
(
x
&
0xff
);
}
/**
* Writes the 32-bit int to standard output.
*
@param
x the {
@code
int} to write.
*/
public
static
void
write
(
int
x
)
{
writeByte
((
x
>>>
24
)
&
0xff
);
writeByte
((
x
>>>
16
)
&
0xff
);
writeByte
((
x
>>>
8
)
&
0xff
);
writeByte
((
x
>>>
0
)
&
0xff
);
}
/**
* Writes the r-bit int to standard output.
*
@param
x the {
@code
int} to write.
*
@param
r the number of relevant bits in the char.
*
@throws
IllegalArgumentException if {
@code
r} is not between 1 and 32.
*
@throws
IllegalArgumentException if {
@code
x} is not between 0 and 2<sup>r</sup> - 1.
*/
public
static
void
write
(
int
x
,
int
r
)
{
if
(
r
==
32
)
{
write
(
x
);
return
;
}
if
(
r
<
1
||
r
>
32
)
throw
new
IllegalArgumentException
(
"Illegal value for r = "
+
r
);
if
(
x
<
0
||
x
>=
(
1
<<
r
))
throw
new
IllegalArgumentException
(
"Illegal "
+
r
+
"-bit char = "
+
x
);
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
boolean
bit
=
((
x
>>>
(
r
-
i
-
1
))
&
1
)
==
1
;
writeBit
(
bit
);
}
}
/**
* Writes the 64-bit double to standard output.
*
@param
x the {
@code
double} to write.
*/
public
static
void
write
(
double
x
)
{
write
(
Double
.
doubleToRawLongBits
(
x
));
}
/**
* Writes the 64-bit long to standard output.
*
@param
x the {
@code
long} to write.
*/
public
static
void
write
(
long
x
)
{
writeByte
((
int
)
((
x
>>>
56
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
48
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
40
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
32
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
24
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
16
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
8
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
0
)
&
0xff
));
}
/**
* Writes the 32-bit float to standard output.
*
@param
x the {
@code
float} to write.
*/
public
static
void
write
(
float
x
)
{
write
(
Float
.
floatToRawIntBits
(
x
));
}
/**
* Writes the 16-bit int to standard output.
*
@param
x the {
@code
short} to write.
*/
public
static
void
write
(
short
x
)
{
writeByte
((
x
>>>
8
)
&
0xff
);
writeByte
((
x
>>>
0
)
&
0xff
);
}
/**
* Writes the 8-bit char to standard output.
*
@param
x the {
@code
char} to write.
*
@throws
IllegalArgumentException if {
@code
x} is not betwen 0 and 255.
*/
public
static
void
write
(
char
x
)
{
if
(
x
<
0
||
x
>=
256
)
throw
new
IllegalArgumentException
(
"Illegal 8-bit char = "
+
x
);
writeByte
(
x
);
}
/**
* Writes the r-bit char to standard output.
*
@param
x the {
@code
char} to write.
*
@param
r the number of relevant bits in the char.
*
@throws
IllegalArgumentException if {
@code
r} is not between 1 and 16.
*
@throws
IllegalArgumentException if {
@code
x} is not between 0 and 2<sup>r</sup> - 1.
*/
public
static
void
write
(
char
x
,
int
r
)
{
if
(
r
==
8
)
{
write
(
x
);
return
;
}
if
(
r
<
1
||
r
>
16
)
throw
new
IllegalArgumentException
(
"Illegal value for r = "
+
r
);
if
(
x
>=
(
1
<<
r
))
throw
new
IllegalArgumentException
(
"Illegal "
+
r
+
"-bit char = "
+
x
);
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
boolean
bit
=
((
x
>>>
(
r
-
i
-
1
))
&
1
)
==
1
;
writeBit
(
bit
);
}
}
/**
* Writes the string of 8-bit characters to standard output.
*
@param
s the {
@code
String} to write.
*
@throws
IllegalArgumentException if any character in the string is not
* between 0 and 255.
*/
public
static
void
write
(
String
s
)
{
for
(
int
i
=
0
;
i
<
s
.
length
();
i
++
)
write
(
s
.
charAt
(
i
));
}
/**
* Writes the string of r-bit characters to standard output.
*
@param
s the {
@code
String} to write.
*
@param
r the number of relevants bits in each character.
*
@throws
IllegalArgumentException if r is not between 1 and 16.
*
@throws
IllegalArgumentException if any character in the string is not
* between 0 and 2<sup>r</sup> - 1.
*/
public
static
void
write
(
String
s
,
int
r
)
{
for
(
int
i
=
0
;
i
<
s
.
length
();
i
++
)
write
(
s
.
charAt
(
i
),
r
);
}
/**
* Tests the methods in this class.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
int
m
=
Integer
.
parseInt
(
args
[
0
]);
// write n integers to binary standard output
for
(
int
i
=
0
;
i
<
m
;
i
++
)
{
BinaryStdOut
.
write
(
i
);
}
BinaryStdOut
.
flush
();
}
}
Draw.java
Draw.java
/******************************************************************************
* Compilation: javac Draw.java
* Execution: java Draw
* Dependencies: none
*
* Drawing library. This class provides a basic capability for creating
* drawings with your programs. It uses a simple graphics model that
* allows you to create drawings consisting of points, lines, and curves
* in a window on your computer and to save the drawings to a file.
* This is the object-oriented version of standard draw; it supports
* multiple indepedent drawing windows.
*
* Todo
* ----
* - Add support for gradient fill, etc.
*
* Remarks
* -------
* - don't use AffineTransform for rescaling since it inverts
* images and strings
* - careful using setFont in inner loop within an animation -
* it can cause flicker
*
******************************************************************************/
import
java
.
awt
.
BasicStroke
;
import
java
.
awt
.
Color
;
import
java
.
awt
.
Component
;
import
java
.
awt
.
FileDialog
;
import
java
.
awt
.
Font
;
import
java
.
awt
.
FontMetrics
;
import
java
.
awt
.
Graphics
;
import
java
.
awt
.
Graphics2D
;
import
java
.
awt
.
Image
;
import
java
.
awt
.
MediaTracker
;
import
java
.
awt
.
RenderingHints
;
import
java
.
awt
.
Toolkit
;
import
java
.
awt
.
event
.
ActionEvent
;
import
java
.
awt
.
event
.
ActionListener
;
import
java
.
awt
.
event
.
MouseEvent
;
import
java
.
awt
.
event
.
MouseListener
;
import
java
.
awt
.
event
.
MouseMotionListener
;
import
java
.
awt
.
event
.
KeyEvent
;
import
java
.
awt
.
event
.
KeyListener
;
import
java
.
awt
.
geom
.
Arc2D
;
import
java
.
awt
.
geom
.
Ellipse2D
;
import
java
.
awt
.
geom
.
GeneralPath
;
import
java
.
awt
.
geom
.
Line2D
;
import
java
.
awt
.
geom
.
Rectangle2D
;
import
java
.
awt
.
image
.
BufferedImage
;
import
java
.
awt
.
image
.
DirectColorModel
;
import
java
.
awt
.
image
.
WritableRaster
;
import
java
.
io
.
File
;
import
java
.
io
.
IOException
;
import
java
.
net
.
MalformedURLException
;
import
java
.
net
.
URL
;
import
java
.
util
.
ArrayList
;
import
java
.
util
.
LinkedList
;
import
java
.
util
.
TreeSet
;
import
javax
.
imageio
.
ImageIO
;
import
javax
.
swing
.
ImageIcon
;
import
javax
.
swing
.
JFrame
;
import
javax
.
swing
.
JLabel
;
import
javax
.
swing
.
JMenu
;
import
javax
.
swing
.
JMenuBar
;
import
javax
.
swing
.
JMenuItem
;
import
javax
.
swing
.
KeyStroke
;
/**
* <i>Draw</i>. This class provides a basic capability for
* creating drawings with your programs. It uses a simple graphics model that
* allows you to create drawings consisting of points, lines, and curves
* in a window on your computer and to save the drawings to a file.
* This is the object-oriented version of standard draw; it supports
* multiple indepedent drawing windows.
* <p>
* For additional documentation, see
* <a href="https://introcs.cs.princeton.edu/31datatype">Section 3.1</a> of
* <i>Computer Science: An Interdisciplinary Approach</i> by Robert Sedgewick and Kevin Wayne.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
Draw
implements
ActionListener
,
MouseListener
,
MouseMotionListener
,
KeyListener
{
/**
* The color black.
*/
public
static
final
Color
BLACK
=
Color
.
BLACK
;
/**
* The color blue.
*/
public
static
final
Color
BLUE
=
Color
.
BLUE
;
/**
* The color cyan.
*/
public
static
final
Color
CYAN
=
Color
.
CYAN
;
/**
* The color dark gray.
*/
public
static
final
Color
DARK_GRAY
=
Color
.
DARK_GRAY
;
/**
* The color gray.
*/
public
static
final
Color
GRAY
=
Color
.
GRAY
;
/**
* The color green.
*/
public
static
final
Color
GREEN
=
Color
.
GREEN
;
/**
* The color light gray.
*/
public
static
final
Color
LIGHT_GRAY
=
Color
.
LIGHT_GRAY
;
/**
* The color magenta.
*/
public
static
final
Color
MAGENTA
=
Color
.
MAGENTA
;
/**
* The color orange.
*/
public
static
final
Color
ORANGE
=
Color
.
ORANGE
;
/**
* The color pink.
*/
public
static
final
Color
PINK
=
Color
.
PINK
;
/**
* The color red.
*/
public
static
final
Color
RED
=
Color
.
RED
;
/**
* The color white.
*/
public
static
final
Color
WHITE
=
Color
.
WHITE
;
/**
* The color yellow.
*/
public
static
final
Color
YELLOW
=
Color
.
YELLOW
;
/**
* Shade of blue used in Introduction to Programming in Java.
* It is Pantone 300U. The RGB values are approximately (9, 90, 166).
*/
public
static
final
Color
BOOK_BLUE
=
new
Color
(
9
,
90
,
166
);
/**
* Shade of light blue used in Introduction to Programming in Java.
* The RGB values are approximately (103, 198, 243).
*/
public
static
final
Color
BOOK_LIGHT_BLUE
=
new
Color
(
103
,
198
,
243
);
/**
* Shade of red used in <em>Algorithms, 4th edition</em>.
* It is Pantone 1805U. The RGB values are approximately (150, 35, 31).
*/
public
static
final
Color
BOOK_RED
=
new
Color
(
150
,
35
,
31
);
/**
* Shade of orange used in Princeton's identity.
* It is PMS 158. The RGB values are approximately (245, 128, 37).
*/
public
static
final
Color
PRINCETON_ORANGE
=
new
Color
(
245
,
128
,
37
);
// default colors
private
static
final
Color
DEFAULT_PEN_COLOR
=
BLACK
;
private
static
final
Color
DEFAULT_CLEAR_COLOR
=
WHITE
;
// boundary of drawing canvas, 0% border
private
static
final
double
BORDER
=
0.0
;
private
static
final
double
DEFAULT_XMIN
=
0.0
;
private
static
final
double
DEFAULT_XMAX
=
1.0
;
private
static
final
double
DEFAULT_YMIN
=
0.0
;
private
static
final
double
DEFAULT_YMAX
=
1.0
;
// default canvas size is SIZE-by-SIZE
private
static
final
int
DEFAULT_SIZE
=
512
;
// default pen radius
private
static
final
double
DEFAULT_PEN_RADIUS
=
0.002
;
// default font
private
static
final
Font
DEFAULT_FONT
=
new
Font
(
"SansSerif"
,
Font
.
PLAIN
,
16
);
// current pen color
private
Color
penColor
;
// canvas size
private
int
width
=
DEFAULT_SIZE
;
private
int
height
=
DEFAULT_SIZE
;
// current pen radius
private
double
penRadius
;
// show we draw immediately or wait until next show?
private
boolean
defer
=
false
;
private
double
xmin
,
ymin
,
xmax
,
ymax
;
// name of window
private
String
name
=
"Draw"
;
// for synchronization
private
final
Object
mouseLock
=
new
Object
();
private
final
Object
keyLock
=
new
Object
();
// current font
private
Font
font
;
// the JLabel for drawing
private
JLabel
draw
;
// double buffered graphics
private
BufferedImage
offscreenImage
,
onscreenImage
;
private
Graphics2D
offscreen
,
onscreen
;
// the frame for drawing to the screen
private
JFrame
frame
=
new
JFrame
();
// mouse state
private
boolean
isMousePressed
=
false
;
private
double
mouseX
=
0
;
private
double
mouseY
=
0
;
// keyboard state
private
final
LinkedList
<
Character
>
keysTyped
=
new
LinkedList
<
Character
>
();
private
final
TreeSet
<
Integer
>
keysDown
=
new
TreeSet
<
Integer
>
();
// event-based listeners
private
final
ArrayList
<
DrawListener
>
listeners
=
new
ArrayList
<
DrawListener
>
();
/**
* Initializes an empty drawing object with the given name.
*
*
@param
name the title of the drawing window.
*/
public
Draw
(
String
name
)
{
this
.
name
=
name
;
init
();
}
/**
* Initializes an empty drawing object.
*/
public
Draw
()
{
init
();
}
private
void
init
()
{
if
(
frame
!=
null
)
frame
.
setVisible
(
false
);
frame
=
new
JFrame
();
offscreenImage
=
new
BufferedImage
(
2
*
width
,
2
*
height
,
BufferedImage
.
TYPE_INT_ARGB
);
onscreenImage
=
new
BufferedImage
(
2
*
width
,
2
*
height
,
BufferedImage
.
TYPE_INT_ARGB
);
offscreen
=
offscreenImage
.
createGraphics
();
onscreen
=
onscreenImage
.
createGraphics
();
offscreen
.
scale
(
2.0
,
2.0
);
// since we made it 2x as big
setXscale
();
setYscale
();
offscreen
.
setColor
(
DEFAULT_CLEAR_COLOR
);
offscreen
.
fillRect
(
0
,
0
,
width
,
height
);
setPenColor
();
setPenRadius
();
setFont
();
clear
();
// add antialiasing
RenderingHints
hints
=
new
RenderingHints
(
RenderingHints
.
KEY_ANTIALIASING
,
RenderingHints
.
VALUE_ANTIALIAS_ON
);
hints
.
put
(
RenderingHints
.
KEY_RENDERING
,
RenderingHints
.
VALUE_RENDER_QUALITY
);
offscreen
.
addRenderingHints
(
hints
);
// frame stuff
RetinaImageIcon
icon
=
new
RetinaImageIcon
(
onscreenImage
);
draw
=
new
JLabel
(
icon
);
draw
.
addMouseListener
(
this
);
draw
.
addMouseMotionListener
(
this
);
frame
.
setContentPane
(
draw
);
frame
.
addKeyListener
(
this
);
// JLabel cannot get keyboard focus
frame
.
setResizable
(
false
);
// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // closes all windows
frame
.
setDefaultCloseOperation
(
JFrame
.
DISPOSE_ON_CLOSE
);
// closes only current window
frame
.
setFocusTraversalKeysEnabled
(
false
);
// to recognize VK_TAB with isKeyPressed()
frame
.
setTitle
(
name
);
frame
.
setJMenuBar
(
createMenuBar
());
frame
.
pack
();
frame
.
requestFocusInWindow
();
frame
.
setVisible
(
true
);
}
/**
* Sets the upper-left hand corner of the drawing window to be (x, y), where (0, 0) is upper left.
*
*
@param
x the number of pixels from the left
*
@param
y the number of pixels from the top
*
@throws
IllegalArgumentException if the width or height is 0 or negative
*/
public
void
setLocationOnScreen
(
int
x
,
int
y
)
{
if
(
x
<=
0
||
y
<=
0
)
throw
new
IllegalArgumentException
();
frame
.
setLocation
(
x
,
y
);
}
/**
* Sets the default close operation.
*
*
@param
value the value, typically {
@code
JFrame.EXIT_ON_CLOSE}
* (close all windows) or {
@code
JFrame.DISPOSE_ON_CLOSE}
* (close current window)
*/
public
void
setDefaultCloseOperation
(
int
value
)
{
frame
.
setDefaultCloseOperation
(
value
);
}
/**
* Sets the canvas (drawing area) to be <em>width</em>-by-<em>height</em> pixels.
* This also erases the current drawing and resets the coordinate system, pen radius,
* pen color, and font back to their default values.
* Ordinarly, this method is called once, at the very beginning of a program.
*
*
@param
canvasWidth the width as a number of pixels
*
@param
canvasHeight the height as a number of pixels
*
@throws
IllegalArgumentException unless both {
@code
canvasWidth}
* and {
@code
canvasHeight} are positive
*/
public
void
setCanvasSize
(
int
canvasWidth
,
int
canvasHeight
)
{
if
(
canvasWidth
<
1
||
canvasHeight
<
1
)
{
throw
new
IllegalArgumentException
(
"width and height must be positive"
);
}
width
=
canvasWidth
;
height
=
canvasHeight
;
init
();
}
// create the menu bar (changed to private)
private
JMenuBar
createMenuBar
()
{
JMenuBar
menuBar
=
new
JMenuBar
();
JMenu
menu
=
new
JMenu
(
"File"
);
menuBar
.
add
(
menu
);
JMenuItem
menuItem1
=
new
JMenuItem
(
" Save... "
);
menuItem1
.
addActionListener
(
this
);
// Java 10+: replace getMenuShortcutKeyMask() with getMenuShortcutKeyMaskEx()
menuItem1
.
setAccelerator
(
KeyStroke
.
getKeyStroke
(
KeyEvent
.
VK_S
,
Toolkit
.
getDefaultToolkit
().
getMenuShortcutKeyMask
()));
menu
.
add
(
menuItem1
);
return
menuBar
;
}
/***************************************************************************
* User and screen coordinate systems.
***************************************************************************/