package nl.wldelft.fews.system.plugin.dataImport;
import com.sun.media.jai.codec.ByteArraySeekableStream;
import com.sun.media.jai.codec.SeekableStream;
import nl.wldelft.util.ColorUtils;
import nl.wldelft.util.FileUtils;
import nl.wldelft.util.IOUtils;
import nl.wldelft.util.coverage.Geometry;
import nl.wldelft.util.coverage.RegularGridGeometry;
import nl.wldelft.util.geodatum.GeoDatum;
import nl.wldelft.util.geodatum.GeoPoint;
import nl.wldelft.util.io.BinaryParser;
import nl.wldelft.util.io.VirtualInputDir;
import nl.wldelft.util.io.VirtualInputDirConsumer;
import nl.wldelft.util.timeseries.DefaultTimeSeriesHeader;
import nl.wldelft.util.timeseries.TimeSeriesContentHandler;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.awt.image.renderable.ParameterBlock;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GrayscaleImageTimeSeriesParser implements BinaryParser<TimeSeriesContentHandler>, VirtualInputDirConsumer, FileFilter {
private BufferedImage bufferedImage = null;
private Graphics2D graphics = null;
private int[] rgbs = null;
private float[] values = null;
private VirtualInputDir virtualInputDir = null;
private String virtualFileName = null;
private TimeSeriesContentHandler contentHandler = null;
@Override
public boolean accept(File pathname) {
return getWorldFileExt(FileUtils.getFileExt(pathname)) != null;
}
@Override
public void setVirtualInputDir(VirtualInputDir virtualInputDir) {
this.virtualInputDir = virtualInputDir;
}
@Override
public void parse(BufferedInputStream inputStream, String virtualFileName, TimeSeriesContentHandler contentHandler) throws Exception {
this.virtualFileName = virtualFileName;
this.contentHandler = contentHandler;
DefaultTimeSeriesHeader header = new DefaultTimeSeriesHeader();
header.setParameterId("image");
header.setLocationId("image");
contentHandler.setNewTimeSeriesHeader(header);
if (contentHandler.isCurrentTimeSeriesHeaderForAllTimesRejected()) return;
contentHandler.setTime(getTime(new File(virtualFileName).getName(), contentHandler.getDefaultTimeZone()));
if (contentHandler.isCurrentTimeSeriesHeaderForCurrentTimeRejected()) return;
loadImage(inputStream, virtualFileName);
Geometry geometry = loadGeometry();
contentHandler.setGeometry(geometry);
contentHandler.setValueResolution(1.0f);
contentHandler.setCoverageValues(values);
contentHandler.applyCurrentFields();
}
private Geometry loadGeometry() throws Exception {
Geometry res = contentHandler.getOverrulingGeometry();
if (res == null) res = readWorldFile();
if (res.getCols() != bufferedImage.getWidth()) {
throw new Exception("Width of image file (" + bufferedImage.getWidth()
+ ") differs from number of cols (" + res.getCols() + ") in grid required geometry or world file");
}
if (res.getRows() != bufferedImage.getHeight()) {
throw new Exception("Height of image file (" + bufferedImage.getHeight()
+ ") differs from number of rows (" + res.getRows() + ") in grid required geometry or world file");
}
return res;
}
private void loadImage(InputStream inputStream, String fileName) throws Exception {
String ext = FileUtils.getFileExt(fileName);
String jaiFormatId = getJaiFormatId(ext);
if (jaiFormatId == null)
throw new Exception("Unsupported bitmap format " + inputStream);
ParameterBlock parameterBlock = new ParameterBlock();
SeekableStream seekableStream = new ByteArraySeekableStream(IOUtils.readBytes(inputStream));
try {
parameterBlock.add(seekableStream);
RenderedOp image = JAI.create(jaiFormatId, parameterBlock);
try {
checkBuffers(image.getWidth(), image.getHeight());
graphics.clearRect(0, 0, image.getWidth(), image.getHeight());
graphics.drawImage(image.getAsBufferedImage(), 0, 0, null);
for (int i = 0; i < values.length; i++) {
int rgb = rgbs[i];
int a = rgb >>> 24 & 0xff;
if (a == 0) {
values[i] = Float.NaN;
continue;
}
int r = rgb >>> 16 & 0xff;
int g = rgb >>> 8 & 0xff;
int b = rgb >>> 0 & 0xff;
values[i] = (r + g + b) / 3;
}
} finally {
image.dispose();
}
} finally {
seekableStream.close();
}
}
private void checkBuffers(int width, int height) {
if (bufferedImage != null && bufferedImage.getWidth() == width && bufferedImage.getHeight() == height) return;
bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
graphics = bufferedImage.createGraphics();
graphics.setBackground(ColorUtils.TRANSPARANT_COLOR);
DataBufferInt dataBufferInt = (DataBufferInt) bufferedImage.getRaster().getDataBuffer();
rgbs = dataBufferInt.getData();
values = new float[width * height];
}
public static String getWorldFileExt(String bitMapExt) {
if (bitMapExt.equalsIgnoreCase("tif")) return "tfw";
if (bitMapExt.equalsIgnoreCase("gif")) return "gfw";
if (bitMapExt.equalsIgnoreCase("png")) return "pgw";
if (bitMapExt.equalsIgnoreCase("bmp")) return "bpw";
if (bitMapExt.equalsIgnoreCase("pcx")) return "pxw";
if (bitMapExt.equalsIgnoreCase("jpg")) return "jgw";
return null;
}
private static String getJaiFormatId(String bitmapExt) {
if (bitmapExt.equalsIgnoreCase("tif")) return "tiff";
if (bitmapExt.equalsIgnoreCase("gif")) return "gif";
if (bitmapExt.equalsIgnoreCase("bmp")) return "bmp";
if (bitmapExt.equalsIgnoreCase("png")) return "png";
if (bitmapExt.equalsIgnoreCase("jpg")) return "jpeg";
return null;
}
private RegularGridGeometry readWorldFile() throws Exception {
String worldFileExt = getWorldFileExt(FileUtils.getFileExt(virtualFileName));
String worldFile = FileUtils.getPathWithOtherExtension(virtualFileName, worldFileExt);
if (!virtualInputDir.exists(worldFile))
throw new FileNotFoundException("Can not file world file " + worldFile);
String[] values = IOUtils.readAllLines(virtualInputDir.getReader(worldFile));
double cellWidth = Double.parseDouble(values[0]);
double cellHeight = -Double.parseDouble(values[3]);
double x = Double.parseDouble(values[4]);
double y = Double.parseDouble(values[5]);
GeoDatum geoDatum = contentHandler.getDefaultGeoDatum();
GeoPoint bitMapUpperLeft = geoDatum.createXYZ(x, y, 0);
return RegularGridGeometry.create(geoDatum, bitMapUpperLeft, cellWidth, cellHeight, bufferedImage.getHeight(), bufferedImage.getWidth());
}
public static long getTime(String fileName, TimeZone timeZone) throws Exception {
Pattern p = Pattern.compile("\\d{8}.\\d{4}");
Matcher matcher = p.matcher(fileName);
boolean successfull = matcher.find();
if (!successfull)
throw new Exception("File name should contain date time yyyyMMdd_HHmm " + fileName);
String dateTimeText = matcher.group();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd" + dateTimeText.charAt(8) + "HHmm");
dateFormat.setTimeZone(timeZone);
try {
return dateFormat.parse(dateTimeText).getTime();
} catch (ParseException e) {
throw new Exception("File name should contain valid date time yyyyMMdd_HHmm " + fileName);
}
}
}
|