New java.awt.Image to support animation.

Guilhem Lavaux lavaux at easynet.fr
Mon Jun 28 10:23:24 PDT 1999


Hello,

This java.awt.Image enables the creation of animation using
MemoryImageSource.

Included an applet I picked on Internet to test it (Plasma).

--
------------------------------------
| Guilhem Lavaux lavaux at easynet.fr |
------------------------------------


-------------- next part --------------
package java.awt;

import java.awt.image.ColorModel;
import java.awt.image.DirectColorModel;
import java.awt.image.ImageConsumer;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;
import java.awt.image.IndexColorModel;
import java.awt.image.MemoryImageSource;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import kaffe.io.AccessibleBAOStream;
import kaffe.util.Ptr;
import kaffe.util.VectorSnapshot;

/**
 * Copyright (c) 1998
 *    Transvirtual Technologies, Inc.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file.
 *
 * @author P.C.Mehlitz
 */
public class Image
{
	Ptr nativeData;
	int width = -1;
	int height = -1;
	ImageProducer producer;
	Object observers;
	int flags;
	Hashtable props;
	Image next;
	final public static int SCALE_DEFAULT = 1;
	final public static int SCALE_FAST = 2;
	final public static int SCALE_SMOOTH = 4;
	final public static int SCALE_REPLICATE = 8;
	final public static int SCALE_AREA_AVERAGING = 16;
	final static int MASK = ImageObserver.WIDTH|ImageObserver.HEIGHT|
			ImageObserver.PROPERTIES|ImageObserver.SOMEBITS|
			ImageObserver.FRAMEBITS|ImageObserver.ALLBITS|
			ImageObserver.ERROR|ImageObserver.ABORT;
	final static int PRODUCING = 1 << 8;
	final static int READY = ImageObserver.WIDTH | ImageObserver.HEIGHT | ImageObserver.ALLBITS | PRODUCING;
	final static int SCREEN = 1 << 10;
	final static int BLOCK_FRAMELOADER = 1 << 11;
	final public static Object UndefinedProperty = ImageLoader.class;

Image ( File file ) {
	producer = new ImageNativeProducer( this, file);
}

Image ( Image img, int w, int h ) {
	nativeData = Toolkit.imgCreateScaledImage(img.nativeData, w, h);
	width = w;
	height = h;
	flags = READY;
}

Image ( ImageProducer ip ) {
	producer = ip;

	// there currently is no way to check the size of a MemoryImageSource, 
	// so everything != 0 causes async production
	if ( (Defaults.MemImageSrcThreshold == 0) && (producer instanceof MemoryImageSource) ) {
		flags |= PRODUCING;
		synchronized ( ImageLoader.syncLoader ) {
			ImageLoader.syncLoader.img = this;
			ip.startProduction( ImageLoader.syncLoader);
		}
	}
}

Image ( URL url ) {
	producer = new ImageNativeProducer( url);
}

Image ( byte[] data, int offs, int len) {
	producer = new ImageNativeProducer( this, data, offs, len);
}

Image ( int w, int h ) {
	nativeData = Toolkit.imgCreateScreenImage( w, h );
	width = w;
	height = h;
	flags = READY | SCREEN;
}

synchronized void activateFrameLoader () {
  // activate waiting FrameLoader
	if ( (flags & BLOCK_FRAMELOADER) != 0 ){
		flags &= ~BLOCK_FRAMELOADER;
		notify();
	}
}

// -------------------------------------------------------------------------
void addObserver ( ImageObserver observer ) {
	if ( observer == null ) {
		return;
	}

	if ( observers == null ) {
		observers = observer;
	}	
	else if ( observers instanceof Vector ) {
		Vector v = (Vector) observers;
		if ( !v.contains(observer) )
			v.addElement(observer);
	}
	else {
		if ( observer != observers ) {
			Vector v = new Vector( 3);
			v.addElement( observers);
			v.addElement( observer);
			observers = v;
		}
	}
}

synchronized int checkImage ( int w, int h, ImageObserver obs, boolean load ){
	if ( (flags & (ImageObserver.ALLBITS | ImageObserver.FRAMEBITS)) != 0 ) {
		if ( ((w > 0) || (h > 0)) && (w != width) && (h != height) ){
			scale( w, h);
		}
		
		if ( load && (flags & ImageObserver.FRAMEBITS) != 0 )
			addObserver( obs);
	}
	else if ( load && ((flags & PRODUCING) == 0) ) {
		loadImage( w, h, obs);
	}

	return (flags & MASK);
}

protected void finalize () throws Throwable {
	flush();
	super.finalize();
}

public void flush () {
	// This is the bad guy - the spec demands that it reverts us into a "not-yet-loaded"
	// state, "to be recreated or fetched again from its source" when a subsequent
	// rendering takes place. Since "its source" doesn't mean the *original* source
	// (see getSource() - "an object that *produces* the image"), we could stay with the
	// native representation (probably the most efficient storage and prod environment),
	// but apps explicitly using flush most probably use it because the original
	// image source has changed, i.e. they use flush() as a way to in-situ modify
	// otherwise constant images (by means of changed sources). Only heaven knows why
	// they don't replace the image (this is like a Graphics that can be brought back
	// to life after a dispose()). That means we have to keep a ref of byte[] data, and
	// we can't produce on-screen images

	if ( nativeData != null && (flags & ImageObserver.ALLBITS) != 0){
		Toolkit.imgFreeImage( nativeData);
		nativeData = null;
		flags = 0;
		width = -1;
		height = -1;
	}
}

public Graphics getGraphics () {
	if ((flags & SCREEN) == 0 || nativeData == null) {
		return null;
	}
	else {
		return NativeGraphics.getGraphics( this,
		                   nativeData, NativeGraphics.TGT_TYPE_IMAGE,
		                   0, 0, 0, 0, width, height,
										   Color.black, Color.white, Defaults.WndFont, false);
	}
}

public synchronized int getHeight ( ImageObserver observer ) {
	if ( (flags & ImageObserver.HEIGHT) != 0 ) {
		return height;
	}
	else {
		loadImage(-1, -1, observer);
		return (-1);
	}
}

public Object getProperty ( String name, ImageObserver observer ) {
	if ( props == null ) {
		if ( (flags & (ImageObserver.FRAMEBITS | ImageObserver.ALLBITS)) != 0 )
			return UndefinedProperty;
		else if ( (flags & PRODUCING) == 0 )
			loadImage( -1, -1, observer);

		return null;
	}
	else {
		Object val = props.get( name);
		if ( val == null )
			return UndefinedProperty;
			
		return val;
	}
}

public Image getScaledInstance (int width, int height, int hints) {
	if (nativeData == null || width <= 0 || height <= 0 || (flags & SCREEN) != 0 || (flags & ImageObserver.ALLBITS) == 0) {
		return (null);
	}
	return (new Image(this, width, height));
}

public ImageProducer getSource () {
	if ( producer == null )
		producer = new ImageNativeProducer( this);

	return producer;
}

public synchronized int getWidth ( ImageObserver observer ) {
	if ( (flags & ImageObserver.WIDTH) != 0 ) {
		return (width);
	}
	else {
		loadImage(-1, -1, observer);
		return (-1);
	}
}

synchronized boolean loadImage ( int w, int h, ImageObserver obs ) {
	// it's (partly?) loaded already
	if ( (flags & (ImageObserver.FRAMEBITS|ImageObserver.ALLBITS)) != 0 ){
		if ( ((w > 0) || (h > 0)) && (w != width) && (h != height) ) {
		        // but do we have to scale it? 
			scale( w, h);
		}
		if ( (flags & ImageObserver.FRAMEBITS) != 0 ) {
			addObserver( obs);
		}
		return (true);
	}
	// we ultimately failed
	else if ( (flags & ImageObserver.ABORT) != 0 ) {
		return (false);
	}
        // there's work ahead, kick it off
	else if ( (flags & PRODUCING) == 0 ) {
		flags |= PRODUCING;
		if ( obs != null ) {
			addObserver( obs);
		}
		/*
		 * We now load the image data synchronously - it's not clear
		 * that's what you should actually do but it fixes a problem
		 * with the Citrix ICA client. (Tim 1/18/99)
		 */
		ImageLoader.loadSync( this);
		return (true);
	}
	return (false);
}

void removeObserver ( ImageObserver observer ) {
	if ( (observers == null) || (observer == null) )
		return;

	if ( observers == observer ){
		observers = null;
	}
	else if ( observers instanceof Vector ) {
		Vector v = (Vector)observers;
		v.removeElement( observer);
		
		if ( v.size() == 1 )
			observers = v.firstElement();
	}
}

private boolean scale (int w, int h) {
	if ((flags & SCREEN) != 0 || (flags & ImageObserver.ALLBITS) == 0 || nativeData == null) {
		return (false);
	}
	if (w != width || h != height) {
		Ptr oldNativeData = nativeData;
		nativeData = Toolkit.imgCreateScaledImage( nativeData, w, h );
		Toolkit.imgFreeImage( oldNativeData);
		width = w;
		height = h;
	}
	return (true);
}

synchronized void stateChange(int flags, int x, int y, int w, int h) {
	ImageObserver obs;

	this.flags |= flags;

	if (observers == null) {
		return;
	}

	// We get false if they're no longer interested in updates. This is *NOT* what is said in the
	// Addison-Wesley documentation, but is what is says in the JDK javadoc documentation.	
	if ( observers instanceof ImageObserver ){
		obs = (ImageObserver) observers;
		if ( obs.imageUpdate( this, flags, x, y, w, h) == false ) {
			observers = null;
		}
	}
	else if ( observers instanceof Vector ){
		// we can't use a (index-based) standard Vector enumerator because we have
		// to notify *all* elements regardless of any removals
		for ( Enumeration e=VectorSnapshot.getCached( (Vector)observers); e.hasMoreElements(); ) {
			obs = (ImageObserver) e.nextElement();
			if ( obs.imageUpdate( this, flags, x, y, w, h) == false )
				removeObserver( obs);
		}
	}
}

public String toString() {
	String s = getClass().getName() + " [" + width + ',' + height + 
	              ((nativeData != null) ? ", native" : ", non-native") +
                ", flags: "  + Integer.toHexString( flags);

	if ( (flags & PRODUCING) != 0 )
		s += " producing";
	if ( (flags & ImageObserver.ALLBITS) != 0 )
		s += " allbits";
	else if ( (flags & ImageObserver.FRAMEBITS) != 0 )
		s += " framebits";
	else if ( (flags & ImageObserver.ERROR) != 0 )
		s += " error";

	s += "]";

	return s;		
}
}

