org.jdesktop.swingx.painter.ImagePainter Maven / Gradle / Ivy
/*
* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
* Santa Clara, California 95054, U.S.A. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.jdesktop.swingx.painter;
import java.awt.BasicStroke;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.TexturePaint;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.util.logging.Logger;
import org.jdesktop.beans.JavaBean;
import org.jdesktop.swingx.painter.effects.AreaEffect;
/**
* A Painter instance that paints an image. Any Image is acceptable. This
* Painter also allows the developer to specify a "Style" -- CENTERED, TILED,
* SCALED, POSITIONED, and CSS_POSITIONED; with the following meanings:
*
*
* - CENTERED: draws the image unscaled and positioned in the center of
* the component
* - TILED: draws the image repeatedly across the component, filling the
* entire background.
* - SCALED: draws the image stretched large enough (or small enough) to
* cover the entire component. The stretch may not preserve the aspect ratio of the
* original image.
* - POSITIONED: draws the image at the location specified by the imageLocation
* property. This style of drawing will respect the imageScale property.
* - CSS_POSITIONED: draws the image using CSS style background positioning.
*It will use the location specified by the imageLocation property. This property should
*contain a point with the x and y values between 0 and 1. 0,0 will put the image in the
*upper left hand corner, 1,1 in the lower right, and 0.5,0.5 in the center. All other values
*will be interpolated accordingly. For a more
* complete definition of the positioning algorithm see the
* CSS 2.1 spec.
*
*
*
* @author Richard
*/
@JavaBean
/*
AbstractPainter extends AbstractBean implements Painter
abstract void doPaint(Graphics2D g, T object, int width, int height)
AbstractLayoutPainter extends AbstractPainter
AbstractAreaPainter extends AbstractLayoutPainter
abstract Shape provideShape(Graphics2D g, T comp, int width, int height);
*/
public class ImagePainter extends AbstractAreaPainter {
/**
* {@inheritDoc}
*/
@Override // implements the abstract method AbstractPainter.doPaint
protected void doPaint(Graphics2D g, Component component, int width, int height) {
Shape shape = provideShape(g, component,width,height);
switch (getStyle()) {
case BOTH:
drawBackground(g,shape,width,height);
drawBorder(g,shape,width,height);
break;
case FILLED:
drawBackground(g,shape,width,height);
break;
case OUTLINE:
drawBorder(g,shape,width,height);
break;
case NONE:
break;
default:
break;
}
}
/**
* {@inheritDoc}
*/
@Override
protected Shape provideShape(Graphics2D g, Component comp, int width, int height) {
if (getImage() != null) {
BufferedImage bi = getImage();
int imgWidth = bi.getWidth();
int imgHeight = bi.getHeight();
return calculateLayout(imgWidth, imgHeight, width, height);
}
return new Rectangle(0, 0, 0, 0);
}
/**
* An enum to be used as "scaleType" property
*/
public enum ScaleType {
/**
* the default ScaleType
*/
InsideFit,
/**
* outside fitting ScaleType
*/
OutsideFit,
/**
* deform ScaleType
*/
Distort }
/**
* Logger to use
*/
@SuppressWarnings("unused")
private static final Logger LOG = Logger.getLogger(ImagePainter.class.getName());
/**
* The image to draw
*/
private transient BufferedImage img;
private boolean horizontalRepeat;
private boolean verticalRepeat;
private boolean scaleToFit = false;
private ScaleType scaleType = ScaleType.InsideFit;
private double imageScale = 1.0;
/**
* Create a new ImagePainter. By default there is no image, and the alignment is centered.
*/
public ImagePainter() {
this((BufferedImage)null);
}
/**
* Create a new ImagePainter with the specified image and the Style
* Style.CENTERED
*
* @param image the image to be painted
*/
public ImagePainter(BufferedImage image) {
this(image,HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
}
/**
* Create a new ImagePainter with the specified image and alignment.
* @param horizontal the horizontal alignment
* @param vertical the vertical alignment
* @param image the image to be painted
*/
public ImagePainter(BufferedImage image, HorizontalAlignment horizontal, VerticalAlignment vertical) {
super();
setCacheable(true);
this.img = image;
this.setVerticalAlignment(vertical);
this.setHorizontalAlignment(horizontal);
this.setFillPaint(null);
this.setBorderPaint(null);
this.setDirty(false);
}
/**
* Sets the image to paint with.
* @param image if null, clears the image. Otherwise, this will set the
* image to be painted.
*/
public void setImage(BufferedImage image) {
if (image != img) {
Image oldImage = img;
img = image;
setDirty(true);
firePropertyChange("image", oldImage, img);
}
}
/**
* Gets the current image used for painting.
* @return the image used for painting
*/
public BufferedImage getImage() {
return img;
}
private void drawBackground(Graphics2D g, Shape shape, int width, int height) {
Paint p = getFillPaint();
if(p != null) {
if(isPaintStretched()) {
p = calculateSnappedPaint(p, width, height);
}
g.setPaint(p);
g.fill(shape);
}
if(getAreaEffects() != null) {
for(AreaEffect ef : getAreaEffects()) {
ef.apply(g, shape, width, height);
}
}
if (img != null) {
int imgWidth = img.getWidth(null);
int imgHeight = img.getHeight(null);
if (imgWidth == -1 || imgHeight == -1) {
//image hasn't completed loading, do nothing
} else {
Rectangle rect = shape.getBounds();
if(verticalRepeat || horizontalRepeat) {
Shape oldClip = g.getClip();
Shape clip = g.getClip();
if(clip == null) {
clip = new Rectangle(0,0,width,height);
}
Area area = new Area(clip);
Insets insets = getInsets();
area.intersect(new Area(new Rectangle(insets.left, insets.top, width - insets.left - insets.right, height - insets.top - insets.bottom)));
if (verticalRepeat && horizontalRepeat) {
area.intersect(new Area(new Rectangle(0, 0, width, height)));
g.setClip(area);
} else if (verticalRepeat) {
area.intersect(new Area(new Rectangle(rect.x, 0, rect.width, height)));
g.setClip(area);
} else {
area.intersect(new Area(new Rectangle(0, rect.y, width, rect.height)));
g.setClip(area);
}
TexturePaint tp = new TexturePaint(img, rect);
g.setPaint(tp);
g.fillRect(0,0,width,height);
g.setClip(oldClip);
} else {
if(scaleToFit) {
int sw = imgWidth;
int sh = imgHeight;
if(scaleType == ScaleType.InsideFit) {
if(sw > width) {
float scale = (float)width/(float)sw;
sw = (int)(sw * scale);
sh = (int)(sh * scale);
}
if(sh > height) {
float scale = (float)height/(float)sh;
sw = (int)(sw * scale);
sh = (int)(sh * scale);
}
}
if(scaleType == ScaleType.OutsideFit) {
if(sw > width) {
float scale = (float)width/(float)sw;
sw = (int)(sw * scale);
sh = (int)(sh * scale);
}
if(sh < height) {
float scale = (float)height/(float)sh;
sw = (int)(sw * scale);
sh = (int)(sh * scale);
}
}
if(scaleType == ScaleType.Distort) {
sw = width;
sh = height;
}
int x=0;
int y=0;
switch(getHorizontalAlignment()) {
case CENTER:
x=(width/2)-(sw/2);
break;
case RIGHT:
x=width-sw;
break;
case LEFT:
break;
default:
break;
}
switch(getVerticalAlignment()) {
case CENTER:
y=(height/2)-(sh/2);
break;
case BOTTOM:
y=height-sh;
break;
case TOP:
break;
default:
break;
}
g.drawImage(img, x, y, sw, sh, null);
} else {
int sw = rect.width;
int sh = rect.height;
if(imageScale != 1.0) {
sw = (int)(sw * imageScale);
sh = (int)(sh * imageScale);
}
g.drawImage(img, rect.x, rect.y, sw, sh, null);
}
}
}
}
}
private void drawBorder(Graphics2D g, Shape shape, int width, int height) {
if(getBorderPaint() != null) {
g.setPaint(getBorderPaint());
g.setStroke(new BasicStroke(getBorderWidth()));
g.draw(shape);
}
}
/**
* returns the value of boolean "scaleToFit" property
* @return value of "scaleToFit" property
*/
public boolean isScaleToFit() {
return scaleToFit;
}
/**
* sets "scaleToFit" property
* @param scaleToFit boolean value of the property
*/
public void setScaleToFit(boolean scaleToFit) {
boolean old = isScaleToFit();
this.scaleToFit = scaleToFit;
setDirty(true);
firePropertyChange("scaleToFit", old, isScaleToFit());
}
/**
* returns the enum of "scaleType" property
* @return value of "scaleType" property
*/
public ScaleType getScaleType() {
return scaleType;
}
/**
* sets "scaleType" property
* @param scaleType enum ScaleType
*/
public void setScaleType(ScaleType scaleType) {
ScaleType old = getScaleType();
this.scaleType = scaleType;
setDirty(true);
firePropertyChange("scaleType", old, getScaleType());
}
/**
* Gets the current scaling factor used when drawing an image.
* @return the current scaling factor
*/
public double getImageScale() {
return imageScale;
}
/**
* Sets the scaling factor used when drawing the image
* @param imageScale the new image scaling factor
*/
public void setImageScale(double imageScale) {
double old = getImageScale();
this.imageScale = imageScale;
setDirty(true);
firePropertyChange("imageScale",old,this.imageScale);
}
/**
* Indicates if the image will be repeated horizontally.
* @return if the image will be repeated horizontally
*/
public boolean isHorizontalRepeat() {
return horizontalRepeat;
}
/**
* Sets if the image should be repeated horizontally.
* @param horizontalRepeat the new horizontal repeat value
*/
public void setHorizontalRepeat(boolean horizontalRepeat) {
boolean old = this.isHorizontalRepeat();
this.horizontalRepeat = horizontalRepeat;
setDirty(true);
firePropertyChange("horizontalRepeat",old,this.horizontalRepeat);
}
/**
* Indicates if the image will be repeated vertically.
* @return if the image will be repeated vertically
*/
public boolean isVerticalRepeat() {
return verticalRepeat;
}
/**
* Sets if the image should be repeated vertically.
* @param verticalRepeat new value for the vertical repeat
*/
public void setVerticalRepeat(boolean verticalRepeat) {
boolean old = this.isVerticalRepeat();
this.verticalRepeat = verticalRepeat;
setDirty(true);
firePropertyChange("verticalRepeat",old,this.verticalRepeat);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return getClass().getSimpleName() + "[img=" + img + "]";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy