/**
* Copyright 2010-2013 Jingjing Li.
*
* This file is part of jplot2d.
*
* jplot2d is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or any later version.
*
* jplot2d 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 Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with jplot2d. If not, see .
*/
package org.jplot2d.element.impl;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.geom.Dimension2D;
import java.awt.image.AffineTransformOp;
import java.awt.image.BandedSampleModel;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferUShort;
import java.awt.image.LookupOp;
import java.awt.image.PixelInterleavedSampleModel;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.util.Map;
import org.jplot2d.data.ImageDataBuffer;
import org.jplot2d.data.SingleBandImageData;
import org.jplot2d.element.ImageMapping;
import org.jplot2d.transform.NormalTransform;
import org.jplot2d.transform.PaperTransform;
public class ImageGraphImpl extends GraphImpl implements ImageGraphEx, IntermediateCacheEx {
private ImageMappingEx mapping;
private SingleBandImageData data;
public ImageGraphImpl() {
super();
}
public String getId() {
if (getParent() != null) {
return "ImageGraph" + getParent().indexOf(this);
} else {
return "ImageGraph@" + Integer.toHexString(System.identityHashCode(this));
}
}
public ImageMappingEx getMapping() {
return mapping;
}
public void setMapping(ImageMapping mapping) {
if (this.mapping != null) {
this.mapping.removeImageGraph(this);
}
this.mapping = (ImageMappingEx) mapping;
if (this.mapping != null) {
this.mapping.addImageGraph(this);
}
}
public SingleBandImageData getData() {
return data;
}
public void setData(SingleBandImageData data) {
this.data = data;
mapping.recalcLimits();
redraw(this);
}
public void thisEffectiveColorChanged() {
// the color for NaN?
}
public void mappingChanged() {
// release the cache holder if condition changed
redraw(this);
}
public Object createCacheHolder() {
if (data == null) {
return null;
}
return ImageZscaleCache.createCacheFor(data.getDataBuffer(), data.getWidth(), data.getHeight(),
mapping.getLimits(), mapping.getIntensityTransform(), mapping.getBias(), mapping.getGain(),
mapping.getILUTOutputBits());
}
@Override
public ComponentEx copyStructure(Map orig2copyMap) {
ImageGraphImpl result = (ImageGraphImpl) super.copyStructure(orig2copyMap);
// copy or link image mapping
ImageMappingEx mappingCopy = (ImageMappingEx) orig2copyMap.get(mapping);
if (mappingCopy == null) {
mappingCopy = (ImageMappingEx) mapping.copyStructure(orig2copyMap);
}
result.mapping = mappingCopy;
mappingCopy.addImageGraph(result);
return result;
}
@Override
public void copyFrom(ElementEx src) {
super.copyFrom(src);
this.data = ((ImageGraphImpl) src).data;
}
public void draw(Graphics2D graphics) {
if (data == null) {
return;
}
double[] limits = mapping.getLimits();
// limits is null means there is no valid data
if (limits == null) {
return;
}
// find a proper region to process
int width = data.getWidth();
int height = data.getHeight();
double xval = data.getXRange().getMin();
double yval = data.getYRange().getMin();
ImageDataBuffer idb = data.getDataBuffer();
int lutOutputBits = mapping.getILUTOutputBits();
WritableRaster raster;
Object result = ImageZscaleCache.getValue(idb, width, height, limits, mapping.getIntensityTransform(),
mapping.getBias(), mapping.getGain(), lutOutputBits);
if (lutOutputBits <= 8) {
// create a SampleModel for byte data
SampleModel sampleModel = new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, width, height, 1, width,
new int[] { 0 });
// and a DataBuffer with the image data
DataBufferByte dbuffer = new DataBufferByte((byte[]) result, width * height);
// create a raster
raster = Raster.createWritableRaster(sampleModel, dbuffer, null);
} else {
// create a SampleModel for short data
SampleModel sampleModel = new PixelInterleavedSampleModel(DataBuffer.TYPE_USHORT, width, height, 1, width,
new int[] { 0 });
// and a DataBuffer with the image data
DataBufferUShort dbuffer = new DataBufferUShort((short[]) result, width * height);
// create a raster
raster = Raster.createWritableRaster(sampleModel, dbuffer, null);
}
// zoom raster to device size
PaperTransform pxf = getPaperTransform();
NormalTransform xntrans = getParent().getXAxisTransform().getNormalTransform();
NormalTransform yntrans = getParent().getYAxisTransform().getNormalTransform();
Dimension2D paperSize = getParent().getSize();
double xorig = pxf.getXPtoD(xntrans.convToNR(xval) * paperSize.getWidth());
double yorig = pxf.getYPtoD(yntrans.convToNR(yval) * paperSize.getHeight());
double xscale = pxf.getScale() / xntrans.getScale() * paperSize.getWidth() * data.getXcdelt();
double yscale = pxf.getScale() / yntrans.getScale() * paperSize.getHeight() * data.getYcdelt();
AffineTransform scaleAT = AffineTransform.getScaleInstance(xscale, yscale);
AffineTransformOp axop = new AffineTransformOp(scaleAT, AffineTransformOp.TYPE_BILINEAR);
raster = axop.filter(raster, null);
// apply pseudo-color mapping
BufferedImage image = colorImage(mapping.getILUTOutputBits(), raster);
// draw the image
Graphics2D g = (Graphics2D) graphics.create();
Shape clip = getPaperTransform().getPtoD(getBounds());
g.setClip(clip);
AffineTransform at = new AffineTransform(1, 0.0, 0.0, -1, xorig, yorig);
g.drawRenderedImage(image, at);
g.dispose();
}
/**
* Apply the color LUT to the given raster. If the given raster only has a band, it will be duplicated to meet the
* output band number.
*
* @param bits
* the number of bits for the single band raster
* @param raster
* @return
*/
private BufferedImage colorImage(int bits, WritableRaster raster) {
int destNumComps;
if (mapping.getColorMap() == null) {
destNumComps = 3;
} else {
destNumComps = mapping.getColorMap().getColorModel().getNumComponents();
}
// duplicate the source band to as many bands as the number of dest CM
if (destNumComps > 1) {
SampleModel scm = raster.getSampleModel();
SampleModel dupSM = new BandedSampleModel(scm.getDataType(), scm.getWidth(), scm.getHeight(), destNumComps);
int singleBandSize = raster.getDataBuffer().getSize();
int[] bitsArray = new int[destNumComps];
if (raster.getDataBuffer().getDataType() == DataBuffer.TYPE_BYTE) {
// create a new raster which has duplicate bands
byte[] singleBandData = ((DataBufferByte) raster.getDataBuffer()).getData();
byte[][] dupDataArray = new byte[destNumComps][];
for (int i = 0; i < destNumComps; i++) {
bitsArray[i] = bits;
dupDataArray[i] = singleBandData;
}
DataBufferByte dbuffer = new DataBufferByte(dupDataArray, singleBandSize);
raster = Raster.createWritableRaster(dupSM, dbuffer, null);
} else {
// create a new raster which has duplicate bands
short[] singleBandData = ((DataBufferUShort) raster.getDataBuffer()).getData();
short[][] dupDataArray = new short[destNumComps][];
for (int i = 0; i < destNumComps; i++) {
bitsArray[i] = bits;
dupDataArray[i] = singleBandData;
}
DataBufferUShort dbuffer = new DataBufferUShort(dupDataArray, singleBandSize);
raster = Raster.createWritableRaster(dupSM, dbuffer, null);
}
}
if (mapping.getColorMap() == null) {
// assembly a BufferedImage with sRGB color sapce
int[] bitsArray = new int[] { bits, bits, bits };
ColorModel destCM = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bitsArray, false,
true, Transparency.OPAQUE, raster.getSampleModel().getDataType());
return new BufferedImage(destCM, raster, false, null);
} else {
// lookup and create a BufferedImage
ColorModel destCM = mapping.getColorMap().getColorModel();
WritableRaster destRaster = destCM.createCompatibleWritableRaster(raster.getWidth(), raster.getHeight());
LookupOp op = new LookupOp(mapping.getColorMap().getLookupTable(), null);
op.filter(raster, destRaster);
return new BufferedImage(destCM, destRaster, false, null);
}
}
}
Ads help maintain this website.