Changeset 6209 in josm for trunk/src/org


Ignore:
Timestamp:
2013-08-30T11:36:28+02:00 (11 years ago)
Author:
Don-vip
Message:

fix #8895, fix #9030 - fix regression in geottaged pictures support caused by metadata-extractor upgrade, enhance ExifReader, add JUnit tests + javadoc

Location:
trunk/src/org/openstreetmap/josm
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java

    r6128 r6209  
    6565import com.drew.imaging.jpeg.JpegMetadataReader;
    6666import com.drew.lang.CompoundException;
    67 import com.drew.lang.Rational;
    6867import com.drew.metadata.Directory;
    6968import com.drew.metadata.Metadata;
     
    7271import com.drew.metadata.exif.GpsDirectory;
    7372
     73/**
     74 * Layer displaying geottaged pictures.
     75 */
    7476public class GeoImageLayer extends Layer implements PropertyChangeListener, JumpToMarkerLayer {
    7577
     
    263265    }
    264266
     267    /**
     268     * Constructs a new {@code GeoImageLayer}.
     269     * @param data The list of images to display
     270     * @param gpxLayer The associated GPX layer
     271     */
    265272    public GeoImageLayer(final List<ImageEntry> data, GpxLayer gpxLayer) {
    266 
    267273        super(tr("Geotagged Images"));
    268274
     
    499505    }
    500506
    501     /*
    502      * Extract gps from image exif
     507    /**
     508     * Extract GPS metadata from image EXIF
    503509     *
    504      * If successful, fills in the LatLon and EastNorth attributes of passed in
    505      * image;
     510     * If successful, fills in the LatLon and EastNorth attributes of passed in image
    506511     */
    507 
    508512    private static void extractExif(ImageEntry e) {
    509513
    510         double deg;
    511         double min, sec;
    512         double lon, lat;
    513514        Metadata metadata;
    514515        Directory dirExif;
     
    542543
    543544        try {
    544             double ele=dirGps.getDouble(GpsDirectory.TAG_GPS_ALTITUDE);
     545            double ele = dirGps.getDouble(GpsDirectory.TAG_GPS_ALTITUDE);
    545546            int d = dirGps.getInt(GpsDirectory.TAG_GPS_ALTITUDE_REF);
    546547            if (d == 1) {
     
    552553
    553554        try {
    554             // longitude
    555 
    556             Rational[] components = dirGps.getRationalArray(GpsDirectory.TAG_GPS_LONGITUDE);
    557             if (components != null) {
    558                 deg = components[0].doubleValue();
    559                 min = components[1].doubleValue();
    560                 sec = components[2].doubleValue();
    561 
    562                 if (Double.isNaN(deg) && Double.isNaN(min) && Double.isNaN(sec))
    563                     throw new IllegalArgumentException();
    564 
    565                 lon = (Double.isNaN(deg) ? 0 : deg + (Double.isNaN(min) ? 0 : (min / 60)) + (Double.isNaN(sec) ? 0 : (sec / 3600)));
    566 
    567                 if (dirGps.getString(GpsDirectory.TAG_GPS_LONGITUDE_REF).charAt(0) == 'W') {
    568                     lon = -lon;
    569                 }
    570             } else {
    571                 // Try to read lon/lat as double value (Nonstandard, created by some cameras -> #5220)
    572                 lon = dirGps.getDouble(GpsDirectory.TAG_GPS_LONGITUDE);
    573             }
    574 
    575             // latitude
    576 
    577             components = dirGps.getRationalArray(GpsDirectory.TAG_GPS_LATITUDE);
    578             if (components != null) {
    579                 deg = components[0].doubleValue();
    580                 min = components[1].doubleValue();
    581                 sec = components[2].doubleValue();
    582 
    583                 if (Double.isNaN(deg) && Double.isNaN(min) && Double.isNaN(sec))
    584                     throw new IllegalArgumentException();
    585 
    586                 lat = (Double.isNaN(deg) ? 0 : deg + (Double.isNaN(min) ? 0 : (min / 60)) + (Double.isNaN(sec) ? 0 : (sec / 3600)));
    587 
    588                 if (Double.isNaN(lat))
    589                     throw new IllegalArgumentException();
    590 
    591                 if (dirGps.getString(GpsDirectory.TAG_GPS_LATITUDE_REF).charAt(0) == 'S') {
    592                     lat = -lat;
    593                 }
    594             } else {
    595                 lat = dirGps.getDouble(GpsDirectory.TAG_GPS_LATITUDE);
    596             }
    597 
    598             // Store values
    599 
    600             e.setExifCoor(new LatLon(lat, lon));
     555            LatLon latlon = ExifReader.readLatLon(dirGps);
     556            e.setExifCoor(latlon);
    601557            e.setPos(e.getExifCoor());
    602558
     
    607563        }
    608564
    609         // compass direction value
    610 
    611         Rational direction = null;
    612 
    613565        try {
    614             direction = dirGps.getRational(GpsDirectory.TAG_GPS_IMG_DIRECTION);
     566            Double direction = ExifReader.readDirection(dirGps);
    615567            if (direction != null) {
    616568                e.setExifImgDir(direction.doubleValue());
     
    846798    }
    847799
     800    /**
     801     * Returns the associated GPX layer.
     802     * @return The associated GPX layer
     803     */
    848804    public GpxLayer getGpxLayer() {
    849805        return gpxLayer;
  • trunk/src/org/openstreetmap/josm/tools/ExifReader.java

    r6142 r6209  
    77import java.util.Date;
    88
     9import org.openstreetmap.josm.data.coor.LatLon;
     10
    911import com.drew.imaging.jpeg.JpegMetadataReader;
    1012import com.drew.imaging.jpeg.JpegProcessingException;
     13import com.drew.lang.Rational;
    1114import com.drew.metadata.Directory;
    1215import com.drew.metadata.Metadata;
     
    1518import com.drew.metadata.exif.ExifIFD0Directory;
    1619import com.drew.metadata.exif.ExifSubIFDDirectory;
     20import com.drew.metadata.exif.GpsDirectory;
    1721
    1822/**
    19  * Read out exif file information from a jpeg file
     23 * Read out EXIF information from a JPEG file
    2024 * @author Imi
     25 * @since 99
    2126 */
    2227public class ExifReader {
    2328
    24     @SuppressWarnings("unchecked") public static Date readTime(File filename) throws ParseException {
     29    /**
     30     * Returns the date/time from the given JPEG file.
     31     * @param filename The JPEG file to read
     32     * @return The date/time read in the EXIF section, or {@code null} if not found
     33     * @throws ParseException if {@link DateParser#parse} fails to parse date/time
     34     */
     35    public static Date readTime(File filename) throws ParseException {
    2536        try {
    2637            Metadata metadata = JpegMetadataReader.readMetadata(filename);
     
    5162    }
    5263
    53     public static Integer readOrientation(File filename) throws ParseException {
    54         Integer orientation = null;
     64    /**
     65     * Returns the image orientation of the given JPEG file.
     66     * @param filename The JPEG file to read
     67     * @return The image orientation as an {@code int}. Default value is 1. Possible values are listed in EXIF spec as follows:<br>
     68     * <ul>1. The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.</ul>
     69     * <ul>2. The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.</ul>
     70     * <ul>3. The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.</ul>
     71     * <ul>4. The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.</ul>
     72     * <ul>5. The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.</ul>
     73     * <ul>6. The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.</ul>
     74     * <ul>7. The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.</ul>
     75     * <ul>8. The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.</ul>
     76     * @see <a href="http://www.impulseadventure.com/photo/exif-orientation.html">http://www.impulseadventure.com/photo/exif-orientation.html</a>
     77     * @see <a href="http://www.daveperrett.com/articles/2012/07/28/exif-orientation-handling-is-a-ghetto">http://www.daveperrett.com/articles/2012/07/28/exif-orientation-handling-is-a-ghetto</a>
     78     */
     79    public static Integer readOrientation(File filename) {
    5580        try {
    5681            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
    5782            final Directory dir = metadata.getDirectory(ExifIFD0Directory.class);
    58             orientation = dir.getInt(ExifIFD0Directory.TAG_ORIENTATION);
     83            return dir.getInt(ExifIFD0Directory.TAG_ORIENTATION);
    5984        } catch (JpegProcessingException e) {
    6085            e.printStackTrace();
     
    6489            e.printStackTrace();
    6590        }
    66         return orientation;
     91        return null;
    6792    }
    6893
     94    /**
     95     * Returns the geolocation of the given JPEG file.
     96     * @param filename The JPEG file to read
     97     * @return The lat/lon read in the EXIF section, or {@code null} if not found
     98     * @since 6209
     99     */
     100    public static LatLon readLatLon(File filename) {
     101        try {
     102            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
     103            final GpsDirectory dirGps = metadata.getDirectory(GpsDirectory.class);
     104            return readLatLon(dirGps);
     105        } catch (JpegProcessingException e) {
     106            e.printStackTrace();
     107        } catch (IOException e) {
     108            e.printStackTrace();
     109        } catch (MetadataException e) {
     110            e.printStackTrace();
     111        }
     112        return null;
     113    }
     114
     115    /**
     116     * Returns the geolocation of the given EXIF GPS directory.
     117     * @param dirGps The EXIF GPS directory
     118     * @return The lat/lon read in the EXIF section, or {@code null} if {@code dirGps} is null
     119     * @throws MetadataException
     120     * @since 6209
     121     */
     122    public static LatLon readLatLon(GpsDirectory dirGps) throws MetadataException {
     123        if (dirGps != null) {
     124            double lat = readAxis(dirGps, GpsDirectory.TAG_GPS_LATITUDE, GpsDirectory.TAG_GPS_LATITUDE_REF, 'S');
     125            double lon = readAxis(dirGps, GpsDirectory.TAG_GPS_LONGITUDE, GpsDirectory.TAG_GPS_LONGITUDE_REF, 'W');
     126            return new LatLon(lat, lon);
     127        }
     128        return null;
     129    }
     130   
     131    /**
     132     * Returns the direction of the given JPEG file.
     133     * @param filename The JPEG file to read
     134     * @return The direction of the image when it was captures (in degrees between 0.0 and 359.99), or {@code null} if missing or if {@code dirGps} is null
     135     * @since 6209
     136     */
     137    public static Double readDirection(File filename) {
     138        try {
     139            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
     140            final GpsDirectory dirGps = metadata.getDirectory(GpsDirectory.class);
     141            return readDirection(dirGps);
     142        } catch (JpegProcessingException e) {
     143            e.printStackTrace();
     144        } catch (IOException e) {
     145            e.printStackTrace();
     146        }
     147        return null;
     148    }
     149   
     150    /**
     151     * Returns the direction of the given EXIF GPS directory.
     152     * @param dirGps The EXIF GPS directory
     153     * @return The direction of the image when it was captures (in degrees between 0.0 and 359.99), or {@code null} if missing or if {@code dirGps} is null
     154     * @since 6209
     155     */
     156    public static Double readDirection(GpsDirectory dirGps) {
     157        if (dirGps != null) {
     158            Rational direction = dirGps.getRational(GpsDirectory.TAG_GPS_IMG_DIRECTION);
     159            if (direction != null) {
     160                return direction.doubleValue();
     161            }
     162        }
     163        return null;
     164    }
     165
     166    private static double readAxis(GpsDirectory dirGps, int gpsTag, int gpsTagRef, char cRef) throws MetadataException  {
     167        double value;
     168        Rational[] components = dirGps.getRationalArray(gpsTag);
     169        if (components != null) {
     170            double deg = components[0].doubleValue();
     171            double min = components[1].doubleValue();
     172            double sec = components[2].doubleValue();
     173   
     174            if (Double.isNaN(deg) && Double.isNaN(min) && Double.isNaN(sec))
     175                throw new IllegalArgumentException();
     176   
     177            value = (Double.isNaN(deg) ? 0 : deg + (Double.isNaN(min) ? 0 : (min / 60)) + (Double.isNaN(sec) ? 0 : (sec / 3600)));
     178   
     179            if (dirGps.getString(gpsTagRef).charAt(0) == cRef) {
     180                value = -value;
     181            }
     182        } else {
     183            // Try to read lon/lat as double value (Nonstandard, created by some cameras -> #5220)
     184            value = dirGps.getDouble(gpsTag);
     185        }
     186        return value;
     187    }
    69188}
Note: See TracChangeset for help on using the changeset viewer.