home *** CD-ROM | disk | FTP | other *** search
Java Source | 1996-09-20 | 13.8 KB | 556 lines |
- import java.io.*;
- import java.net.*;
- import java.util.*;
- import java.awt.*;
- import java.awt.image.*;
- import java.applet.*;
-
- // Wiper v1.0
- //
- // Copyright (c) 1996 Bryan McNett
- //
- // This program is free software; you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation; either version 2 of the License, or (at
- // your option) any later version.
- //
- // This program is distributed in the hope that it will be useful, but
- // WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- // General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with this program (as the file COPYING in the main directory of
- // the distribution); if not, write to the Free Software Foundation,
- // Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- //
- // Wiper is an advertising billboard that cycles through a list of images
- // by applying user-defined special effects. When the user clicks
- // on an advertisement, Wiper takes her to the advertiser's home page.
- //
- // Here is a list of Wiper's parameters, all of which assume reasonable
- // default values if left unspecified:
- //
- // name type description default
- // -----------------------------------------------------------------------------
- // src URL location of play list play.txt
- // secondsBetweenSleeps double seconds between sleeps 0.1
- // secondsBetweenWipes double seconds between wipe effects 3.0
- // secondsBetweenFrames double seconds between display frames 0.1
- // wipeBits int frame count equal to two to this power 5
- //
- // The play list is text with one advertisement per line as follows:
- //
- // <url of advertiser's home page> <url of advertisement> [url of fade effect]
- //
- // for example:
- //
- // http://www.bigpanda.com/ bigpanda.gif wackywipe.gif
- // http://www.intrasteve.com/ intrasteve.gif
- //
- // Due to the security restrictions imposed upon applets, the applet code,
- // advertisement, and fade effect URLs must refer to the same hostname.
- //
-
- public class Wiper extends Applet implements Runnable {
- String pinfo[][] = {
- { "src" , "URL" , "location of play list" },
- { "secondsBetweenSleeps", "double", "seconds between sleeps" },
- { "secondsBetweenWipes" , "double", "seconds between wipe effects" },
- { "secondsBetweenFrames", "double", "seconds between display frames" },
- { "wipeBits" , "int" , "frame count equal to two to this power" }
- };
-
- public String[][] getParameterInfo() { return pinfo; }
-
- String ainfo =
- "Wiper v1.0 (c) 1996 Bryan McNett - distributed under the terms of the GNU General Public License";
-
- public String getAppletInfo() { return ainfo; }
-
- Thread thread = null;
-
- public void start() {
- if( thread == null ) {
- thread = new Thread( this );
- thread.start();
- }
- }
-
- public void stop() {
- if( thread != null ) {
- thread.stop();
- thread = null;
- }
- }
-
- String getParameterSafely( String name, String otherwise ) {
- String value = null;
- value = getParameter( name );
- if( value == null ) return otherwise;
- return value;
- }
-
- int getIntParamSafely( String name, String otherwise ) {
- String s = getParameterSafely( name, otherwise );
- Integer i = Integer.valueOf( s );
- return i.intValue();
- }
-
- double getDoubleParamSafely( String name, String otherwise ) {
- String s = getParameterSafely( name, otherwise );
- Double d = Double.valueOf( s );
- return d.doubleValue();
- }
-
- // initialize the applet
-
- int secondsBetweenSleeps;
- int secondsBetweenWipes;
- int secondsBetweenFrames;
-
- Vector effectvect = null;
- Hashtable bitmaphash = null;
- Hashtable wipehash = null;
- LineReader linereader = null;
-
- int width = 0;
- int height = 0;
-
- Bitmap bitmap = null;
-
- public static int wipeBits = 5;
- public static int wipeFactor = 32;
-
- public void init() {
- Rectangle r = bounds();
- width = r.width;
- height = r.height;
-
- bitmap = new Bitmap( width, height );
- backdrop = createImage( bitmap.prepare() );
-
- effectvect = new Vector();
- bitmaphash = new Hashtable();
- wipehash = new Hashtable();
-
- secondsBetweenSleeps = (int)(1000 * getDoubleParamSafely( "secondsBetweenSleeps", "0.100" ) );
- secondsBetweenWipes = (int)(1000 * getDoubleParamSafely( "secondsBetweenWipes", "3.000" ) );
- secondsBetweenFrames = (int)(1000 * getDoubleParamSafely( "secondsBetweenFrames", "0.100" ) );
- wipeBits = getIntParamSafely ( "wipeBits", "5" );
-
- wipeFactor = 1 << wipeBits;
- wipeBits = 8 - wipeBits;
-
- String src = getParameterSafely( "src", "play.txt" );
-
- URL u = null;
- DataInputStream d = null;
-
- try {
- u = new URL( getDocumentBase(), src );
- d = new DataInputStream( u.openStream() );
- } catch( Exception e );
-
- linereader = new LineReader( d, this );
- }
-
- // make sure to load each unique image URL exactly once
- // to conserve bandwidth, cpu and memory
-
- Bitmap loadBitmap( String s ) {
- URL u = null;
- try {
- u = new URL( getDocumentBase(), s );
- } catch( Exception e ) {;}
- if( bitmaphash.containsKey( u ) ) {
- return (Bitmap)bitmaphash.get( u );
- }
- Bitmap b = new Bitmap( getImage( u ), width, height );
- bitmaphash.put( u, b );
- return b;
- }
-
- // make sure to create wipe data at most once per Bitmap.
-
- Wipe loadWipe( Bitmap b ) {
- if( wipehash.containsKey( b ) ) {
- return (Wipe)wipehash.get( b );
- }
- Wipe w = new Wipe( b );
- wipehash.put( b, w );
- return w;
- }
-
- public void addLine( String line ) {
- StringTokenizer token;
- String u,b,w;
- Bitmap bitmap, wipe;
- URL url;
-
- token = new StringTokenizer( line );
-
- u = token.nextToken();
- b = token.nextToken();
- w = b;
- if( token.hasMoreElements() ) w = token.nextToken();
-
- url = getDocumentBase();
- try {
- url = new URL( getDocumentBase(), u );
- } catch( Exception e );
-
- bitmap = loadBitmap( b );
- wipe = loadBitmap( w );
-
- effectvect.addElement( new Effect( url, bitmap, loadWipe( wipe ) ) );
- }
-
- Image backdrop;
-
- public void paint( Graphics g ) {
- synchronized( backdrop ) g.drawImage( backdrop, 0, 0, this );
- }
-
- public void update( Graphics g ) {
- paint( g );
- }
-
- Effect lastEffect = null;
- Effect effect = null;
- URL url = null;
- boolean mouseInside = false;
- int mouseX = 0;
- int mouseY = 0;
-
- void mouseIt( int x, int y ) {
- mouseX = x; mouseY = y;
- if( effect == null ) return;
- Effect e = lastEffect;
- if( effect.get(x,y) ) e = effect;
- if( e == null ) return;
- URL u = e.getURL();
- if( u == url ) return;
- url = u;
- showStatus( url.toString() );
- }
-
- public boolean mouseMove( Event evt, int x, int y ) {
- mouseIt( x, y );
- return true;
- }
-
- public boolean mouseUp( Event evt, int x, int y ) {
- mouseIt( x, y );
- if( url != null ) getAppletContext().showDocument( url );
- return true;
- }
-
- public boolean mouseEnter( Event evt, int x, int y ) {
- mouseInside = true;
- mouseIt( x, y );
- return true;
- }
-
- public boolean mouseExit( Event evt, int x, int y ) {
- mouseInside = false;
- return true;
- }
-
- int index = 0;
-
- public void run() {
- Waiter wipewaiter = new Waiter( secondsBetweenWipes );
- Waiter framewaiter = new Waiter( secondsBetweenFrames );
- while( effectvect.isEmpty() == true ) {
- try {
- Thread.sleep( secondsBetweenSleeps );
- } catch( Exception e ) {;}
- }
- while( true ) {
- if( index >= effectvect.size() ) index = 0;
- lastEffect = effect;
- wipewaiter.go();
- effect = (Effect)effectvect.elementAt( index++ );
- effect.start();
- boolean done;
- do {
- done = effect.go(bitmap);
- if( mouseInside ) mouseIt( mouseX, mouseY );
- framewaiter.go();
- backdrop = createImage( bitmap.prepare() );
- update( getGraphics() );
- } while( done == false );
- wipewaiter.go();
- }
- }
- }
-
-
- // A LineReader spawns a thread to read text lines from a DataInputStream.
- // It updates Wiper's play list as lines arrive.
-
-
- class LineReader extends Thread {
- DataInputStream d;
- Wiper w;
- Thread thread;
-
- public LineReader( DataInputStream d, Wiper w ) {
- super( "line reader" );
- this.setPriority( 1 );
- this.d = d;
- this.w = w;
- this.start();
- }
-
- public void run() {
- String line;
- while( true ) {
- try {
- line = d.readLine();
- } catch( IOException e ) break;
- if( line == null ) break;
- synchronized ( w ) w.addLine( line );
- }
- }
-
- }
-
-
- // A PixelMuncher spawns a thread to fill an array of ints with the pixels of
- // an image.
-
-
- class PixelMuncher extends Thread {
- static int muncher_number = 0;
- int done=0;
- PixelGrabber p = null;
- Thread thread = null;
-
- public PixelMuncher( Image image, int width, int height, int[] data ) {
- super( "pixel muncher number " + muncher_number++ );
- this.setPriority( 1 );
- p = new PixelGrabber( image.getSource(), 0, 0, width, height, data, 0, width );
- this.start();
- }
-
- public void run() {
- try {
- p.grabPixels();
- done = 1;
- } catch( Exception e ) {}
- }
-
- public int ready() {
- return done;
- }
-
- }
-
-
- // A Bitmap knows how to play with its pixels.
-
-
- class Bitmap {
- int[] data = null;
- int width=0,height=0;
- PixelMuncher muncher = null;
-
- public Bitmap( Image image, int width, int height ) {
- this.width = width;
- this.height = height;
- data = new int[width*height];
- clear();
- muncher = new PixelMuncher( image, width, height, data );
- }
-
- public Bitmap( int width, int height ) {
- this.width = width;
- this.height = height;
- data = new int[width*height];
- clear();
- }
-
- void clear( ) {
- for( int i=0; i<pixels(); i++ ) {
- data[i] = 0xff000000;
- }
- }
-
- public int get( int index ) {
- // You've uncovered Wiper's secret weakness! Yes, when Wiper is working
- // with images as transition effects, it checks only the blue channel for
- // brightness values. If you uncomment the following two lines of code,
- // it will consider all three color channels (at a slightly higher cost).
- // int i = data[index];
- // return ((( i>>16 & 0xff )+( i>>8 & 0xff )+( i & 0xff )) / 3) >> Wiper.wipeBits;
- return (data[index] & 0xff) >> Wiper.wipeBits;
- }
-
- public int get( int x, int y ) {
- return get( y*width + x );
- }
-
- public void paste( Bitmap src, int index, int count ) {
- System.arraycopy( src.data, index, data, index, count );
- }
-
- public int pixels() {
- return width*height;
- }
-
- public int ready() {
- return muncher.ready();
- }
-
- public MemoryImageSource prepare() {
- return new MemoryImageSource( width, height, data, 0, width );
- }
- }
-
-
- // A Wipe knows how to decompose an image into 256 RLE compressed
- // representations of a single gray value.
-
-
- class Wipe {
- Bitmap bitmap = null;
- int[][] data = null;
-
- public Wipe( Bitmap bitmap ) {
- this.bitmap = bitmap;
- data = new int[256][];
- for( int i=0; i<256; i++ ) {
- data[i] = null;
- }
- }
-
- public void go( Bitmap dest, Bitmap src, int value ) {
- int j=0,index=0;
- int r[] = rle(value);
- while( j < r.length ) {
- index += r[j++];
- dest.paste( src, index, r[j] );
- index += r[j++];
- }
- }
-
- public int get( int x, int y ) {
- return bitmap.get( x, y );
- }
-
- int[] rle( int value ) {
- int ready = 0;
- if( data[value] != null ) return data[value];
- int j=0, skip, run, index = 0, count;
- int[] r = new int[ count = bitmap.pixels() ];
-
- // set this flag if the bitmap has completed loading
-
- if( bitmap.ready() != 0 ) ready=1;
-
- // rle encode all pixels with a particular gray value
-
- while( count>0 ) {
- skip = run = 0;
- while( (count>0) && ( bitmap.get(index) != value ) ) {
- skip++; index++; count--;
- }
- while( (count>0) && ( bitmap.get(index) == value ) ) {
- run++; index++; count--;
- }
- if( j == r.length ) {
- int temp[] = new int[ j + bitmap.pixels() ];
- System.arraycopy( r, 0, temp, 0, j );
- r = temp;
- }
- r[j++] = skip;
- r[j++] = run;
- }
- if( j != r.length ) {
- int temp[] = new int[j];
- System.arraycopy( r, 0, temp, 0, j );
- r = temp;
- }
-
- // if we set this flag earlier, it means that we can cache the results of our encoding.
-
- if( ready != 0 ) data[value] = r;
- return r;
- }
-
- }
-
-
- // An Effect knows how to run a Wipe.
-
- class Effect {
- Bitmap src = null, map = null;
- Wipe wipe = null;
- int ticker = 0;
- boolean complete = false;
- URL url;
-
- public Effect( URL url, Bitmap bitmap, Wipe wipe ) {
- this.url = url;
- this.src = bitmap;
- this.wipe = wipe;
- this.start();
- }
-
- public URL getURL() {
- return url;
- }
-
- public void start() {
- this.ticker=0;
- this.complete=false;
- }
-
- public boolean go( Bitmap dest ) {
- if( this.complete == true ) return this.complete;
- wipe.go( dest, this.src, this.ticker++ );
- if( this.ticker >= Wiper.wipeFactor ) this.complete=true;
- return this.complete;
- }
-
- public boolean get( int x, int y ) {
- if( this.wipe.get( x, y ) < this.ticker ) return true;
- return false;
- }
-
- }
-
-
- // a waiter is something that knows how to wait.
-
-
- class Waiter {
- int time=0, delay=0;
-
- int set() {
- int now = (int)System.currentTimeMillis();
- time = now+delay;
- return now;
- }
-
- public Waiter( int delay ) {
- this.delay = delay;
- set();
- }
-
- public void go() {
- int ticks = time;
- ticks -= set();
- if( ticks > 0 )
- try Thread.sleep( ticks );
- catch( Exception e ) ;
- }
-
- }
-
-
-
-
-