Hi Jason
Here is some code we have done to do JAI supported rasters incl
geotiff's etc. It is a modification of some code by William Art
<artw_at_saharamaps.com> posted on the openmap mailing list previously.
Hope this helps.
regards
/carsten
/*
* Copyright NAVICON A/S 2005
* com_at_navicon.dk
*
**/
package dk.navicon.openmap.layer;
import java.awt.Component;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import com.bbn.openmap.LatLonPoint;
import com.bbn.openmap.omGraphics.OMGraphicList;
import com.bbn.openmap.omGraphics.OMScalingRaster;
import com.bbn.openmap.plugin.OMGraphicHandlerPlugIn;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.proj.coords.DMSLatLonPoint;
import com.bbn.openmap.util.Debug;
import com.bbn.openmap.util.PropUtils;
import com.sun.media.jai.codec.FileSeekableStream;
import com.sun.media.jai.codec.TIFFDirectory;
import com.sun.media.jai.codec.TIFFField;
/**
* _at_author com_at_navicon.dk
*
* This is a modification of some code by William Art <artw_at_saharamaps.com>
* posted on the openmap mailing list
*
* This class will open any of the following image file formats:
*
* <ul>
* <li>geo tiff
* <li>jpeg
* <li>bmp</li>
* </ul>
*
* Only lat/lon projection is supported.
*
* Using the java JAI package
(
http://java.sun.com/products/java-media/jai/). To
* use this class you must have the JAI package installed and available
in your
* classpath when running OpenMap.
*
* Properties example:
*
* <pre>
*
*
* JAILayer.prettyName=MyJAILayer
* JAILayer.class=dk.navicon.openmap.layer.JAIPlugIn
*
JAILayer.imageFile=/opt/Mapdata/AHOWEB_DP001/AUS00605/A00605.tif
*
*
* </pre>
*
* Currently the image must be in lat/lon this includes the world file.
If you
* have geo tiff files in a different format like UTM you can use GDAL to
* reformat to lat/lon gdalwarp -co INTERLEAVE=PIXEL -t_srs WGS84
* S_10000_127.tif aarhus-havn.tif
*
* World files are assumed to end with w, i.e., xxx.jpg -> xxx.jgw etc.
*
*/
public class JAIPlugIn extends OMGraphicHandlerPlugIn {
double lat, lon, lat2, lon2, ximage_scale, yimage_scale;
// sourcelat,sourcelon;
protected PlanarImage source = null;
boolean DEBUG = false;
/** The property for the data file - tileFile. */
public final static String FileNameProperty = "imageFile";
/**
* The property for whether the data file has a descriptive header
on the
* first line, to let the reader know to ignore that line -
fileHasHeader.
* Default is true.
*/
protected String imageFileName = null;
// the map
OMScalingRaster raster = null;
/**
* Default constructor.
*/
public JAIPlugIn() {
super();
DEBUG = Debug.debugging("JAIPlugIn");
}
public JAIPlugIn(Component comp) {
super(comp);
}
/**
* The getRectangle call is the main call into the PlugIn module.
The module
* is expected to fill the graphics list with objects that are
within the
* screen parameters passed.
*
* _at_param p
* projection of the screen, holding scale, center coords,
* height, width.
*/
public OMGraphicList getRectangle(Projection p) {
OMGraphicList list = (OMGraphicList) getList();
list.clear();
if (DEBUG) {
Debug.output("CSVTIPI: getRectangle");
}
if (raster == null) {
loadRaster(imageFileName);
}
if (raster.isOnMap(p)) {
if (DEBUG) {
Debug.output("CSVTIPI: image on map");
}
raster.generate(p);
list.add(raster);
} else if (DEBUG) {
Debug.output("CSVTIPI: image not on map, skipping");
}
repaint();
return list;
} // end getRectangle
/**
* PropertyConsumer method, setting the PlugIn with properties that
apply to
* it.
*/
public void setProperties(String prefix, Properties props) {
super.setProperties(prefix, props);
String realPrefix = PropUtils.getScopedPropertyPrefix(prefix);
imageFileName = props.getProperty(realPrefix + FileNameProperty);
if (DEBUG) {
Debug.output("CSVTIPI: file: " + imageFileName);
}
}
/**
* Takes the URL to a csv file and parses it into OMScaledRasters,
adding
* them to the tiles HashSet.
*/
protected void loadRaster(String csvFileName) {
if (imageFileName != null) {
try {
init();
} catch (FileNotFoundException e) {
Debug.output("CSVTIPI: file: " + imageFileName + " not
found");
e.printStackTrace();
}
// OMScalingRaster omsr
raster = new OMScalingRaster((float) lat, (float) lon,
(float) lat2, (float) lon2,
source.getAsBufferedImage());
}
}
/**
* Method to fill in a Properties object, reflecting the current
values of
* the PropertyConsumer. If the PropertyConsumer has a prefix set, the
* property keys should have that prefix plus a separating '.'
prepended to
* each propery key it uses for configuration.
*
* _at_param getList
* a Properties object to load the PropertyConsumer
properties
* into. If getList equals null, then a new Properties object
* should be created.
* _at_return Properties object containing PropertyConsumer property
values. If
* getList was not null, this should equal getList.
Otherwise, it
* should be the Properties object created by the
PropertyConsumer.
*/
public Properties getProperties(Properties getList) {
if (getList == null) {
getList = new Properties();
}
String prefix = PropUtils.getScopedPropertyPrefix(this);
getList.put(prefix + FileNameProperty,
PropUtils.unnull(imageFileName));
return getList;
}
int sourceWidth;
int sourceHeigth;
public void init() throws FileNotFoundException {
try {
String associatedfile = imageFileName;
source = JAI.create("fileload", associatedfile);
sourceWidth = source.getWidth();
sourceHeigth = source.getHeight();
double xscale, yscale;
double lonNW, latNW;
String projfilename = imageFileName;
FileSeekableStream st;
if (imageFileName.endsWith(".tif")
|| imageFileName.endsWith(".TIF")) {
st = new FileSeekableStream(imageFileName);
TIFFDirectory td;
td = new TIFFDirectory(st, 0);
TIFFField tfMPS = td.getField(33550); // ModelPixelScaleTag
TIFFField tfMTP = td.getField(33922); // ModelTiepointTag
System.out.println("tfMPS " + tfMPS + "\ntfMTP " + tfMTP);
try {
xscale = tfMPS.getAsDouble(0);
yscale = tfMPS.getAsDouble(1);
double[] tiepoints = tfMTP.getAsDoubles();
System.out.println("count=" + tfMTP.getCount());
for (int i = 0; i < tiepoints.length; i++) {
System.out.println("-->" + tiepoints[i]);
}
System.out.println("type=" + tfMPS.getType());
System.out.println("type=" + tfMTP.getType());
System.out.println("nb of tiepoints = "
+ tfMTP.getAsDouble(0));
if (tfMTP.getCount() != 6 && tfMTP.getCount() != 4) {
System.out
.println("warning tif file may pose
problems...");
}
if (tfMTP.getCount() == 6) {
lonNW = tfMTP.getAsDouble(3);
latNW = tfMTP.getAsDouble(4);
} else if (tfMTP.getCount() == 2) {
lonNW = tfMTP.getAsDouble(0);
latNW = tfMTP.getAsDouble(1);
} else {
lonNW = tfMTP.getAsDouble(2);
latNW = tfMTP.getAsDouble(3);
}
DMSLatLonPoint upperLeft = new DMSLatLonPoint(
new LatLonPoint(latNW, lonNW));
DMSLatLonPoint lowerRight = new DMSLatLonPoint(
new LatLonPoint(latNW
- (yscale * (source.getHeight())), lonNW
+ (xscale * (source.getWidth()))));
System.out.println("xscale " + xscale + " yscale " +
yscale
+ " lonNW " + lonNW + " latNW " + latNW
+ " img height " + source.getHeight()
+ " img width " + source.getWidth() + " "
+ formatDMSPoint(upperLeft) + " "
+ formatDMSPoint(lowerRight));
init((double) (latNW), (double) (lonNW),
(double) (latNW - (yscale *
(source.getHeight()))),
(double) (lonNW + (xscale *
(source.getWidth()))),
(double) xscale, (double) yscale);
st.close();
} catch (Exception e) {
st.close();
System.out.println("Error reading geotiff" + e);
e.printStackTrace();
System.out
.println("No Geotiff referencing found.
Attempting projection file.");
if (imageFileName.endsWith(".tif"))
projfilename = imageFileName.replaceAll("\\.tif",
".tfw");
setGeoReferencing(source, projfilename);
}
} else {
if (imageFileName.endsWith(".bmp"))
projfilename = imageFileName.replaceAll("\\.bmp",
".bpw");
else if (imageFileName.endsWith(".BMP"))
projfilename = imageFileName.replaceAll("\\.BMP",
".BPW");
else if (imageFileName.endsWith(".JPG"))
projfilename = imageFileName.replaceAll("\\.JPG",
".JGW");
else if (imageFileName.endsWith(".jpg"))
projfilename = imageFileName.replaceAll("\\.jpg",
".jgw");
setGeoReferencing(source, projfilename);
}
} catch (IOException e) {
System.out.println("OMJAIScalingRaster...");
System.out.println(e.getMessage());
}
}
public void setGeoReferencing(PlanarImage src, String projfilename)
throws FileNotFoundException {
double xscale;
double yscale;
double lonNW;
double latNW;
try {
FileReader projectionFile;
projectionFile = new FileReader(projfilename);
BufferedReader reader = new BufferedReader(projectionFile);
String line = reader.readLine();
System.out.println("xscale=" + line);
xscale = Double.valueOf(line).doubleValue();
line = reader.readLine();
line = reader.readLine();
line = reader.readLine();
System.out.println("yscale=" + line);
yscale = -Double.valueOf(line).doubleValue();
// System.out.println(line);
line = reader.readLine();
lonNW = Double.valueOf(line).doubleValue();
System.out.println("lonNW=" + line);
line = reader.readLine();
latNW = Double.valueOf(line).doubleValue();
System.out.println("latNW=" + line + " width=" + sourceWidth
+ " sourceHeigth" + sourceHeigth);
// reader.close();
projectionFile.close();
reader.close();
// if (xsize == -1 || ysize == -1)
// {
init((double) (latNW), (double) (lonNW),
(double) (latNW - (xscale * (sourceHeigth))),
(double) (lonNW + (yscale * (sourceWidth))),
(double) xscale, (double) yscale);
// }
// else
// init((double) (latNW), (double) (lonNW), (double) (latNW -
// (xscale * ysize)), (double) (lonNW + (yscale * xsize)),
(double)
// xscale, (double) yscale);
} catch (IOException e) {
System.out.println("setgeo :" + e.getMessage());
}
}
void init(double lt, double ln, double lt_2, double ln_2, double
xim_scale,
double yim_scale) {
lat = (float) lt;
lon = (float) ln;
ximage_scale = xim_scale;
yimage_scale = yim_scale;
// sourcelat = lt;
// sourcelon = lon;
lat2 = lt_2;
lon2 = ln_2;
System.out.println("lat " + lat + " lon " + lon + " lat2 " + lat2
+ " lon2 " + lon2);
}
private String formatDMSPoint(DMSLatLonPoint p) {
String res = "[[";
res += p.lat_isnegative ? "-" : "";
res += p.lat_degrees + " " + p.lat_minutes + " " + p.lat_seconds
+ "] [";
res += p.lon_isnegative ? "-" : "";
res += p.lon_degrees + " " + p.lon_minutes + " " + p.lon_seconds
+ "]]";
return res;
}
}
Don Dietrick wrote:
> HI Jason,
>
> On Sep 30, 2005, at 3:10 AM, Butler, Jason wrote:
>
>> Hello everyone,
>>
>> I have been asked by my clients to support the geotiff file format,
>> so I am attempting to develop a geotiff layer for openmap. I just
>> thought I would run my thought process past you all to check that I
>> am on the right track as I am a novice when it comes to geographic
>> terminology and maths.
>>
>> So far I have wirtten some prototype code that can load and display
>> a geotiff as a normal tiff using the jai image io code provided by
>> sun. (http://java.sun.com/products/java-media/jai/downloads/
>> download-iio-1_0_01.html) This api includes a reader for tiffs, that
>> allows access to the tiff's meta data through an xml document tree,
>> including the geotiff meta data. From the meta data tree, I have
>> been able to parse the geo tiff speciffic keys into a helper object.
>> So far so good. I should be able to get all the info I need for
>> placing the geo tiff by implementing some helper methods based on
>> the geo tiff specification. (http://www.remotesensing.org/
>> geotiff/spec/geotiffhome.html)
>
> Excellent!
>
>> My roadmap for the next few steps is
>> 1. create a Layer that takes a path to a geotiff file as a property,
>> and renders it as a raster OMGraphic at (0,0).
>> 2. extract the upper left and lower right coordinates of the tiff
>> from the meta data and render the tiff as a scaling raster omgraphic
>> within these confines.
>>
>> As far as I can tell from reading the openmap mail archives, this is
>> about where most people have gotten in past attempts. The next step is
>>
>> 3. write some code to render the geotiff directly into the current
>> openmap projection. Sounds easy, but I think this is going to be
>> difficult to implement.
>>
>> This is the bit that I would like some confirmation in my thinking.
>>
>> First I had better define a couple of terms to try and make sure I
>> am communicating clearly.
>> - Raster Space: The data in the tiff. Lets say the coordinate system
>> is I, and j and the notation R(i,,j) defines a point in the raster
>> space.
>>
>> - Geocentric Space: The coordinates on a sphere or elipsoid (like
>> the earth). The coordinate system is La (latitude) and Lo
>> (Longitude), and the notation G(La,Lo) defines a point on the elipsoid.
>>
>> - Device Space: The data being displayed in the mapbean. Lets say
>> the coordinate system is X and Y and the notation D(x,y) defines a
>> point on the screen in the mapbean (or a layer if you want).
>>
>> - Projection: A function P the maps G(La,Lo) -> D(x,y). I am not
>> sure that this function is always reversible. Does anyone know if
>> this function is always reversible?
>
> In OpenMap, the Projection is an Object that translates coordinates
> from your Geocentric Space to your Device Space (projection.forward
> (lat, lon)). The function is reversible, called with the inverse()
> function (projection.inverse(x, y). The MapBean's main
> responsibility is to manage the current Projection object and make
> sure the active Layers get a projection notification when it changes.
>
>> The main problem is we need to convert the tiff from its current
>> coordinate sytem (Raster Space) into Device Space. At the moment I
>> am thinking that perhaps the best approach is to initally convert
>> the tiff into Geocentric space and then buffer this for between
>> projection changes. This raises the question about what is the best
>> grainularity for the lat and longs in the buffer, but that should be
>> easy to adjust based on parameters. I am not so sure how easy it is
>> to actually do the conversion from raster space to geocentric space.
>> Any helpful pointers for resources on this would be most welcome.
>>
>> Then we just have to render the geocentric buffer into device
>> space. There are two possible approaches to this.
>
> It really depends on the projection of the image in Raster Space,
> which may be different for every image. If you automatically convert
> all images to be re-projected into Geocentric Space, then all the
> layer has to do after that is the same operation for all images. You
> probably don't want to hold the original image data in memory after
> the first conversion.
>
> Depending on the size of the original images, you may want to tile
> the geocentric images and manage them separately.
>
> The com.bbn.openmap.plugin.earthImage.EarthImagePlugIn is an brute-
> force example of converting images that cover the entire earth
> (-180/180, -90/90, Mercator Projection) to the current OpenMap
> projection. It takes a pixel-by-pixel approach for the projection
> image space, inverse projection the pixel location to find the lat/
> lon location, and then going into the image to get the pixel color
> for that lat/lon (which is why it only works for Mercator projections
> with the total extents, it assumes these dimensions in order to do
> that pixel color lookup). It's not all *that* slow, and it
> automatically determines the granularity needed for the given
> projection.
>
> The other thing that's on my list to try out is to use the
> javax.media.jai.WarpGrid class in JAI to do some of the re-
> projecting, using values set by the projection to do translation for
> the entire image.
>
>
> Hope this helps,
>
> Don
>
>> A) If P is always reversible, then whenever a projectionChange event
>> occurs I should be able to draw the tiff by doing a reverse mapping
>> from D(x,y) to G(la,lo), sampling at each D(x,y). The problems I can
>> see with this is that it may be slow. (Have to sample each and every
>> pixel in the bounding box each time a projection changes) Also
>> D(x,y) may map to more than one R(i,,j), so may need to code for
>> multiple samples per pixel to avoid aliasing artifacts, etc.
>> Especially as scaling occurs. The more samples per pixel, the slower
>> things are going to be.
>>
>> B) Otherwise, I will just have to loop though the Geocentric buffer
>> and build up a picture that way.
>>
>>
>>
>> Have I missed anything out so far in my thinking? Any comments or
>> help you can give me is greatly appreciated.
>>
>> Best regards,
>>
>> Jason Butler.
>>
>>
>>
>
>
>
> =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
> Don Dietrick, dietrick_at_bbn.com
> BBN Technologies, Cambridge, MA
> =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
>
>
> --
> [To unsubscribe to this list send an email to "majdart_at_bbn.com"
> with the following text in the BODY of the message "unsubscribe
> openmap-users"]
--
[To unsubscribe to this list send an email to "majdart_at_bbn.com"
with the following text in the BODY of the message "unsubscribe openmap-users"]
Received on Wed Oct 05 2005 - 05:19:20 EDT