package com.vividsolutions.jump.workbench.imagery.geotiff;
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.renderable.ParameterBlock;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jump.workbench.ui.Viewport;
public class RasterPainter
{
GeoReferencedRaster geoRaster;
Envelope envModel_viewportCached;
double scaleCached;
RenderedOp imgScaled;
RenderedOp imgWindow;
RenderedOp imgRescaled;
// Rescaling parameters
final static double DEFAULT_RESCALINGCONSTANT = 1;
final static double DEFAULT_RESCALINGOFFSET = 0;
double rescalingConstant = DEFAULT_RESCALINGCONSTANT;
double rescalingOffset = DEFAULT_RESCALINGOFFSET;
// private final int VIEWPORT_MINX = 0;
// private final int VIEWPORT_MINY = 0;
boolean enabled = true;
public RasterPainter(GeoReferencedRaster geoRaster)
{
this.geoRaster = geoRaster;
}
public void setRescalingConstant(double x)
{
rescalingConstant = x;
}
public void setRescalingOffset(double x)
{
rescalingOffset = x;
}
/**
* @param image
* @param constant
* @param offset
* @return
*/
private RenderedOp rescale(RenderedOp image, double constant, double offset)
{
// If constant and offset equal to default values, don't do
// anything, saves time (hopefully).
if (constant == DEFAULT_RESCALINGCONSTANT
&& offset == DEFAULT_RESCALINGOFFSET)
return image;
else
{
int bands = imgWindow.getNumBands();
double[] constants = new double[bands];
double[] offsets = new double[bands];
for (int i = 0; i < bands; i++)
{
constants[i] = constant;
offsets[i] = offset;
}
ParameterBlock pb = new ParameterBlock();
pb.addSource(image);
pb.add(constants);
pb.add(offsets);
return JAI.create("rescale", pb, null);
}
}
/**
* @param image
* @return
*/
private RenderedOp rescale(RenderedOp image)
{
return rescale(image, rescalingConstant, rescalingOffset);
}
/**
* @param viewport
* @return @throws
* Exception
*/
private RenderedOp getWindow(Viewport viewport) throws Exception
{
// Wat is de gewenste uitsnede in model-coordinaten ?
Envelope envModel_viewport = viewport.getEnvelopeInModelCoordinates();
if (envModel_viewportCached == null
|| !envModel_viewportCached.equals(envModel_viewport))
{
// Most images perform better with calculateWindow2.
// Geomedia/USSampleimage.tif perform better with
// calculateWindow however. calculateWindow2 shows
// better when panning.
imgWindow = calculateWindow2(viewport, envModel_viewport);
}
return imgWindow;
}
private void scaleImage(double scale) throws Exception
{
double scaleX = scale * geoRaster.getDblModelUnitsPerRasterUnit_X();
double scaleY = scale * geoRaster.getDblModelUnitsPerRasterUnit_Y();
ParameterBlock pb = new ParameterBlock();
pb.addSource(geoRaster.getImage());
pb.add((float) scaleX);
pb.add((float) scaleY);
pb.add(0f);
pb.add(0f);
imgScaled = JAI.create("scale", pb, null);
// (new TestFrame(imgScaled)).show();
}
private RenderedOp calculateWindow2(Viewport viewport,
Envelope envModel_viewport) throws Exception
{
// First, scale the original image if necessary.
final double scale = viewport.getScale();
if (scale != scaleCached)
{
scaleImage(scale);
scaleCached = scale;
}
// Next, crop the part which is needed out of the
// scaled image.
double ratio_cropX = (envModel_viewport.getMinX() - geoRaster.getEnvelope()
.getMinX())
/ geoRaster.getEnvelope().getWidth();
double ratio_cropY = (geoRaster.getEnvelope().getMaxY() - envModel_viewport
.getMaxY())
/ geoRaster.getEnvelope().getHeight();
double ratio_cropW = envModel_viewport.getWidth()
/ geoRaster.getEnvelope().getWidth();
double ratio_cropH = envModel_viewport.getHeight()
/ geoRaster.getEnvelope().getHeight();
float raster_cropX = (int) (ratio_cropX * imgScaled.getWidth());
float raster_cropY = (int) (ratio_cropY * imgScaled.getHeight());
float raster_cropW = (int) (ratio_cropW * imgScaled.getWidth());
float raster_cropH = (int) (ratio_cropH * imgScaled.getHeight());
float raster_offsetX = 0;
float raster_offsetY = 0;
if (raster_cropX < 0)
{
raster_offsetX = -raster_cropX;
raster_cropX = 0;
}
if (raster_cropY < 0)
{
raster_offsetY = -raster_cropY;
raster_cropY = 0;
}
raster_cropW = Math.min(raster_cropW, imgScaled.getWidth()
- (int) raster_cropX);
raster_cropH = Math.min(raster_cropH, imgScaled.getHeight()
- (int) raster_cropY);
ParameterBlock pb = new ParameterBlock();
pb.addSource(imgScaled);
pb.add(raster_cropX);
pb.add(raster_cropY);
pb.add(raster_cropW);
pb.add(raster_cropH);
imgWindow = JAI.create("crop", pb, null);
// imgWindow = imgScaled;
pb = new ParameterBlock();
pb.addSource(imgWindow);
pb.add(raster_offsetX - imgWindow.getMinX());
pb.add(raster_offsetY - imgWindow.getMinY());
imgWindow = JAI.create("translate", pb, null);
return imgWindow;
}
/**
*
*/
public void paint(Graphics2D g, Viewport viewport)
throws Exception
{
// Get the image for the current viewport.
RenderedOp imgWindowed = getWindow(viewport);
if (imgWindowed == null)
return;
// Adjust brightness and contrast of this image.
RenderedOp imgRescaled = rescale(imgWindowed);
if (imgRescaled == null)
return;
g.setComposite(AlphaComposite.SrcOver);
// The image has been translated and scaled by JAI
// allready. Just draw it with an identity transformation.
g.drawRenderedImage(imgRescaled, new AffineTransform());
}
/**
*
*/
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
/**
* @return Returns the rescalingConstant.
*/
public double getRescalingConstant()
{
return rescalingConstant;
}
/**
* @return Returns the rescalingOffset.
*/
public double getRescalingOffset()
{
return rescalingOffset;
}
}