package com.revolsys.gdal.raster;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.List;
import org.gdal.gdal.Band;
import org.gdal.gdal.Dataset;
import com.revolsys.gdal.Gdal;
import com.revolsys.geometry.cs.CoordinateSystem;
import com.revolsys.geometry.cs.epsg.EpsgCoordinateSystems;
import com.revolsys.geometry.cs.esri.EsriCoordinateSystems;
import com.revolsys.geometry.model.BoundingBox;
import com.revolsys.geometry.model.GeometryFactory;
import com.revolsys.raster.AbstractGeoreferencedImage;
import com.revolsys.spring.resource.Resource;
public class GdalImage extends AbstractGeoreferencedImage {
private Dataset dataset;
public GdalImage(final GdalImageFactory readerSpi, final Resource imageResource) {
setImageResource(imageResource);
final Dataset dataset = getDataset();
final Band band = dataset.GetRasterBand(1);
for (int i = 0; i < band.GetOverviewCount(); i++) {
final Band overview = band.GetOverview(i);
final int overviewWidth = overview.getXSize();
final int overviewHeight = overview.getYSize();
addOverviewSize(overviewWidth, overviewHeight);
}
final String projection = dataset.GetProjection();
final double[] geoTransform = dataset.GetGeoTransform();
if (projection != null) {
final CoordinateSystem esriCoordinateSystem = EsriCoordinateSystems
.getCoordinateSystem(projection);
if (esriCoordinateSystem != null) {
CoordinateSystem epsgCoordinateSystem = EpsgCoordinateSystems
.getCoordinateSystem(esriCoordinateSystem);
if (epsgCoordinateSystem == null) {
epsgCoordinateSystem = esriCoordinateSystem;
}
final int srid = epsgCoordinateSystem.getCoordinateSystemId();
if (srid > 0 && srid < 2000000) {
setGeometryFactory(GeometryFactory.floating(srid, 2));
} else {
setGeometryFactory(GeometryFactory.floating(epsgCoordinateSystem, 2));
}
}
}
setBoundingBox(geoTransform[0], geoTransform[3], geoTransform[1], geoTransform[5]);
postConstruct();
}
@Override
public void drawImage(final Graphics2D graphics, final BoundingBox viewBoundingBox,
final int viewWidth, final int viewHeight, final boolean useTransform) {
try {
final Dataset dataset = getDataset();
final BoundingBox imageBoundingBox = getBoundingBox();
final BoundingBox clipBoundingBox = viewBoundingBox.intersection(imageBoundingBox);
final double scaleFactor = viewWidth / viewBoundingBox.getWidth();
final double clipModelWidth = clipBoundingBox.getWidth();
final int targetWidth = (int)Math.ceil(clipModelWidth * scaleFactor);
final double clipModelHeight = clipBoundingBox.getHeight();
final int targetHeight = (int)Math.ceil(clipModelHeight * scaleFactor);
int bestOverviewIdx = -1;
int srcWidth = getImageWidth();
final double clipResolution = Math.abs(clipBoundingBox.getHeight() / targetHeight);
final List<Dimension> overviewSizes = getOverviewSizes();
for (int i = 0; i < overviewSizes.size(); i++) {
final Dimension overviewSize = overviewSizes.get(i);
final int width = overviewSize.width;
final int height = overviewSize.height;
if (0 != height && 0 != width) {
final double overviewResolution = Math.abs(imageBoundingBox.getHeight() / height);
if (overviewResolution <= clipResolution) {
bestOverviewIdx = i;
srcWidth = width;
}
}
}
final double scale = srcWidth / imageBoundingBox.getWidth();
final int clipXoff = (int)Math
.floor((clipBoundingBox.getMinX() - imageBoundingBox.getMinX()) * scale);
final int clipYoff = (int)Math
.floor((imageBoundingBox.getMaxY() - clipBoundingBox.getMaxY()) * scale);
final int clipWidth = (int)Math.ceil(clipModelWidth * scale);
final int clipHeight = (int)Math.ceil(clipModelHeight * scale);
final BufferedImage bufferedImage = Gdal.getBufferedImage(dataset, bestOverviewIdx, clipXoff,
clipYoff, clipWidth, clipHeight, targetWidth, targetHeight);
super.drawRenderedImage(bufferedImage, clipBoundingBox, graphics, viewBoundingBox, viewWidth,
useTransform);
} catch (final Throwable e) {
e.printStackTrace();
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
this.dataset = Gdal.closeDataSet(this.dataset);
}
public synchronized Dataset getDataset() {
if (this.dataset == null) {
final File file = getFile();
this.dataset = Gdal.getDataset(file);
}
return this.dataset;
}
@Override
public int getImageHeight() {
return getDataset().getRasterYSize();
}
@Override
public int getImageWidth() {
return getDataset().getRasterXSize();
}
}