import java.awt.*;
import java.awt.image.*;

public class ImageDissolver {
  private static int _defaultNumImages = 10,
                     _defaultPause = 50;

  Component comp;
  int numImages, pauseInterval;
  Image image, offscreen;
  Image[] dissolvedImages;

  static public Image[] createImages(Image image,
                                     int numImages,
                                     Component component) {
    Image images[] = new Image[numImages];
    MediaTracker tracker = new MediaTracker(component);

    DissolveFilter filter;
    FilteredImageSource fis;

    for (int i=0; i < numImages; ++i) {
      filter = new DissolveFilter((255/(numImages-1))*i);
      fis = new FilteredImageSource(image.getSource(),filter);
      images[i] = component.createImage(fis);
      tracker.addImage(images[i],i);
    }
    try { tracker.waitForAll(); }
    catch(InterruptedException e) { }

    return images;
  }

  public ImageDissolver(Component comp, Image image) {
    this(comp, image, _defaultNumImages, _defaultPause);
  }

  public ImageDissolver(Component comp, Image im, int numImages, 
                        int pause) {
    this.image = im;
    this.comp = comp;
    this.numImages = numImages;
    pauseInterval = pause;

    MediaTracker tracker = new MediaTracker(comp);
    tracker.addImage(im,1);
    try { tracker.waitForID(1); } catch (InterruptedException e) {;}
    if (tracker.isErrorID(1)) return;
    tracker.removeImage(im);

    dissolvedImages = createImages(image, numImages, comp);
  }
}

class DissolveFilter extends RGBImageFilter {
  private int opacity;

  public DissolveFilter() {
    this(0);
  }

  public DissolveFilter(int opacity) {
    canFilterIndexColorModel = true;
    setOpacity(opacity);
  }

  public void setOpacity(int opacity) {
    if (opacity < 0) opacity = 0;
    if (opacity > 255) opacity = 255;
    this.opacity = opacity;
  }

  public int filterRGB(int x, int y, int rgb) {
    DirectColorModel cm = 
      (DirectColorModel)ColorModel.getRGBdefault();
    int alpha = cm.getAlpha(rgb);
    int red = cm.getRed(rgb);
    int green = cm.getGreen(rgb);
    int blue = cm.getBlue(rgb);
    
    // ONLY CHANGE alpha if the current pixel is NOT black.
    if (red < 7 && green < 7 && blue < 7)
        return alpha << 24 | red << 16 | green << 8 | blue;

    // ONLY CHANGE alpha if NOT ALREADY completely transparent:
    //  need to do this, because (transparent) background was changed to
    //  white-ish.
    if (alpha != 0) alpha = opacity;
    return alpha << 24 | red << 16 | green << 8 | blue;
  }
}
