📄 shadowfactory.java
字号:
/**
* Copyright (c) 2006, Sun Microsystems, Inc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of the TimingFramework project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.progx.dropinmotion.shadow;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ConvolveOp;
import java.awt.image.DataBufferInt;
import java.awt.image.Kernel;
import java.awt.image.WritableRaster;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.HashMap;
/**
* <p>A shadow factory generates a drop shadow for any given picture, respecting
* the transparency channel if present. The resulting picture contains the
* shadow only and to create a drop shadow effect you will need to stack the
* original picture and the shadow generated by the factory. If you are using
* Swing you can get this done very easily with the layout
* {@link org.jdesktop.swingx.StackLayout}.</p>
* <h2>Shadow Properties</h2>
* <p>A shadow is defined by three properties:
* <ul>
* <li><i>size</i>: The size, in pixels, of the shadow. This property also
* defines the fuzzyness.</li>
* <li><i>opacity</i>: The opacity, between 0.0 and 1.0, of the shadow.</li>
* <li><i>color</i>: The color of the shadow. Shadows are not meant to be
* black only.</li>
* </ul>
* You can set these properties using the provided mutaters or the appropriate
* constructor. Here are two ways of creating a green shadow of size 10 and
* with an opacity of 50%:
* <pre>
* ShadowFactory factory = new ShadowFactory(10, 0.5f, Color.GREEN);
* // ..
* factory = new ShadowFactory();
* factory.setSize(10);
* factory.setOpacity(0.5f);
* factory.setColor(Color.GREEN);
* </pre>
* The default constructor provides the following default values:
* <ul>
* <li><i>size</i>: 5 pixels</li>
* <li><i>opacity</i>: 50%</li>
* <li><i>color</i>: Black</li>
* </ul></p>
* <h2>Shadow Quality</h2>
* <p>The factory provides two shadow generation algorithms: <i>fast quality blur</i>
* and <i>high quality blur</i>. You can select your preferred algorithm by
* setting the appropriate rendering hint:
* <pre>
* ShadowFactory factory = new ShadowFactory();
* factory.setRenderingHint(ShadowFactory.KEY_BLUR_QUALITY,
* ShadowFactory.VALUE_BLUR_QUALITY_HIGH);
* </pre>
* The default rendering algorihtm is <code>VALUE_BLUR_QUALITY_FAST</code>.</p>
* <p>The current implementation should provide the same quality with both
* algorithms but performances are guaranteed to be better (about 30 times
* faster) with the <i>fast quality blur</i>.</p>
* <h2>Generating a Shadow</h2>
* <p>A shadow is generated as a <code>BufferedImage</code> from another
* <code>BufferedImage</code>. Once the factory is set up, you must call
* {@link #createShadow} to actually generate the shadow:
* <pre>
* ShadowFactory factory = new ShadowFactory();
* // factory setup
* BufferedImage shadow = factory.createShadow(bufferedImage);
* </pre>
* The resulting image is of type <code>BufferedImage.TYPE_INT_ARGB</code>.
* Both dimensions of this image are larger than original image's:
* <ul>
* <li>new width = original width + 2 * shadow size</li>
* <li>new height = original height + 2 * shadow size</li>
* </ul>
* This must be taken into account when you need to create a drop shadow effect.</p>
* <h2>Properties Changes</h2>
* <p>This factory allows to register property change listeners with
* {@link #addPropertyChangeListener}. Listening to properties changes is very
* useful when you emebed the factory in a graphical component and give the API
* user the ability to access the factory. By listening to properties changes,
* you can easily repaint the component when needed.</p>
* <h2>Threading Issues</h2>
* <p><code>ShadowFactory</code> is not guaranteed to be thread-safe.</p>
*
* @author Romain Guy <romain.guy@mac.com>
* @author S閎astien Petrucci <sebastien_petrucci@yahoo.fr>
*/
public class ShadowFactory {
/**
* <p>Key for the blur quality rendering hint.</p>
*/
public static final String KEY_BLUR_QUALITY = "blur_quality";
/**
* <p>Selects the fast rendering algorithm. This is the default rendering
* hint for <code>KEY_BLUR_QUALITY</code>.</p>
*/
public static final String VALUE_BLUR_QUALITY_FAST = "fast";
/**
* <p>Selects the high quality rendering algorithm. With current implementation,
* This algorithm does not guarantee a better rendering quality and should
* not be used.</p>
*/
public static final String VALUE_BLUR_QUALITY_HIGH = "high";
/**
* <p>Identifies a change to the size used to render the shadow.</p>
* <p>When the property change event is fired, the old value and the new
* value are provided as <code>Integer</code> instances.</p>
*/
public static final String SIZE_CHANGED_PROPERTY = "shadow_size";
/**
* <p>Identifies a change to the opacity used to render the shadow.</p>
* <p>When the property change event is fired, the old value and the new
* value are provided as <code>Float</code> instances.</p>
*/
public static final String OPACITY_CHANGED_PROPERTY = "shadow_opacity";
/**
* <p>Identifies a change to the color used to render the shadow.</p>
*/
public static final String COLOR_CHANGED_PROPERTY = "shadow_color";
// size of the shadow in pixels (defines the fuzziness)
private int size = 5;
// opacity of the shadow
private float opacity = 0.5f;
// color of the shadow
private Color color = Color.BLACK;
// rendering hints map
private HashMap<Object, Object> hints;
// notifies listeners of properties changes
private PropertyChangeSupport changeSupport;
/**
* <p>Creates a default good looking shadow generator.
* The default shadow factory provides the following default values:
* <ul>
* <li><i>size</i>: 5 pixels</li>
* <li><i>opacity</i>: 50%</li>
* <li><i>color</i>: Black</li>
* <li><i>rendering quality</i>: VALUE_BLUR_QUALITY_FAST</li>
* </ul></p>
* <p>These properties provide a regular, good looking shadow.</p>
*/
public ShadowFactory() {
this(5, 0.5f, Color.BLACK);
}
/**
* <p>A shadow factory needs three properties to generate shadows.
* These properties are:</p>
* <ul>
* <li><i>size</i>: The size, in pixels, of the shadow. This property also
* defines the fuzzyness.</li>
* <li><i>opacity</i>: The opacity, between 0.0 and 1.0, of the shadow.</li>
* <li><i>color</i>: The color of the shadow. Shadows are not meant to be
* black only.</li>
* </ul></p>
* <p>Besides these properties you can set rendering hints to control the
* rendering process. The default rendering hints let the factory use the
* fastest shadow generation algorithm.</p>
* @param size The size of the shadow in pixels. Defines the fuzziness.
* @param opacity The opacity of the shadow.
* @param color The color of the shadow.
* @see #setRenderingHint(Object, Object)
*/
public ShadowFactory(final int size, final float opacity, final Color color) {
hints = new HashMap<Object, Object>();
hints.put(KEY_BLUR_QUALITY, VALUE_BLUR_QUALITY_FAST);
changeSupport = new PropertyChangeSupport(this);
setSize(size);
setOpacity(opacity);
setColor(color);
}
/**
* <p>Add a PropertyChangeListener to the listener list. The listener is
* registered for all properties. The same listener object may be added
* more than once, and will be called as many times as it is added. If
* <code>listener</code> is null, no exception is thrown and no action
* is taken.</p>
* @param listener the PropertyChangeListener to be added
*/
public void addPropertyChangeListener(PropertyChangeListener listener) {
changeSupport.addPropertyChangeListener(listener);
}
/**
* <p>Remove a PropertyChangeListener from the listener list. This removes
* a PropertyChangeListener that was registered for all properties. If
* <code>listener</code> was added more than once to the same event source,
* it will be notified one less time after being removed. If
* <code>listener</code> is null, or was never added, no exception is thrown
* and no action is taken.</p>
* @param listener
*/
public void removePropertyChangeListener(PropertyChangeListener listener) {
changeSupport.removePropertyChangeListener(listener);
}
/**
* <p>Maps the specified rendering hint <code>key</code> to the specified
* <code>value</code> in this <code>SahdowFactory</code> object.</p>
* @param key The rendering hint key
* @param value The rendering hint value
*/
public void setRenderingHint(final Object key, final Object value) {
hints.put(key, value);
}
/**
* <p>Gets the color used by the factory to generate shadows.</p>
* @return this factory's shadow color
*/
public Color getColor() {
return color;
}
/**
* <p>Sets the color used by the factory to generate shadows.</p>
* <p>Consecutive calls to {@link #createShadow} will all use this color
* until it is set again.</p>
* <p>If the color provided is null, the previous color will be retained.</p>
* @param shadowColor the generated shadows color
*/
public void setColor(final Color shadowColor) {
if (shadowColor != null) {
Color oldColor = this.color;
this.color = shadowColor;
changeSupport.firePropertyChange(COLOR_CHANGED_PROPERTY,
oldColor,
this.color);
}
}
/**
* <p>Gets the opacity used by the factory to generate shadows.</p>
* <p>The opacity is comprised between 0.0f and 1.0f; 0.0f being fully
* transparent and 1.0f fully opaque.</p>
* @return this factory's shadow opacity
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -