DUE TO SPAM, SIGN-UP IS DISABLED. Goto Selfserve wiki signup and request an account.
How can I create an image that is a composition of any number of other images ?
Here is a simple solution that relies on a "source" ResourceReference and a "decoration" ResourceReference array, used to decorate the source.
/**
* Dynamic image resource
*
* @author Antoine
*
*/
public class CompositeImageResource extends RenderedDynamicImageResource {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* 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;
/**
* @param width
* @param height
*/
public CompositeImageResource(ResourceReference originalIcon,
ResourceReference... overlays) {
super(ICON_WIDTH, ICON_HEIGHT);
// Disable any caching
setCacheable(false);
// Set GIF format to stay away from transparency issues on IE < 7
setFormat("png");
// Insure transparency management
setType(BufferedImage.TYPE_INT_ARGB);
this.source = originalIcon;
this.overlays = overlays;
}
/*
* (non-Javadoc)
*
* @see org.apache.wicket.markup.html.image.resource.RenderedDynamicImageResource#render(java.awt.Graphics2D)
*/
@Override
protected boolean render(Graphics2D g2) {
this.source.bind(Application.get());
for (ResourceReference ref : this.overlays) {
// Not sure this is the right way to ensure binding?
ref.bind(Application.get());
}
BufferedImage baseIcon;
BufferedImage[] errorIcons = new BufferedImage[overlays.length];
// Try reading the original images from the resource reference
// resource
// streams
try {
baseIcon = ImageIO.read(source.getResource().getResourceStream()
.getInputStream());
for (int i = 0; i < overlays.length; i++) {
errorIcons[i] = ImageIO.read(overlays[i].getResource()
.getResourceStream().getInputStream());
}
} catch (IOException e) {
throw new WicketRuntimeException(e);
} catch (ResourceStreamNotFoundException e) {
throw new WicketRuntimeException(e);
}
// Prepare g2 for transparency
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));
g2.drawImage(baseIcon, null, null);
for (Image overlay : errorIcons) {
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
1f));
g2.drawImage(overlay, null, null);
}
return true;
}
}
Let's see how to use this for implement a Tree that renders the node's icon decorated with errors, notification, etc... images :
import java.io.Serializable;
import javax.swing.tree.TreeNode;
import org.apache.wicket.Component;
import org.apache.wicket.IResourceListener;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.Resource;
import org.apache.wicket.ResourceReference;
import org.apache.wicket.extensions.markup.html.tree.Tree;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.link.Link;
public class DecoratedTree extends Tree {
static final ResourceReference ERROR = new ResourceReference(
FormTree.class, "error.gif");
[...]
@Override
protected Component newNodeIcon(MarkupContainer parent, String id,
final TreeNode node) {
class IconComponent extends WebMarkupContainer {
private static final long serialVersionUID = 1L;
private ResourceReference reference;
IconComponent(String id) {
super(id);
// Obtain the original image resource reference
ResourceReference icon = ...
if (hasError) {
// Error? Let's use the CompositeImageResource with our icon
// and the static ERROR decoration and name accordingly the ResourceReference
this.reference = new DynamicResourceReference(icon.getName()
+ "_error", new CompositeImageResource(icon, ERROR));
} else {
// No error? let's stick to the source resource reference
this.reference = icon;
}
}
protected void onComponentTag(ComponentTag tag) {
super.onComponentTag(tag);
// Obtain an url to our image, wheter it be the original icon
// or the generated image
CharSequence url = reference != null ? RequestCycle.get()
.urlFor(reference) : this
.urlFor(IResourceListener.INTERFACE);
tag.put("style", "background-image: url('"
+ RequestCycle.get().getOriginalResponse().encodeURL(
url) + "')");
}
@Override
public void onResourceRequested() {
this.icon.onResourceRequested();
}
}
return new IconComponent(id);
}
/**
* A resource reference implem used to wrap the dynamic generated resource
*/
private static class DynamicResourceReference extends ResourceReference {
//Wrapped resource
private final Resource res;
public DynamicResourceReference(String name, Resource res) {
super(DecoratedTree.class, name);
this.res = res;
}
@Override
protected Resource newResource() {
return res;
}
}
[...]
}