/*
* Copyright 2010-2015 Institut Pasteur.
*
* This file is part of Icy.
*
* Icy is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Icy 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Icy. If not, see <http://www.gnu.org/licenses/>.
*/
package icy.image;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.ComponentSampleModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferDouble;
import java.awt.image.DataBufferFloat;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferShort;
import java.awt.image.DataBufferUShort;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.media.jai.PlanarImage;
import icy.common.CollapsibleEvent;
import icy.common.UpdateEventHandler;
import icy.common.exception.TooLargeArrayException;
import icy.common.listener.ChangeListener;
import icy.image.IcyBufferedImageEvent.IcyBufferedImageEventType;
import icy.image.colormap.IcyColorMap;
import icy.image.colormap.LinearColorMap;
import icy.image.colormodel.IcyColorModel;
import icy.image.colormodel.IcyColorModelEvent;
import icy.image.colormodel.IcyColorModelListener;
import icy.image.lut.LUT;
import icy.math.ArrayMath;
import icy.math.MathUtil;
import icy.math.Scaler;
import icy.type.DataType;
import icy.type.TypeUtil;
import icy.type.collection.array.Array1DUtil;
import icy.type.collection.array.Array2DUtil;
import icy.type.collection.array.ArrayUtil;
import icy.type.collection.array.ByteArrayConvert;
import loci.formats.FormatException;
import loci.formats.IFormatReader;
import loci.formats.gui.SignedByteBuffer;
import loci.formats.gui.SignedShortBuffer;
import loci.formats.gui.UnsignedIntBuffer;
import plugins.kernel.importer.LociImporterPlugin;
/**
* @author stephane
*/
public class IcyBufferedImage extends BufferedImage implements IcyColorModelListener, ChangeListener
{
/**
* @deprecated Use {@link IcyBufferedImageUtil.FilterType} instead.
*/
@Deprecated
public static enum FilterType
{
NEAREST, BILINEAR, BICUBIC
};
protected static IcyBufferedImageUtil.FilterType getNewFilterType(FilterType ft)
{
switch (ft)
{
default:
case NEAREST:
return IcyBufferedImageUtil.FilterType.NEAREST;
case BILINEAR:
return IcyBufferedImageUtil.FilterType.BILINEAR;
case BICUBIC:
return IcyBufferedImageUtil.FilterType.BICUBIC;
}
}
/**
* Convert a list of BufferedImage to an IcyBufferedImage (multi component).<br>
* IMPORTANT : source images can be used as part or as the whole result<br>
* so consider them as "lost"
*
* @param imageList
* list of {@link BufferedImage}
* @return {@link IcyBufferedImage}
* @deprecated
* use {@link #createFrom} instead
*/
@Deprecated
public static IcyBufferedImage convert(List<BufferedImage> imageList)
{
return createFrom(imageList);
}
/**
* Create an IcyBufferedImage (multi component) from a list of BufferedImage.<br>
* IMPORTANT : source images can be used as part or as the whole result so consider them as
* 'lost'.
*
* @param imageList
* list of {@link BufferedImage}
* @return {@link IcyBufferedImage}
* @throws IllegalArgumentException
* if imageList is empty or contains incompatible images.
*/
public static IcyBufferedImage createFrom(List<? extends BufferedImage> imageList) throws IllegalArgumentException
{
if (imageList.size() == 0)
throw new IllegalArgumentException("imageList should contains at least 1 image");
final List<IcyBufferedImage> icyImageList = new ArrayList<IcyBufferedImage>();
// transform images to icy images
for (BufferedImage image : imageList)
icyImageList.add(IcyBufferedImage.createFrom(image));
final IcyBufferedImage firstImage = icyImageList.get(0);
if (icyImageList.size() == 1)
return firstImage;
final DataType dataType = firstImage.getDataType_();
final int width = firstImage.getWidth();
final int height = firstImage.getHeight();
// calculate channel number
int numChannel = 0;
for (IcyBufferedImage image : icyImageList)
numChannel += image.getSizeC();
final Object[] data = Array2DUtil.createArray(dataType, numChannel);
// get data from all images
int destC = 0;
for (IcyBufferedImage image : icyImageList)
{
if (dataType != image.getDataType_())
throw new IllegalArgumentException("All images contained in imageList should have the same dataType");
if ((width != image.getWidth()) || (height != image.getHeight()))
throw new IllegalArgumentException("All images contained in imageList should have the same dimension");
for (int c = 0; c < image.getSizeC(); c++)
data[destC++] = image.getDataXY(c);
}
// create and return the image
return new IcyBufferedImage(width, height, data, dataType.isSigned());
}
/**
* Convert a BufferedImage to an IcyBufferedImage.<br>
* IMPORTANT : source image can be used as part or as the whole result<br>
* so consider it as "lost"
*
* @param image
* {@link BufferedImage}
* @return {@link IcyBufferedImage}
* @deprecated
* use {@link #createFrom} instead
*/
@Deprecated
public static IcyBufferedImage convert(BufferedImage image)
{
return createFrom(image);
}
/**
* Create an IcyBufferedImage from a {@link PlanarImage}.<br>
* IMPORTANT : source image can be used as part or as the whole result<br>
* so consider it as lost.
*
* @param image
* {@link PlanarImage}
* @return {@link IcyBufferedImage}
*/
public static IcyBufferedImage createFrom(PlanarImage image, boolean signedDataType)
{
final DataBuffer db = image.getData().getDataBuffer();
final int w = image.getWidth();
final int h = image.getHeight();
if (db instanceof DataBufferByte)
return new IcyBufferedImage(w, h, ((DataBufferByte) db).getBankData(), signedDataType);
else if (db instanceof DataBufferShort)
return new IcyBufferedImage(w, h, ((DataBufferShort) db).getBankData(), signedDataType);
else if (db instanceof DataBufferUShort)
return new IcyBufferedImage(w, h, ((DataBufferUShort) db).getBankData(), signedDataType);
else if (db instanceof DataBufferInt)
return new IcyBufferedImage(w, h, ((DataBufferInt) db).getBankData(), signedDataType);
else if (db instanceof DataBufferFloat)
return new IcyBufferedImage(w, h, ((DataBufferFloat) db).getBankData(), true);
else if (db instanceof javax.media.jai.DataBufferFloat)
return new IcyBufferedImage(w, h, ((javax.media.jai.DataBufferFloat) db).getBankData(), true);
else if (db instanceof DataBufferDouble)
return new IcyBufferedImage(w, h, ((DataBufferDouble) db).getBankData(), true);
else if (db instanceof javax.media.jai.DataBufferDouble)
return new IcyBufferedImage(w, h, ((javax.media.jai.DataBufferDouble) db).getBankData(), true);
else
// JAI keep dataType and others stuff in their BufferedImage
return IcyBufferedImage.createFrom(image.getAsBufferedImage());
}
/**
* Create an IcyBufferedImage from a {@link PlanarImage}.<br>
* IMPORTANT : source image can be used as part or as the whole result<br>
* so consider it as lost.
*
* @param image
* {@link PlanarImage}
* @return {@link IcyBufferedImage}
*/
public static IcyBufferedImage createFrom(PlanarImage image)
{
return createFrom(image, false);
}
/**
* Create an IcyBufferedImage from a BufferedImage.<br>
* IMPORTANT : source image can be used as part or as the whole result<br>
* so consider it as lost.
*
* @param image
* {@link BufferedImage}
* @return {@link IcyBufferedImage}
*/
public static IcyBufferedImage createFrom(BufferedImage image)
{
// IcyBufferedImage --> no conversion needed
if (image instanceof IcyBufferedImage)
return (IcyBufferedImage) image;
// sort of IcyBufferedImage (JAI can return that type) --> no conversion needed
if (image.getColorModel() instanceof IcyColorModel)
return new IcyBufferedImage(
IcyColorModel.createInstance((IcyColorModel) image.getColorModel(), false, false),
image.getRaster());
final int w = image.getWidth();
final int h = image.getHeight();
final int type = image.getType();
final BufferedImage temp;
final Graphics g;
// we first want a component based image
switch (type)
{
case BufferedImage.TYPE_INT_RGB:
case BufferedImage.TYPE_INT_BGR:
case BufferedImage.TYPE_USHORT_555_RGB:
case BufferedImage.TYPE_USHORT_565_RGB:
temp = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR);
g = temp.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
break;
case BufferedImage.TYPE_INT_ARGB:
case BufferedImage.TYPE_INT_ARGB_PRE:
case BufferedImage.TYPE_4BYTE_ABGR_PRE:
temp = new BufferedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);
g = temp.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
break;
default:
// if we have severals components with an unknown / incompatible sampleModel
if ((image.getColorModel().getNumComponents() > 1)
&& (!(image.getSampleModel() instanceof ComponentSampleModel)))
{
// change it to a basic ABGR components image
temp = new BufferedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);
g = temp.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
}
else
temp = image;
break;
}
// convert initial data type in our data type
final DataType dataType = DataType.getDataTypeFromDataBufferType(temp.getColorModel().getTransferType());
// get number of components
final int numComponents = temp.getRaster().getNumBands();
// create a compatible image in our format
final IcyBufferedImage result = new IcyBufferedImage(w, h, numComponents, dataType);
// copy data from the source image
result.copyData(temp);
// in some case we want to restore colormaps from source image
switch (type)
{
case BufferedImage.TYPE_BYTE_BINARY:
case BufferedImage.TYPE_BYTE_INDEXED:
if (numComponents == 2)
result.setColorMaps(image);
break;
case BufferedImage.TYPE_INT_ARGB:
case BufferedImage.TYPE_INT_ARGB_PRE:
case BufferedImage.TYPE_4BYTE_ABGR_PRE:
case BufferedImage.TYPE_4BYTE_ABGR:
if (numComponents == 4)
result.setColorMap(3, LinearColorMap.alpha_, true);
break;
}
return result;
}
/**
* @deprecated Use
* {@link LociImporterPlugin#getThumbnailCompatible(IFormatReader, int, int, int)}
* instead.
*/
@Deprecated
public static IcyBufferedImage createCompatibleThumbnailFrom(IFormatReader reader, int z, int t)
throws FormatException, IOException
{
return LociImporterPlugin.getThumbnailCompatible(reader, z, t, -1);
}
/**
* @deprecated Use {@link LociImporterPlugin#getThumbnail(IFormatReader, int, int, int)}
* instead.
*/
@Deprecated
public static IcyBufferedImage createThumbnailFrom(IFormatReader reader, int z, int t)
throws FormatException, IOException
{
return LociImporterPlugin.getThumbnail(reader, z, t, -1);
}
/**
* @deprecated Use {@link LociImporterPlugin#getImage(IFormatReader, Rectangle, int, int, int)}
* instead.
*/
@Deprecated
public static IcyBufferedImage createFrom(IFormatReader reader, int x, int y, int w, int h, int z, int t, int c)
throws FormatException, IOException
{
return LociImporterPlugin.getImage(reader, new Rectangle(x, y, w, h), z, t, c);
}
/**
* @deprecated Use {@link LociImporterPlugin#getImage(IFormatReader, Rectangle, int, int)}
* instead.
*/
@Deprecated
public static IcyBufferedImage createFrom(IFormatReader reader, int z, int t) throws FormatException, IOException
{
return LociImporterPlugin.getImage(reader, null, z, t);
}
/**
* @deprecated Use {@link #IcyBufferedImage(int, int, IcyColorModel)} instead.
*/
@Deprecated
public static IcyBufferedImage createEmptyImage(int width, int height, IcyColorModel cm)
{
return new IcyBufferedImage(width, height, cm);
}
@SuppressWarnings("unused")
private static final int TYPE_CUSTOM = 0;
@SuppressWarnings("unused")
private static final int TYPE_INT_RGB = 1;
@SuppressWarnings("unused")
private static final int TYPE_INT_ARGB = 2;
@SuppressWarnings("unused")
private static final int TYPE_INT_ARGB_PRE = 3;
@SuppressWarnings("unused")
private static final int TYPE_INT_BGR = 4;
@SuppressWarnings("unused")
private static final int TYPE_3BYTE_BGR = 5;
@SuppressWarnings("unused")
private static final int TYPE_4BYTE_ABGR = 6;
@SuppressWarnings("unused")
private static final int TYPE_4BYTE_ABGR_PRE = 7;
@SuppressWarnings("unused")
private static final int TYPE_USHORT_565_RGB = 8;
@SuppressWarnings("unused")
private static final int TYPE_USHORT_555_RGB = 9;
@SuppressWarnings("unused")
private static final int TYPE_BYTE_GRAY = 10;
@SuppressWarnings("unused")
private static final int TYPE_USHORT_GRAY = 11;
@SuppressWarnings("unused")
private static final int TYPE_BYTE_BINARY = 12;
@SuppressWarnings("unused")
private static final int TYPE_BYTE_INDEXED = 13;
/**
* @deprecated
*/
@Deprecated
public static int TYPE_BYTE = TypeUtil.TYPE_BYTE;
/**
* @deprecated
*/
@Deprecated
public static int TYPE_DOUBLE = TypeUtil.TYPE_DOUBLE;
/**
* @deprecated
*/
@Deprecated
public static int TYPE_FLOAT = TypeUtil.TYPE_FLOAT;
/**
* @deprecated
*/
@Deprecated
public static int TYPE_INT = TypeUtil.TYPE_INT;
/**
* @deprecated
*/
@Deprecated
public static int TYPE_SHORT = TypeUtil.TYPE_SHORT;
/**
* @deprecated
*/
@Deprecated
public static int TYPE_UNDEFINED = TypeUtil.TYPE_UNDEFINED;
/**
* automatic update of channel bounds
*/
private boolean autoUpdateChannelBounds;
/**
* internal updater
*/
private final UpdateEventHandler updater;
/**
* listeners
*/
private final List<IcyBufferedImageListener> listeners;
/**
* Build an Icy formatted BufferedImage, takes an IcyColorModel and a WritableRaster as input
*
* @param cm
* {@link IcyColorModel}
* @param wr
* {@link WritableRaster}
* @param autoUpdateChannelBounds
* If true then channel bounds are automatically calculated.<br>
*/
protected IcyBufferedImage(IcyColorModel cm, WritableRaster wr, boolean autoUpdateChannelBounds)
{
super(cm, wr, false, null);
updater = new UpdateEventHandler(this, false);
listeners = new ArrayList<IcyBufferedImageListener>();
// automatic update of channel bounds
this.autoUpdateChannelBounds = autoUpdateChannelBounds;
// add listener to colorModel
cm.addListener(this);
}
/**
* Create an Icy formatted BufferedImage, takes an IcyColorModel and a WritableRaster as input
*
* @param cm
* {@link IcyColorModel}
* @param wr
* {@link WritableRaster}
*/
protected IcyBufferedImage(IcyColorModel cm, WritableRaster wr)
{
this(cm, wr, false);
}
/**
* Create an Icy formatted BufferedImage with specified IcyColorModel, width and height.<br>
* Private version, {@link IcyColorModel} is directly used internally.
*/
protected IcyBufferedImage(IcyColorModel cm, int width, int height)
{
this(cm, cm.createCompatibleWritableRaster(width, height), false);
}
/**
* Create an Icy formatted BufferedImage with specified colorModel, width, height and input data.<br>
* ex : <code>img = new IcyBufferedImage(640, 480, new byte[3][640 * 480], true);</code><br>
* <br>
* This constructor provides the best performance for massive image creation and computation as it allow you to
* directly send the data array and disable the channel bounds calculation.
*
* @param cm
* the color model
* @param width
* @param height
* @param data
* image data<br>
* Should be a 2D array with first dimension giving the number of component<br>
* and second dimension equals to <code>width * height</code><br>
* The array data type specify the internal data type and should match the given color
* model parameter.
* @param autoUpdateChannelBounds
* If true then channel bounds are automatically calculated.<br>
* When set to false, you have to set bounds manually by calling
* {@link #updateChannelsBounds()} or #setC
*/
protected IcyBufferedImage(IcyColorModel cm, Object[] data, int width, int height, boolean autoUpdateChannelBounds)
{
this(cm, cm.createWritableRaster(data, width, height), autoUpdateChannelBounds);
// data has been modified
dataChanged();
}
/**
* Create an Icy formatted BufferedImage with specified width, height and input data.<br>
* ex : <code>img = new IcyBufferedImage(640, 480, new byte[3][640 * 480], true);</code><br>
* <br>
* This constructor provides the best performance for massive image creation and computation as
* it allow you to directly send the data array and disable the channel bounds calculation.
*
* @param width
* @param height
* @param data
* image data<br>
* Should be a 2D array with first dimension giving the number of component<br>
* and second dimension equals to <code>width * height</code><br>
* The array data type specify the internal data type.
* @param signed
* use signed data for data type
* @param autoUpdateChannelBounds
* If true then channel bounds are automatically calculated.<br>
* When set to false, you have to set bounds manually by calling
* {@link #updateChannelsBounds()} or #setC
*/
public IcyBufferedImage(int width, int height, Object[] data, boolean signed, boolean autoUpdateChannelBounds)
{
this(IcyColorModel.createInstance(data.length, ArrayUtil.getDataType(data[0], signed)), data, width, height,
autoUpdateChannelBounds);
}
/**
* Create an Icy formatted BufferedImage with specified width, height and input data.<br>
* ex : <code>img = new IcyBufferedImage(640, 480, new byte[3][640 * 480]);</code>
*
* @param width
* @param height
* @param data
* image data<br>
* Should be a 2D array with first dimension giving the number of component<br>
* and second dimension equals to <code>width * height</code><br>
* The array data type specify the internal data type.
* @param signed
* use signed data for data type
*/
public IcyBufferedImage(int width, int height, Object[] data, boolean signed)
{
this(IcyColorModel.createInstance(data.length, ArrayUtil.getDataType(data[0], signed)), data, width, height,
false);
}
/**
* Create an Icy formatted BufferedImage with specified width, height and input data.<br>
* ex : <code>img = new IcyBufferedImage(640, 480, new byte[3][640 * 480]);</code>
*
* @param width
* @param height
* @param data
* image data<br>
* Should be a 2D array with first dimension giving the number of component<br>
* and second dimension equals to <code>width * height</code><br>
* The array data type specify the internal data type.
*/
public IcyBufferedImage(int width, int height, Object[] data)
{
this(width, height, data, false);
}
/**
* Create a single channel Icy formatted BufferedImage with specified width, height and input data.<br>
* ex : <code>img = new IcyBufferedImage(640, 480, new byte[640 * 480], true);</code><br>
* <br>
* This constructor provides the best performance for massive image creation and computation as it allow you to
* directly send the data array and disable the channel bounds calculation.
*
* @param width
* @param height
* @param data
* image data array.<br>
* The length of the array should be equals to <code>width * height</code>.<br>
* The array data type specify the internal data type.
* @param signed
* use signed data for data type
* @param autoUpdateChannelBounds
* If true then channel bounds are automatically calculated.<br>
* When set to false, you have to set bounds manually by calling
* {@link #updateChannelsBounds()} or #setC
* @see #IcyBufferedImage(int, int, Object[], boolean, boolean)
*/
public IcyBufferedImage(int width, int height, Object data, boolean signed, boolean autoUpdateChannelBounds)
{
this(width, height, ArrayUtil.encapsulate(data), signed, autoUpdateChannelBounds);
}
/**
* Create a single channel Icy formatted BufferedImage with specified width, height and input
* data.<br>
* ex : <code>img = new IcyBufferedImage(640, 480, new byte[640 * 480]);</code>
*
* @param width
* @param height
* @param data
* image data<br>
* The length of the array should be equals to <code>width * height</code>.<br>
* The array data type specify the internal data type.
* @param signed
* use signed data for data type
*/
public IcyBufferedImage(int width, int height, Object data, boolean signed)
{
this(width, height, ArrayUtil.encapsulate(data), signed);
}
/**
* Create a single channel Icy formatted BufferedImage with specified width, height and input
* data.<br>
* ex : <code>img = new IcyBufferedImage(640, 480, new byte[640 * 480]);</code>
*
* @param width
* @param height
* @param data
* image data<br>
* The length of the array should be equals to <code>width * height</code>.<br>
* The array data type specify the internal data type.
*/
public IcyBufferedImage(int width, int height, Object data)
{
this(width, height, ArrayUtil.encapsulate(data));
}
/**
* Create an ICY formatted BufferedImage with specified width, height,<br>
* number of component and dataType.
*
* @param width
* @param height
* @param numComponents
* @param dataType
* image data type {@link DataType}
*/
public IcyBufferedImage(int width, int height, int numComponents, DataType dataType)
{
this(IcyColorModel.createInstance(numComponents, dataType), width, height);
}
/**
* Create an ICY formatted BufferedImage with specified width, height and IcyColorModel
* type.<br>
*/
public IcyBufferedImage(int width, int height, IcyColorModel cm)
{
this(width, height, cm.getNumComponents(), cm.getDataType_());
}
/**
* @deprecated use {@link #IcyBufferedImage(int, int, int, DataType)} instead
*/
@Deprecated
public IcyBufferedImage(int width, int height, int numComponents, int dataType, boolean signed)
{
this(IcyColorModel.createInstance(numComponents, dataType, signed), width, height);
}
/**
* @deprecated use {@link #IcyBufferedImage(int, int, int, DataType)} instead
*/
@Deprecated
public IcyBufferedImage(int width, int height, int numComponents, int dataType)
{
this(IcyColorModel.createInstance(numComponents, dataType, false), width, height);
}
/**
* @return true is channel bounds are automatically updated when image data is modified.
* @see #setAutoUpdateChannelBounds(boolean)
*/
public boolean getAutoUpdateChannelBounds()
{
return autoUpdateChannelBounds;
}
/**
* If set to <code>true</code> (default) then channel bounds will be automatically recalculated
* when image data is modified.<br>
* This can consume some time if you make many updates on a large image.<br>
* In this case you should do your updates in a {@link #beginUpdate()} ... {@link #endUpdate()}
* block to avoid
* severals recalculation.
*/
public void setAutoUpdateChannelBounds(boolean value)
{
if (autoUpdateChannelBounds != value)
{
if (value)
updateChannelsBounds();
autoUpdateChannelBounds = value;
}
}
/**
* @deprecated Uses
* {@link IcyBufferedImageUtil#toBufferedImage(IcyBufferedImage, BufferedImage, LUT)}
* instead.
*/
@Deprecated
public BufferedImage convertToBufferedImage(BufferedImage out, LUT lut)
{
return IcyBufferedImageUtil.toBufferedImage(this, out, lut);
}
/**
* @deprecated Uses
* {@link IcyBufferedImageUtil#toBufferedImage(IcyBufferedImage, BufferedImage)}
* instead.
*/
@Deprecated
public BufferedImage convertToBufferedImage(BufferedImage out)
{
return IcyBufferedImageUtil.toBufferedImage(this, out);
}
/**
* @deprecated Uses
* {@link IcyBufferedImageUtil#toBufferedImage(IcyBufferedImage, BufferedImage, LUT)}
* instead.
*/
@Deprecated
public BufferedImage getARGBImage(LUT lut, BufferedImage out)
{
return IcyBufferedImageUtil.getARGBImage(this, lut, out);
}
/**
* @deprecated Use {@link IcyBufferedImageUtil#toBufferedImage(IcyBufferedImage, BufferedImage)}
* instead.
*/
@Deprecated
public BufferedImage getARGBImage(BufferedImage out)
{
return IcyBufferedImageUtil.getARGBImage(this, out);
}
/**
* @deprecated Use {@link IcyBufferedImageUtil#getARGBImage(IcyBufferedImage, LUT)} instead.
*/
@Deprecated
public BufferedImage getARGBImage(LUT lut)
{
return IcyBufferedImageUtil.getARGBImage(this, lut);
}
/**
* @deprecated Use {@link IcyBufferedImageUtil#getARGBImage(IcyBufferedImage)} instead.
*/
@Deprecated
public BufferedImage getARGBImage()
{
return IcyBufferedImageUtil.getARGBImage(this);
}
/**
* @deprecated Uses
* {@link IcyBufferedImageUtil#convertType(IcyBufferedImage, DataType, Scaler[])}
* instead.
*/
@Deprecated
public IcyBufferedImage convertToType(DataType dataType, Scaler scaler)
{
return IcyBufferedImageUtil.convertToType(this, dataType, scaler);
}
/**
* @deprecated Uses
* {@link IcyBufferedImageUtil#convertType(IcyBufferedImage,DataType, Scaler[])}
* instead.
*/
@Deprecated
public IcyBufferedImage convertToType(int dataType, boolean signed, Scaler scaler)
{
return IcyBufferedImageUtil.convertToType(this, DataType.getDataType(dataType, signed), scaler);
}
/**
* @deprecated Uses
* {@link IcyBufferedImageUtil#convertToType(IcyBufferedImage, DataType, boolean)}
* instead.
*/
@Deprecated
public IcyBufferedImage convertToType(DataType dataType, boolean rescale)
{
return IcyBufferedImageUtil.convertToType(this, dataType, rescale);
}
/**
* @deprecated Uses
* {@link IcyBufferedImageUtil#convertToType(IcyBufferedImage,DataType, boolean)}
* instead
*/
@Deprecated
public IcyBufferedImage convertToType(int dataType, boolean signed, boolean rescale)
{
return convertToType(DataType.getDataType(dataType, signed), rescale);
}
/**
* @deprecated Use {@link IcyBufferedImageUtil#toBufferedImage(IcyBufferedImage, int, LUT)}
* instead
*/
@Deprecated
public BufferedImage convertToBufferedImage(LUT lut, int imageType)
{
return IcyBufferedImageUtil.toBufferedImage(this, imageType, lut);
}
/**
* @deprecated Use {@link IcyBufferedImageUtil#toBufferedImage(IcyBufferedImage, int, LUT)}
* instead
*/
@Deprecated
public BufferedImage convertToBufferedImage(int imageType, LUT lut)
{
return IcyBufferedImageUtil.toBufferedImage(this, imageType, lut);
}
/**
* @deprecated Use {@link IcyBufferedImageUtil#getCopy(IcyBufferedImage)} instead
*/
@Deprecated
public IcyBufferedImage getCopy()
{
return IcyBufferedImageUtil.getCopy(this);
}
/**
* @deprecated Uses
* {@link IcyBufferedImageUtil#getSubImage(IcyBufferedImage, int, int, int, int)}
* instead
*/
@Deprecated
public IcyBufferedImage getSubImageCopy(int x, int y, int w, int h)
{
return IcyBufferedImageUtil.getSubImage(this, x, y, w, h);
}
/**
* Not supported on IcyBufferedImage, use getSubImageCopy instead.
*/
@Deprecated
@Override
public IcyBufferedImage getSubimage(int x, int y, int w, int h)
{
// IcyBufferedImage doesn't support subImaging (incorrect draw and copy operation)
throw new UnsupportedOperationException(
"IcyBufferedImage doesn't support getSubimage method, use getSubImageCopy instead.");
// return new IcyBufferedImage(getIcyColorModel(), getRaster().createWritableChild(x, y, w,
// h, 0, 0, null));
}
/**
* Return a single component image corresponding to the component c of current image.<br>
* This actually create a new image which share its data with internal image
* so any modifications to one affect the other.<br>
* if <code>(c == -1)</code> then current image is directly returned<br>
* if <code>((c == 0) || (sizeC == 1))</code> then current image is directly returned<br>
* if <code>((c < 0) || (c >= sizeC))</code> then it returns <code>null</code>
*
* @see IcyBufferedImageUtil#extractChannel(IcyBufferedImage, int)
* @since version 1.0.3.3b
*/
public IcyBufferedImage getImage(int c)
{
if (c == -1)
return this;
final int sizeC = getSizeC();
if ((c < 0) || (c >= sizeC))
return null;
if (sizeC == 1)
return this;
return new IcyBufferedImage(getWidth(), getHeight(), getDataXY(c), isSignedDataType());
}
/**
* @deprecated Use {@link IcyBufferedImageUtil#extractChannel(IcyBufferedImage, int)} instead.
*/
@Deprecated
public IcyBufferedImage extractChannel(int channelNumber)
{
return IcyBufferedImageUtil.extractChannel(this, channelNumber);
}
/**
* @deprecated Use {@link IcyBufferedImageUtil#extractChannels(IcyBufferedImage, List)} instead.
*/
@Deprecated
public IcyBufferedImage extractChannels(List<Integer> channelNumbers)
{
return IcyBufferedImageUtil.extractChannels(this, channelNumbers);
}
/**
* @deprecated Use {@link IcyBufferedImageUtil#extractChannel(IcyBufferedImage, int)} instead
*/
@Deprecated
public IcyBufferedImage extractBand(int bandNumber)
{
return IcyBufferedImageUtil.extractChannel(this, bandNumber);
}
/**
* @deprecated Use {@link IcyBufferedImageUtil#extractChannels(IcyBufferedImage, List)} instead
*/
@Deprecated
public IcyBufferedImage extractBands(List<Integer> bandNumbers)
{
return IcyBufferedImageUtil.extractChannels(this, bandNumbers);
}
/**
* @deprecated Uses
* {@link IcyBufferedImageUtil#scale(IcyBufferedImage, int, int, boolean, int, int, IcyBufferedImageUtil.FilterType)}
* instead.
*/
@Deprecated
public IcyBufferedImage getScaledCopy(int width, int height, boolean resizeContent, int xAlign, int yAlign,
FilterType filterType)
{
return IcyBufferedImageUtil.scale(this, width, height, resizeContent, xAlign, yAlign,
getNewFilterType(filterType));
}
/**
* @deprecated Uses
* {@link IcyBufferedImageUtil#scale(IcyBufferedImage, int, int, boolean, int, int)}
* instead.
*/
@Deprecated
public IcyBufferedImage getScaledCopy(int width, int height, boolean resizeContent, int xAlign, int yAlign)
{
return IcyBufferedImageUtil.scale(this, width, height, resizeContent, xAlign, yAlign);
}
/**
* @deprecated Uses
* {@link IcyBufferedImageUtil#scale(IcyBufferedImage, int, int, IcyBufferedImageUtil.FilterType)}
* instead.
*/
@Deprecated
public IcyBufferedImage getScaledCopy(int width, int height, FilterType filterType)
{
return IcyBufferedImageUtil.scale(this, width, height, getNewFilterType(filterType));
}
/**
* @deprecated Use {@link IcyBufferedImageUtil#scale(IcyBufferedImage, int, int)} instead.
*/
@Deprecated
public IcyBufferedImage getScaledCopy(int width, int height)
{
return IcyBufferedImageUtil.scale(this, width, height);
}
/**
* @deprecated Use {@link IcyBufferedImageUtil#translate(IcyBufferedImage, int, int, int)}
* instead.
*/
@Deprecated
public void translate(int dx, int dy, int channel)
{
IcyBufferedImageUtil.translate(this, dx, dy, channel);
}
/**
* @deprecated Use {@link IcyBufferedImageUtil#translate(IcyBufferedImage, int, int)} instead.
*/
@Deprecated
public void translate(int dx, int dy)
{
IcyBufferedImageUtil.translate(this, dx, dy);
}
/**
* Get calculated image channel bounds (min and max values)
*/
protected double[] getCalculatedChannelBounds(int channel)
{
final DataType dataType = getDataType_();
final boolean signed = dataType.isSigned();
final Object data = getDataXY(channel);
final double min = ArrayMath.min(data, signed);
final double max = ArrayMath.max(data, signed);
return new double[] {min, max};
}
/**
* Adjust specified bounds depending internal data type
*/
protected double[] adjustBoundsForDataType(double[] bounds)
{
double min, max;
min = bounds[0];
max = bounds[1];
// only for integer data type
if (!isFloatDataType())
{
// we force min to 0 if > 0
if (min > 0d)
min = 0d;
// we force max to 0 if < 0
if (max < 0d)
max = 0d;
}
final DataType dataType = getDataType_();
switch (dataType.getJavaType())
{
case BYTE:
// return default bounds ([0..255] / [-128..127])
return dataType.getDefaultBounds();
case SHORT:
case INT:
case LONG:
min = MathUtil.prevPow2((long) min + 1);
max = MathUtil.nextPow2Mask((long) max);
break;
case FLOAT:
case DOUBLE:
// if [min..max] is included in [-1..1]
if ((min >= -1d) && (max <= 1d))
{
min = MathUtil.prevPow10(min);
max = MathUtil.nextPow10(max);
}
break;
}
return new double[] {min, max};
}
/**
* Get the data type minimum value.
*/
public double getDataTypeMin()
{
return getDataType_().getMinValue();
}
/**
* Get the data type maximum value.
*/
public double getDataTypeMax()
{
return getDataType_().getMaxValue();
}
/**
* Get data type bounds (min and max values)
*/
public double[] getDataTypeBounds()
{
return new double[] {getDataTypeMin(), getDataTypeMax()};
}
/**
* Get the minimum type value for the specified channel.
*/
public double getChannelTypeMin(int channel)
{
return getIcyColorModel().getComponentAbsMinValue(channel);
}
/**
* Get the maximum type value for the specified channel.
*/
public double getChannelTypeMax(int channel)
{
return getIcyColorModel().getComponentAbsMaxValue(channel);
}
/**
* Get type bounds (min and max values) for the specified channel.
*/
public double[] getChannelTypeBounds(int channel)
{
return getIcyColorModel().getComponentAbsBounds(channel);
}
/**
* Get type bounds (min and max values) for all channels.
*/
public double[][] getChannelsTypeBounds()
{
final int sizeC = getSizeC();
final double[][] result = new double[sizeC][];
for (int c = 0; c < sizeC; c++)
result[c] = getChannelTypeBounds(c);
return result;
}
/**
* Get global type bounds (min and max values) for all channels.
*/
public double[] getChannelsGlobalTypeBounds()
{
final int sizeC = getSizeC();
final double[] result = getChannelTypeBounds(0);
for (int c = 1; c < sizeC; c++)
{
final double[] bounds = getChannelTypeBounds(c);
result[0] = Math.min(bounds[0], result[0]);
result[1] = Math.max(bounds[1], result[1]);
}
return result;
}
/**
* @deprecated Use {@link #getChannelsGlobalTypeBounds()} instead.
*/
@Deprecated
public double[] getChannelTypeGlobalBounds()
{
return getChannelsGlobalTypeBounds();
}
/**
* @deprecated Use {@link #getChannelTypeGlobalBounds()} instead.
*/
@Deprecated
public double[] getGlobalChannelTypeBounds()
{
return getChannelTypeGlobalBounds();
}
/**
* @deprecated Use {@link #getChannelTypeMin(int)} instead.
*/
@Deprecated
public double getComponentAbsMinValue(int component)
{
return getChannelTypeMin(component);
}
/**
* @deprecated Use {@link #getChannelTypeMax(int)} instead.
*/
@Deprecated
public double getComponentAbsMaxValue(int component)
{
return getChannelTypeMax(component);
}
/**
* @deprecated Use {@link #getChannelTypeBounds(int)} instead.
*/
@Deprecated
public double[] getComponentAbsBounds(int component)
{
return getChannelTypeBounds(component);
}
/**
* @deprecated Use {@link #getChannelsTypeBounds()} instead.
*/
@Deprecated
public double[][] getComponentsAbsBounds()
{
return getChannelsTypeBounds();
}
/**
* @deprecated Use {@link #getGlobalChannelTypeBounds()} instead.
*/
@Deprecated
public double[] getGlobalComponentAbsBounds()
{
return getChannelTypeGlobalBounds();
}
/**
* Get the minimum value for the specified channel.
*/
public double getChannelMin(int channel)
{
return getIcyColorModel().getComponentUserMinValue(channel);
}
/**
* Get maximum value for the specified channel.
*/
public double getChannelMax(int channel)
{
return getIcyColorModel().getComponentUserMaxValue(channel);
}
/**
* Get bounds (min and max values) for the specified channel.
*/
public double[] getChannelBounds(int channel)
{
return getIcyColorModel().getComponentUserBounds(channel);
}
/**
* Get bounds (min and max values) for all channels.
*/
public double[][] getChannelsBounds()
{
final int sizeC = getSizeC();
final double[][] result = new double[sizeC][];
for (int c = 0; c < sizeC; c++)
result[c] = getChannelBounds(c);
return result;
}
/**
* Get global bounds (min and max values) for all channels.
*/
public double[] getChannelsGlobalBounds()
{
final int sizeC = getSizeC();
final double[] result = new double[2];
result[0] = Double.MAX_VALUE;
result[1] = -Double.MAX_VALUE;
for (int c = 0; c < sizeC; c++)
{
final double[] bounds = getChannelBounds(c);
if (bounds[0] < result[0])
result[0] = bounds[0];
if (bounds[1] > result[1])
result[1] = bounds[1];
}
return result;
}
/**
* @deprecated Use {@link #getChannelMin(int)} instead.
*/
@Deprecated
public double getComponentUserMinValue(int component)
{
return getChannelMin(component);
}
/**
* @deprecated Use {@link #getChannelMax(int)} instead.
*/
@Deprecated
public double getComponentUserMaxValue(int component)
{
return getChannelMax(component);
}
/**
* @deprecated Use {@link #getChannelBounds(int)} instead.
*/
@Deprecated
public double[] getComponentUserBounds(int component)
{
return getChannelBounds(component);
}
/**
* @deprecated Use {@link #getChannelsBounds()} instead.
*/
@Deprecated
public double[][] getComponentsUserBounds()
{
return getChannelsBounds();
}
/**
* Set the preferred data type minimum value for the specified channel.
*/
public void setChannelTypeMin(int channel, double min)
{
getIcyColorModel().setComponentAbsMinValue(channel, min);
}
/**
* Set the preferred data type maximum value for the specified channel.
*/
public void setChannelTypeMax(int channel, double max)
{
getIcyColorModel().setComponentAbsMaxValue(channel, max);
}
/**
* /**
* Set the preferred data type min and max values for the specified channel.
*/
public void setChannelTypeBounds(int channel, double min, double max)
{
getIcyColorModel().setComponentAbsBounds(channel, min, max);
}
/**
* Set the preferred data type bounds (min and max values) for all channels.
*/
public void setChannelsTypeBounds(double[][] bounds)
{
getIcyColorModel().setComponentsAbsBounds(bounds);
}
/**
* @deprecated Use {@link #setChannelTypeMin(int, double)} instead.
*/
@Deprecated
public void setComponentAbsMinValue(int component, double min)
{
setChannelTypeMin(component, min);
}
/**
* @deprecated Use {@link #setChannelTypeMax(int, double)} instead.
*/
@Deprecated
public void setComponentAbsMaxValue(int component, double max)
{
setChannelTypeMax(component, max);
}
/**
* @deprecated Use {@link #setChannelTypeBounds(int, double, double)} instead.
*/
@Deprecated
public void setComponentAbsBounds(int component, double[] bounds)
{
setChannelTypeBounds(component, bounds[0], bounds[1]);
}
/**
* @deprecated Use {@link #setChannelTypeBounds(int, double, double)} instead.
*/
@Deprecated
public void setComponentAbsBounds(int component, double min, double max)
{
setChannelTypeBounds(component, min, max);
}
/**
* @deprecated Use {@link #setChannelsTypeBounds(double[][])} instead.
*/
@Deprecated
public void setComponentsAbsBounds(double[][] bounds)
{
setChannelsTypeBounds(bounds);
}
/**
* Set channel minimum value.
*/
public void setChannelMin(int channel, double min)
{
final IcyColorModel cm = getIcyColorModel();
if ((min < cm.getComponentAbsMinValue(channel)))
cm.setComponentAbsMinValue(channel, min);
cm.setComponentUserMinValue(channel, min);
}
/**
* Set channel maximum value.
*/
public void setChannelMax(int channel, double max)
{
final IcyColorModel cm = getIcyColorModel();
if ((max > cm.getComponentAbsMaxValue(channel)))
cm.setComponentAbsMinValue(channel, max);
cm.setComponentUserMaxValue(channel, max);
}
/**
* Set channel bounds (min and max values)
*/
public void setChannelBounds(int channel, double min, double max)
{
final IcyColorModel cm = getIcyColorModel();
final double[] typeBounds = cm.getComponentAbsBounds(channel);
if ((min < typeBounds[0]) || (max > typeBounds[1]))
cm.setComponentAbsBounds(channel, min, max);
cm.setComponentUserBounds(channel, min, max);
}
/**
* Set all channel bounds (min and max values)
*/
public void setChannelsBounds(double[][] bounds)
{
// we use the setChannelBounds(..) method so we do range check
for (int c = 0; c < bounds.length; c++)
{
final double[] b = bounds[c];
setChannelBounds(c, b[0], b[1]);
}
}
/**
* @deprecated Use {@link #setChannelMin(int, double)} instead.
*/
@Deprecated
public void setComponentUserMinValue(int component, double min)
{
setChannelMin(component, min);
}
/**
* @deprecated Use {@link #setChannelMax(int, double)} instead.
*/
@Deprecated
public void setComponentUserMaxValue(int component, double max)
{
setChannelMax(component, max);
}
/**
* @deprecated Use {@link #setChannelBounds(int, double, double)} instead.
*/
@Deprecated
public void setComponentUserBounds(int component, double[] bounds)
{
setChannelBounds(component, bounds[0], bounds[1]);
}
/**
* @deprecated Use {@link #setChannelBounds(int, double, double)} instead
*/
@Deprecated
public void setComponentUserBounds(int component, double min, double max)
{
setChannelBounds(component, min, max);
}
/**
* @deprecated Use {@link #setChannelsBounds(double[][])} instead.
*/
@Deprecated
public void setComponentsUserBounds(double[][] bounds)
{
setChannelsBounds(bounds);
}
/**
* Update channels bounds (min and max values).
*/
public void updateChannelsBounds()
{
final IcyColorModel cm = getIcyColorModel();
if (cm != null)
{
final int sizeC = getSizeC();
for (int c = 0; c < sizeC; c++)
{
// get data type bounds
final double[] bounds = getCalculatedChannelBounds(c);
cm.setComponentAbsBounds(c, adjustBoundsForDataType(bounds));
cm.setComponentUserBounds(c, bounds);
// we do user bounds adjustment on "non ALPHA" component only
// if (cm.getColorMap(c).getType() != IcyColorMapType.ALPHA)
// cm.setComponentUserBounds(c, bounds);
}
}
}
/**
* @deprecated Use {@link #updateChannelsBounds()} instead.
*/
@SuppressWarnings("unused")
@Deprecated
public void updateComponentsBounds(boolean updateChannelBounds, boolean adjustByteToo)
{
updateChannelsBounds();
}
/**
* @deprecated Use {@link #updateChannelsBounds()} instead.
*/
@SuppressWarnings("unused")
@Deprecated
public void updateComponentsBounds(boolean updateUserBounds)
{
updateChannelsBounds();
}
/**
* Return true if point is inside the image
*/
public boolean isInside(Point p)
{
return isInside(p.x, p.y);
}
/**
* Return true if point of coordinate (x, y) is inside the image
*/
public boolean isInside(int x, int y)
{
return (x >= 0) && (x < getSizeX()) && (y >= 0) && (y < getSizeY());
}
/**
* Return true if point of coordinate (x, y) is inside the image
*/
public boolean isInside(double x, double y)
{
return (x >= 0) && (x < getSizeX()) && (y >= 0) && (y < getSizeY());
}
/**
* Return the IcyColorModel
*
* @return IcyColorModel
*/
public IcyColorModel getIcyColorModel()
{
return (IcyColorModel) getColorModel();
}
/**
* Return the data type of this image
*
* @return dataType
* @see DataType
*/
public DataType getDataType_()
{
return getIcyColorModel().getDataType_();
}
/**
* @deprecated use {@link #getDataType_()} instead
*/
@Deprecated
public int getDataType()
{
return getIcyColorModel().getDataType();
}
/**
* Return true if this is a float data type image
*/
public boolean isFloatDataType()
{
return getDataType_().isFloat();
}
/**
* Return true if this is a signed data type image
*/
public boolean isSignedDataType()
{
return getDataType_().isSigned();
}
/**
* @deprecated Use {@link #getSizeC()} instead.
*/
@Deprecated
public int getNumComponents()
{
return getSizeC();
}
/**
* @return the number of components of this image
*/
public int getSizeC()
{
return getColorModel().getNumComponents();
}
/**
* @return the width of the image
*/
public int getSizeX()
{
return getWidth();
}
/**
* @return the height of the image
*/
public int getSizeY()
{
return getHeight();
}
/**
* Return 2D dimension of image {sizeX, sizeY}
*/
public Dimension getDimension()
{
return new Dimension(getSizeX(), getSizeY());
}
/**
* Return 2D bounds of image {0, 0, sizeX, sizeY}
*/
public Rectangle getBounds()
{
return new Rectangle(getSizeX(), getSizeY());
}
/**
* Return the number of sample.<br>
* This is equivalent to<br>
* <code>getSizeX() * getSizeY() * getSizeC()</code>
*/
public int getNumSample()
{
return getSizeX() * getSizeY() * getSizeC();
}
/**
* Return the offset for specified (x, y) location
*/
public int getOffset(int x, int y)
{
return (y * getWidth()) + x;
}
/**
* create a compatible LUT for this image.
*
* @param createColorModel
* set to <code>true</code> to create a LUT using a new compatible ColorModel else it
* will use the image
* internal ColorModel
*/
public LUT createCompatibleLUT(boolean createColorModel)
{
final IcyColorModel cm;
if (createColorModel)
cm = IcyColorModel.createInstance(getIcyColorModel(), false, false);
else
cm = getIcyColorModel();
return new LUT(cm);
}
/**
* create a compatible LUT for this image
*/
public LUT createCompatibleLUT()
{
return createCompatibleLUT(true);
}
/**
* @deprecated No attached LUT to an image.<br/>
* Use {@link #createCompatibleLUT(boolean)} instead.
*/
@Deprecated
public LUT getLUT()
{
return createCompatibleLUT();
}
/**
* Return a direct reference to internal 2D array data [C][XY]
*/
public Object getDataXYC()
{
switch (getDataType_().getJavaType())
{
case BYTE:
return getDataXYCAsByte();
case SHORT:
return getDataXYCAsShort();
case INT:
return getDataXYCAsInt();
case FLOAT:
return getDataXYCAsFloat();
case DOUBLE:
return getDataXYCAsDouble();
default:
return null;
}
}
/**
* Return a direct reference to internal 1D array data [XY] for specified c
*/
public Object getDataXY(int c)
{
switch (getDataType_().getJavaType())
{
case BYTE:
return getDataXYAsByte(c);
case SHORT:
return getDataXYAsShort(c);
case INT:
return getDataXYAsInt(c);
case FLOAT:
return getDataXYAsFloat(c);
case DOUBLE:
return getDataXYAsDouble(c);
default:
return null;
}
}
/**
* Return a 1D array data copy [XYC] of internal 2D array data [C][XY]
*/
public Object getDataCopyXYC()
{
return getDataCopyXYC(null, 0);
}
/**
* Return a 1D array data copy [XYC] of internal 2D array data [C][XY]<br>
* If (out != null) then it's used to store result at the specified offset
*/
public Object getDataCopyXYC(Object out, int offset)
{
switch (getDataType_().getJavaType())
{
case BYTE:
return getDataCopyXYCAsByte((byte[]) out, offset);
case SHORT:
return getDataCopyXYCAsShort((short[]) out, offset);
case INT:
return getDataCopyXYCAsInt((int[]) out, offset);
case FLOAT:
return getDataCopyXYCAsFloat((float[]) out, offset);
case DOUBLE:
return getDataCopyXYCAsDouble((double[]) out, offset);
default:
return null;
}
}
/**
* Return a 1D array data copy [XY] of internal 1D array data [XY] for specified c
*/
public Object getDataCopyXY(int c)
{
return getDataCopyXY(c, null, 0);
}
/**
* Return a 1D array data copy [XY] of internal 1D array data [XY] for specified c<br>
* If (out != null) then it's used to store result at the specified offset
*/
public Object getDataCopyXY(int c, Object out, int offset)
{
switch (getDataType_().getJavaType())
{
case BYTE:
return getDataCopyXYAsByte(c, (byte[]) out, offset);
case SHORT:
return getDataCopyXYAsShort(c, (short[]) out, offset);
case INT:
return getDataCopyXYAsInt(c, (int[]) out, offset);
case FLOAT:
return getDataCopyXYAsFloat(c, (float[]) out, offset);
case DOUBLE:
return getDataCopyXYAsDouble(c, (double[]) out, offset);
default:
return null;
}
}
/**
* Return a 1D array data copy [CXY] of internal 2D array data [C][XY]
*/
public Object getDataCopyCXY()
{
return getDataCopyCXY(null, 0);
}
/**
* Return a 1D array data copy [CXY] of internal 2D array data [C][XY]<br>
* If (out != null) then it's used to store result at the specified offset
*/
public Object getDataCopyCXY(Object out, int offset)
{
switch (getDataType_().getJavaType())
{
case BYTE:
return getDataCopyCXYAsByte((byte[]) out, offset);
case SHORT:
return getDataCopyCXYAsShort((short[]) out, offset);
case INT:
return getDataCopyCXYAsInt((int[]) out, offset);
case FLOAT:
return getDataCopyCXYAsFloat((float[]) out, offset);
case DOUBLE:
return getDataCopyCXYAsDouble((double[]) out, offset);
default:
return null;
}
}
/**
* Return a 1D array data copy [C] of specified (x, y) position
*/
public Object getDataCopyC(int x, int y)
{
return getDataCopyC(x, y, null, 0);
}
/**
* Return a 1D array data copy [C] of specified (x, y) position<br>
* If (out != null) then it's used to store result at the specified offset
*/
public Object getDataCopyC(int x, int y, Object out, int offset)
{
switch (getDataType_().getJavaType())
{
case BYTE:
return getDataCopyCAsByte(x, y, (byte[]) out, offset);
case SHORT:
return getDataCopyCAsShort(x, y, (short[]) out, offset);
case INT:
return getDataCopyCAsInt(x, y, (int[]) out, offset);
case FLOAT:
return getDataCopyCAsFloat(x, y, (float[]) out, offset);
case DOUBLE:
return getDataCopyCAsDouble(x, y, (double[]) out, offset);
default:
return null;
}
}
/**
* Set internal 1D byte array data ([XY]) for specified component
*/
public void setDataXY(int c, Object values)
{
ArrayUtil.arrayToArray(values, getDataXY(c), getDataType_().isSigned());
// notify data changed
dataChanged();
}
/**
* Set 1D array data [C] of specified (x, y) position
*/
public void setDataC(int x, int y, Object values)
{
switch (getDataType_().getJavaType())
{
case BYTE:
setDataCAsByte(x, y, (byte[]) values);
break;
case SHORT:
setDataCAsShort(x, y, (short[]) values);
break;
case INT:
setDataCAsInt(x, y, (int[]) values);
break;
case FLOAT:
setDataCAsFloat(x, y, (float[]) values);
break;
case DOUBLE:
setDataCAsDouble(x, y, (double[]) values);
break;
}
}
/**
* Return a direct reference to internal 2D array data [C][XY]
*/
public byte[][] getDataXYCAsByte()
{
return ((DataBufferByte) getRaster().getDataBuffer()).getBankData();
}
/**
* Return a direct reference to internal 2D array data [C][XY]
*/
public short[][] getDataXYCAsShort()
{
final DataBuffer db = getRaster().getDataBuffer();
if (db instanceof DataBufferUShort)
return ((DataBufferUShort) db).getBankData();
return ((DataBufferShort) db).getBankData();
}
/**
* Return a direct reference to internal 2D array data [C][XY]
*/
public int[][] getDataXYCAsInt()
{
return ((DataBufferInt) getRaster().getDataBuffer()).getBankData();
}
/**
* Return a direct reference to internal 2D array data [C][XY]
*/
public float[][] getDataXYCAsFloat()
{
return ((DataBufferFloat) getRaster().getDataBuffer()).getBankData();
}
/**
* Return a direct reference to internal 2D array data [C][XY]
*/
public double[][] getDataXYCAsDouble()
{
return ((DataBufferDouble) getRaster().getDataBuffer()).getBankData();
}
/**
* Return a direct reference to internal 1D array data [XY] for specified c
*/
public byte[] getDataXYAsByte(int c)
{
return ((DataBufferByte) getRaster().getDataBuffer()).getData(c);
}
/**
* Return a direct reference to internal 1D array data [XY] for specified c
*/
public short[] getDataXYAsShort(int c)
{
final DataBuffer db = getRaster().getDataBuffer();
if (db instanceof DataBufferUShort)
return ((DataBufferUShort) db).getData(c);
return ((DataBufferShort) db).getData(c);
}
/**
* Return a direct reference to internal 1D array data [XY] for specified c
*/
public int[] getDataXYAsInt(int c)
{
return ((DataBufferInt) getRaster().getDataBuffer()).getData(c);
}
/**
* Return a direct reference to internal 1D array data [XY] for specified c
*/
public float[] getDataXYAsFloat(int c)
{
return ((DataBufferFloat) getRaster().getDataBuffer()).getData(c);
}
/**
* Return a direct reference to internal 1D array data [XY] for specified c
*/
public double[] getDataXYAsDouble(int c)
{
return ((DataBufferDouble) getRaster().getDataBuffer()).getData(c);
}
/**
* Return a 1D array data copy [XYC] of internal 2D array data [C][XY]
*/
public byte[] getDataCopyXYCAsByte()
{
return getDataCopyXYCAsByte(null, 0);
}
/**
* Return a 1D array data copy [XYC] of internal 2D array data [C][XY] If (out != null) then
* it's used to store result at the specified offset
*/
public byte[] getDataCopyXYCAsByte(byte[] out, int off)
{
final long sizeC = getSizeC();
final long len = (long) getSizeX() * (long) getSizeY();
if ((len * sizeC) >= Integer.MAX_VALUE)
throw new TooLargeArrayException();
final byte[][] banks = ((DataBufferByte) getRaster().getDataBuffer()).getBankData();
final byte[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeC));
int offset = off;
for (int c = 0; c < sizeC; c++)
{
final byte[] src = banks[c];
System.arraycopy(src, 0, result, offset, (int) len);
offset += len;
}
return result;
}
/**
* Return a 1D array data copy [XYC] of internal 2D array data [C][XY]
*/
public short[] getDataCopyXYCAsShort()
{
return getDataCopyXYCAsShort(null, 0);
}
/**
* Return a 1D array data copy [XYC] of internal 2D array data [C][XY] If (out != null) then
* it's used to store result at the specified offset
*/
public short[] getDataCopyXYCAsShort(short[] out, int off)
{
final long sizeC = getSizeC();
final long len = (long) getSizeX() * (long) getSizeY();
if ((len * sizeC) >= Integer.MAX_VALUE)
throw new TooLargeArrayException();
final DataBuffer db = getRaster().getDataBuffer();
final short[][] banks;
if (db instanceof DataBufferUShort)
banks = ((DataBufferUShort) db).getBankData();
else
banks = ((DataBufferShort) db).getBankData();
final short[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeC));
int offset = off;
for (int c = 0; c < sizeC; c++)
{
final short[] src = banks[c];
System.arraycopy(src, 0, result, offset, (int) len);
offset += len;
}
return result;
}
/**
* Return a 1D array data copy [XYC] of internal 2D array data [C][XY]
*/
public int[] getDataCopyXYCAsInt()
{
return getDataCopyXYCAsInt(null, 0);
}
/**
* Return a 1D array data copy [XYC] of internal 2D array data [C][XY] If (out != null) then
* it's used to store result at the specified offset
*/
public int[] getDataCopyXYCAsInt(int[] out, int off)
{
final long sizeC = getSizeC();
final long len = (long) getSizeX() * (long) getSizeY();
if ((len * sizeC) >= Integer.MAX_VALUE)
throw new TooLargeArrayException();
final int[][] banks = ((DataBufferInt) getRaster().getDataBuffer()).getBankData();
final int[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeC));
int offset = off;
for (int c = 0; c < sizeC; c++)
{
final int[] src = banks[c];
System.arraycopy(src, 0, result, offset, (int) len);
offset += len;
}
return result;
}
/**
* Return a 1D array data copy [XYC] of internal 2D array data [C][XY]
*/
public float[] getDataCopyXYCAsFloat()
{
return getDataCopyXYCAsFloat(null, 0);
}
/**
* Return a 1D array data copy [XYC] of internal 2D array data [C][XY] If (out != null) then
* it's used to store result at the specified offset
*/
public float[] getDataCopyXYCAsFloat(float[] out, int off)
{
final long sizeC = getSizeC();
final long len = (long) getSizeX() * (long) getSizeY();
if ((len * sizeC) >= Integer.MAX_VALUE)
throw new TooLargeArrayException();
final float[][] banks = ((DataBufferFloat) getRaster().getDataBuffer()).getBankData();
final float[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeC));
int offset = off;
for (int c = 0; c < sizeC; c++)
{
final float[] src = banks[c];
System.arraycopy(src, 0, result, offset, (int) len);
offset += len;
}
return result;
}
/**
* Return a 1D array data copy [XYC] of internal 2D array data [C][XY]
*/
public double[] getDataCopyXYCAsDouble()
{
return getDataCopyXYCAsDouble(null, 0);
}
/**
* Return a 1D array data copy [XYC] of internal 2D array data [C][XY] If (out != null) then
* it's used to store result at the specified offset
*/
public double[] getDataCopyXYCAsDouble(double[] out, int off)
{
final long sizeC = getSizeC();
final long len = (long) getSizeX() * (long) getSizeY();
if ((len * sizeC) >= Integer.MAX_VALUE)
throw new TooLargeArrayException();
final double[][] banks = ((DataBufferDouble) getRaster().getDataBuffer()).getBankData();
final double[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeC));
int offset = off;
for (int c = 0; c < sizeC; c++)
{
final double[] src = banks[c];
System.arraycopy(src, 0, result, offset, (int) len);
offset += len;
}
return result;
}
/**
* Return a 1D array data copy [XY] of internal 1D array data [XY] for specified c<br>
*/
public byte[] getDataCopyXYAsByte(int c)
{
return getDataCopyXYAsByte(c, null, 0);
}
/**
* Return a 1D array data copy [XY] of internal 1D array data [XY] for specified c<br>
* If (out != null) then it's used to store result at the specified offset
*/
public byte[] getDataCopyXYAsByte(int c, byte[] out, int off)
{
final int len = getSizeX() * getSizeY();
final byte[] src = ((DataBufferByte) getRaster().getDataBuffer()).getData(c);
final byte[] result = Array1DUtil.allocIfNull(out, len);
System.arraycopy(src, 0, result, off, len);
return result;
}
/**
* Return a 1D array data copy [XY] of internal 1D array data [XY] for specified c<br>
*/
public short[] getDataCopyXYAsShort(int c)
{
return getDataCopyXYAsShort(c, null, 0);
}
/**
* Return a 1D array data copy [XY] of internal 1D array data [XY] for specified c<br>
* If (out != null) then it's used to store result at the specified offset
*/
public short[] getDataCopyXYAsShort(int c, short[] out, int off)
{
final int len = getSizeX() * getSizeY();
final DataBuffer db = getRaster().getDataBuffer();
final short[] src;
if (db instanceof DataBufferUShort)
src = ((DataBufferUShort) db).getData(c);
else
src = ((DataBufferShort) db).getData(c);
final short[] result = Array1DUtil.allocIfNull(out, len);
System.arraycopy(src, 0, result, off, len);
return result;
}
/**
* Return a 1D array data copy [XY] of internal 1D array data [XY] for specified c<br>
*/
public int[] getDataCopyXYAsInt(int c)
{
return getDataCopyXYAsInt(c, null, 0);
}
/**
* Return a 1D array data copy [XY] of internal 1D array data [XY] for specified c<br>
* If (out != null) then it's used to store result at the specified offset
*/
public int[] getDataCopyXYAsInt(int c, int[] out, int off)
{
final int len = getSizeX() * getSizeY();
final int[] src = ((DataBufferInt) getRaster().getDataBuffer()).getData(c);
final int[] result = Array1DUtil.allocIfNull(out, len);
System.arraycopy(src, 0, result, off, len);
return result;
}
/**
* Return a 1D array data copy [XY] of internal 1D array data [XY] for specified c<br>
*/
public float[] getDataCopyXYAsFloat(int c)
{
return getDataCopyXYAsFloat(c, null, 0);
}
/**
* Return a 1D array data copy [XY] of internal 1D array data [XY] for specified c<br>
* If (out != null) then it's used to store result at the specified offset
*/
public float[] getDataCopyXYAsFloat(int c, float[] out, int off)
{
final int len = getSizeX() * getSizeY();
final float[] src = ((DataBufferFloat) getRaster().getDataBuffer()).getData(c);
final float[] result = Array1DUtil.allocIfNull(out, len);
System.arraycopy(src, 0, result, off, len);
return result;
}
/**
* Return a 1D array data copy [XY] of internal 1D array data [XY] for specified c<br>
*/
public double[] getDataCopyXYAsDouble(int c)
{
return getDataCopyXYAsDouble(c, null, 0);
}
/**
* Return a 1D array data copy [XY] of internal 1D array data [XY] for specified c<br>
* If (out != null) then it's used to store result at the specified offset
*/
public double[] getDataCopyXYAsDouble(int c, double[] out, int off)
{
final int len = getSizeX() * getSizeY();
final double[] src = ((DataBufferDouble) getRaster().getDataBuffer()).getData(c);
final double[] result = Array1DUtil.allocIfNull(out, len);
System.arraycopy(src, 0, result, off, len);
return result;
}
/**
* Return a 1D array data copy [CXY] of internal 2D array data [C][XY]<br>
*/
public byte[] getDataCopyCXYAsByte()
{
return getDataCopyCXYAsByte(null, 0);
}
/**
* Return a 1D array data copy [CXY] of internal 2D array data [C][XY]<br>
* If (out != null) then it's used to store result at the specified offset
*/
public byte[] getDataCopyCXYAsByte(byte[] out, int off)
{
final long sizeC = getSizeC();
final long len = (long) getSizeX() * (long) getSizeY();
if ((len * sizeC) >= Integer.MAX_VALUE)
throw new TooLargeArrayException();
final byte[][] banks = ((DataBufferByte) getRaster().getDataBuffer()).getBankData();
final byte[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeC));
for (int c = 0; c < sizeC; c++)
{
final byte[] src = banks[c];
int offset = c + off;
for (int i = 0; i < len; i++, offset += sizeC)
result[offset] = src[i];
}
return result;
}
/**
* Return a 1D array data copy [CXY] of internal 2D array data [C][XY]<br>
*/
public short[] getDataCopyCXYAsShort()
{
return getDataCopyCXYAsShort(null, 0);
}
/**
* Return a 1D array data copy [CXY] of internal 2D array data [C][XY]<br>
* If (out != null) then it's used to store result at the specified offset
*/
public short[] getDataCopyCXYAsShort(short[] out, int off)
{
final long sizeC = getSizeC();
final long len = (long) getSizeX() * (long) getSizeY();
if ((len * sizeC) >= Integer.MAX_VALUE)
throw new TooLargeArrayException();
final DataBuffer db = getRaster().getDataBuffer();
final short[][] banks;
if (db instanceof DataBufferUShort)
banks = ((DataBufferUShort) db).getBankData();
else
banks = ((DataBufferShort) db).getBankData();
final short[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeC));
for (int c = 0; c < sizeC; c++)
{
final short[] src = banks[c];
int offset = c + off;
for (int i = 0; i < len; i++, offset += sizeC)
result[offset] = src[i];
}
return result;
}
/**
* Return a 1D array data copy [CXY] of internal 2D array data [C][XY]<br>
*/
public int[] getDataCopyCXYAsInt()
{
return getDataCopyCXYAsInt(null, 0);
}
/**
* Return a 1D array data copy [CXY] of internal 2D array data [C][XY]<br>
* If (out != null) then it's used to store result at the specified offset
*/
public int[] getDataCopyCXYAsInt(int[] out, int off)
{
final long sizeC = getSizeC();
final long len = (long) getSizeX() * (long) getSizeY();
if ((len * sizeC) >= Integer.MAX_VALUE)
throw new TooLargeArrayException();
final int[][] banks = ((DataBufferInt) getRaster().getDataBuffer()).getBankData();
final int[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeC));
for (int c = 0; c < sizeC; c++)
{
final int[] src = banks[c];
int offset = c + off;
for (int i = 0; i < len; i++, offset += sizeC)
result[offset] = src[i];
}
return result;
}
/**
* Return a 1D array data copy [CXY] of internal 2D array data [C][XY]<br>
*/
public float[] getDataCopyCXYAsFloat()
{
return getDataCopyCXYAsFloat(null, 0);
}
/**
* Return a 1D array data copy [CXY] of internal 2D array data [C][XY]<br>
* If (out != null) then it's used to store result at the specified offset
*/
public float[] getDataCopyCXYAsFloat(float[] out, int off)
{
final long sizeC = getSizeC();
final long len = (long) getSizeX() * (long) getSizeY();
if ((len * sizeC) >= Integer.MAX_VALUE)
throw new TooLargeArrayException();
final float[][] banks = ((DataBufferFloat) getRaster().getDataBuffer()).getBankData();
final float[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeC));
for (int c = 0; c < sizeC; c++)
{
final float[] src = banks[c];
int offset = c + off;
for (int i = 0; i < len; i++, offset += sizeC)
result[offset] = src[i];
}
return result;
}
/**
* Return a 1D array data copy [CXY] of internal 2D array data [C][XY]<br>
*/
public double[] getDataCopyCXYAsDouble()
{
return getDataCopyCXYAsDouble(null, 0);
}
/**
* Return a 1D array data copy [CXY] of internal 2D array data [C][XY]<br>
* If (out != null) then it's used to store result at the specified offset
*/
public double[] getDataCopyCXYAsDouble(double[] out, int off)
{
final long sizeC = getSizeC();
final long len = (long) getSizeX() * (long) getSizeY();
if ((len * sizeC) >= Integer.MAX_VALUE)
throw new TooLargeArrayException();
final double[][] banks = ((DataBufferDouble) getRaster().getDataBuffer()).getBankData();
final double[] result = Array1DUtil.allocIfNull(out, (int) (len * sizeC));
for (int c = 0; c < sizeC; c++)
{
final double[] src = banks[c];
int offset = c + off;
for (int i = 0; i < len; i++, offset += sizeC)
result[offset] = src[i];
}
return result;
}
/**
* Return a 1D array data copy [C] of specified (x, y) position
*/
public byte[] getDataCopyCAsByte(int x, int y)
{
return getDataCopyCAsByte(x, y, null, 0);
}
/**
* Return a 1D array data copy [C] of specified (x, y) position<br>
* If (out != null) then it's used to store result at the specified offset
*/
public byte[] getDataCopyCAsByte(int x, int y, byte[] out, int off)
{
final int sizeC = getSizeC();
final int offset = x + (y * getWidth());
final byte[][] data = ((DataBufferByte) getRaster().getDataBuffer()).getBankData();
final byte[] result = Array1DUtil.allocIfNull(out, sizeC);
for (int c = 0; c < sizeC; c++)
// ignore band offset as it's always 0 here
result[c + off] = data[c][offset];
return result;
}
/**
* Return a 1D array data copy [C] of specified (x, y) position
*/
public short[] getDataCopyCAsShort(int x, int y)
{
return getDataCopyCAsShort(x, y, null, 0);
}
/**
* Return a 1D array data copy [C] of specified (x, y) position<br>
* If (out != null) then it's used to store result at the specified offset
*/
public short[] getDataCopyCAsShort(int x, int y, short[] out, int off)
{
final int sizeC = getSizeC();
final int offset = x + (y * getWidth());
final DataBuffer db = getRaster().getDataBuffer();
final short[][] data;
if (db instanceof DataBufferUShort)
data = ((DataBufferUShort) db).getBankData();
else
data = ((DataBufferShort) db).getBankData();
final short[] result = Array1DUtil.allocIfNull(out, sizeC);
for (int c = 0; c < sizeC; c++)
// ignore band offset as it's always 0 here
result[c + off] = data[c][offset];
return result;
}
/**
* Return a 1D array data copy [C] of specified (x, y) position
*/
public int[] getDataCopyCAsInt(int x, int y)
{
return getDataCopyCAsInt(x, y, null, 0);
}
/**
* Return a 1D array data copy [C] of specified (x, y) position<br>
* If (out != null) then it's used to store result at the specified offset
*/
public int[] getDataCopyCAsInt(int x, int y, int[] out, int off)
{
final int sizeC = getSizeC();
final int offset = x + (y * getWidth());
final int[][] data = ((DataBufferInt) getRaster().getDataBuffer()).getBankData();
final int[] result = Array1DUtil.allocIfNull(out, sizeC);
for (int c = 0; c < sizeC; c++)
// ignore band offset as it's always 0 here
result[c + off] = data[c][offset];
return result;
}
/**
* Return a 1D array data copy [C] of specified (x, y) position
*/
public float[] getDataCopyCAsFloat(int x, int y)
{
return getDataCopyCAsFloat(x, y, null, 0);
}
/**
* Return a 1D array data copy [C] of specified (x, y) position<br>
* If (out != null) then it's used to store result at the specified offset
*/
public float[] getDataCopyCAsFloat(int x, int y, float[] out, int off)
{
final int sizeC = getSizeC();
final int offset = x + (y * getWidth());
final float[][] data = ((DataBufferFloat) getRaster().getDataBuffer()).getBankData();
final float[] result = Array1DUtil.allocIfNull(out, sizeC);
for (int c = 0; c < sizeC; c++)
// ignore band offset as it's always 0 here
result[c + off] = data[c][offset];
return result;
}
/**
* Return a 1D array data copy [C] of specified (x, y) position
*/
public double[] getDataCopyCAsDouble(int x, int y)
{
return getDataCopyCAsDouble(x, y, null, 0);
}
/**
* Return a 1D array data copy [C] of specified (x, y) position<br>
* If (out != null) then it's used to store result at the specified offset
*/
public double[] getDataCopyCAsDouble(int x, int y, double[] out, int off)
{
final int sizeC = getSizeC();
final int offset = x + (y * getWidth());
final double[][] data = ((DataBufferDouble) getRaster().getDataBuffer()).getBankData();
final double[] result = Array1DUtil.allocIfNull(out, sizeC);
for (int c = 0; c < sizeC; c++)
// ignore band offset as it's always 0 here
result[c + off] = data[c][offset];
return result;
}
/**
* Set internal 1D byte array data ([XY]) for specified component
*/
public void setDataXYAsByte(int c, byte[] values)
{
System.arraycopy(values, 0, getDataXYAsByte(c), 0, getSizeX() * getSizeY());
// notify data changed
dataChanged();
}
/**
* Set internal 1D byte array data ([XY]) for specified component
*/
public void setDataXYAsShort(int c, short[] values)
{
System.arraycopy(values, 0, getDataXYAsShort(c), 0, getSizeX() * getSizeY());
// notify data changed
dataChanged();
}
/**
* Set internal 1D byte array data ([XY]) for specified component
*/
public void setDataXYAsInt(int c, int[] values)
{
System.arraycopy(values, 0, getDataXYAsInt(c), 0, getSizeX() * getSizeY());
// notify data changed
dataChanged();
}
/**
* Set internal 1D byte array data ([XY]) for specified component
*/
public void setDataXYAsFloat(int c, float[] values)
{
System.arraycopy(values, 0, getDataXYAsFloat(c), 0, getSizeX() * getSizeY());
// notify data changed
dataChanged();
}
/**
* Set internal 1D byte array data ([XY]) for specified component
*/
public void setDataXYAsDouble(int c, double[] values)
{
System.arraycopy(values, 0, getDataXYAsDouble(c), 0, getSizeX() * getSizeY());
// notify data changed
dataChanged();
}
/**
* Set 1D array data [C] of specified (x, y) position
*/
public void setDataCAsByte(int x, int y, byte[] values)
{
final int offset = x + (y * getWidth());
final int len = values.length;
final byte[][] data = ((DataBufferByte) getRaster().getDataBuffer()).getBankData();
for (int comp = 0; comp < len; comp++)
// ignore band offset as it's always 0 here
data[comp][offset] = values[comp];
// notify data changed
dataChanged();
}
/**
* Set 1D array data [C] of specified (x, y) position
*/
public void setDataCAsShort(int x, int y, short[] values)
{
final int offset = x + (y * getWidth());
final int len = values.length;
final DataBuffer db = getRaster().getDataBuffer();
final short[][] data;
if (db instanceof DataBufferUShort)
data = ((DataBufferUShort) db).getBankData();
else
data = ((DataBufferShort) db).getBankData();
for (int comp = 0; comp < len; comp++)
// ignore band offset as it's always 0 here
data[comp][offset] = values[comp];
// notify data changed
dataChanged();
}
/**
* Set 1D array data [C] of specified (x, y) position
*/
public void setDataCAsInt(int x, int y, int[] values)
{
final int offset = x + (y * getWidth());
final int len = values.length;
final int[][] data = ((DataBufferInt) getRaster().getDataBuffer()).getBankData();
for (int comp = 0; comp < len; comp++)
// ignore band offset as it's always 0 here
data[comp][offset] = values[comp];
// notify data changed
dataChanged();
}
/**
* Set 1D array data [C] of specified (x, y) position
*/
public void setDataCAsFloat(int x, int y, float[] values)
{
final int offset = x + (y * getWidth());
final int len = values.length;
final float[][] data = ((DataBufferFloat) getRaster().getDataBuffer()).getBankData();
for (int comp = 0; comp < len; comp++)
// ignore band offset as it's always 0 here
data[comp][offset] = values[comp];
// notify data changed
dataChanged();
}
/**
* Set 1D array data [C] of specified (x, y) position
*/
public void setDataCAsDouble(int x, int y, double[] values)
{
final int offset = x + (y * getWidth());
final int len = values.length;
final double[][] data = ((DataBufferDouble) getRaster().getDataBuffer()).getBankData();
for (int comp = 0; comp < len; comp++)
// ignore band offset as it's always 0 here
data[comp][offset] = values[comp];
// notify data changed
dataChanged();
}
/**
* Return the value located at (x, y, c) position as a double
* whatever is the internal data type
*/
public double getData(int x, int y, int c)
{
return Array1DUtil.getValue(getDataXY(c), getOffset(x, y), getDataType_());
}
/**
* Set the value located at (x, y, c) position as a double
* whatever is the internal data type
*/
public void setData(int x, int y, int c, double value)
{
Array1DUtil.setValue(getDataXY(c), getOffset(x, y), getDataType_(), value);
// notify data changed
dataChanged();
}
/**
* Return the value located at (x, y, c) position
*/
public byte getDataAsByte(int x, int y, int c)
{
// ignore band offset as it's always 0 here
return (((DataBufferByte) getRaster().getDataBuffer()).getData(c))[x + (y * getWidth())];
}
/**
* Set the value located at (x, y, c) position
*/
public void setDataAsByte(int x, int y, int c, byte value)
{
// ignore band offset as it's always 0 here
(((DataBufferByte) getRaster().getDataBuffer()).getData(c))[x + (y * getWidth())] = value;
// notify data changed
dataChanged();
}
/**
* Return the value located at (x, y, c) position
*/
public short getDataAsShort(int x, int y, int c)
{
// ignore band offset as it's always 0 here
final DataBuffer db = getRaster().getDataBuffer();
if (db instanceof DataBufferUShort)
return (((DataBufferUShort) db).getData(c))[x + (y * getWidth())];
return (((DataBufferShort) db).getData(c))[x + (y * getWidth())];
}
/**
* Set the value located at (x, y, c) position
*/
public void setDataAsShort(int x, int y, int c, short value)
{
final DataBuffer db = getRaster().getDataBuffer();
if (db instanceof DataBufferUShort)
// ignore band offset as it's always 0 here
(((DataBufferUShort) db).getData(c))[x + (y * getWidth())] = value;
else
(((DataBufferShort) db).getData(c))[x + (y * getWidth())] = value;
// notify data changed
dataChanged();
}
/**
* Return the value located at (x, y, c) position
*/
public int getDataAsInt(int x, int y, int c)
{
// ignore band offset as it's always 0 here
return (((DataBufferInt) getRaster().getDataBuffer()).getData(c))[x + (y * getWidth())];
}
/**
* Set the value located at (x, y, c) position
*/
public void setDataAsInt(int x, int y, int c, int value)
{
// ignore band offset as it's always 0 here
(((DataBufferInt) getRaster().getDataBuffer()).getData(c))[x + (y * getWidth())] = value;
// notify data changed
dataChanged();
}
/**
* Return the value located at (x, y, c) position
*/
public float getDataAsFloat(int x, int y, int c)
{
// ignore band offset as it's always 0 here
return (((DataBufferFloat) getRaster().getDataBuffer()).getData(c))[x + (y * getWidth())];
}
/**
* Set the value located at (x, y, c) position
*/
public void setDataAsFloat(int x, int y, int c, float value)
{
// ignore band offset as it's always 0 here
(((DataBufferFloat) getRaster().getDataBuffer()).getData(c))[x + (y * getWidth())] = value;
// notify data changed
dataChanged();
}
/**
* Return the value located at (x, y, c) position
*/
public double getDataAsDouble(int x, int y, int c)
{
// ignore band offset as it's always 0 here
return (((DataBufferDouble) getRaster().getDataBuffer()).getData(c))[x + (y * getWidth())];
}
/**
* Set the value located at (x, y, c) position
*/
public void setDataAsDouble(int x, int y, int c, double value)
{
// ignore band offset as it's always 0 here
(((DataBufferDouble) getRaster().getDataBuffer()).getData(c))[x + (y * getWidth())] = value;
// notify data changed
dataChanged();
}
/**
* Same as getRGB but by using the specified LUT instead of internal one
*
* @see java.awt.image.BufferedImage#getRGB(int, int)
*/
public int getRGB(int x, int y, LUT lut)
{
return getIcyColorModel().getRGB(getRaster().getDataElements(x, y, null), lut);
}
/**
* Internal copy data from an icy image (notify data changed)
*
* @param srcImage
* source icy image
* @param srcRect
* source region
* @param dstPt
* destination X,Y position
* @param srcChannel
* source channel
* @param dstChannel
* destination channel
*/
protected void fastCopyData(IcyBufferedImage srcImage, Rectangle srcRect, Point dstPt, int srcChannel,
int dstChannel)
{
final int srcSizeX = srcImage.getSizeX();
final int dstSizeX = getSizeX();
// limit to source image size
Rectangle adjSrcRect = srcRect.intersection(new Rectangle(srcSizeX, srcImage.getSizeY()));
// negative destination x position
if (dstPt.x < 0)
// adjust source rect
adjSrcRect.x += -dstPt.x;
// negative destination y position
if (dstPt.y < 0)
// adjust source rect
adjSrcRect.y += -dstPt.y;
final Rectangle dstRect = new Rectangle(dstPt.x, dstPt.y, adjSrcRect.width, adjSrcRect.height);
// limit to destination image size
final Rectangle adjDstRect = dstRect.intersection(new Rectangle(dstSizeX, getSizeY()));
final int w = Math.min(adjSrcRect.width, adjDstRect.width);
final int h = Math.min(adjSrcRect.height, adjDstRect.height);
// nothing to copy
if ((w == 0) || (h == 0))
return;
final boolean signed = srcImage.getDataType_().isSigned();
final Object src = srcImage.getDataXY(srcChannel);
final Object dst = getDataXY(dstChannel);
int srcOffset = adjSrcRect.x + (adjSrcRect.y * srcSizeX);
int dstOffset = adjDstRect.x + (adjDstRect.y * dstSizeX);
for (int y = 0; y < h; y++)
{
ArrayUtil.arrayToArray(src, srcOffset, dst, dstOffset, w, signed);
srcOffset += srcSizeX;
dstOffset += dstSizeX;
}
// notify data changed
dataChanged();
}
/**
* Internal copy data from a compatible image (notify data changed)
*
* @param srcImage
* source image
*/
protected void internalCopyData(int srcChannel, int dstChannel, DataBuffer src_db, DataBuffer dst_db, int[] indices,
int[] band_offsets, int[] bank_offsets, int scanlineStride_src, int pixelStride_src, int maxX, int maxY,
int decOffsetSrc)
{
final int scanlineStride_dst = getSizeX();
final int bank = indices[srcChannel];
final int offset = band_offsets[srcChannel] + bank_offsets[bank] - decOffsetSrc;
switch (getDataType_().getJavaType())
{
case BYTE:
{
final byte[] src;
final byte[] dst = ((DataBufferByte) dst_db).getData(dstChannel);
// LOCI use its own buffer classes
if (src_db instanceof SignedByteBuffer)
src = ((SignedByteBuffer) src_db).getData(bank);
else
src = ((DataBufferByte) src_db).getData(bank);
int offset_src = offset;
int offset_dst = 0;
for (int y = 0; y < maxY; y++)
{
int offset_src_pix = offset_src;
int offset_dst_pix = offset_dst;
for (int x = 0; x < maxX; x++)
{
dst[offset_dst_pix] = src[offset_src_pix];
offset_src_pix += pixelStride_src;
offset_dst_pix++;
}
offset_src += scanlineStride_src;
offset_dst += scanlineStride_dst;
}
break;
}
case SHORT:
{
final short[] src;
final short[] dst;
// LOCI use its own buffer classes
if (src_db instanceof SignedShortBuffer)
src = ((SignedShortBuffer) src_db).getData(bank);
else if (src_db instanceof DataBufferShort)
src = ((DataBufferShort) src_db).getData(bank);
else
src = ((DataBufferUShort) src_db).getData(bank);
if (dst_db instanceof DataBufferShort)
dst = ((DataBufferShort) dst_db).getData(dstChannel);
else
dst = ((DataBufferUShort) dst_db).getData(dstChannel);
int offset_src = offset;
int offset_dst = 0;
for (int y = 0; y < maxY; y++)
{
int offset_src_pix = offset_src;
int offset_dst_pix = offset_dst;
for (int x = 0; x < maxX; x++)
{
dst[offset_dst_pix] = src[offset_src_pix];
offset_src_pix += pixelStride_src;
offset_dst_pix++;
}
offset_src += scanlineStride_src;
offset_dst += scanlineStride_dst;
}
break;
}
case INT:
{
final int[] src;
final int[] dst = ((DataBufferInt) dst_db).getData(dstChannel);
// LOCI use its own buffer classes
if (src_db instanceof UnsignedIntBuffer)
src = ((UnsignedIntBuffer) src_db).getData(bank);
else
src = ((DataBufferInt) src_db).getData(bank);
int offset_src = offset;
int offset_dst = 0;
for (int y = 0; y < maxY; y++)
{
int offset_src_pix = offset_src;
int offset_dst_pix = offset_dst;
for (int x = 0; x < maxX; x++)
{
dst[offset_dst_pix] = src[offset_src_pix];
offset_src_pix += pixelStride_src;
offset_dst_pix++;
}
offset_src += scanlineStride_src;
offset_dst += scanlineStride_dst;
}
break;
}
case FLOAT:
{
final float[] src = ((DataBufferFloat) src_db).getData(bank);
final float[] dst = ((DataBufferFloat) dst_db).getData(dstChannel);
int offset_src = offset;
int offset_dst = 0;
for (int y = 0; y < maxY; y++)
{
int offset_src_pix = offset_src;
int offset_dst_pix = offset_dst;
for (int x = 0; x < maxX; x++)
{
dst[offset_dst_pix] = src[offset_src_pix];
offset_src_pix += pixelStride_src;
offset_dst_pix++;
}
offset_src += scanlineStride_src;
offset_dst += scanlineStride_dst;
}
break;
}
case DOUBLE:
{
final double[] src = ((DataBufferDouble) src_db).getData(bank);
final double[] dst = ((DataBufferDouble) dst_db).getData(dstChannel);
int offset_src = offset;
int offset_dst = 0;
for (int y = 0; y < maxY; y++)
{
int offset_src_pix = offset_src;
int offset_dst_pix = offset_dst;
for (int x = 0; x < maxX; x++)
{
dst[offset_dst_pix] = src[offset_src_pix];
offset_src_pix += pixelStride_src;
offset_dst_pix++;
}
offset_src += scanlineStride_src;
offset_dst += scanlineStride_dst;
}
break;
}
}
}
/**
* Copy channel data from a compatible sample model and writable raster (notify data changed).
*
* @param sampleModel
* source sample model
* @param raster
* source writable raster to read data from
* @param srcChannel
* source channel (-1 for all channels)
* @param dstChannel
* destination channel (only significant if source channel != -1)
* @return <code>true</code> if the copy operation succeed, <code>false</code> otherwise
*/
public boolean copyData(ComponentSampleModel sampleModel, WritableRaster raster, int srcChannel, int dstChannel)
{
// not compatible sample model
if (DataType.getDataTypeFromDataBufferType(sampleModel.getDataType()) != getDataType_())
return false;
final DataBuffer src_db = raster.getDataBuffer();
final DataBuffer dst_db = getRaster().getDataBuffer();
final int[] indices = sampleModel.getBankIndices();
final int[] band_offsets = sampleModel.getBandOffsets();
final int[] bank_offsets = src_db.getOffsets();
final int scanlineStride_src = sampleModel.getScanlineStride();
final int pixelStride_src = sampleModel.getPixelStride();
final int maxX = Math.min(getSizeX(), sampleModel.getWidth());
final int maxY = Math.min(getSizeY(), sampleModel.getHeight());
final int decOffsetSrc = raster.getSampleModelTranslateX()
+ (raster.getSampleModelTranslateY() * scanlineStride_src);
// all channels
if (srcChannel == -1)
{
final int numBands = sampleModel.getNumBands();
for (int band = 0; band < numBands; band++)
internalCopyData(band, band, src_db, dst_db, indices, band_offsets, bank_offsets, scanlineStride_src,
pixelStride_src, maxX, maxY, decOffsetSrc);
}
else
{
internalCopyData(srcChannel, dstChannel, src_db, dst_db, indices, band_offsets, bank_offsets,
scanlineStride_src, pixelStride_src, maxX, maxY, decOffsetSrc);
}
// notify data changed
dataChanged();
return true;
}
/**
* Copy data to specified location from an data array.
*
* @param data
* source data array (should be same type than image data type)
* @param dataDim
* source data dimension (array length should be >= Dimension.width * Dimension.heigth)
* @param signed
* if the source data array should be considered as signed data (meaningful for integer
* data type only)
* @param dstPt
* destination X,Y position (assume [0,0] if null)
* @param dstChannel
* destination channel
*/
public void copyData(Object data, Dimension dataDim, boolean signed, Point dstPt, int dstChannel)
{
if ((data == null) || (dataDim == null))
return;
// source image size
final Rectangle adjSrcRect = new Rectangle(dataDim);
// negative destination x position
if (dstPt.x < 0)
// adjust source rect
adjSrcRect.x += -dstPt.x;
// negative destination y position
if (dstPt.y < 0)
// adjust source rect
adjSrcRect.y += -dstPt.y;
final Rectangle dstRect = new Rectangle(dstPt.x, dstPt.y, adjSrcRect.width, adjSrcRect.height);
// limit to destination image size
final Rectangle adjDstRect = dstRect.intersection(new Rectangle(getSizeX(), getSizeY()));
final int w = Math.min(adjSrcRect.width, adjDstRect.width);
final int h = Math.min(adjSrcRect.height, adjDstRect.height);
// nothing to copy
if ((w == 0) || (h == 0))
return;
final Object dst = getDataXY(dstChannel);
final int srcSizeX = dataDim.width;
final int dstSizeX = getSizeX();
int srcOffset = adjSrcRect.x + (adjSrcRect.y * srcSizeX);
int dstOffset = adjDstRect.x + (adjDstRect.y * dstSizeX);
for (int y = 0; y < h; y++)
{
// do data copy (and conversion if needed)
ArrayUtil.arrayToArray(data, srcOffset, dst, dstOffset, w, signed);
srcOffset += srcSizeX;
dstOffset += dstSizeX;
}
// notify data changed
dataChanged();
}
/**
* Copy data from an image (notify data changed)
*
* @param srcImage
* source image
* @param srcRect
* source region to copy (assume whole image if null)
* @param dstPt
* destination X,Y position (assume [0,0] if null)
* @param srcChannel
* source channel (-1 for all channels)
* @param dstChannel
* destination channel (only significant if source channel != -1)
*/
public void copyData(IcyBufferedImage srcImage, Rectangle srcRect, Point dstPt, int srcChannel, int dstChannel)
{
if (srcImage == null)
return;
final Rectangle adjSrcRect;
final Point adjDstPt;
if (srcRect == null)
adjSrcRect = new Rectangle(srcImage.getSizeX(), srcImage.getSizeY());
else
adjSrcRect = srcRect;
if (dstPt == null)
adjDstPt = new Point(0, 0);
else
adjDstPt = dstPt;
// copy all possible components
if (srcChannel == -1)
{
final int sizeC = Math.min(srcImage.getSizeC(), getSizeC());
beginUpdate();
try
{
for (int c = 0; c < sizeC; c++)
fastCopyData(srcImage, adjSrcRect, adjDstPt, c, c);
}
finally
{
endUpdate();
}
}
else
fastCopyData(srcImage, adjSrcRect, adjDstPt, srcChannel, dstChannel);
}
/**
* Copy data from an image (notify data changed)
*
* @param srcImage
* source image
* @param srcRect
* source region to copy (assume whole image if null)
* @param dstPt
* destination (assume [0,0] if null)
*/
public void copyData(IcyBufferedImage srcImage, Rectangle srcRect, Point dstPt)
{
if (srcImage == null)
return;
copyData(srcImage, srcRect, dstPt, -1, 0);
}
/**
* Copy data from an image (notify data changed)
*
* @param srcImage
* source image
* @param srcChannel
* source channel to copy (-1 for all channels)
* @param dstChannel
* destination channel to receive data (only significant if source channel != -1)
*/
public void copyData(BufferedImage srcImage, int srcChannel, int dstChannel)
{
if (srcImage == null)
return;
if (srcImage instanceof IcyBufferedImage)
copyData(((IcyBufferedImage) srcImage), null, null, srcChannel, dstChannel);
else
{
final boolean done;
// try to use faster copy for compatible image
if (srcImage.getSampleModel() instanceof ComponentSampleModel)
done = copyData((ComponentSampleModel) srcImage.getSampleModel(), srcImage.getRaster(), srcChannel,
dstChannel);
else
done = false;
if (!done)
{
// image not compatible, use generic (and slow) data copy
srcImage.copyData(getRaster());
// notify data changed
dataChanged();
}
}
}
/**
* Copy data from an image (notify data changed)
*
* @param srcImage
* source image
*/
public void copyData(BufferedImage srcImage)
{
copyData(srcImage, -1, -1);
}
/**
* Return raw data component as an array of byte
*
* @param c
* component index
* @param out
* output array (can be null)
* @param offset
* output offset
* @param little
* little endian order
*/
public byte[] getRawData(int c, byte[] out, int offset, boolean little)
{
// alloc output array if needed
final byte[] result = Array1DUtil.allocIfNull(out,
offset + (getSizeX() * getSizeY() * getDataType_().getSize()));
return ByteArrayConvert.toByteArray(getDataXY(c), 0, result, offset, little);
}
/**
* Return raw data component as an array of byte
*
* @param c
* component index
* @param little
* little endian order
*/
public byte[] getRawData(int c, boolean little)
{
return getRawData(c, null, 0, little);
}
/**
* Return raw data for all components as an array of byte
*
* @param out
* output array (can be null)
* @param offset
* output offset
* @param little
* little endian order
*/
public byte[] getRawData(byte[] out, int offset, boolean little)
{
final int sizeXY = getSizeX() * getSizeY();
final int sizeC = getSizeC();
final int sizeType = getDataType_().getSize();
// alloc output array if needed
final byte[] result = Array1DUtil.allocIfNull(out, offset + (sizeC * sizeXY * sizeType));
int outOff = offset;
for (int c = 0; c < sizeC; c++)
{
getRawData(c, result, outOff, little);
outOff += sizeXY * sizeType;
}
return result;
}
/**
* Return raw data for all components as an array of byte
*
* @param little
* little endian order
*/
public byte[] getRawData(boolean little)
{
return getRawData(null, 0, little);
}
/**
* Set raw data component from an array of byte (notify data changed)
*
* @param c
* component index
* @param data
* data as byte array
* @param offset
* input offset
* @param little
* little endian order
*/
public void setRawData(int c, byte[] data, int offset, boolean little)
{
if (data == null)
return;
ByteArrayConvert.byteArrayTo(data, offset, getDataXY(c), 0, -1, little);
// notify data changed
dataChanged();
}
/**
* Set raw data component from an array of byte (notify data changed)
*
* @param c
* component index
* @param data
* data as byte array
* @param little
* little endian order
*/
public void setRawData(int c, byte[] data, boolean little)
{
setRawData(c, data, 0, little);
}
/**
* Set raw data for all components from an array of byte (notify data changed).<br/>
* Data are arranged in the following dimension order: XYC
*
* @param data
* data as byte array
* @param offset
* input offset
* @param little
* little endian order
*/
public void setRawData(byte[] data, int offset, boolean little)
{
if (data == null)
return;
final int sizeXY = getSizeX() * getSizeY();
final int sizeC = getSizeC();
final int sizeType = getDataType_().getSize();
beginUpdate();
try
{
int inOff = offset;
for (int c = 0; c < sizeC; c++)
{
setRawData(c, data, inOff, little);
inOff += sizeXY * sizeType;
}
}
finally
{
endUpdate();
}
}
/**
* Set raw data for all components from an array of byte (notify data changed)
*
* @param data
* data as byte array
* @param little
* little endian order
*/
public void setRawData(byte[] data, boolean little)
{
setRawData(data, 0, little);
}
/**
* Return the colormap of the specified channel.
*/
public IcyColorMap getColorMap(int channel)
{
return getIcyColorModel().getColorMap(channel);
}
/**
* @deprecated Use {@link #getColorMap(int)} instead (different case).
*/
@Deprecated
public IcyColorMap getColormap(int channel)
{
return getColorMap(channel);
}
/**
* @deprecated Use {@link #setColorMaps(BufferedImage)} instead.
*/
@Deprecated
public void copyColormap(BufferedImage srcImage)
{
setColorMaps(srcImage);
}
/**
* Set colormaps from specified image.
*/
public void setColorMaps(BufferedImage srcImage)
{
getIcyColorModel().setColorMaps(srcImage.getColorModel());
}
/**
* @deprecated Use {@link #setColorMaps(BufferedImage)} instead (different case).
*/
@Deprecated
public void setColormaps(BufferedImage srcImage)
{
setColorMaps(srcImage);
}
/**
* Set the colormap for the specified channel.
*
* @param channel
* channel we want to set the colormap
* @param map
* source colorspace to copy
* @param setAlpha
* also set the alpha information
*/
public void setColorMap(int channel, IcyColorMap map, boolean setAlpha)
{
getIcyColorModel().setColorMap(channel, map, setAlpha);
}
/**
* @deprecated Use {@link #setColorMap(int, IcyColorMap, boolean)} instead.
*/
@Deprecated
public void setColormap(int channel, IcyColorMap map)
{
setColorMap(channel, map, true);
}
/**
* notify image data has changed
*/
public void dataChanged()
{
updater.changed(new IcyBufferedImageEvent(this, IcyBufferedImageEventType.DATA_CHANGED));
}
/**
* notify image colorMap has changed
*/
protected void colormapChanged(int component)
{
updater.changed(new IcyBufferedImageEvent(this, IcyBufferedImageEventType.COLORMAP_CHANGED, component));
}
/**
* notify image channels bounds has changed
*/
public void channelBoundsChanged(int channel)
{
updater.changed(new IcyBufferedImageEvent(this, IcyBufferedImageEventType.BOUNDS_CHANGED, channel));
}
/**
* @deprecated Use {@link #channelBoundsChanged(int)} instead.
*/
@Deprecated
public void componentBoundsChanged(int component)
{
channelBoundsChanged(component);
}
/**
* fire change event
*/
protected void fireChangeEvent(IcyBufferedImageEvent e)
{
for (IcyBufferedImageListener listener : new ArrayList<IcyBufferedImageListener>(listeners))
listener.imageChanged(e);
}
public void addListener(IcyBufferedImageListener listener)
{
listeners.add(listener);
}
public void removeListener(IcyBufferedImageListener listener)
{
listeners.remove(listener);
}
public void beginUpdate()
{
updater.beginUpdate();
}
public void endUpdate()
{
updater.endUpdate();
}
public boolean isUpdating()
{
return updater.isUpdating();
}
@Override
public void onChanged(CollapsibleEvent object)
{
IcyBufferedImageEvent event = (IcyBufferedImageEvent) object;
switch (event.getType())
{
// do here global process on image data change
case DATA_CHANGED:
// update image components bounds
if (autoUpdateChannelBounds)
updateChannelsBounds();
break;
// do here global process on image bounds change
case BOUNDS_CHANGED:
break;
// do here global process on image colormap change
case COLORMAP_CHANGED:
break;
}
// notify listener we have changed
fireChangeEvent(event);
}
@Override
public void colorModelChanged(IcyColorModelEvent e)
{
switch (e.getType())
{
case COLORMAP_CHANGED:
colormapChanged(e.getComponent());
break;
case SCALER_CHANGED:
channelBoundsChanged(e.getComponent());
break;
}
}
}