class ImageFrameLoader
  extends Thread implements ImageConsumer
{
	Image img;

public void imageComplete( int status ) {
	int s = 0;

	if ( status == STATICIMAGEDONE ){
	  s = ImageObserver.ALLBITS;
	  // give native layer a chance to do alpha channel reduction
	  Toolkit.imgComplete( img.nativeData, status);

	  img.producer.removeConsumer(this);
	}
	else if ( status == SINGLEFRAMEDONE ) {
	    s = ImageObserver.FRAMEBITS;
	    Toolkit.imgComplete( img.nativeData, status);
	}
	else {
	    if ( (status & IMAGEERROR) != 0 )       s |= ImageObserver.ERROR;
	    if ( (status & IMAGEABORTED) != 0 )     s |= ImageObserver.ABORT;
	    img.producer.removeConsumer(this);
	}

	img.stateChange( s, 0, 0, img.width, img.height);	
}

public void setColorModel( ColorModel model ) {
}

public void setDimensions ( int width, int height ) {
}

public void setHints ( int hints ) {
}

public void setPixels ( int x, int y, int w, int h, ColorModel model, byte pixels[], int offset, int scansize ) {
    if ( img.nativeData == null ) {
	// producer trouble, we haven't got dimensions yet
	return;
    }
    
    if ( model instanceof IndexColorModel ) {
	IndexColorModel icm = (IndexColorModel) model;
	Toolkit.imgSetIdxPels( img.nativeData, x, y, w, h, icm.rgbs,
			       pixels, icm.trans, offset, scansize);
	img.stateChange( ImageObserver.SOMEBITS, x, y, w, h);
    }
    else {
	System.err.println("Unhandled colorModel: " + model.getClass());        
    }
    
}

public void setPixels ( int x, int y, int w, int h, ColorModel model, int pixels[], int offset, int scansize ) {
	if ( img.nativeData == null ) {
		// producer trouble, we haven't got dimensions yet
	    return;
	}

	if ( model instanceof DirectColorModel ) {
	    // in case our pels aren't default RGB yet, convert them using the ColorModel
	    if ( model != ColorModel.getRGBdefault() ){
		int xw = x + w;
		int yh = y + h;
		int i, j, idx;
		int i0 = y * scansize + offset;
		for ( j = y; j < yh; j++, i0 += scansize ) {
		    for ( i = x, idx = i+i0; i < xw; i++, idx++) {
			// are we allowed to in-situ change the array?
			pixels[idx] = model.getRGB( pixels[idx]);
		    }
		}
	    }
	    
	    Toolkit.imgSetRGBPels( img.nativeData, x, y, w, h, pixels, offset, scansize);
	    img.stateChange( ImageObserver.SOMEBITS, x, y, w, h);
	}
	else {
	    System.out.println("Unhandled colorModel: " + model.getClass());
	}
}

public void setProperties ( Hashtable properties ) {
    img.props = properties;
    img.stateChange( img.flags | ImageObserver.PROPERTIES, 0, 0, img.width, img.height);
}

ImageFrameLoader ( Image img ) {
	super("ImageFrameLoader");
	this.img = img;

	img.flags |= Image.BLOCK_FRAMELOADER;
	img.producer.startProduction( this );

	setPriority( NORM_PRIORITY - 3);
	start();
}

public void run () {

	// Note that we get started *after* the first SINGLEFRAMEDONE, i.e. our image observers
	// already got the preceeding dimension notification

	if ( img.producer instanceof ImageNativeProducer ) {
		runINPLoop();
 	}
        else {
	}
}

public void runINPLoop () {
	int w, h, latency;
	Ptr ptr;

	// we already have the whole thing physically read in, so just start to notify round-robin. We also
	// got the first frame propperly reported, i.e. we start with flipping to the next one
	do {
	  // wait until we get requested the next time (to prevent being spinned around by a MediaTracker)
		synchronized ( img ) {
			try {
				while ( (img.flags & Image.BLOCK_FRAMELOADER) != 0 ){
					img.wait();
				}
			} catch ( InterruptedException _ ) {}
		}
		latency = Toolkit.imgGetLatency( img.nativeData);
		try { Thread.sleep( latency); } catch ( Exception _ ) {}

		if ( (ptr = Toolkit.imgGetNextFrame( img.nativeData)) == null )

			break;
		img.nativeData = ptr;
		w = Toolkit.imgGetWidth( img.nativeData);
		h = Toolkit.imgGetHeight( img.nativeData);
		if ( (img.width != w) || (img.height != h) ){
			img.width = w;
			img.height = h;
			img.stateChange( ImageObserver.WIDTH|ImageObserver.HEIGHT, 0, 0, img.width, img.height);
		}

		img.flags |= Image.BLOCK_FRAMELOADER;
		img.stateChange( ImageObserver.FRAMEBITS, 0, 0, img.width, img.height);

	} while ( img.observers != null );
}
}

