Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.IOException;

import javax.imageio.ImageIO;

import org.apache.wicket.Application;
import org.apache.wicket.ResourceReference;
import org.apache.wicket.WicketRuntimeException;
import org.apache.wicket.markup.html.image.resource.RenderedDynamicImageResource;
import org.apache.wicket.util.resource.ResourceStreamNotFoundException;

/**
 * Dynamic image resource
 * 
 * @author Antoine
 * 
 */
public class CompositeImageResource extends RenderedDynamicImageResource
		implements ImageObserver {


	/**
	 * Default icon width. Other implementations could obtain this data from the
	 * images meta datas
	 */
	private static final int ICON_WIDTH = 16;

	/**
	 * Default icon height. Other implementations could obtain this data from
	 * the images meta datas
	 */
	private static final int ICON_HEIGHT = 16;

	/**
	 * {@link ResourceReference} to the base image to decorate
	 */
	private final ResourceReference source;

	/**
	 * {@link ResourceReference}[] to use as decorations (will be stacked over
	 * the source)
	 */
	private final ResourceReference[] overlays;

	/**
	 * Internal field to monitor the awt image rendering process
	 */
	private int ongoing = 0;

	/**
	 * @param width
	 * @param height
	 */
	public CompositeImageResource(ResourceReference originalIcon,
			ResourceReference... overlays) {
		super(ICON_WIDTH, ICON_HEIGHT);
		// Insure transparency management
		setType(BufferedImage.TYPE_INT_ARGB);
		this.source = originalIcon;
		this.source.bind(Application.get());
		this.overlays = overlays;
		for (ResourceReference ref : this.overlays) {
			// Not sure this is the right way to ensure binding?
			ref.bind(Application.get());
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.wicket.markup.html.image.resource.RenderedDynamicImageResource#render(java.awt.Graphics2D)
	 */
	@Override
	protected boolean render(Graphics2D g2) {
		BufferedImage baseIcon;
		BufferedImage[] errorIcons = new BufferedImage[overlays.length];
		ongoing = 0;
		// Try reading the original images from the resource reference resource
		// streams
		try {
			baseIcon = ImageIO.read(source.getResource().getResourceStream()
					.getInputStream());
			ongoing++;
			for (int i = 0; i < overlays.length; i++) {
				errorIcons[i] = ImageIO.read(overlays[i].getResource()
						.getResourceStream().getInputStream());
				ongoing++;
			}
		} catch (IOException e) {
			throw new WicketRuntimeException(e);
		} catch (ResourceStreamNotFoundException e) {
			throw new WicketRuntimeException(e);
		}
		// Prepare g2 for trnasparency
		g2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
		Rectangle2D.Double rect = new Rectangle2D.Double(0, 0, ICON_WIDTH,
				ICON_HEIGHT);
		g2.fill(rect);
		
		// Prepare g2 for image overlay
		g2
				.setComposite(AlphaComposite.getInstance(
						AlphaComposite.SRC_OVER, 1f));
		if (g2.drawImage(baseIcon, null, this)) {
			ongoing--;
		}
		for (Image overlay : errorIcons) {
			g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
					1f));
			if (g2.drawImage(overlay, null, this)) {
				ongoing--;
			}
		}
		// Wait until the awt process finishes loading the images
		while (ongoing > 0) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		return true;
	}

	/* (non-Javadoc)
	 * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)
	 */
	@Override
	public boolean imageUpdate(Image img, int infoflags, int x, int y,
			int width, int height) {
		boolean done = (infoflags & ImageObserver.ALLBITS) != 0;
		if (done) {
			ongoing--;
		}
		return !done;
	}
}

Let's see how to use this for implement a Tree that renders the node's icon decorated with errors, notification, etc... images :

...