/* * @(#)ImageChanger.java * * Copyright (c) 1996 NAKAGAWA Masami * * Permission to use, copy, modify, and distribute this software * for NON-COMMERCIAL purpose and without fee is hereby granted. */ import java.applet.*; import java.awt.*; import java.awt.image.*; import java.util.*; import java.net.*; /** A class of GIF(JPEG) image changer to decorate a Web page * @author NAKAGAWA Masami * @version 1.3, 30 Jun 1997 */ public class ImageChanger extends Applet implements Runnable { final int FADEMAX = 16; final int FADEWID = 64; final int EFFECTNUM = 20; final int NONE = 0; final int SCROLLUP = 1; final int SCROLLDOWN = 2; final int SCROLLRIGHT = 3; final int SCROLLLEFT = 4; final int TEARVERTICAL = 5; final int TEARHORIZONTAL = 6; final int OPEN = 7; final int CLOSE = 8; final int FADE = 9; final int MOSAIC = 10; final int TEARUP = 11; final int TEARDOWN = 12; final int TEARRIGHT = 13; final int TEARLEFT = 14; final int SLIDEUP = 15; final int SLIDEDOWN = 16; final int SLIDERIGHT = 17; final int SLIDELEFT = 18; final int SHRINKVERTICAL = 19; final int SHRINKHORIZONTAL = 20; Dimension mySize; MediaTracker tracker; Image[] images; String[] imageFile; int[] change; int[] time; String imageDir = "."; int imageNum; int defaultChange; int defaultTime = 5000; Color fadeColor = Color.black; Color bgColor = Color.black; int scrollSpeed = 6; int changeSpeed = 3; int fadeTime = 80; Image[] fadeImage = new Image[FADEMAX]; Image mosaicImage; Thread kicker; int current; Graphics offScreen; Graphics onScreen; Image offImage; boolean drawWhileLoading = true; int mosaicWidth = 16; int mosaicHeight = 16; int mosaicSpeed = 4; Random rand; URL[] url; boolean randomOrder = false; boolean randomEffect = false; boolean cursorIn = false; AppletContext ac; public void init() { setBackground(bgColor); String s; s = getParameter("imageDir"); if (s != null) imageDir = s; s = getParameter("change"); if (s != null) defaultChange = Integer.parseInt(s); s = getParameter("time"); if (s != null) defaultTime = Integer.parseInt(s); s = getParameter("fadeColor"); if (s != null) fadeColor = new Color(Integer.parseInt(s, 16)); s = getParameter("bgColor"); if (s != null) bgColor = new Color(Integer.parseInt(s, 16)); s = getParameter("scrollSpeed"); if (s != null) scrollSpeed = Integer.parseInt(s); s = getParameter("changeSpeed"); if (s != null) changeSpeed = Integer.parseInt(s); s = getParameter("fadeTime"); if (s != null) fadeTime = Integer.parseInt(s) / FADEMAX; s = getParameter("drawWhileLoading"); if (s != null) drawWhileLoading = Boolean.valueOf(s).booleanValue(); s = getParameter("mosaicWidth"); if (s != null) mosaicWidth = Integer.parseInt(s); s = getParameter("mosaicHeight"); if (s != null) mosaicHeight = Integer.parseInt(s); s = getParameter("mosaicSpeed"); if (s != null) mosaicSpeed = Integer.parseInt(s); s = getParameter("randomOrder"); if (s != null) randomOrder = Boolean.valueOf(s).booleanValue(); s = getParameter("randomEffect"); if (s != null) randomEffect = Boolean.valueOf(s).booleanValue(); s = getParameter("images"); StringTokenizer t1 = new StringTokenizer(s, ","); imageNum = t1.countTokens(); images = new Image[imageNum]; imageFile = new String[imageNum]; change = new int[imageNum]; time = new int[imageNum]; url = new URL[imageNum]; int count = 0; while (t1.hasMoreTokens()) { s = t1.nextToken(); StringTokenizer t2 = new StringTokenizer(s, "|"); imageFile[count] = t2.nextToken().trim(); change[count] = defaultChange; if (t2.hasMoreTokens()) { s = t2.nextToken().trim(); try { if (s != null && !s.equals("-")) change[count] = Integer.parseInt(s); } catch (NumberFormatException e) { } } time[count] = defaultTime; if (t2.hasMoreTokens()) { s = t2.nextToken().trim(); try { if (s != null && !s.equals("-")) time[count] = Integer.parseInt(s); } catch (NumberFormatException e) { } } if (t2.hasMoreTokens()) { s = t2.nextToken().trim(); try { if (s != null && !s.equals("-")) url[count] = new URL(s); } catch (MalformedURLException e) { try { url[count] = new URL(getDocumentBase(), s); } catch (MalformedURLException ex) { } } } count++; } mySize = size(); rand = new Random(); ac = getAppletContext(); } public void start() { for (int i = 0; i < images.length; i++) { try { URL imgUrl = new URL(imageFile[i]); images[i] = getImage(imgUrl); } catch (MalformedURLException e) { images[i] = getImage(getDocumentBase(), imageDir + "/" + imageFile[i]); } } offImage = createImage(mySize.width, mySize.height); offScreen = offImage.getGraphics(); onScreen = getGraphics(); mosaicImage = createImage(mySize.width, mySize.height); tracker = new MediaTracker(this); for (int i = 0; i < images.length; i++) { tracker.addImage(images[i], i); } makeFadeImages(); if (kicker == null) { kicker = new Thread(this); kicker.start(); } } void makeFadeImages() { int[][] pix = new int[FADEMAX][FADEWID*FADEWID]; for (int i = 0; i < FADEMAX; i++) { for (int y = 0; y < FADEWID; y++) { for (int x = 0; x < FADEWID; x++) { pix[i][x+y*FADEWID] = (0xff*(i+1)/FADEMAX)<<24 | (fadeColor.getRGB() & 0x00ffffff); } } MemoryImageSource mis = new MemoryImageSource(FADEWID, FADEWID, pix[i], 0, FADEWID); fadeImage[i] = createImage(mis); } } public void stop() { if (kicker != null) { kicker.stop(); } kicker = null; } public void paint(Graphics g) { g.drawImage(offImage, 0, 0, null); } public void update(Graphics g) { paint(g); } void drawMessage(String message) { offScreen.setColor(bgColor); offScreen.fillRect(0, 0, mySize.width, mySize.height); offScreen.setColor(Color.cyan); offScreen.drawString(message, 10, 20); } void scrollImage(Image fore, Image back, int dx, int dy) { int fx = (mySize.width - fore.getWidth(null)) / 2; int fy = (mySize.height - fore.getHeight(null)) / 2; int bx = (mySize.width - back.getWidth(null)) / 2; int by = (mySize.height - back.getHeight(null)) / 2; int width = fore.getWidth(null); int height = fore.getHeight(null); while (fx + width > 0 && fx < mySize.width && fy + height > 0 && fy < mySize.height) { fx += dx; fy += dy; offScreen.setColor(bgColor); offScreen.fillRect(0, 0, mySize.width, mySize.height); offScreen.drawImage(back, bx, by, null); offScreen.drawImage(fore, fx, fy, null); onScreen.drawImage(offImage, 0, 0, null); try { Thread.currentThread().sleep(50); } catch (InterruptedException e) { } } } void slideImage(Image back, Image fore, int dx, int dy) { int fx = 0; int fy = 0; int width = fore.getWidth(null); int height = fore.getHeight(null); int bx = (mySize.width - back.getWidth(null)) / 2; int by = (mySize.height - back.getHeight(null)) / 2; int endx = (mySize.width - width) / 2; int endy = (mySize.height - height) / 2; if (dx != 0) { fx = (dx > 0)?-width:mySize.width; fy = endy; } else { fy = (dy > 0)?-height:mySize.height; fx = endx; } while (true) { if (dx != 0) { fx += dx; if ((dx > 0 && fx > endx) || (dx < 0 && fx < endx)) break; } else { fy += dy; if ((dy > 0 && fy > endy) || (dy < 0 && fy < endy)) break; } offScreen.setColor(bgColor); offScreen.fillRect(0, 0, mySize.width, mySize.height); offScreen.drawImage(back, bx, by, null); offScreen.drawImage(fore, fx, fy, null); onScreen.drawImage(offImage, 0, 0, null); try { Thread.currentThread().sleep(50); } catch (InterruptedException e) { } } } void tearImage(Image image, int dx, int dy) { int w = 0; int h = 0; int x1 = (mySize.width - image.getWidth(null)) / 2; int y1 = (mySize.height - image.getHeight(null)) / 2; int x2 = x1+image.getWidth(null); int y2 = y1+image.getHeight(null); while (w < image.getWidth(null) && h < image.getHeight(null)) { if (dx > 0) { w += dx; offScreen.clipRect(x1, 0, w, mySize.height); } else if (dy > 0) { h += dy; offScreen.clipRect(0, y1, mySize.width, h); } else if (dx < 0) { x2 += dx; w -= dx; offScreen.clipRect(x2, 0, w, mySize.height); } else if (dy < 0) { y2 += dy; h -= dy; offScreen.clipRect(0, y2, mySize.width, h); } offScreen.drawImage(image, x1, y1, null); onScreen.drawImage(offImage, 0, 0, null); try { Thread.currentThread().sleep(50); } catch (InterruptedException e) { } offScreen = offImage.getGraphics(); } } void tearOpenImage(Image image, int dx, int dy) { int x = mySize.width / 2; int y = mySize.height / 2; int w = 0; int h = 0; int nx = (mySize.width - image.getWidth(null)) / 2; int ny = (mySize.height - image.getHeight(null)) / 2; while (x > nx && y > ny) { if (dx > 0) { x -= dx; w += dx * 2; offScreen.clipRect(x, 0, w, mySize.height); } else if (dy > 0) { y -= dy; h += dy * 2; offScreen.clipRect(0, y, mySize.width, h); } offScreen.drawImage(image, nx, ny, null); onScreen.drawImage(offImage, 0, 0, null); try { Thread.currentThread().sleep(50); } catch (InterruptedException e) { } offScreen = offImage.getGraphics(); } } void shrinkImage(Image current, Image next, int dx, int dy) { int w = next.getWidth(null); int h = next.getHeight(null); int nx = (mySize.width - w) / 2; int ny = (mySize.height - h) / 2; int cx = (mySize.width - current.getWidth(null)) / 2; int cy = (mySize.height - current.getHeight(null)) / 2; int x = nx; int y = ny; while (w > 0 && h > 0) { offScreen.drawImage(current, cx, cy, null); if (dx != 0) { offScreen.clipRect(0, 0, x, mySize.height); } else { offScreen.clipRect(0, 0, mySize.width, y); } offScreen.drawImage(next, nx, ny, null); offScreen = offImage.getGraphics(); if (dx != 0) { offScreen.clipRect(x+w, 0, mySize.width-(x+w), mySize.height); } else { offScreen.clipRect(0, y+h, mySize.width, mySize.height-(y+h)); } offScreen.drawImage(next, nx, ny, null); onScreen.drawImage(offImage, 0, 0, null); try { Thread.currentThread().sleep(50); } catch (InterruptedException e) { } if (dx > 0) { x += dx; w -= dx * 2; } else if (dy > 0) { y += dy; h -= dy * 2; } offScreen = offImage.getGraphics(); } } void openImage(Image next, int speed) { double dx, dy; int nw = next.getWidth(null); int nh = next.getHeight(null); int nx = (mySize.width - nw) / 2; int ny = (mySize.height - nh) / 2; if (nw < nh) { dy = (double)speed; dx = (double)speed * nw / nh; } else { dx = (double)speed; dy = (double)speed * nh / nw; } double w = 0; double h = 0; double x = mySize.width / 2; double y = mySize.height / 2; while (x > nx || y > ny) { x -= dx; w += dx * 2; y -= dy; h += dy * 2; offScreen.clipRect((int)x, (int)y, (int)w, (int)h); offScreen.drawImage(next, nx, ny, null); onScreen.drawImage(offImage, 0, 0, null); try { Thread.currentThread().sleep(50); } catch (InterruptedException e) { } offScreen = offImage.getGraphics(); } } void closeImage(Image current, Image next, int speed) { double dx, dy; double w = current.getWidth(null); double h = current.getHeight(null); if (w < h) { dy = (double)speed; dx = (double)speed * w / h; } else { dx = (double)speed; dy = (double)speed * h / w; } int cx = (mySize.width - (int)w) / 2; int cy = (mySize.height - (int)h) / 2; double x = cx; double y = cy; int nx = (mySize.width - next.getWidth(null)) / 2; int ny = (mySize.height - next.getHeight(null)) / 2; while (w > 0 && h > 0) { x += dx; w -= dx * 2; y += dy; h -= dy * 2; offScreen.drawImage(next, nx, ny, null); offScreen.clipRect((int)x, (int)y, (int)w, (int)h); offScreen.drawImage(current, cx, cy, null); onScreen.drawImage(offImage, 0, 0, null); try { Thread.currentThread().sleep(50); } catch (InterruptedException e) { } offScreen = offImage.getGraphics(); } } void fadeImage(Image current, Image next) { int x = (mySize.width - current.getWidth(null)) / 2; int y = (mySize.height - current.getHeight(null)) / 2; for (int i = 0; i < FADEMAX; i++) { offScreen.setColor(bgColor); offScreen.fillRect(0, 0, mySize.width, mySize.height); offScreen.drawImage(current, x, y, null); for (int fy = 0; fy < mySize.height; fy += FADEWID) { for (int fx = 0; fx < mySize.width; fx += FADEWID) { offScreen.drawImage(fadeImage[i], fx, fy, null); } } onScreen.drawImage(offImage, 0, 0, null); try { Thread.currentThread().sleep(fadeTime); } catch (InterruptedException e) { } } x = (mySize.width - next.getWidth(null)) / 2; y = (mySize.height - next.getHeight(null)) / 2; for (int i = FADEMAX-1; i >= 0; i--) { offScreen.setColor(bgColor); offScreen.fillRect(0, 0, mySize.width, mySize.height); offScreen.drawImage(next, x, y, null); for (int fy = 0; fy < mySize.height; fy += FADEWID) { for (int fx = 0; fx < mySize.width; fx += FADEWID) { offScreen.drawImage(fadeImage[i], fx, fy, null); } } onScreen.drawImage(offImage, 0, 0, null); try { Thread.currentThread().sleep(fadeTime); } catch (InterruptedException e) { } } } void mosaicImage(Image image) { int x = 0; int y = 0; int n = 0; int line = mySize.height/mosaicHeight; if (line*mosaicHeight < mySize.height) line++; int column = mySize.width/mosaicWidth; if (column*mosaicWidth < mySize.width) column++; Point[] p = new Point[line*column]; for (int i = 0; i < p.length; i++) { p[i] = new Point(i/line, i%line); } for (int i = 0; i < p.length; i++) { int r = (int)(rand.nextFloat()*line*column); Point tmp = p[i]; p[i] = p[r]; p[r] = tmp; } Graphics g = mosaicImage.getGraphics(); g.setColor(bgColor); g.fillRect(0, 0, mySize.width, mySize.height); g.drawImage(image, (mySize.width-image.getWidth(null))/2, (mySize.height-image.getHeight(null))/2, null); while (n < line*column) { for (int i = 0; i < mosaicSpeed; i++) { x = p[n].x; y = p[n].y; offScreen.clipRect(x*mosaicWidth, y*mosaicHeight, mosaicWidth, mosaicHeight); offScreen.drawImage(mosaicImage, 0, 0, null); offScreen = offImage.getGraphics(); if (++n >= line*column) break; } onScreen.drawImage(offImage, 0, 0, null); try { Thread.currentThread().sleep(50); } catch (InterruptedException e) { } } } private boolean loadImage(int n) { drawMessage("Loading image... " + imageFile[n]); repaint(); try { tracker.waitForID(n); } catch (InterruptedException e) { e.printStackTrace(); return false; } if (tracker.isErrorID(n)) { drawMessage("Error loading image " + imageFile[n]); repaint(); return false; } return true; } public void run() { if (randomOrder) { current = (int)(rand.nextFloat()*images.length); } if (randomEffect) { change[current] = (int)(rand.nextFloat()*EFFECTNUM+1); if (change[current] != FADE && change[current] != MOSAIC && change[current] != OPEN && change[current] != CLOSE) { change[current] = (int)(rand.nextFloat()*EFFECTNUM+1); } } if (drawWhileLoading) { if (loadImage(current) == false) { return; } } else { for (int i = 0; i < images.length; i++) { if (loadImage(i) == false) { return; } } } drawMessage(""); while (true) { long stime = System.currentTimeMillis(); int next; int x = (mySize.width - images[current].getWidth(null)) / 2; int y = (mySize.height - images[current].getHeight(null)) / 2; offScreen.setColor(bgColor); offScreen.fillRect(0, 0, mySize.width, mySize.height); offScreen.drawImage(images[current], x, y, null); repaint(); if (randomOrder) { do { next = (int)(rand.nextFloat()*images.length); } while (next == current); } else { next = current + 1; if (next >= images.length) { next = 0; } } if (randomEffect) { change[next] = (int)(rand.nextFloat()*EFFECTNUM+1); } try { tracker.waitForID(next); } catch (InterruptedException e) { e.printStackTrace(); } if (tracker.isErrorID(next)) { drawMessage("Error loading image " + imageFile[next]); repaint(); return; } try { if (time[current] == 0) { Thread.currentThread().suspend(); } else { long sleepTime = time[current]-(System.currentTimeMillis()-stime); if (sleepTime > 0) { Thread.currentThread().sleep(sleepTime); } } } catch (InterruptedException e) { e.printStackTrace(); } switch (change[current]) { case NONE : break; case SCROLLUP : scrollImage(images[current], images[next], 0, -scrollSpeed); break; case SCROLLDOWN : scrollImage(images[current], images[next], 0, scrollSpeed); break; case SCROLLRIGHT : scrollImage(images[current], images[next], scrollSpeed, 0); break; case SCROLLLEFT : scrollImage(images[current], images[next], -scrollSpeed, 0); break; case TEARVERTICAL : tearOpenImage(images[next], 0, changeSpeed); break; case TEARHORIZONTAL : tearOpenImage(images[next], changeSpeed, 0); break; case OPEN : openImage(images[next], changeSpeed); break; case CLOSE : closeImage(images[current], images[next], changeSpeed); break; case FADE : fadeImage(images[current], images[next]); break; case MOSAIC : mosaicImage(images[next]); break; case TEARUP : tearImage(images[next], 0, -changeSpeed); break; case TEARDOWN : tearImage(images[next], 0, changeSpeed); break; case TEARRIGHT : tearImage(images[next], changeSpeed, 0); break; case TEARLEFT : tearImage(images[next], -changeSpeed, 0); break; case SLIDEUP: slideImage(images[current], images[next], 0, -scrollSpeed); break; case SLIDEDOWN: slideImage(images[current], images[next], 0, scrollSpeed); break; case SLIDERIGHT: slideImage(images[current], images[next], scrollSpeed, 0); break; case SLIDELEFT: slideImage(images[current], images[next], -scrollSpeed, 0); break; case SHRINKVERTICAL: shrinkImage(images[current], images[next], 0, changeSpeed); break; case SHRINKHORIZONTAL: shrinkImage(images[current], images[next], changeSpeed, 0); break; } current = next; if (cursorIn) showURL(url[current]); } } private Frame getFrame() { Component parent = getParent(); while (parent != null && !(parent instanceof Frame)) { parent = parent.getParent(); } return (Frame)parent; } private void showURL(URL u) { if (u == null) { ac.showStatus(""); getFrame().setCursor(Frame.DEFAULT_CURSOR); } else { ac.showStatus(u.toString()); getFrame().setCursor(Frame.HAND_CURSOR); } } public boolean mouseDown(Event evt, int x, int y) { if (url[current] != null) { ac.showDocument(url[current]); } else { if (kicker != null) { kicker.resume(); } } return true; } public boolean mouseEnter(Event evt, int x, int y) { cursorIn = true; showURL(url[current]); return true; } public boolean mouseExit(Event evt, int x, int y) { cursorIn = false; showURL(null); return true; } }