class ImageLoader
  implements ImageConsumer, Runnable
{
	Image queueHead;
	Image queueTail;
	Image img;
	static ImageLoader asyncLoader;
	static ImageLoader syncLoader = new ImageLoader();

public synchronized void imageComplete ( int status ) {
	int s = 0;

	if ( status == STATICIMAGEDONE ){
	  s = ImageObserver.ALLBITS;
		// give native layer a chance to do alpha channel reduction
		if ( !(img.producer instanceof ImageNativeProducer) )
			Toolkit.imgComplete( img.nativeData, status);
	}
	else if ( status == SINGLEFRAMEDONE ) {
		s = ImageObserver.FRAMEBITS;

		// This is a (indefinite) movie production - move it out of the way (in its own thread)
		// so that we can go on with useful work. Note that if our producer was a ImageNativeProducer,
		// the whole external image has been read in already (no IO required, anymore)
		new ImageFrameLoader(img);
	}
	else {
		if ( (status & IMAGEERROR) != 0 )       s |= ImageObserver.ERROR;
		if ( (status & IMAGEABORTED) != 0 )     s |= ImageObserver.ABORT;
	}

	img.stateChange( s, 0, 0, img.width, img.height);

	// this has to be called *after* a optional ImageFrameLoader went into action, since
	// the producer might decide to stop if it doesn't have another consumer
	img.producer.removeConsumer( this);
	
	img = null; 	// we are done with it, prevent memory leaks
	if ( this == asyncLoader )
		notify();     // in case we had an async producer
}

static synchronized void load ( Image img ) {
	if ( asyncLoader == null ){
		asyncLoader = new ImageLoader();
		asyncLoader.queueHead = asyncLoader.queueTail = img;

		Thread t = new Thread( asyncLoader, "asyncLoader");
		t.setPriority( Thread.NORM_PRIORITY - 1);
		t.start();
	}
	else {
		if ( asyncLoader.queueTail == null ) {
			asyncLoader.queueHead = asyncLoader.queueTail = img;
		}
		else {
			asyncLoader.queueTail.next = img;
			asyncLoader.queueTail = img;
		}
		
		ImageLoader.class.notify();
	}
}

static void loadSync( Image img ) {
	synchronized ( syncLoader ) {
		syncLoader.img = img;
		img.producer.startProduction(syncLoader);
	}
}

public void run () {
	for (;;) {
		synchronized ( ImageLoader.class ) {
			if ( queueHead != null ) {
				img = queueHead;
				queueHead = img.next;
				img.next = null;
				if ( img == queueTail )
					queueTail = null;
			}
			else {
				try {
					ImageLoader.class.wait( 20000);
					if ( queueHead == null ) {
						// Ok, we waited for too long, lets do suicide
						asyncLoader = null;
						return;
					}
					else {
						continue;
					}
				}
				catch ( InterruptedException xx ) { xx.printStackTrace(); }
			}
		}
		
		try {
			// this is hopefully sync, but who knows what kinds of producers are out there
			img.producer.startProduction( this);

			if ( img != null ) {
				synchronized ( this ){
					wait();
				}
			}
		}
		catch ( Throwable x ) {
			x.printStackTrace();
			imageComplete( IMAGEERROR | IMAGEABORTED);
		}
	}
}

public void setColorModel ( ColorModel model ) {
	// No way to pass this to ImageObservers. Since we also get it in setPixels, we
	// just ignore it
}

public void setDimensions ( int width, int height ) {
	img.width = width;
	img.height = height;

	// If we were notified by a ImageNativeProducer, the nativeData field is already
	// set. In case this is just an arbitrary producer, create it so that we have a
	// target for subsequent setPixel() calls
	if ( img.nativeData == null ){
		img.nativeData = Toolkit.imgCreateImage( width, height);
	}

	img.stateChange( ImageObserver.WIDTH|ImageObserver.HEIGHT, 0, 0, width, height);
}

public void setHints ( int hints ) {
	// we don't honor them
}

public void setPixels ( int x, int y, int w, int h,
                        ColorModel model, byte pixels[], int offset, int scansize ) {
	if ( img.nativeData == null ) {
		// producer trouble, we haven't got dimensions yet
		return;
	}

	if ( model instanceof IndexColorModel ) {
		IndexColorModel icm = (IndexColorModel) model;
		Toolkit.imgSetIdxPels( img.nativeData, x, y, w, h, icm.rgbs,
		                       pixels, icm.trans, offset, scansize);
		img.stateChange( ImageObserver.SOMEBITS, x, y, w, h);
	}
	else {
		System.err.println("Unhandled colorModel: " + model.getClass());
	}
}

public void setPixels ( int x, int y, int w, int h,
                        ColorModel model, int pixels[], int offset, int scansize ) {
	if ( img.nativeData == null ) {
		// producer trouble, we haven't got dimensions yet
		return;
	}

	if ( model instanceof DirectColorModel ) {
		// in case our pels aren't default RGB yet, convert them using the ColorModel
		if ( model != ColorModel.getRGBdefault() ){
			int xw = x + w;
			int yh = y + h;
			int i, j, idx;
			int i0 = y * scansize + offset;
			for ( j = y; j < yh; j++, i0 += scansize ) {
				for ( i = x, idx = i+i0; i < xw; i++, idx++) {
					// are we allowed to in-situ change the array?
					pixels[idx] = model.getRGB( pixels[idx]);
				}
			}
		}

		Toolkit.imgSetRGBPels( img.nativeData, x, y, w, h, pixels, offset, scansize);
		img.stateChange( ImageObserver.SOMEBITS, x, y, w, h);
	}
	else {
		System.out.println("Unhandled colorModel: " + model.getClass());
	}
}

public void setProperties ( Hashtable properties ) {
	img.props = properties;
  img.stateChange( img.flags | ImageObserver.PROPERTIES, 0, 0, img.width, img.height);
}
}

