Changeset 11745 in josm


Ignore:
Timestamp:
2017-03-19T01:16:39+01:00 (6 months ago)
Author:
Don-vip
Message:

fix #14536 - Improved ExifReader.readTime(), Refactored ImageEntry.extractExif() (patch by holgermappt)

Location:
trunk
Files:
1 added
4 edited

Legend:

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

    r11620 r11745  
    99
    1010import org.openstreetmap.josm.Main;
    11 import org.openstreetmap.josm.data.SystemOfMeasurement;
    1211import org.openstreetmap.josm.data.coor.CachedLatLon;
    1312import org.openstreetmap.josm.data.coor.LatLon;
     
    432431
    433432        Metadata metadata;
    434         Directory dirExif;
    435         GpsDirectory dirGps;
    436433
    437434        if (file == null) {
     435            return;
     436        }
     437
     438        try {
     439            metadata = JpegMetadataReader.readMetadata(file);
     440        } catch (CompoundException | IOException ex) {
     441            Main.error(ex);
     442            setExifTime(null);
     443            setExifCoor(null);
     444            setPos(null);
    438445            return;
    439446        }
     
    442449        // of person having time that couldn't be parsed, but valid GPS info
    443450        try {
    444             setExifTime(ExifReader.readTime(file));
     451            setExifTime(ExifReader.readTime(metadata));
    445452        } catch (RuntimeException ex) {
    446453            Main.warn(ex);
     
    448455        }
    449456
    450         try {
    451             metadata = JpegMetadataReader.readMetadata(file);
    452             dirExif = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
    453             dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
    454         } catch (CompoundException | IOException ex) {
    455             Main.warn(ex);
    456             setExifCoor(null);
    457             setPos(null);
    458             return;
    459         }
     457        final Directory dirExif = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
     458        final GpsDirectory dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
    460459
    461460        try {
     
    474473        }
    475474
     475        final Double speed = ExifReader.readSpeed(dirGps);
     476        if (speed != null) {
     477            setSpeed(speed);
     478        }
     479
     480        final Double ele = ExifReader.readElevation(dirGps);
     481        if (ele != null) {
     482            setElevation(ele);
     483        }
     484
    476485        try {
    477             double speed = dirGps.getDouble(GpsDirectory.TAG_SPEED);
    478             String speedRef = dirGps.getString(GpsDirectory.TAG_SPEED_REF);
    479             if ("M".equalsIgnoreCase(speedRef)) {
    480                 // miles per hour
    481                 speed *= SystemOfMeasurement.IMPERIAL.bValue / 1000;
    482             } else if ("N".equalsIgnoreCase(speedRef)) {
    483                 // knots == nautical miles per hour
    484                 speed *= SystemOfMeasurement.NAUTICAL_MILE.bValue / 1000;
    485             }
    486             // default is K (km/h)
    487             setSpeed(speed);
    488         } catch (MetadataException ex) {
    489             Main.debug(ex);
    490         }
    491 
    492         try {
    493             double ele = dirGps.getDouble(GpsDirectory.TAG_ALTITUDE);
    494             int d = dirGps.getInt(GpsDirectory.TAG_ALTITUDE_REF);
    495             if (d == 1) {
    496                 ele *= -1;
    497             }
    498             setElevation(ele);
    499         } catch (MetadataException ex) {
    500             Main.debug(ex);
    501         }
    502 
    503         try {
    504             LatLon latlon = ExifReader.readLatLon(dirGps);
     486            final LatLon latlon = ExifReader.readLatLon(dirGps);
    505487            setExifCoor(latlon);
    506488            setPos(getExifCoor());
    507 
    508489        } catch (MetadataException | IndexOutOfBoundsException ex) { // (other exceptions, e.g. #5271)
    509490            Main.error("Error reading EXIF from file: " + ex);
     
    513494
    514495        try {
    515             Double direction = ExifReader.readDirection(dirGps);
     496            final Double direction = ExifReader.readDirection(dirGps);
    516497            if (direction != null) {
    517498                setExifImgDir(direction);
  • trunk/src/org/openstreetmap/josm/tools/ExifReader.java

    r11514 r11745  
    99
    1010import org.openstreetmap.josm.Main;
     11import org.openstreetmap.josm.data.SystemOfMeasurement;
    1112import org.openstreetmap.josm.data.coor.LatLon;
    1213import org.openstreetmap.josm.tools.date.DateUtils;
     
    4243    public static Date readTime(File filename) {
    4344        try {
    44             Metadata metadata = JpegMetadataReader.readMetadata(filename);
    45             String dateStr = null;
     45            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
     46            return readTime(metadata);
     47        } catch (JpegProcessingException | IOException e) {
     48            Main.error(e);
     49        }
     50        return null;
     51    }
     52
     53    /**
     54     * Returns the date/time from the given JPEG file.
     55     * @param metadata The EXIF metadata
     56     * @return The date/time read in the EXIF section, or {@code null} if not found
     57     * @since 11745
     58     */
     59    public static Date readTime(Metadata metadata) {
     60        try {
     61            String dateTimeOrig = null;
    4662            String dateTime = null;
    47             String subSeconds = null;
     63            String dateTimeDig = null;
     64            String subSecOrig = null;
     65            String subSec = null;
     66            String subSecDig = null;
     67            // The date fields are preferred in this order: DATETIME_ORIGINAL
     68            // (0x9003), DATETIME (0x0132), DATETIME_DIGITIZED (0x9004).  Some
     69            // cameras store the fields in the wrong directory, so all
     70            // directories are searched.  Assume that the order of the fields
     71            // in the directories is random.
    4872            for (Directory dirIt : metadata.getDirectories()) {
    4973                if (!(dirIt instanceof ExifDirectoryBase)) {
     
    5377                    if (tag.getTagType() == ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL /* 0x9003 */ &&
    5478                            !tag.getDescription().matches("\\[[0-9]+ .+\\]")) {
    55                         // prefer DATETIME_ORIGINAL
    56                         dateStr = tag.getDescription();
     79                        dateTimeOrig = tag.getDescription();
     80                    } else if (tag.getTagType() == ExifIFD0Directory.TAG_DATETIME /* 0x0132 */) {
     81                        dateTime = tag.getDescription();
     82                    } else if (tag.getTagType() == ExifSubIFDDirectory.TAG_DATETIME_DIGITIZED /* 0x9004 */) {
     83                        dateTimeDig = tag.getDescription();
     84                    } else if (tag.getTagType() == ExifSubIFDDirectory.TAG_SUBSECOND_TIME_ORIGINAL /* 0x9291 */) {
     85                        subSecOrig = tag.getDescription();
     86                    } else if (tag.getTagType() == ExifSubIFDDirectory.TAG_SUBSECOND_TIME /* 0x9290 */) {
     87                        subSec = tag.getDescription();
     88                    } else if (tag.getTagType() == ExifSubIFDDirectory.TAG_SUBSECOND_TIME_DIGITIZED /* 0x9292 */) {
     89                        subSecDig = tag.getDescription();
    5790                    }
    58                     if (tag.getTagType() == ExifIFD0Directory.TAG_DATETIME /* 0x0132 */) {
    59                         // prefer DATETIME over DATETIME_DIGITIZED
    60                         dateTime = tag.getDescription();
    61                     }
    62                     if (tag.getTagType() == ExifSubIFDDirectory.TAG_DATETIME_DIGITIZED /* 0x9004 */ && dateTime == null) {
    63                         dateTime = tag.getDescription();
    64                     }
    65                     if (tag.getTagType() == ExifIFD0Directory.TAG_SUBSECOND_TIME_ORIGINAL) {
    66                         subSeconds = tag.getDescription();
    67                     }
    68                 }
    69             }
    70             if (dateStr == null) {
     91                }
     92            }
     93            String dateStr = null;
     94            String subSeconds = null;
     95            if (dateTimeOrig != null) {
     96                // prefer TAG_DATETIME_ORIGINAL
     97                dateStr = dateTimeOrig;
     98                subSeconds = subSecOrig;
     99            } else if (dateTime != null) {
     100                // TAG_DATETIME is second choice, see #14209
    71101                dateStr = dateTime;
     102                subSeconds = subSec;
     103            } else if (dateTimeDig != null) {
     104                dateStr = dateTimeDig;
     105                subSeconds = subSecDig;
    72106            }
    73107            if (dateStr != null) {
     
    84118                return date;
    85119            }
    86         } catch (UncheckedParseException | JpegProcessingException | IOException e) {
     120        } catch (UncheckedParseException e) {
    87121            Main.error(e);
    88122        }
     
    154188     * @param filename The JPEG file to read
    155189     * @return The direction of the image when it was captures (in degrees between 0.0 and 359.99),
    156      * or {@code null} if missing or if {@code dirGps} is null
     190     * or {@code null} if not found
    157191     * @since 6209
    158192     */
     
    171205     * Returns the direction of the given EXIF GPS directory.
    172206     * @param dirGps The EXIF GPS directory
    173      * @return The direction of the image when it was captures (in degrees between 0.0 and 359.99),
     207     * @return The direction of the image when it was captured (in degrees between 0.0 and 359.99),
    174208     * or {@code null} if missing or if {@code dirGps} is null
    175209     * @since 6209
     
    206240        }
    207241        return value;
     242    }
     243
     244    /**
     245     * Returns the speed of the given JPEG file.
     246     * @param filename The JPEG file to read
     247     * @return The speed of the camera when the image was captured (in km/h),
     248     *         or {@code null} if not found
     249     * @since 11745
     250     */
     251    public static Double readSpeed(File filename) {
     252        try {
     253            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
     254            final GpsDirectory dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
     255            return readSpeed(dirGps);
     256        } catch (JpegProcessingException | IOException e) {
     257            Main.error(e);
     258        }
     259        return null;
     260    }
     261
     262    /**
     263     * Returns the speed of the given EXIF GPS directory.
     264     * @param dirGps The EXIF GPS directory
     265     * @return The speed of the camera when the image was captured (in km/h),
     266     *         or {@code null} if missing or if {@code dirGps} is null
     267     * @since 11745
     268     */
     269    public static Double readSpeed(GpsDirectory dirGps) {
     270        if (dirGps != null) {
     271            Double speed = dirGps.getDoubleObject(GpsDirectory.TAG_SPEED);
     272            if (speed != null) {
     273                final String speedRef = dirGps.getString(GpsDirectory.TAG_SPEED_REF);
     274                if ("M".equalsIgnoreCase(speedRef)) {
     275                    // miles per hour
     276                    speed *= SystemOfMeasurement.IMPERIAL.bValue / 1000;
     277                } else if ("N".equalsIgnoreCase(speedRef)) {
     278                    // knots == nautical miles per hour
     279                    speed *= SystemOfMeasurement.NAUTICAL_MILE.bValue / 1000;
     280                }
     281                // default is K (km/h)
     282                return speed;
     283            }
     284        }
     285        return null;
     286    }
     287
     288    /**
     289     * Returns the elevation of the given JPEG file.
     290     * @param filename The JPEG file to read
     291     * @return The elevation of the camera when the image was captured (in m),
     292     *         or {@code null} if not found
     293     * @since 11745
     294     */
     295    public static Double readElevation(File filename) {
     296        try {
     297            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
     298            final GpsDirectory dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
     299            return readElevation(dirGps);
     300        } catch (JpegProcessingException | IOException e) {
     301            Main.error(e);
     302        }
     303        return null;
     304    }
     305
     306    /**
     307     * Returns the elevation of the given EXIF GPS directory.
     308     * @param dirGps The EXIF GPS directory
     309     * @return The elevation of the camera when the image was captured (in m),
     310     *         or {@code null} if missing or if {@code dirGps} is null
     311     * @since 11745
     312     */
     313    public static Double readElevation(GpsDirectory dirGps) {
     314        if (dirGps != null) {
     315            Double ele = dirGps.getDoubleObject(GpsDirectory.TAG_ALTITUDE);
     316            if (ele != null) {
     317                final Integer d = dirGps.getInteger(GpsDirectory.TAG_ALTITUDE_REF);
     318                if (d != null && d.intValue() == 1) {
     319                    ele *= -1;
     320                }
     321                return ele;
     322            }
     323        }
     324        return null;
    208325    }
    209326
  • trunk/test/unit/org/openstreetmap/josm/tools/ExifReaderTest.java

    r11514 r11745  
    117117
    118118    /**
     119     * Test speed extraction
     120     */
     121    @Test
     122    public void testReadSpeed() {
     123        assertEquals(Double.valueOf(12.3), ExifReader.readSpeed(new File("data_nodist/exif-example_speed_ele.jpg")));
     124    }
     125
     126    /**
     127     * Test elevation extraction
     128     */
     129    @Test
     130    public void testReadElevation() {
     131        assertEquals(Double.valueOf(23.4), ExifReader.readElevation(new File("data_nodist/exif-example_speed_ele.jpg")));
     132    }
     133
     134    /**
    119135     * Non-regression test for ticket <a href="https://josm.openstreetmap.de/ticket/11685">#11685</a>
    120136     * @throws IOException if an error occurs during reading
Note: See TracChangeset for help on using the changeset viewer.