package org.ianturton.cookbook.input;
import java.awt.event.ActionEvent;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
import javax.swing.JToolBar;
import org.geotools.coverage.GridSampleDimension;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.GridFormatFinder;
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.map.FeatureLayer;
import org.geotools.map.GridReaderLayer;
import org.geotools.map.Layer;
import org.geotools.map.MapContent;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.styling.ChannelSelection;
import org.geotools.styling.ContrastEnhancement;
import org.geotools.styling.RasterSymbolizer;
import org.geotools.styling.SLD;
import org.geotools.styling.SelectedChannelType;
import org.geotools.styling.Style;
import org.geotools.styling.StyleFactory;
import org.geotools.swing.JMapFrame;
import org.geotools.swing.JMapPane;
import org.geotools.swing.data.JFileDataStoreChooser;
import org.geotools.swing.dialog.JFileImageChooser;
import org.opengis.filter.FilterFactory2;
import org.opengis.style.ContrastMethod;
public class SaveMapAsImage {
private JMapFrame frame;
private MapContent mapContent;
public static void main(String[] args) throws IOException {
File file = null;
File raster = null;
if (args.length == 0) {
raster = JFileImageChooser.showOpenFile(null);
// display a data store file chooser dialog for shapefiles
file = JFileDataStoreChooser.showOpenFile("shp", null);
if (file == null) {
return;
}
} else {
file = new File(args[0]);
if (!file.exists()) {
System.err.println(file + " doesn't exist");
return;
}
raster = new File(args[1]);
if (!raster.exists()) {
System.err.println(raster + " doesn't exist");
return;
}
}
new SaveMapAsImage(file, raster);
}
public SaveMapAsImage(File file, File raster) throws IOException {
FileDataStore store = FileDataStoreFinder.getDataStore(file);
SimpleFeatureSource featureSource = store.getFeatureSource();
// Create a map content and add our shapefile to it
mapContent = new MapContent();
mapContent.setTitle("GeoTools Mapping");
AbstractGridFormat format = GridFormatFinder.findFormat(raster);
AbstractGridCoverage2DReader reader = format.getReader(raster);
GridCoverage2D cov;
try {
cov = reader.read(null);
} catch (IOException giveUp) {
throw new RuntimeException(giveUp);
}
Style rasterStyle = createRGBStyle(cov);
Layer rasterLayer = new GridReaderLayer(reader, rasterStyle);
mapContent.addLayer(rasterLayer);
Style style = SLD.createSimpleStyle(featureSource.getSchema());
Layer layer = new FeatureLayer(featureSource, style);
mapContent.addLayer(layer);
mapContent.getViewport().setCoordinateReferenceSystem(
DefaultGeographicCRS.WGS84);
frame = new JMapFrame(mapContent);
frame.enableStatusBar(true);
frame.enableToolBar(true);
JToolBar toolBar = frame.getToolBar();
toolBar.addSeparator();
SaveAction save = new SaveAction("Save");
toolBar.add(save);
frame.initComponents();
frame.setSize(1000, 500);
frame.setVisible(true);
}
public void drawMapToImage(File outputFile, String outputType) {
JMapPane mapPane = frame.getMapPane();
ImageOutputStream outputImageFile = null;
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(outputFile);
outputImageFile = ImageIO.createImageOutputStream(fileOutputStream);
RenderedImage bufferedImage = mapPane.getBaseImage();
ImageIO.write(bufferedImage, outputType, outputImageFile);
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
if (outputImageFile != null) {
outputImageFile.flush();
outputImageFile.close();
fileOutputStream.flush();
fileOutputStream.close();
}
} catch (IOException e) {// don't care now
}
}
}
private class SaveAction extends AbstractAction {
/**
* Private SaveAction
*/
private static final long serialVersionUID = 3071568727121984649L;
public SaveAction(String text) {
super(text);
}
public void actionPerformed(ActionEvent arg0) {
String[] writers = ImageIO.getWriterFormatNames();
String format = (String) JOptionPane.showInputDialog(frame,
"Choose output format:", "Customized Dialog",
JOptionPane.PLAIN_MESSAGE, null, writers, "png");
drawMapToImage(new File("ian." + format), format);
}
}
private StyleFactory sf = CommonFactoryFinder.getStyleFactory();
private FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
/**
* This method examines the names of the sample dimensions in the provided
* coverage looking for "red...", "green..." and "blue..." (case insensitive
* match). If these names are not found it uses bands 1, 2, and 3 for the red,
* green and blue channels. It then sets up a raster symbolizer and returns
* this wrapped in a Style.
*
* @return a new Style object containing a raster symbolizer set up for RGB
* image
*/
private Style createRGBStyle(GridCoverage2D cov) {
// We need at least three bands to create an RGB style
int numBands = cov.getNumSampleDimensions();
if (numBands < 3) {
return null;
}
// Get the names of the bands
String[] sampleDimensionNames = new String[numBands];
for (int i = 0; i < numBands; i++) {
GridSampleDimension dim = cov.getSampleDimension(i);
sampleDimensionNames[i] = dim.getDescription().toString();
}
final int RED = 0, GREEN = 1, BLUE = 2;
int[] channelNum = { -1, -1, -1 };
// We examine the band names looking for "red...", "green...", "blue...".
// Note that the channel numbers we record are indexed from 1, not 0.
for (int i = 0; i < numBands; i++) {
String name = sampleDimensionNames[i].toLowerCase();
if (name != null) {
if (name.matches("red.*")) {
channelNum[RED] = i + 1;
} else if (name.matches("green.*")) {
channelNum[GREEN] = i + 1;
} else if (name.matches("blue.*")) {
channelNum[BLUE] = i + 1;
}
}
}
// If we didn't find named bands "red...", "green...", "blue..."
// we fall back to using the first three bands in order
if (channelNum[RED] < 0 || channelNum[GREEN] < 0 || channelNum[BLUE] < 0) {
channelNum[RED] = 1;
channelNum[GREEN] = 2;
channelNum[BLUE] = 3;
}
// Now we create a RasterSymbolizer using the selected channels
SelectedChannelType[] sct = new SelectedChannelType[cov
.getNumSampleDimensions()];
ContrastEnhancement ce = sf.contrastEnhancement(ff.literal(1.0),
ContrastMethod.NORMALIZE);
for (int i = 0; i < 3; i++) {
sct[i] = sf.createSelectedChannelType(String.valueOf(channelNum[i]), ce);
}
RasterSymbolizer sym = sf.getDefaultRasterSymbolizer();
ChannelSelection sel = sf.channelSelection(sct[RED], sct[GREEN], sct[BLUE]);
sym.setChannelSelection(sel);
return SLD.wrapSymbolizers(sym);
}
}