// **********************************************************************
//
// <copyright>
//
// BBN Technologies
// 10 Moulton Street
// Cambridge, MA 02138
// (617) 873-8000
//
// Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/omGraphics/OMRaster.java,v $
// $RCSfile: OMRaster.java,v $
// $Revision: 1.8 $
// $Date: 2009/01/21 01:24:41 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.omGraphics;
import java.awt.Color;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.Serializable;
import java.util.logging.Level;
import javax.swing.ImageIcon;
import com.bbn.openmap.MoreMath;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.util.DeepCopyUtil;
/**
* The OMRaster object lets you create multi-colored images. An image is a two
* dimensional array of pixel values that correspond to some color values. The
* pixels are used from the top left, across each row to the right, down to the
* bottom row.
* <p>
* There are two colormodels that are implemented in OMRaster - the direct
* colormodel and the indexed colormodel. The direct colormodel is implemented
* when the pixel values contain the actual java.awt.Color values for the image.
* The indexed colormodel is implemented when the pixel values are actually
* indexes into an array of java.awt.Colors. NOTE: The direct colormodel
* OMRaster is faster to display, because it doesn't need to take the time to
* resolve the colortable values into pixels.
* <P>
*
* For direct colormodel images: If you pass in a null pix or a pix with a zero
* length, the object will create the pixels for you but will not general a
* renderable version of the object. You will need to call render before
* generate after the pixels have been set. This feature is for cached rasters,
* where the content may be changed later. Use this (null pix) if you are
* building images in a cache, for tiled mapping data or something else where
* the data is not yet known. The memory for the pixels will be allocated, and
* then they can be set with image data later when a database is accessed.
* <P>
*
* For ImageIcon OMRasters: Using an ImageIcon to create an OMRaster gives you
* the ability to put an image on the screen based on an ImageIcon made from
* file or URL. The OMRaster uses this ImageIcon as is - there is no opportunity
* to change any parameters of this image. So set the colors, transparency, etc.
* before you create the OMRaster.
* <P>
*
* For indexed colormodel images: If you pass in an empty byte array, a byte
* array will be created based on the width and height. You will have to resolve
* empty colortables and set the pixels later. Use this method (null bytes) if
* you are building images in a cache, for tiled mapping data or something else
* where the data is not yet known. The memory for the pixels will be allocated,
* and then they can be set with image data later when a database is accessed.
*
* There is the ability to add a filter to the image, to change it's appearance
* for rendering. The most common filter, which is included as a kind of
* default, is the scale filter. Filtering the OMRasterObject replaces the
* bitmap variable, which is the internal java.awt.Image used for rendering. For
* OMRasters created with pixels, or with the colortable and the colortable
* index, the original data is left intact, and can be recreated later, or
* rescaled on the fly, because the internal bitmap will be recreated prior to
* re-scaling. For OMRasters created by ImageIcons or Images, though, you'll
* need to hold on to the original Image. The internal version is replaced by
* the filtered version.
*
* @see OMRasterObject
*/
public class OMRaster extends OMRasterObject implements Serializable {
/**
* The integer colors that are needed in a java colortable. The Color[] that
* gets passed into some of the constructors goes to build this, but this
* array is really used to build the image pixel array.
*/
protected int[] colors = null;
/**
* The transparency of the image. If this is set to anything less than 255,
* this value is used for all colors in the image. If it is set to 255, then
* the alpha value in each Color regulates the transparency of the image.
* The value of this variable should stay in the range:
* <code>0 <= transparent <= 255</code>
*/
protected int transparent = 255;
/**
* Construct a blank OMRaster, to be filled in with setX calls.
*/
public OMRaster() {
super(RENDERTYPE_UNKNOWN, LINETYPE_UNKNOWN, DECLUTTERTYPE_NONE);
}
// /////////////////////////////////// INT PIXELS - DIRECT
// COLORMODEL
/**
* Creates an OMRaster images, Lat/Lon placement with a direct colormodel.
*
* @param lt latitude of the top of the image.
* @param ln longitude of the left side of the image.
* @param w width of the image, in pixels.
* @param h height of the image, in pixels.
* @param pix color values for the pixels.
* @see #setPixel
*/
public OMRaster(double lt, double ln, int w, int h, int[] pix) {
super(RENDERTYPE_LATLON, LINETYPE_UNKNOWN, DECLUTTERTYPE_NONE);
setColorModel(COLORMODEL_DIRECT);
lat = lt;
lon = ln;
width = w;
height = h;
pixels = pix;
if (pixels == null || pixels.length == 0)
pixels = new int[height * width];
}
/**
* Create an OMRaster image, XY placement with a direct colormodel.
*
* @param x1 window location of the left side of the image.
* @param y1 window location of the top of the image.
* @param w width of the image, in pixels.
* @param h height of the image, in pixels.
* @param pix color values for the pixels.
* @see #setPixel
*/
public OMRaster(int x1, int y1, int w, int h, int[] pix) {
super(RENDERTYPE_XY, LINETYPE_UNKNOWN, DECLUTTERTYPE_NONE);
setColorModel(COLORMODEL_DIRECT);
x = x1;
y = y1;
width = w;
height = h;
pixels = pix;
if (pixels == null || pixels.length == 0)
pixels = new int[height * width];
}
/**
* Create an OMRaster, Lat/lon placement with XY offset with a direct
* colormodel.
*
* @param lt latitude of the top of the image, before the offset.
* @param ln longitude of the left side of the image, before the offset.
* @param offset_x1 number of pixels to move image to the right.
* @param offset_y1 number of pixels to move image down.
* @param w width of the image, in pixels.
* @param h height of the image, in pixels.
* @param pix color values for the pixels.
* @see #setPixel
*/
public OMRaster(double lt, double ln, int offset_x1, int offset_y1, int w, int h, int[] pix) {
super(RENDERTYPE_OFFSET, LINETYPE_UNKNOWN, DECLUTTERTYPE_NONE);
setColorModel(COLORMODEL_DIRECT);
lat = lt;
lon = ln;
x = offset_x1;
y = offset_y1;
width = w;
height = h;
pixels = pix;
if (pixels == null || pixels.length == 0) {
pixels = new int[height * width];
}
}
// //////////////////////////////////// IMAGEICON
/**
* Create an OMRaster, Lat/Lon placement with an ImageIcon.
*
* @param lt latitude of the top of the image.
* @param ln longitude of the left side of the image.
* @param ii ImageIcon used for the image.
*/
public OMRaster(double lt, double ln, ImageIcon ii) {
this(lt, ln, ii.getImage());
}
/**
* Create an OMRaster, Lat/Lon placement with an Image.
*
* @param lt latitude of the top of the image.
* @param ln longitude of the left side of the image.
* @param ii Image used for the image.
*/
public OMRaster(double lt, double ln, Image ii) {
super(RENDERTYPE_LATLON, LINETYPE_UNKNOWN, DECLUTTERTYPE_NONE);
setColorModel(COLORMODEL_IMAGEICON);
lat = lt;
lon = ln;
setImage(ii);
}
/**
* Create an OMRaster image, X/Y placement with an ImageIcon.
*
* @param x1 window location of the left side of the image.
* @param y1 window location of the top of the image.
* @param ii ImageIcon used for the image.
*/
public OMRaster(int x1, int y1, ImageIcon ii) {
this(x1, y1, ii.getImage());
}
/**
* Create an OMRaster image, X/Y placement with an Image.
*
* @param x1 window location of the left side of the image.
* @param y1 window location of the top of the image.
* @param ii Image used for the image.
*/
public OMRaster(int x1, int y1, Image ii) {
super(RENDERTYPE_XY, LINETYPE_UNKNOWN, DECLUTTERTYPE_NONE);
setColorModel(COLORMODEL_IMAGEICON);
x = x1;
y = y1;
setImage(ii);
}
/**
* Create an OMRaster, Lat/Lon with X/Y placement with an ImageIcon.
*
* @param lt latitude of the top of the image, before the offset.
* @param ln longitude of the left side of the image, before the offset.
* @param offset_x1 number of pixels to move image to the right.
* @param offset_y1 number of pixels to move image down.
* @param ii ImageIcon used for the image.
*/
public OMRaster(double lt, double ln, int offset_x1, int offset_y1, ImageIcon ii) {
this(lt, ln, offset_x1, offset_y1, ii.getImage());
}
/**
* Create an OMRaster, Lat/Lon with X/Y placement with an Image. Make sure
* that the Image is complete( if being loaded over the internet) and ready
* to be drawn. Otherwise, you have to figure out when the Image is
* complete, so that you can get the layer to paint it! Use the ImageIcon
* constructor if you don't mind blocking to wait for the pixels to arrive.
*
* @param lt latitude of the top of the image, before the offset.
* @param ln longitude of the left side of the image, before the offset.
* @param offset_x1 number of pixels to move image to the right.
* @param offset_y1 number of pixels to move image down.
* @param ii Image used for the image.
*/
public OMRaster(double lt, double ln, int offset_x1, int offset_y1, Image ii) {
super(RENDERTYPE_OFFSET, LINETYPE_UNKNOWN, DECLUTTERTYPE_NONE);
setColorModel(COLORMODEL_IMAGEICON);
lat = lt;
lon = ln;
x = offset_x1;
y = offset_y1;
setImage(ii);
}
// //////////////////////////////////// BYTE PIXELS with
// COLORTABLE
/**
* Lat/Lon placement with a indexed colormodel, which is using a colortable
* and a byte array to construct the int[] pixels.
*
* @param lt latitude of the top of the image.
* @param ln longitude of the left side of the image.
* @param w width of the image, in pixels.
* @param h height of the image, in pixels.
* @param bytes colortable index values for the pixels.
* @param colorTable color array corresponding to bytes
* @param trans transparency of image.
* @see #setPixel
*/
public OMRaster(double lt, double ln, int w, int h, byte[] bytes, Color[] colorTable, int trans) {
super(RENDERTYPE_LATLON, LINETYPE_UNKNOWN, DECLUTTERTYPE_NONE);
setColorModel(COLORMODEL_INDEXED);
lat = lt;
lon = ln;
width = w;
height = h;
bits = bytes;
transparent = trans;
if (colorTable != null) {
setColors(colorTable);
}
if (bits != null && bits.length != 0) {
if (colorTable != null && colors.length != 0) {
pixels = computePixels(bits);
}
} else {
bits = new byte[height * width];
}
}
/**
* XY placement with a indexed colormodel, which is using a colortable and a
* byte array to construct the int[] pixels.
*
* @param x1 window location of the left side of the image.
* @param y1 window location of the top of the image.
* @param w width of the image, in pixels.
* @param h height of the image, in pixels.
* @param bytes colortable index values for the pixels.
* @param colorTable color array corresponding to bytes
* @param trans transparency of image.
* @see #setPixel
*/
public OMRaster(int x1, int y1, int w, int h, byte[] bytes, Color[] colorTable, int trans) {
super(RENDERTYPE_XY, LINETYPE_UNKNOWN, DECLUTTERTYPE_NONE);
setColorModel(COLORMODEL_INDEXED);
x = x1;
y = y1;
width = w;
height = h;
bits = bytes;
transparent = trans;
if (colorTable != null) {
setColors(colorTable);
}
if (bits != null && bits.length != 0) {
if (colorTable != null && colors.length != 0) {
pixels = computePixels(bits);
}
} else {
bits = new byte[height * width];
}
}
/**
* Lat/lon placement with XY offset with a indexed colormodel, which is
* using a colortable and a byte array to construct the int[] pixels.
*
* @param lt latitude of the top of the image, before the offset.
* @param ln longitude of the left side of the image, before the offset.
* @param offset_x1 number of pixels to move image to the right.
* @param offset_y1 number of pixels to move image down.
* @param w width of the image, in pixels.
* @param h height of the image, in pixels.
* @param bytes colortable index values for the pixels.
* @param colorTable color array corresponding to bytes
* @param trans transparency of image.
* @see #setPixel
*/
public OMRaster(double lt, double ln, int offset_x1, int offset_y1, int w, int h, byte[] bytes,
Color[] colorTable, int trans) {
super(RENDERTYPE_OFFSET, LINETYPE_UNKNOWN, DECLUTTERTYPE_NONE);
setColorModel(COLORMODEL_INDEXED);
lat = lt;
lon = ln;
x = offset_x1;
y = offset_y1;
width = w;
height = h;
transparent = trans;
bits = bytes;
if (colorTable != null) {
setColors(colorTable);
}
if (bits != null && bits.length != 0) {
if (colorTable != null && colors.length != 0) {
pixels = computePixels(bits);
}
} else {
bits = new byte[height * width];
}
}
// ////////////////////////////////////////////////////
/**
* Just a simple check to see if the x, y pair actually fits into the pixel
* array.
*
* @param x x location of pixel, from the left side of image.
* @param y y location of pixel, from the top of image.
* @return true if location within pixel array.
*/
private boolean boundsSafe(int x, int y) {
if ((y < 0) || (y >= height) || (x < 0) || (x >= width)) {
return false;
}
return true;
}
/**
* Set the ImageIcon.
*
* @param img ImageIcon
*/
public void setImageIcon(ImageIcon img) {
setImage(img.getImage());
}
/**
* Set the image pixel value at a location.
*
* @param x Horizontal location of pixel from left.
* @param y Vertical location of pixel from top.
* @param colorValue the color value of the pixel.
* @return true if x, y location valid.
*/
public boolean setPixel(int x, int y, int colorValue) {
if (boundsSafe(x, y)) {
pixels[(y * width) + x] = colorValue;
setNeedToRegenerate(true);
return true;
}
return false; // fail
}
/**
* Get the image pixel value at a location.
*
* @param x Horizontal location of pixel from left.
* @param y Vertical location of pixel from top.
* @return the integer color value of the image at x, y
*/
public int getPixel(int x, int y) {
if (boundsSafe(x, y)) {
return pixels[(y * width) + x];
}
return 0; // fail - but also the ct[0] - hmmmmm.
}
/**
* Set image byte data, for index frame using colortable.
*
* @param x Horizontal location of pixel from left.
* @param y Vertical location of pixel from top.
* @param ctIndex The array index of the applicable color in the color
* table.
* @return true if x, y location valid.
*/
public boolean setByte(int x, int y, byte ctIndex) {
if (boundsSafe(x, y) && bits != null) {
bits[(y * width) + x] = ctIndex;
setNeedToRegenerate(true);
return true;
}
return false; // fail
}
/**
* Get image byte data, which the index to a colortable for indexed images.
*
* @param x Horizontal location of pixel from left.
* @param y Vertical location of pixel from top.
* @return byte value of bytes(x, y)
*/
public byte getByte(int x, int y) {
if (boundsSafe(x, y) && bits != null) {
return bits[(y * width) + x];
}
return 0; // fail - but also the ct[0] - hmmmmm.
}
/**
* Set the bytes used to create the pixels used to create the image. Checks
* to see of the length matches the height * width, but doesn't do anything
* if they don't match, except print out a warning. Make sure it does.
*
* @param values byte values containing bit pixel values.
*/
public void setBits(byte[] values) {
super.setBits(values);
if ((values.length) != (height * width)) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("OMBitmap: new byte[] size (" + +values.length + ") doesn't"
+ " match [height*width (" + height * width + ")]");
}
}
}
/**
* Set the transparency of the index type images. For the Direct Colormodel
* the pixel data needs to be reconstructed, so this is an O(pixels.length)
* operation. For an indexed colormodel, the data still needs to be
* reconstructed, but it will cost you the time in generate(). The
* transparency value should be a number between 0-255.
*
* @param value New value of the alpha value for the image.
*/
public void setTransparent(int value) {
value &= 0x000000ff;
if (transparent == value)
return;
transparent = value;
setNeedToRegenerate(true);
if (bits != null) {
pixels = computePixels(bits);
} else {
value <<= 24;// move to alpha position
// direct color model, touch each pixel in the image
for (int i = 0; i < pixels.length; i++) {
// Do this if we want to support images that have
// transparent pixels, and we want each pixel to have
// the most transparent pixel.
// Why don't we want to do this??? DFD
// int pixAlpha = 0xFF000000 & pixels[i];
// pixAlpha = (pixAlpha < value)?pixAlpha:value;
// pixels[i] = (0x00ffffff & pixels[i]) | pixAlpha;
pixels[i] = (0x00ffffff & pixels[i]) | value;
}
}
}
/**
* Get the transparent setting of the image.
*
* @return the transparent value (0-255) of the image.
*/
public int getTransparent() {
return transparent;
}
/**
* Set the color table to the int RGB values passed in. Valid for the
* indexed colormodel only. The pixels will be colored according to these
* values.
*
* @param values array of color RGB values.
*/
public void setColors(int[] values) {
if (colorModel != COLORMODEL_INDEXED) {
logger.fine("OMRaster: Setting colors for final colortable when a colortable isn't needed!");
} else {
colors = values;
setNeedToRegenerate(true);
}
}
/**
* Set the color table according to the java.awt.Color array passed in.
* Valid for the indexed colormodel only. The pixels will be colored
* according to these values. The transparency values of these colors will
* only take effect of they are less than the transparency value of the
* images' value.
*
* @param values array of java.awt.Color colors.
*/
public void setColors(Color[] values) {
if (colorModel != COLORMODEL_INDEXED) {
logger.fine("Setting colors for final colortable when a colortable isn't needed!");
return;
} else if (values == null || values.length == 0) {
colors = new int[0];
logger.fine("What are you trying to do to me?!? The colortables gots to have values!");
return;
} else {
if (values.length > 0) {
colors = new int[values.length];
boolean allTransparent = true;
int trans = (transparent << 24) & 0xff000000;
// Turn the color table into a table using the
// default OMava color model.
for (int i = 0; i < values.length; i++) {
// The transparent field can be set for the whole
// image, while the open part of the colortable
// entry
// structure is the transparent setting for that
// particular color.
if (transparent < 255) {
int argb = values[i].getRGB();
if (values[i].getAlpha() > transparent) {
// If the transparent value of the pixel
// is
// lower than the transparency value, keep
// that instead - don't make things more
// visible then they were.
colors[i] = (0x00ffffff & argb) | trans;
} else {
colors[i] = argb;
}
} else {
colors[i] = values[i].getRGB();
}
// Just check if all the colors are transparent -
// this is a pain to figure out if you are
// getting colors from some server that doesn't
// know about alpha values.
if (allTransparent && ((colors[i] >>> 24) != 0)) {
allTransparent = false;
}
}
if (DEBUG && allTransparent) {
logger.fine("OMRaster: **Whasamatta?** Image created with all transparent pixels!");
}
}
// This is wrong - we do need to force a computePixels,
// but in generate...
// computePixels();
// This will do it....
pixels = null;
setNeedToRegenerate(true);
}
}
/**
* Get the array of colors used in the indexed color model. If the image is
* not a indexed colormodel, the int[] will be null.
*
* @return color int[] if index colormodel, null otherwise.
*/
public int[] getColors() {
return colors;
}
// ///////////////////////////////////////////////////////
/**
* Compute pixels is the function that resolves the color table into pixel
* integer values used in the Image. It uses the bits as indexes into the
* color table, and builds a big array of ints to use in the bitmap image.
* If the bits are null, then the object was created in the direct color
* model where the colors are already built into the pixels. So, if you call
* this, the pixels have to be null and the bits good indexes into the
* colortable.
*
* @return new int[] for image pixels, null if there was a problem or if the
* colormodel is not COLORMODEL_INDEXED.
*/
protected int[] computePixels(byte[] bits) {
if (DEBUG) {
logger.fine("OMRaster.compute pixels!");
}
if (colorModel != COLORMODEL_INDEXED) {
// I don't like this... DFD
return new int[0];
}
if (colors == null || colors.length == 0 || bits == null || bits.length == 0) {
logger.fine("OMRaster: attempting to compute pixels without color table or proper indexes!");
return null;
}
int nPixels = width * height;
if (DEBUG) {
logger.fine("Computing pixels for image size:" + width + ", " + height);
}
int[] iPixels = new int[nPixels];
// Now, using the new constructed color table, build a set of
// pixels. alpha is a ready, shifted version of the overall
// transparency value;
int alpha = (transparent << 24) & 0xff000000;
int numColors = colors.length;
int bitsLength = bits.length;
for (int i = 0; i < bitsLength && i < nPixels; i++) {
byte b = bits[i];
int color = 0;
// make the alpha for this color the lessor of what the
// colortable is, versus the transparent value
// int pixAlpha;
if (b < 0) {
color = colors[MoreMath.signedToInt(b)];
} else if (b < numColors) {
color = colors[b];
}
// OK, got an int value, argb, for the color to be put on
// the pixel. Now we need to straighten out the
// transparency.
if (transparent < 255 && ((color >> 24) > transparent)) {
// this means that the overall transparency should be
// more (lower number, more transparent) than the
// pixel color.
color = alpha | (0x00FFFFFF & color);
} // Otherwise, just go with the alpha value set on the
// color...
iPixels[i] = color;
}
return iPixels;
}
/**
* Prepare the graphics for rendering. For all image types, it positions the
* image relative to the projection. For direct and indexed colormodel
* images, it creates the ImageIcon used for drawing to the window (internal
* to object). For indexed colormodel images, it also calls computePixels,
* to resolve the colortable and the bytes to create the image pixels.
*
* @param proj Projection used to position the image on the window.
* @return true if the image is ready to paint.
*/
public boolean generate(Projection proj) {
renderRotationAngle = null;
// Position sets the position for the OMRaster!!!!
if (!position(proj)) {
if (DEBUG) {
logger.fine("OMRaster.generate(): positioning failed!");
}
return false;
}
// We used to just return here if the OMRaster didn't need to
// be regenerated, but that didn't create the shape properly.
if (getNeedToRegenerate()) {
bitmap = getBitmapFromInternalData();
if (bitmap == null) {
return false;
}
}
evaluateRotationAngle(proj);
// generate shape that is a boundary of the generated image.
// We'll make it a GeneralPath rectangle.
setShape();
setLabelLocation(getShape(), proj);
setNeedToRegenerate(false);
return true;
}
/**
* Set the renderRotationAngle based on the projection angle and OMRaster
* settings.
*
* @param proj the current projection.
*/
protected void evaluateRotationAngle(Projection proj) {
renderRotationAngle = null;
double projRotation = proj.getRotationAngle();
if (projRotation != 0.0) {
// Only do the attribute check if the projection is rotated.
Object noRotationAtt = getAttribute(OMGraphicConstants.NO_ROTATE);
boolean compensateForProjRot = noRotationAtt != null
&& !noRotationAtt.equals(Boolean.FALSE);
if (compensateForProjRot) {
renderRotationAngle = rotationAngle - projRotation;
return;
}
}
if (rotationAngle != DEFAULT_ROTATIONANGLE) {
renderRotationAngle = rotationAngle;
}
}
protected Image getBitmapFromInternalData() {
Image bi = bitmap;
int[] iPixels = this.pixels;
byte[] iBits = this.bits;
int iWidth = this.width;
int iHeight = this.height;
java.awt.image.ImageFilter iImageFilter = this.imageFilter;
if (colorModel != COLORMODEL_IMAGEICON) {
// This section is for the indexed color model rasters
// that need to resolve the color map to the bit array
// indexes.
// If pixels == null, then computePixels has not been
// called
if (iPixels == null) {
if (iBits != null) {
iPixels = computePixels(iBits);
pixels = iPixels;
}
if (iPixels != null) {
logger.fine("attempted to generate without pixels defined!");
return null;
}
}
if (iWidth <= 0 || iHeight <= 0 || iPixels == null) {
// NeedToRegenerate should still be true, so it won't
// render.
return null;
}
bi = new BufferedImage(iWidth, iHeight, BufferedImage.TYPE_INT_ARGB);
/**
* Looking at the standard BufferedImage code, an int[0] is
* allocated for every pixel. Maybe the memory usage is optimized
* for that, but it goes through a call stack for every pixel to do
* it. Let's just cycle through the data and write the pixels
* directly into the raster.
*/
WritableRaster raster = (WritableRaster) ((BufferedImage) bi).getRaster();
try {
raster.setDataElements(0, 0, iWidth, iHeight, iPixels);
} catch (ArrayIndexOutOfBoundsException aioobe) {
logger.fine("w: " + iWidth + ", h: " + iHeight + ", p.l: " + (iPixels != null? (iPixels.length + ", diff " + (iWidth * iHeight - iPixels.length)) : "null"));
}
}
/*
* REPLACING bitmap with the filtered version - keep a copy yourself if
* you need the original!!! i.e. for COLORMODEL_IMAGEICON
*/
if (iImageFilter != null) {
bi = filterImage(bi);
}
return bi;
}
public void restore(OMGeometry source) {
super.restore(source);
if (source instanceof OMRaster) {
OMRaster raster = (OMRaster) source;
this.colors = DeepCopyUtil.deepCopy(raster.colors);
this.transparent = raster.transparent;
}
}
}