/* Copyright (C) 2005-2011 Fabio Riccardi */
package com.lightcrafts.utils;
import com.lightcrafts.jai.utils.Functions;
import com.lightcrafts.jai.JAIContext;
import com.lightcrafts.mediax.jai.JAI;
import com.lightcrafts.mediax.jai.BorderExtender;
import com.lightcrafts.mediax.jai.KernelJAI;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.renderable.ParameterBlock;
import java.util.Map;
public class DropShadow {
protected Dimension dimension;
protected float angle = 30;
protected int distance = 5;
protected int shadowSize = 5;
protected float shadowOpacity = 0.5f;
protected Color shadowColor = new Color(0x000000);
protected Color backgroundColor = Color.white;
public boolean equals(Object obj) {
if (obj instanceof DropShadow) {
DropShadow ds = (DropShadow)obj;
return dimension.equals(ds.dimension) &&
angle == ds.angle &&
distance == ds.distance &&
shadowSize == ds.shadowSize &&
shadowColor.equals(ds.shadowColor) &&
backgroundColor.equals(ds.backgroundColor);
}
return false;
}
public int hashCode() {
return (int) (dimension.hashCode() + shadowColor.hashCode() + backgroundColor.hashCode() +
angle + distance + shadowSize + shadowOpacity);
}
// cached values for fast painting
protected int distance_x = 0;
protected int distance_y = 0;
public DropShadow(Dimension d) {
computeShadowPosition();
if (d != null) {
dimension = d;
} else {
dimension = null;
}
}
public float getAngle() {
return angle;
}
public void setAngle(float angle) {
this.angle = angle;
computeShadowPosition();
}
public int getDistance() {
return distance;
}
public void setDistance(int distance) {
this.distance = distance;
computeShadowPosition();
}
public Color getShadowColor() {
return shadowColor;
}
public Color getBackgroundColor() {
return backgroundColor;
}
public void setShadowColor(Color shadowColor) {
if (shadowColor != null) {
this.shadowColor = shadowColor;
}
}
public void setBackgroundColor(Color backgroundColor) {
if (backgroundColor != null) {
this.backgroundColor = backgroundColor;
}
}
public float getShadowOpacity() {
return shadowOpacity;
}
public void setShadowOpacity(float shadowOpacity) {
this.shadowOpacity = shadowOpacity;
}
public int getShadowSize() {
return shadowSize;
}
public void setShadowSize(int shadowSize) {
this.shadowSize = shadowSize;
}
private void computeShadowPosition() {
double angleRadians = Math.toRadians(angle);
distance_x = (int) (Math.cos(angleRadians) * distance);
distance_y = (int) (Math.sin(angleRadians) * distance);
}
private static Map shadowMap = new SoftValueHashMap(); // Soft references stay around longer
private synchronized BufferedImage createDropShadow() {
BufferedImage shadow = (BufferedImage) shadowMap.get(this);
if (shadow == null) {
if ((shadow = (BufferedImage) shadowMap.get(this)) == null) {
BufferedImage shadowMask = shadowOpacity == 1 ?
createShadowMask(dimension) :
createTranslucentShadowMask(dimension);
shadow = getGaussianBlur(shadowSize, shadowMask);
shadowMap.put(this, shadow);
}
}
return shadow;
}
private BufferedImage createTranslucentShadowMask(Dimension d) {
BufferedImage mask = new BufferedImage(d.width + shadowSize * 2, d.height + shadowSize * 2, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = mask.createGraphics();
g2d.fillRect(shadowSize, shadowSize, d.width, d.height);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, shadowOpacity));
g2d.setColor(shadowColor);
g2d.fillRect(0, 0, d.width + shadowSize * 2, d.height + shadowSize * 2);
g2d.dispose();
return mask;
}
private BufferedImage createShadowMask(Dimension d) {
BufferedImage mask = new BufferedImage(d.width + shadowSize * 2, d.height + shadowSize * 2, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = mask.createGraphics();
g2d.setColor(backgroundColor);
g2d.fillRect(0, 0, d.width + shadowSize * 2, d.height + shadowSize * 2);
g2d.setColor(shadowColor);
g2d.fillRect(shadowSize, shadowSize, d.width, d.height);
g2d.dispose();
return mask;
}
private BufferedImage getGaussianBlur(int size, BufferedImage image) {
KernelJAI kernel = Functions.getGaussKernel(size / 3.0);
ParameterBlock pb = new ParameterBlock();
pb.addSource(image);
pb.add(kernel);
RenderingHints hints = new RenderingHints(JAI.KEY_BORDER_EXTENDER,
BorderExtender.createInstance(BorderExtender.BORDER_COPY));
hints.add(JAIContext.noCacheHint);
return JAI.create("LCSeparableConvolve", pb, hints).getAsBufferedImage();
}
public BufferedImage getShadow() {
return createDropShadow();
}
public AffineTransform getShadowTransform(int x, int y) {
return AffineTransform.getTranslateInstance(x - shadowSize + distance_x, y - shadowSize + distance_y);
}
}