Ticket #14536: GeoImageLayer_ExifReader_refactoring.patch
File GeoImageLayer_ExifReader_refactoring.patch, 14.6 KB (added by , 8 years ago) |
---|
-
src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java
8 8 import java.util.Date; 9 9 10 10 import org.openstreetmap.josm.Main; 11 import org.openstreetmap.josm.data.SystemOfMeasurement;12 11 import org.openstreetmap.josm.data.coor.CachedLatLon; 13 12 import org.openstreetmap.josm.data.coor.LatLon; 14 13 import org.openstreetmap.josm.tools.ExifReader; … … 431 430 public void extractExif() { 432 431 433 432 Metadata metadata; 434 Directory dirExif;435 GpsDirectory dirGps;436 433 437 434 if (file == null) { 438 435 return; 439 436 } 440 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); 445 return; 446 } 447 441 448 // Changed to silently cope with no time info in exif. One case 442 449 // of person having time that couldn't be parsed, but valid GPS info 443 450 try { 444 setExifTime(ExifReader.readTime( file));451 setExifTime(ExifReader.readTime(metadata)); 445 452 } catch (RuntimeException ex) { 446 453 Main.warn(ex); 447 454 setExifTime(null); 448 455 } 449 456 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); 460 459 461 460 try { 462 461 if (dirExif != null) { … … 473 472 return; 474 473 } 475 474 476 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) 475 final Double speed = ExifReader.readSpeed(dirGps); 476 if (speed != null) { 487 477 setSpeed(speed); 488 } catch (MetadataException ex) {489 Main.debug(ex);490 478 } 491 479 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 } 480 final Double ele = ExifReader.readElevation(dirGps); 481 if (ele != null) { 498 482 setElevation(ele); 499 } catch (MetadataException ex) {500 Main.debug(ex);501 483 } 502 484 503 485 try { 504 LatLon latlon = ExifReader.readLatLon(dirGps);486 final LatLon latlon = ExifReader.readLatLon(dirGps); 505 487 setExifCoor(latlon); 506 488 setPos(getExifCoor()); 507 508 489 } catch (MetadataException | IndexOutOfBoundsException ex) { // (other exceptions, e.g. #5271) 509 490 Main.error("Error reading EXIF from file: " + ex); 510 491 setExifCoor(null); … … 512 493 } 513 494 514 495 try { 515 Double direction = ExifReader.readDirection(dirGps);496 final Double direction = ExifReader.readDirection(dirGps); 516 497 if (direction != null) { 517 498 setExifImgDir(direction); 518 499 } -
src/org/openstreetmap/josm/tools/ExifReader.java
8 8 import java.util.concurrent.TimeUnit; 9 9 10 10 import org.openstreetmap.josm.Main; 11 import org.openstreetmap.josm.data.SystemOfMeasurement; 11 12 import org.openstreetmap.josm.data.coor.LatLon; 12 13 import org.openstreetmap.josm.tools.date.DateUtils; 13 14 … … 41 42 */ 42 43 public static Date readTime(File filename) { 43 44 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 */ 58 public static Date readTime(Metadata metadata) { 59 try { 60 String dateTimeOrig = null; 46 61 String dateTime = null; 47 String subSeconds = null; 62 String dateTimeDig = null; 63 String subSecOrig = null; 64 String subSec = null; 65 String subSecDig = null; 66 // The date fields are preferred in this order: DATETIME_ORIGINAL 67 // (0x9003), DATETIME (0x0132), DATETIME_DIGITIZED (0x9004). Some 68 // cameras store the fields in the wrong directory, so all 69 // directories are searched. Assume that the order of the fields 70 // in the directories is random. 48 71 for (Directory dirIt : metadata.getDirectories()) { 49 72 if (!(dirIt instanceof ExifDirectoryBase)) { 50 73 continue; … … 52 75 for (Tag tag : dirIt.getTags()) { 53 76 if (tag.getTagType() == ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL /* 0x9003 */ && 54 77 !tag.getDescription().matches("\\[[0-9]+ .+\\]")) { 55 // prefer DATETIME_ORIGINAL 56 dateStr = tag.getDescription(); 57 } 58 if (tag.getTagType() == ExifIFD0Directory.TAG_DATETIME /* 0x0132 */) { 59 // prefer DATETIME over DATETIME_DIGITIZED 78 dateTimeOrig = tag.getDescription(); 79 } else if (tag.getTagType() == ExifIFD0Directory.TAG_DATETIME /* 0x0132 */) { 60 80 dateTime = tag.getDescription(); 81 } else if (tag.getTagType() == ExifSubIFDDirectory.TAG_DATETIME_DIGITIZED /* 0x9004 */) { 82 dateTimeDig = tag.getDescription(); 83 } else if (tag.getTagType() == ExifSubIFDDirectory.TAG_SUBSECOND_TIME_ORIGINAL /* 0x9291 */) { 84 subSecOrig = tag.getDescription(); 85 } else if (tag.getTagType() == ExifSubIFDDirectory.TAG_SUBSECOND_TIME /* 0x9290 */) { 86 subSec = tag.getDescription(); 87 } else if (tag.getTagType() == ExifSubIFDDirectory.TAG_SUBSECOND_TIME_DIGITIZED /* 0x9292 */) { 88 subSecDig = tag.getDescription(); 61 89 } 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 90 } 69 91 } 70 if (dateStr == null) { 92 String dateStr = null; 93 String subSeconds = null; 94 if (dateTimeOrig != null) { 95 // prefer TAG_DATETIME_ORIGINAL 96 dateStr = dateTimeOrig; 97 subSeconds = subSecOrig; 98 } else if (dateTime != null) { 99 // TAG_DATETIME is second choice, see #14209 71 100 dateStr = dateTime; 101 subSeconds = subSec; 102 } else if (dateTimeDig != null) { 103 dateStr = dateTimeDig; 104 subSeconds = subSecDig; 72 105 } 73 106 if (dateStr != null) { 74 107 dateStr = dateStr.replace('/', ':'); // workaround for HTC Sensation bug, see #7228 … … 83 116 } 84 117 return date; 85 118 } 86 } catch (UncheckedParseException | JpegProcessingException | IOExceptione) {119 } catch (UncheckedParseException e) { 87 120 Main.error(e); 88 121 } 89 122 return null; … … 153 186 * Returns the direction of the given JPEG file. 154 187 * @param filename The JPEG file to read 155 188 * @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 null189 * or {@code null} if not found 157 190 * @since 6209 158 191 */ 159 192 public static Double readDirection(File filename) { … … 170 203 /** 171 204 * Returns the direction of the given EXIF GPS directory. 172 205 * @param dirGps The EXIF GPS directory 173 * @return The direction of the image when it was capture s(in degrees between 0.0 and 359.99),206 * @return The direction of the image when it was captured (in degrees between 0.0 and 359.99), 174 207 * or {@code null} if missing or if {@code dirGps} is null 175 208 * @since 6209 176 209 */ … … 208 241 } 209 242 210 243 /** 244 * Returns the speed of the given JPEG file. 245 * @param filename The JPEG file to read 246 * @return The speed of the camera when the image was captured (in km/h), 247 * or {@code null} if not found 248 */ 249 public static Double readSpeed(File filename) { 250 try { 251 final Metadata metadata = JpegMetadataReader.readMetadata(filename); 252 final GpsDirectory dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class); 253 return readSpeed(dirGps); 254 } catch (JpegProcessingException | IOException e) { 255 Main.error(e); 256 } 257 return null; 258 } 259 260 /** 261 * Returns the speed of the given EXIF GPS directory. 262 * @param dirGps The EXIF GPS directory 263 * @return The speed of the camera when the image was captured (in km/h), 264 * or {@code null} if missing or if {@code dirGps} is null 265 */ 266 public static Double readSpeed(GpsDirectory dirGps) { 267 if (dirGps != null) { 268 Double speed = dirGps.getDoubleObject(GpsDirectory.TAG_SPEED); 269 if (speed != null) { 270 final String speedRef = dirGps.getString(GpsDirectory.TAG_SPEED_REF); 271 if ("M".equalsIgnoreCase(speedRef)) { 272 // miles per hour 273 speed *= SystemOfMeasurement.IMPERIAL.bValue / 1000; 274 } else if ("N".equalsIgnoreCase(speedRef)) { 275 // knots == nautical miles per hour 276 speed *= SystemOfMeasurement.NAUTICAL_MILE.bValue / 1000; 277 } 278 // default is K (km/h) 279 return speed; 280 } 281 } 282 return null; 283 } 284 285 /** 286 * Returns the elevation of the given JPEG file. 287 * @param filename The JPEG file to read 288 * @return The elevation of the camera when the image was captured (in m), 289 * or {@code null} if not found 290 */ 291 public static Double readElevation(File filename) { 292 try { 293 final Metadata metadata = JpegMetadataReader.readMetadata(filename); 294 final GpsDirectory dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class); 295 return readElevation(dirGps); 296 } catch (JpegProcessingException | IOException e) { 297 Main.error(e); 298 } 299 return null; 300 } 301 302 /** 303 * Returns the elevation of the given EXIF GPS directory. 304 * @param dirGps The EXIF GPS directory 305 * @return The elevation of the camera when the image was captured (in m), 306 * or {@code null} if missing or if {@code dirGps} is null 307 */ 308 public static Double readElevation(GpsDirectory dirGps) { 309 if (dirGps != null) { 310 Double ele = dirGps.getDoubleObject(GpsDirectory.TAG_ALTITUDE); 311 if (ele != null) { 312 final Integer d = dirGps.getInteger(GpsDirectory.TAG_ALTITUDE_REF); 313 if (d != null && d.intValue() == 1) { 314 ele *= -1; 315 } 316 return ele; 317 } 318 } 319 return null; 320 } 321 322 /** 211 323 * Returns a Transform that fixes the image orientation. 212 324 * 213 325 * Only orientation 1, 3, 6 and 8 are supported. Everything else is treated as 1. -
test/unit/org/openstreetmap/josm/tools/ExifReaderTest.java
Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
116 116 } 117 117 118 118 /** 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 /** 119 135 * Non-regression test for ticket <a href="https://josm.openstreetmap.de/ticket/11685">#11685</a> 120 136 * @throws IOException if an error occurs during reading 121 137 */ -
data_nodist/exif-example_speed_ele.jpg
Cannot display: file marked as a binary type. svn:mime-type = image/jpeg