/**
 * This shouldn't be a inner class since you can easily grab the source of an
 * image and use it outside of this image (e.g. to create other images - whatever
 * it might be good for)
 */
class ImageNativeProducer
  implements ImageProducer
{
	Object consumer;
	Object src;
	int off;
	int len;

ImageNativeProducer ( Image img ) {
	src = img;
}

ImageNativeProducer ( Image img, File file ) {
	src = file;

	// check if we can produce immediately
	if ( file.exists() ) {
		if  ( file.length() < Defaults.FileImageThreshold ){
		  img.flags |= Image.PRODUCING;
			synchronized ( ImageLoader.syncLoader ) {
				ImageLoader.syncLoader.img = img;
				img.producer = this;
				startProduction( ImageLoader.syncLoader);
			}
		}
	}
	else {
		img.flags = ImageObserver.ERROR | ImageObserver.ABORT;
	}
}

ImageNativeProducer ( Image img, byte[] data, int off, int len ) {
	src = data;
	this.off = off;
	this.len = len;
	
	if ( len < Defaults.DataImageThreshold ) {
	  img.flags |= Image.PRODUCING;
		synchronized ( ImageLoader.syncLoader ) {
			ImageLoader.syncLoader.img = img;
			img.producer = this;
			startProduction( ImageLoader.syncLoader);
		}
	}
}

ImageNativeProducer ( URL url ) {
	src = url;
}

public void addConsumer ( ImageConsumer ic ) {
	if ( consumer == null ){
		consumer = ic;
	}
	else if ( this.consumer instanceof Vector ) {
		((Vector)consumer).addElement( ic);
	}
	else {
		Vector v = new Vector(3);
		v.addElement( consumer);
		v.addElement( ic);
		consumer = v;
	}
}

void imageComplete ( int flags ){
	if ( consumer instanceof ImageConsumer ){
		((ImageConsumer)consumer).imageComplete( flags);
	}
	else if ( consumer instanceof Vector) {
		Vector v = (Vector) consumer;
		int i, n = v.size();
		for ( i=0; i<n; i++ ){
			((ImageConsumer)v.elementAt( i)).imageComplete( flags);
		}
	}
}

public boolean isConsumer ( ImageConsumer ic ) {
	if ( consumer instanceof ImageConsumer )
		return (consumer == ic);
	else if ( consumer instanceof Vector )
		return ((Vector)consumer).contains( ic);
	else
		return false;
}

void produceFrom ( File file ) {
	Ptr ptr;

	if ( file.exists() &&
	     (ptr = Toolkit.imgCreateFromFile( file.getAbsolutePath())) != null ){
		produceFrom( ptr);
	}
	else {
		imageComplete( ImageConsumer.IMAGEERROR | ImageConsumer.IMAGEABORTED);
	}
}

void produceFrom ( Ptr ptr ) {
	if ( consumer instanceof ImageLoader ) {
		ImageLoader loader = (ImageLoader)consumer;
		Image img = loader.img;
	
		img.nativeData = ptr;
		img.width = Toolkit.imgGetWidth( ptr);
		img.height = Toolkit.imgGetHeight( ptr);

		loader.setDimensions( img.width, img.height);
		loader.imageComplete( Toolkit.imgIsMultiFrame( ptr) ?
		                           ImageConsumer.SINGLEFRAMEDONE : ImageConsumer.STATICIMAGEDONE);
	}
	else {
		Toolkit.imgProduceImage( this, ptr);
		Toolkit.imgFreeImage( ptr);
	}
}

void produceFrom ( URL url ) {
	Ptr    ptr;
	byte[] buf = new byte[1024];
	int    n;

	// since this is most likely used in a browser context (no file
	// system), the only thing we can do (in the absence of a suspendable
	// native image production) is to temporarily store the data in
	// memory. Note that this is done via kaffe.io.AccessibleBAOStream,
	// to prevent the inacceptable memory consumption duplication of
	// "toByteArray()".
	// Ideally, we would have a suspendable image production (that can
	// deal with reading and processing "incomplete" data), but that
	// simply isn't supported by many native image conversion libraries.
	// Some could be done in Java (at the expense of a significant speed
	// degradation - this is the classical native functionality), but
	// things like Jpeg ?
	try {
		InputStream in = url.openStream();
		if ( in != null ) {
			AccessibleBAOStream out = new AccessibleBAOStream(8192);
			while ((n = in.read(buf)) >= 0) {
				out.write(buf, 0, n);
			}
			in.close();
			if ( (ptr = Toolkit.imgCreateFromData(out.getBuffer(), 0, out.size())) != null ){
				produceFrom( ptr);
				return;
			}
		}
	}
	catch ( Exception x ) {}

	imageComplete( ImageConsumer.IMAGEERROR|ImageConsumer.IMAGEABORTED);
}

void produceFrom ( byte[] data, int off, int len ) {
	Ptr ptr;

	if ( (ptr = Toolkit.imgCreateFromData( data, off, len)) != null )
		produceFrom( ptr);
	else
		imageComplete( ImageConsumer.IMAGEERROR | ImageConsumer.IMAGEABORTED);
}

public void removeConsumer ( ImageConsumer ic ) {
	if ( consumer == ic ){
		consumer = null;
	}
	else if ( consumer instanceof Vector ) {
		Vector v = (Vector) consumer;		
		v.removeElement( ic);
		if ( v.size() == 1 )
			consumer = v.elementAt( 0);
	}
}

public void requestTopDownLeftRightResend ( ImageConsumer consumer ) {
	// ignored
}

void setColorModel ( ColorModel model ){
	if ( consumer instanceof ImageConsumer ){
		((ImageConsumer)consumer).setColorModel( model);
	}
	else if ( consumer instanceof Vector) {
		Vector v = (Vector)consumer;
		int i, n = v.size();
		for ( i=0; i<n; i++ ){
			((ImageConsumer)v.elementAt( i)).setColorModel( model);
		}
	}
}

void setDimensions ( int width, int height ){
	if ( consumer instanceof ImageConsumer ){
		((ImageConsumer)consumer).setDimensions( width, height);
	}
	else if ( consumer instanceof Vector) {
		Vector v = (Vector)consumer;
		int i, n = v.size();
		for ( i=0; i<n; i++ ){
			((ImageConsumer)v.elementAt( i)).setDimensions( width, height);
		}
	}
}

void setHints ( int hints ){
	if ( consumer instanceof ImageConsumer ){
		((ImageConsumer)consumer).setHints( hints);
	}
	else if ( consumer instanceof Vector) {
		Vector v = (Vector)consumer;
		int i, n = v.size();
		for ( i=0; i<n; i++ ){
			((ImageConsumer)v.elementAt( i)).setHints( hints);
		}
	}
}

void setPixels ( int x, int y, int w, int h,
                       ColorModel model, int pixels[], int offset, int scansize ) {
	if ( consumer instanceof ImageConsumer ){
		((ImageConsumer)consumer).setPixels( x, y, w, h, model, pixels, offset, scansize);
	}
	else if ( consumer instanceof Vector) {
		Vector v = (Vector)consumer;
		int i, n = v.size();
		for ( i=0; i<n; i++ ){
			((ImageConsumer)v.elementAt( i)).setPixels( x, y, w, h,
			                                            model, pixels, offset, scansize);
		}
	}
}

public void startProduction ( ImageConsumer ic ) {
	addConsumer( ic);

	if ( src instanceof File )
		produceFrom( (File)src);
	else if ( src instanceof URL )
		produceFrom( (URL)src);
	else if ( src instanceof byte[] )
		produceFrom( (byte[])src, off, len);
	else if ( src instanceof Image ) {
		Toolkit.imgProduceImage( this, ((Image)src).nativeData);
	}
	else
		System.err.println( "unsupported production source: " + src.getClass());
		
	removeConsumer( ic);
}
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://kaffe.org/pipermail/kaffe/attachments/19990628/bfea6364/attachment-0003.html 
-------------- next part --------------


import java.applet.Applet;
import java.awt.*;
import java.awt.image.*;
import java.lang.Math;
import java.lang.Integer;
import java.util.Random;

public
class plasm extends Applet implements Runnable

{

    Thread plasmThread;

    int [] plasmarray;
    int pwidth;
    int pheight;
    int xmove;
    int ymove;
    int plasm_overflow;



	MemoryImageSource bgsource;
    int [] bgarray;
    int bgwidth;
    int bgheight;

    int bgcolor;

    Image bgimage;


    public void init()

    {

        String spof = getParameter("PLASM_OVERFLOW");
        String saw = getParameter("APPLET_WIDTH");
        String sah = getParameter("APPLET_HEIGHT");
        String spw = getParameter("PLASMA_WIDTH");
        String sph = getParameter("PLASMA_HEIGHT");
        String sxm = getParameter("MOVEX");
        String sym = getParameter("MOVEY");
        String bgc = getParameter("BGCOLOR");

        plasm_overflow = (spof != null) ? Integer.parseInt(spof) : 250;
        bgwidth = (saw != null) ? Integer.parseInt(saw) : 200;
        bgheight = (sah != null) ? Integer.parseInt(sah) : 180;
        pwidth = (spw != null) ? Integer.parseInt(spw) : 120;
        pheight = (sph != null) ? Integer.parseInt(sph) : 80;
        xmove = (sxm != null) ? Integer.parseInt(sxm) : 30;
        ymove = (sym != null) ? Integer.parseInt(sym) : 30;
        bgcolor = (bgc != null) ? Integer.parseInt(bgc) : 0;
        bgcolor = bgcolor | 0xff000000;

        setLayout(null);
        setBackground (Color.black);

        bgarray=new int [bgwidth*bgheight];

        plasmarray=new int [pwidth*pheight];

        generatePlasm(plasmarray,pwidth,pheight);
        bgsource=new MemoryImageSource(bgwidth, bgheight, bgarray, 0, bgwidth);
        bgsource.setAnimated(true);
        bgimage = createImage( bgsource );

	}





    public void generatePlasm(int [] _parray, int _w, int _h )
    {


        int wert;
        double yfak, xfak;
        double dPI = 2*Math.PI;

        for ( int x=0 ; x < _w/2 ; x++ ) {
            for ( int y=0 ; y < _h/2 ; y++) {

            xfak = 1 - Math.cos(dPI * x / _w );
            yfak = 1 - Math.cos(dPI * y / _h );

            wert = (int) (68 * xfak * yfak) ;
            wert = (wert > 255) ? 255 : wert;

            _parray [ x + y*_w ]= _parray [ (_w-x-1) + y*_w ] = _parray [ x + (_h-y-1)*_w ] = _parray [ (_w-x-1) + (_h-y-1)*_w ]= wert;
            }
        }

    }


    public void start() {

        if (plasmThread == null )
            {
            plasmThread=new Thread(this);
            plasmThread.start();
            }
        }

    public void stop()
    {
        if (plasmThread != null)
            {

            plasmThread.stop();
            plasmThread = null;
        }
    }


    public void run() {

    int x[][] = new int [360][3];
    int y[][] = new int [360][3];


    int c=0;
    int x0 = (bgwidth/2) - (pwidth/2);
    int y0 = (bgheight/2) - (pheight/2);

    double fak = Math.PI/180;
    double fak3= 3*fak;

    Thread me = Thread.currentThread();


        for (int i=0; i < 360 ; i++) {

            x[i][0]= x0+(int) (Math.sin(i*fak3)*xmove);
            y[i][0]= y0+(int) (Math.cos(i*fak)*Math.sin(i*fak)*ymove);

            x[i][1]= x0+(int) (Math.cos(i*fak3)*xmove);
            y[i][1]= y0+(int) (Math.cos(i*fak3)*Math.sin(i*fak)*ymove);

            x[i][2]= x0+(int) (Math.sin(i*fak)*Math.cos(i*fak)*xmove);
            y[i][2]= y0+(int) (Math.sin(i*fak3)*ymove);

        }



    do {
        paint(getGraphics());

        try {
            me.sleep(20);
        } catch (InterruptedException e) {
            break;
  
        }

        c = (c+2)%360;

        clearbackground();
        drawRGPlasma(x[c][0],y[c][0]);
        drawGBPlasma(x[c][1],y[c][1]);
        drawRBPlasma(x[c][2],y[c][2]);
        bgsource.newPixels();
     } while (true);

    }


    public void clearbackground() {

        for (int i=0; i < bgwidth*bgheight ; i++) {
            bgarray[i]=bgcolor;
        }
	}


    public void drawGBPlasma(int _x, int _y)
    {


	    int r,g,b,p;

        int xs,xe,ys,ye;

        xs = (_x >= 0) ? 0 : -_x;
        ys = (_y >= 0) ? 0 : -_y;
        xe = (_x + pwidth < bgwidth) ? pwidth : (bgwidth - _x);
        ye = (_y + pheight < bgheight) ? pheight : (bgheight - _y);

 	    for (int x=xs ; x < xe ; x++) {
 	        for (int y=ys ; y < ye ; y++) {

 	        p = plasmarray[x+y*pwidth];

            r = bgarray[ x + _x + (y + _y) * bgwidth] ;
            g = (r & 0xff00) >> 8;
            b = r & 0xff;
            r = r & 0xff0000;

            g+=p;
            b+=p;

            g = (g>plasm_overflow) ? 255 : g;
            b = (b>plasm_overflow) ? 255 : b;

            bgarray[ x + _x + (y + _y)*bgwidth] = 0xff000000 | r | (g<<8) |  b;
 	        }
        }
    }

    public void drawRGPlasma(int _x, int _y)
    {
        int xs,xe,ys,ye;
        int r,g,b,p;

        xs = (_x >= 0) ? 0 : -_x;
        ys = (_y >= 0) ? 0 : -_y;
        xe = (_x + pwidth < bgwidth) ? pwidth : (bgwidth - _x);
        ye = (_y + pheight < bgheight) ? pheight : (bgheight - _y);

 	    for (int x=xs ; x < xe ; x++) {
 	        for (int y=ys ; y < ye ; y++) {

 	        p = plasmarray[x+y*pwidth];

            r = bgarray[ x + _x + (y+_y)*bgwidth] ;
            g = (r & 0xff00) >> 8;
            b = r & 0xff;
            r = (r >> 16) & 0xff;

            r+=p;
            g+=p;

            g = (g>plasm_overflow) ? 255 : g;
            r = (r>plasm_overflow) ? 255 : r;

            bgarray[ x + _x + (y+_y)*bgwidth] = 0xff000000 | (r<<16) | (g<<8) |  b;
 	        }
        }
    }

    public void drawRBPlasma(int _x, int _y)
    {
	    int r,g,b,p;
        int xs,xe,ys,ye;

        xs = (_x >= 0) ? 0 : -_x;
        ys = (_y >= 0) ? 0 : -_y;
        xe = (_x + pwidth < bgwidth) ? pwidth : (bgwidth - _x);
        ye = (_y + pheight < bgheight) ? pheight : (bgheight - _y);

 	    for (int x=xs ; x < xe ; x++) {
 	        for (int y=ys ; y < ye ; y++) {

 	        p = plasmarray[x+y*pwidth];

            r = bgarray[ x + _x + (y+_y)*bgwidth] ;
            g = (r & 0xff00);
            b = r & 0xff;
            r = ( r>>16 ) & 0xff;

            r+=p;
            b+=p;

            r = (r>plasm_overflow) ? 255 : r;
            b = (b>plasm_overflow) ? 255 : b;

            bgarray[ x + _x + (y+_y)*bgwidth] = 0xff000000 | (r << 16 ) | g |  b;
 	        }
        }
    }

    public synchronized void paint(Graphics g) {

        g.drawImage(bgimage,0,0,bgwidth,bgheight, Color.black, this);

	}

 	public synchronized void update(Graphics g) {

        g.drawImage(bgimage,0,0,bgwidth,bgheight, Color.black, this);
        g.setColor(Color.white);
        // g.drawString("(c) 1998 eto",5,bgheight-5);


	}




}




More information about the kaffe mailing list