package com.meteogroup.grib2geotiff.geotiff;
import java.awt.image.ColorModel;
import java.awt.image.ComponentSampleModel;
import java.awt.image.DataBuffer;
import java.awt.image.SampleModel;
import java.io.File;
import java.io.IOException;
import javax.media.jai.TiledImage;
import org.geotools.coverage.CoverageFactoryFinder;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.imageio.GeoToolsWriteParams;
import org.geotools.gce.geotiff.GeoTiffFormat;
import org.geotools.gce.geotiff.GeoTiffWriteParams;
import org.geotools.gce.geotiff.GeoTiffWriter;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.FactoryException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.meteogroup.grib2geotiff.RecordMetadata;
import com.meteogroup.grib2geotiff.util.TargetPathGenerator;
import com.sun.media.imageio.plugins.tiff.BaselineTIFFTagSet;
/**
* Created by danielt on 14.09.15.
*/
public class GeoTiffExporter {
static final Logger LOGGER = LoggerFactory.getLogger(GeoTiffExporter.class);
static final int TILE_SIZE = 256;
static final int WORLD_LEFT = -180;
static final int WORLD_RIGHT = 180;
static final int WORLD_TOP = 90;
static final int WORLD_BOTTOM = -90;
private File outDirectory;
/**
* @param outDirectory
*/
public void setOutDirectory(File outDirectory) {
this.outDirectory = outDirectory;
}
/**
* @param data
* @param metadata
* @throws Exception
*/
public void createGeoTiff(float[] data, RecordMetadata metadata) throws Exception {
String targetFile = createTargetFilename(metadata);
verifyDirectories(targetFile);
writeGeotiff(data, metadata, targetFile);
}
/**
* @param targetFile
*/
private void verifyDirectories(String targetFile) {
File target = new File(targetFile);
if (!target.getParentFile().exists()) {
target.getParentFile().mkdirs();
}
}
/**
* writer.writeGrid(GribDataset, GribDatatype, Array, Boolean);
*
* @param data
*/
private void writeGeotiff(float[] data, RecordMetadata metadata, String targetFile) throws Exception {
LOGGER.info("target: " + targetFile);
GridCoverage2D coverage = createCoverage(data, metadata.getColumns(), metadata.getRows());
GeoTiffWriter writer = new GeoTiffWriter(new File(targetFile));
appendTextMetadata(writer, metadata);
writer.write(coverage, createWriteParameters());
}
/**
* Collect parameters to configure a tiles and compressed GeoTiff
* see http://docs.geotools.org/stable/javadocs/org/geotools/gce/geotiff/GeoTiffWriteParams.html
*
* @return
*/
private GeneralParameterValue[] createWriteParameters() {
final GeoTiffFormat format = new GeoTiffFormat();
final GeoTiffWriteParams wp = new GeoTiffWriteParams();
wp.setCompressionMode(GeoTiffWriteParams.MODE_EXPLICIT);
wp.setCompressionType("LZW");
wp.setTilingMode(GeoToolsWriteParams.MODE_EXPLICIT);
wp.setTiling(TILE_SIZE, TILE_SIZE);
final ParameterValueGroup params = format.getWriteParameters();
params.parameter(
AbstractGridFormat.GEOTOOLS_WRITE_PARAMS.getName().toString())
.setValue(wp);
GeneralParameterValue[] writeParameters = params.values().toArray(new GeneralParameterValue[1]);
return writeParameters;
}
private void appendTextMetadata(GeoTiffWriter writer, RecordMetadata metadata) throws IOException {
String desc = GeoTiffDescriptionText.createDescriptionText(metadata);
writer.setMetadataValue(Integer.toString(BaselineTIFFTagSet.TAG_DOCUMENT_NAME), metadata.getName());
writer.setMetadataValue(Integer.toString(BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION), desc);
writer.setMetadataValue(Integer.toString(BaselineTIFFTagSet.TAG_SOFTWARE), "edu.ucar & geotools");
writer.setMetadataValue(Integer.toString(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT), "");
writer.setMetadataValue(Integer.toString(BaselineTIFFTagSet.TAG_X_RESOLUTION), "");
writer.setMetadataValue(Integer.toString(BaselineTIFFTagSet.TAG_Y_RESOLUTION), "");
}
/**
* Creates the
*
* @param data
* @return
*/
public GridCoverage2D createCoverage(float[] data, int columns, int rows) {
GridCoverageFactory gcf = CoverageFactoryFinder.getGridCoverageFactory(null);
TiledImage img = ceateImageContent(data, columns, rows);
ReferencedEnvelope env = createEnvelope();
return gcf.create("coverage", img, env);
}
private TiledImage ceateImageContent(float[] data, int columns, int rows) {
SampleModel sm = new ComponentSampleModel(DataBuffer.TYPE_DOUBLE,
TILE_SIZE, TILE_SIZE, 1, TILE_SIZE, new int[]{0});
ColorModel cm = TiledImage.createColorModel(sm);
TiledImage img = new TiledImage(0, 0, columns, rows, 0, 0, sm, cm);
int i = 0;
int halfColumns = (int) ((double) columns / 2.0);
for (int y = 0; y < rows; y++) {
for (int x = 0; x < columns; x++) {
if (x >= halfColumns) {
img.setSample(x - halfColumns, y, 0, data[i]);
} else {
img.setSample(x + halfColumns, y, 0, data[i]);
}
i++;
}
}
return img;
}
private ReferencedEnvelope createEnvelope() {
ReferencedEnvelope env = null;
try {
env = new ReferencedEnvelope(
WORLD_BOTTOM, WORLD_TOP, WORLD_LEFT, WORLD_RIGHT,
CRS.decode("EPSG:4326"));
} catch (FactoryException e) {
LOGGER.error("Cannot create georeferenced Envelope: " + e.getMessage(), e);
}
return env;
}
/**
* @param metadata
* @return
*/
private String createTargetFilename(RecordMetadata metadata) {
return outDirectory + "/"
+ TargetPathGenerator.generateTargePath(metadata)
+ ".tif";
}
}