Kaleidoscope
/*
* Kaleidoscope Ver 1.0
*
* Created by Tsutomu Ishikura <ishikura@tky.threewebnet.or.jp>
* 1996 Mar 12
*
*/
import java.awt.*;
import java.awt.image.*;
import java.net.URL;
import java.lang.Math;
import java.applet.Applet;
import java.util.StringTokenizer;
/*
* An applet that displays repeated triangular image like
* Kaleidoscope. the triangular image unit is randomly clipped
* from an image that is specified by URL.
*/
public class Kaleidoscope extends Applet implements Runnable {
KaleidoscopeCanvas canvas;
KaleidoscopeControl control;
TriangleCreator triangleCreator;
Label message;
Thread kicker;
public void init () {
setLayout (new BorderLayout ());
control = new KaleidoscopeControl (this);
canvas = new KaleidoscopeCanvas (control.getCanvasSize ());
message = new Label (" ");
message.setAlignment (Label.CENTER);
message.setForeground (Color.blue);
add ("North", canvas);
add ("Center", message);
add ("South", control);
}
public void resetCreator () {
triangleCreator = null;
}
void setNewTriangle () {
if (triangleCreator == null) {
switch (control.getMethod ()) {
case 0:
default:
triangleCreator = new Method0 (control, this);
break;
}
}
if ((triangleCreator != null) && (triangleCreator.next ())) {
Image image = triangleCreator.getImage ();
canvas.setBaseTriangle (image, triangleCreator.getSize ());
} else {
imageProcessError ();
}
}
public void run () {
displayMessage ("");
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
while (true) {
try {
setNewTriangle ();
Thread.sleep (control.getUpdateInterval ());
}
catch (Exception ex) {
}
// System.err.println ("next");
}
}
public void start() {
if (kicker == null) {
kicker = new Thread(this);
kicker.start();
}
}
public void stop() {
if ((kicker != null) && (kicker.isAlive ())) {
kicker.stop();
}
kicker = null;
}
public void displayMessage (String s) {
message.setText (s);
}
public void imageLoadError () {
System.err.println ("image load error");
showStatus ("image load error");
displayMessage ("image load error");
stop ();
}
public void imageProcessError () {
System.err.println ("image convert error");
showStatus ("image convert error");
displayMessage ("image convert error");
stop ();
}
}
/*
* This class is the heart of the kaleidoscope.
* it displays repeated images of a given triangle.
*/
class KaleidoscopeCanvas extends Canvas {
final double SQRT3 = Math.sqrt (3);
Dimension preferredSize;
Image baseTriangle;
int triangleWidth;
int triangleHeight;
Image repeatRectangle;
int rectangleWidth;
int rectangleHeight;
Image imageBuff;
public KaleidoscopeCanvas (Dimension size) {
preferredSize = size;
}
public void setBaseTriangle (Image img, int width) {
baseTriangle = img;
triangleWidth = (width - 1) / 2 * 2 + 1; // force width to odd.
triangleHeight = (int) (triangleWidth * SQRT3 / 2);
createRepeatRectangle ();
}
void createRepeatRectangle () {
int tw = triangleWidth;
int th = triangleHeight;
int rw = rectangleWidth = triangleWidth + (triangleWidth - 1 ) / 2;
int rh = rectangleHeight = 2 * triangleHeight - 1;
int trianglePixels[] = new int[tw * th];
PixelGrabber pg = new PixelGrabber (baseTriangle, 0, 0, tw, th, trianglePixels, 0, tw);
try {
pg.grabPixels ();
} catch (Exception ex) {
System.err.println ("interrupted waiting for pixels");
return;
}
if ((pg.status () & ImageObserver.ABORT) != 0 ) {
System.err.println ("image fetch aborted or errored");
return;
}
int rectanglePixels[] = new int[rw * rh];
int x, y, x2, y2, aw;
aw = tw -1;
for (y = 0; y < rh / 2 + 1; y++) {
for (x = 0; x < aw / 2; x++) {
if (y > SQRT3 * x) {
x2 = (int)((-x + SQRT3 * y) / 2);
y2 = (int)((SQRT3 * x + y) / 2);
} else {
x2 = x;
y2 = y;
}
rectanglePixels[x + rw * (rh - 1 - y)]
= rectanglePixels[x + rw * y] = trianglePixels[x2 + y2 * tw];
}
for (x = aw / 2; x < aw; x++) {
if (y > (aw - x) * SQRT3) {
x2 = (int)((-x - SQRT3 * y + 3 * aw) / 2);
y2 = (int)((-SQRT3 * x + y + SQRT3 * aw) / 2);
} else {
x2 = x;
y2 = y;
}
rectanglePixels[x + rw * (rh - 1 - y)]
= rectanglePixels[x + rw * y] = trianglePixels[x2 + y2 * tw];
}
for (x = aw; x < rw; x++) {
if (y > (x - aw) * SQRT3) {
x2 = (int)((-x - SQRT3 * y + 3 * aw) / 2);
y2 = (int)((-SQRT3 * x + y + SQRT3 * aw) / 2);
} else {
x2 = (int)((-x - SQRT3 * y + 3 * aw) / 2);
y2 = (int)((SQRT3 * x - y - SQRT3 * aw) / 2);
}
rectanglePixels[x + rw * (rh - 1 - y)]
= rectanglePixels[x + rw * y] = trianglePixels[x2 + y2 * tw];
}
}
repeatRectangle
= createImage (new MemoryImageSource (rw, rh, rectanglePixels, 0, rw));
repaint ();
}
public void update (Graphics g) {
paint (g);
}
public synchronized void paint (Graphics g) {
int i,j;
int h = size().height;
int w = size().width;
if (repeatRectangle != null) {
for (i = 0 ; i * (rectangleWidth - 1)< w ; i++ ) {
if ((i % 2) == 0) {
j = 0;
} else {
j = - rectangleHeight / 2;
}
for (; j < h ; j += rectangleHeight - 1) {
g.drawImage (repeatRectangle, i * (rectangleWidth - 1), j,
rectangleWidth, rectangleHeight, this);
}
}
}
}
public Dimension preferredSize () {
return preferredSize;
}
}
class KaleidoscopeControl extends Panel {
Kaleidoscope applet;
URL imageURL;
String imageURLString;
Dimension canvasSize;
int triangleSize;
int updateInterval;
String imageFileList[];
Choice imageSelector;
TextField userImageURL;
TextField updateIntervalText;
TextField triangleSizeText;
KaleidoscopeControl (Kaleidoscope applet0)
{
applet = applet0;
initVariable ();
Panel panel1 = new Panel ();
Panel panel2 = new Panel ();
Panel panel3 = new Panel ();
panel1.add (new Button ("start"));
panel1.add (new Button ("stop"));
panel1.add (new Button ("restart"));
panel1.add (new Label (" update interval (ms):"));
updateIntervalText = new TextField (Integer.toString (updateInterval));
panel1.add (updateIntervalText);
panel2.add (new Label ("select image:"));
imageSelector = new Choice ();
int i;
for (i = 0 ; i < imageFileList.length ; i++) {
imageSelector.addItem (imageFileList [i]);
}
imageSelector.addItem ("From URL");
panel2.add (imageSelector);
panel2.add (new Label ("triangle size:"));
triangleSizeText = new TextField (Integer.toString (triangleSize));
panel2.add (triangleSizeText);
panel3.add (new Label ("Image from URL:"));
userImageURL = new TextField (imageURLString, 40);
panel3.add (userImageURL);
add (panel1);
add (panel2);
add (panel3);
}
void initVariable () {
int canvasWidth, canvasHeight;
try {
updateInterval
= Integer.valueOf (
applet.getParameter ("interval")).intValue ();
} catch (Exception e) {
updateInterval = 1000;
}
try {
triangleSize
= Integer.valueOf (
applet.getParameter ("trianglesize")).intValue ();
} catch (Exception e) {
triangleSize = 76;
}
try {
imageURLString = applet.getParameter ("imageURL");
} catch (Exception e) {
imageURLString = "";
}
try {
String files = applet.getParameter ("localfiles");
StringTokenizer t = new StringTokenizer (files);
imageFileList = new String[t.countTokens ()];
int i = 0;
for (i = 0 ; t.hasMoreTokens () ; i++) {
imageFileList [i] = t.nextToken ();
}
} catch (Exception e) {
String nullArray[] = {};
imageFileList = nullArray;
}
try {
canvasWidth
= Integer.valueOf (
applet.getParameter ("canvaswidth")).intValue ();
} catch (Exception e) {
canvasWidth = 400;
}
try {
canvasHeight
= Integer.valueOf (
applet.getParameter ("canvasheight")).intValue ();
} catch (Exception e) {
canvasHeight = 300;
}
canvasSize = new Dimension (canvasWidth, canvasHeight);
}
public boolean action (Event e, Object o) {
if (e.target instanceof Button) {
if ("start".equals (o)) {
applet.start ();
return true;
} else if ("stop".equals (o)) {
applet.stop ();
return true;
} else if ("restart".equals (o)) {
applet.stop ();
applet.resetCreator ();
applet.start ();
return true;
}
} else if (e.target instanceof Choice) {
applet.stop ();
applet.resetCreator ();
applet.start ();
return true;
} else if (e.target instanceof TextField) {
if (e.target == updateIntervalText) {
try {
updateInterval = Integer.valueOf ((String)o).intValue ();
} catch (Exception ex) {
updateInterval = 1000;
updateIntervalText.setText (Integer.toString (updateInterval));
}
} else if (e.target == triangleSizeText) {
try {
triangleSize = Integer.valueOf ((String)o).intValue ();
} catch (Exception ex) {
triangleSize = 0;
}
if (triangleSize < 10) {
triangleSize = 76;
triangleSizeText.setText (Integer.toString (triangleSize));
}
applet.stop ();
applet.resetCreator ();
applet.start ();
return true;
} else if (e.target == userImageURL) {
imageSelector.select("From URL");
applet.stop ();
applet.resetCreator ();
applet.start ();
return true;
}
}
return false;
}
public URL getImageURL () {
String s = imageSelector.getSelectedItem ();
if ("From URL".equals (s)){
s = userImageURL.getText ();
try {
imageURL = new URL (s);
} catch (Exception ex) {
System.err.println ("user URL is not valid");
return null;
}
} else {
try {
imageURL = new URL (applet.getDocumentBase (), s);
} catch (Exception ex) {
System.err.println ("filename " + s + " is not valid");
return null;
}
}
return imageURL;
}
public Dimension getCanvasSize () {
return canvasSize;
}
public int getUpdateInterval () {
return updateInterval;
}
public int getTriangleSize () {
return triangleSize;
}
public int getMethod () {
return 0;
}
public Dimension preferredSize () {
return new Dimension (400,130);
}
}
/*
* An abstract class that generates triangular images
* for KaleidoscopeCanvas.
*/
abstract class TriangleCreator extends Object {
abstract public boolean next ();
abstract public Image getImage ();
abstract public int getSize ();
}
/*
* This class clips triangular images from a given image.
*/
class Method0 extends TriangleCreator implements ImageObserver {
Kaleidoscope applet;
KaleidoscopeControl control;
int x,y;
int ox,oy;
int iw,ih;
int tw,th;
Image triangleImage;
Image image;
int step;
int interval;
int counter;
volatile boolean imageReadError;
Method0 (KaleidoscopeControl control0, Kaleidoscope applet0) {
applet = applet0;
control = control0;
init ();
}
synchronized void init () {
tw = control.getTriangleSize ();
th = (int) (Math.sqrt(3) * tw / 2);
try {
image = applet.getImage (control.getImageURL ());
} catch (Exception e) {
applet.imageLoadError ();
return;
}
if (image == null) {
applet.imageLoadError ();
return;
}
imageReadError = false;
while (((iw = image.getWidth (this)) < 0) && !imageReadError) {
try {
wait ();
} catch (InterruptedException ex) {
}
}
if (imageReadError) {
applet.imageLoadError ();
return;
}
ih = image.getHeight (this);
if ((ih < th - 10) || (iw < tw - 10)) {
applet.imageProcessError ();
return;
}
x = (int) (((Math.random() - 0.5) * 0.6 + 0.5)*(iw - tw));
y = (int) (((Math.random() - 0.5) * 0.6 + 0.5)*(ih - th));
interval = 10;
counter = 0;
step = 5;
do {
ox = (int)((Math.random () - 0.5) * 2 * step);
oy = (int)((Math.random () - 0.5) * 2 * step);
} while ((ox == 0) && (oy == 0));
}
public synchronized boolean imageUpdate (Image img, int infoFlags,
int x, int y,
int width, int height) {
if ((infoFlags & ERROR) != 0) {
imageReadError = true;
}
notifyAll ();
return true;
}
public boolean next () {
if (counter++ >= interval) {
counter = 0;
do {
ox = (int)((Math.random () - 0.5) * 2 * step);
oy = (int)((Math.random () - 0.5) * 2 * step);
} while ((ox == 0) && (oy == 0));
}
x += ox;
y += oy;
if ((x < 0) || (x + tw >= iw -1) || (y < 0) || (y + th >= ih - 1)) {
ox = -ox;
oy = -oy;
x += 2 * ox;
y += 2 * oy;
}
triangleImage
= applet.createImage (new FilteredImageSource
(image.getSource (),
new CropImageFilter(x, y, tw, th)));
return (triangleImage != null);
}
public Image getImage () {
return triangleImage;
}
public int getSize () {
return tw;
}
}
Back to the Kaleidoscope applet page
New on the Java Boutique:
New Review:
Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling
API boasts simplicity, ease-of-integration, a well-rounded feature
set, and it's free!
New Applet:
Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA
sequences into three useful formats.
Elsewhere on internet.com:
WebDeveloper Java
Lots of Java information on webdeveloper.com
WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.
ScriptSearch Java
Hundreds of free Java code files to download.
jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.
|