- Timestamp:
- 2016-01-02T23:52:56+01:00 (9 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/gui/layer/geoimage
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java
r9243 r9270 157 157 if (yLayer.data != null) { 158 158 for (ImageEntry ie : yLayer.data) { 159 ie. tmp = null;159 ie.discardTmp(); 160 160 } 161 161 } … … 826 826 if (yLayer.data != null) { 827 827 for (ImageEntry ie: yLayer.data) { 828 ie. tmp = null;828 ie.discardTmp(); 829 829 } 830 830 } … … 834 834 // Create a temporary copy for each image 835 835 for (ImageEntry ie : dateImgLst) { 836 ie.cleanTmp(); 836 ie.createTmp(); 837 ie.tmp.setPos(null); 837 838 } 838 839 -
trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
r9243 r9270 22 22 import java.io.File; 23 23 import java.io.IOException; 24 import java.text.ParseException;25 24 import java.util.ArrayList; 26 25 import java.util.Arrays; 27 import java.util.Calendar;28 26 import java.util.Collection; 29 27 import java.util.Collections; 30 import java.util.GregorianCalendar;31 28 import java.util.HashSet; 32 29 import java.util.LinkedHashSet; … … 34 31 import java.util.List; 35 32 import java.util.Set; 36 import java.util.TimeZone;37 33 import java.util.concurrent.ExecutorService; 38 34 import java.util.concurrent.Executors; … … 50 46 import org.openstreetmap.josm.actions.mapmode.SelectAction; 51 47 import org.openstreetmap.josm.data.Bounds; 52 import org.openstreetmap.josm.data.coor.LatLon;53 48 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor; 54 49 import org.openstreetmap.josm.gui.ExtendedDialog; … … 68 63 import org.openstreetmap.josm.gui.util.GuiHelper; 69 64 import org.openstreetmap.josm.io.JpgImporter; 70 import org.openstreetmap.josm.tools.ExifReader;71 65 import org.openstreetmap.josm.tools.ImageProvider; 72 66 import org.openstreetmap.josm.tools.Utils; 73 74 import com.drew.imaging.jpeg.JpegMetadataReader;75 import com.drew.lang.CompoundException;76 import com.drew.metadata.Directory;77 import com.drew.metadata.Metadata;78 import com.drew.metadata.MetadataException;79 import com.drew.metadata.exif.ExifIFD0Directory;80 import com.drew.metadata.exif.GpsDirectory;81 67 82 68 /** … … 158 144 progressMonitor.worked(1); 159 145 160 ImageEntry e = new ImageEntry(); 161 162 // Changed to silently cope with no time info in exif. One case 163 // of person having time that couldn't be parsed, but valid GPS info 164 165 try { 166 e.setExifTime(ExifReader.readTime(f)); 167 } catch (ParseException ex) { 168 e.setExifTime(null); 169 } 170 e.setFile(f); 171 extractExif(e); 146 ImageEntry e = new ImageEntry(f); 147 e.extractExif(); 172 148 data.add(e); 173 149 } … … 499 475 } 500 476 Point p = mv.getPoint(e.getPos()); 501 if (e. thumbnail != null) {502 Dimension d = scaledDimension(e. thumbnail);477 if (e.hasThumbnail()) { 478 Dimension d = scaledDimension(e.getThumbnail()); 503 479 Rectangle target = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height); 504 480 if (clip.intersects(target)) { 505 tempG.drawImage(e. thumbnail, target.x, target.y, target.width, target.height, null);481 tempG.drawImage(e.getThumbnail(), target.x, target.y, target.width, target.height, null); 506 482 } 507 483 } else { // thumbnail not loaded yet … … 535 511 int imgWidth = 100; 536 512 int imgHeight = 100; 537 if (useThumbs && e. thumbnail != null) {538 Dimension d = scaledDimension(e. thumbnail);513 if (useThumbs && e.hasThumbnail()) { 514 Dimension d = scaledDimension(e.getThumbnail()); 539 515 imgWidth = d.width; 540 516 imgHeight = d.height; … … 574 550 } 575 551 576 if (useThumbs && e. thumbnail != null) {552 if (useThumbs && e.hasThumbnail()) { 577 553 g.setColor(new Color(128, 0, 0, 122)); 578 554 g.fillRect(p.x - imgWidth / 2, p.y - imgHeight / 2, imgWidth, imgHeight); … … 591 567 for (ImageEntry e : data) { 592 568 v.visit(e.getPos()); 593 }594 }595 596 /**597 * Extract GPS metadata from image EXIF598 *599 * If successful, fills in the LatLon and EastNorth attributes of passed in image600 * @param e image entry601 */602 private static void extractExif(ImageEntry e) {603 604 Metadata metadata;605 Directory dirExif;606 GpsDirectory dirGps;607 608 try {609 metadata = JpegMetadataReader.readMetadata(e.getFile());610 dirExif = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);611 dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);612 } catch (CompoundException | IOException p) {613 e.setExifCoor(null);614 e.setPos(null);615 return;616 }617 618 try {619 if (dirExif != null) {620 int orientation = dirExif.getInt(ExifIFD0Directory.TAG_ORIENTATION);621 e.setExifOrientation(orientation);622 }623 } catch (MetadataException ex) {624 Main.debug(ex.getMessage());625 }626 627 if (dirGps == null) {628 e.setExifCoor(null);629 e.setPos(null);630 return;631 }632 633 try {634 double speed = dirGps.getDouble(GpsDirectory.TAG_SPEED);635 String speedRef = dirGps.getString(GpsDirectory.TAG_SPEED_REF);636 if ("M".equalsIgnoreCase(speedRef)) {637 // miles per hour638 speed *= 1.609344;639 } else if ("N".equalsIgnoreCase(speedRef)) {640 // knots == nautical miles per hour641 speed *= 1.852;642 }643 // default is K (km/h)644 e.setSpeed(speed);645 } catch (Exception ex) {646 Main.debug(ex.getMessage());647 }648 649 try {650 double ele = dirGps.getDouble(GpsDirectory.TAG_ALTITUDE);651 int d = dirGps.getInt(GpsDirectory.TAG_ALTITUDE_REF);652 if (d == 1) {653 ele *= -1;654 }655 e.setElevation(ele);656 } catch (MetadataException ex) {657 Main.debug(ex.getMessage());658 }659 660 try {661 LatLon latlon = ExifReader.readLatLon(dirGps);662 e.setExifCoor(latlon);663 e.setPos(e.getExifCoor());664 665 } catch (Exception ex) { // (other exceptions, e.g. #5271)666 Main.error("Error reading EXIF from file: "+ex);667 e.setExifCoor(null);668 e.setPos(null);669 }670 671 try {672 Double direction = ExifReader.readDirection(dirGps);673 if (direction != null) {674 e.setExifImgDir(direction.doubleValue());675 }676 } catch (Exception ex) { // (CompoundException and other exceptions, e.g. #5271)677 Main.debug(ex.getMessage());678 }679 680 // Time and date. We can have these cases:681 // 1) GPS_TIME_STAMP not set -> date/time will be null682 // 2) GPS_DATE_STAMP not set -> use EXIF date or set to default683 // 3) GPS_TIME_STAMP and GPS_DATE_STAMP are set684 int[] timeStampComps = dirGps.getIntArray(GpsDirectory.TAG_TIME_STAMP);685 if (timeStampComps != null) {686 int gpsHour = timeStampComps[0];687 int gpsMin = timeStampComps[1];688 int gpsSec = timeStampComps[2];689 Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));690 691 // We have the time. Next step is to check if the GPS date stamp is set.692 // dirGps.getString() always succeeds, but the return value might be null.693 String dateStampStr = dirGps.getString(GpsDirectory.TAG_DATE_STAMP);694 if (dateStampStr != null && dateStampStr.matches("^\\d+:\\d+:\\d+$")) {695 String[] dateStampComps = dateStampStr.split(":");696 cal.set(Calendar.YEAR, Integer.parseInt(dateStampComps[0]));697 cal.set(Calendar.MONTH, Integer.parseInt(dateStampComps[1]) - 1);698 cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateStampComps[2]));699 } else {700 // No GPS date stamp in EXIF data. Copy it from EXIF time.701 // Date is not set if EXIF time is not available.702 if (e.hasExifTime()) {703 // Time not set yet, so we can copy everything, not just date.704 cal.setTime(e.getExifTime());705 }706 }707 708 cal.set(Calendar.HOUR_OF_DAY, gpsHour);709 cal.set(Calendar.MINUTE, gpsMin);710 cal.set(Calendar.SECOND, gpsSec);711 712 e.setExifGpsTime(cal.getTime());713 569 } 714 570 } … … 862 718 Point p = Main.map.mapView.getPoint(img.getPos()); 863 719 Rectangle r; 864 if (useThumbs && img. thumbnail != null) {865 Dimension d = scaledDimension(img. thumbnail);720 if (useThumbs && img.hasThumbnail()) { 721 Dimension d = scaledDimension(img.getThumbnail()); 866 722 r = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height); 867 723 } else { … … 972 828 Point p = Main.map.mapView.getPoint(e.getPos()); 973 829 Rectangle r; 974 if (useThumbs && e. thumbnail != null) {975 Dimension d = scaledDimension(e. thumbnail);830 if (useThumbs && e.hasThumbnail()) { 831 Dimension d = scaledDimension(e.getThumbnail()); 976 832 r = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height); 977 833 } else { -
trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java
r9243 r9270 4 4 import java.awt.Image; 5 5 import java.io.File; 6 import java.io.IOException; 7 import java.text.ParseException; 8 import java.util.Calendar; 6 9 import java.util.Date; 7 10 import java.util.GregorianCalendar; 11 import java.util.TimeZone; 12 13 import com.drew.imaging.jpeg.JpegMetadataReader; 14 import com.drew.lang.CompoundException; 15 import com.drew.metadata.Directory; 16 import com.drew.metadata.Metadata; 17 import com.drew.metadata.MetadataException; 18 import com.drew.metadata.exif.ExifIFD0Directory; 19 import com.drew.metadata.exif.GpsDirectory; 20 import org.openstreetmap.josm.Main; 21 import org.openstreetmap.josm.data.SystemOfMeasurement; 8 22 import org.openstreetmap.josm.data.coor.CachedLatLon; 9 23 import org.openstreetmap.josm.data.coor.LatLon; 24 import org.openstreetmap.josm.tools.ExifReader; 10 25 11 26 /** … … 26 41 /** Temporary source of GPS time if not correlated with GPX track. */ 27 42 private Date exifGpsTime; 28 Image thumbnail;43 private Image thumbnail; 29 44 30 45 /** … … 44 59 * for the current time offset on the map in real time. 45 60 * On the other hand, when the user aborts this operation, the old values 46 * should be restored. We have a temp rary copy, that overrides61 * should be restored. We have a temporary copy, that overrides 47 62 * the normal values if it is not null. (This may be not the most elegant 48 63 * solution for this, but it works.) … … 51 66 52 67 /** 53 * Returns the cached temporary position value. 54 * @return the cached temporary position value 68 * Constructs a new {@code ImageEntry}. 69 */ 70 public ImageEntry() {} 71 72 /** 73 * Constructs a new {@code ImageEntry}. 74 * @param file Path to image file on disk 75 */ 76 public ImageEntry(File file) { 77 setFile(file); 78 } 79 80 /** 81 * Returns the position value. The position value from the temporary copy 82 * is returned if that copy exists. 83 * @return the position value 55 84 */ 56 85 public CachedLatLon getPos() { … … 61 90 62 91 /** 63 * Returns the cached temporary speed value. 64 * @return the cached temporary speed value 92 * Returns the speed value. The speed value from the temporary copy is 93 * returned if that copy exists. 94 * @return the speed value 65 95 */ 66 96 public Double getSpeed() { … … 71 101 72 102 /** 73 * Returns the cached temporary elevation value. 74 * @return the cached temporary elevation value 103 * Returns the elevation value. The elevation value from the temporary 104 * copy is returned if that copy exists. 105 * @return the elevation value 75 106 */ 76 107 public Double getElevation() { … … 81 112 82 113 /** 83 * Returns the cached temporary GPS time value. 84 * @return the cached temporary GPS time value 114 * Returns the GPS time value. The GPS time value from the temporary copy 115 * is returned if that copy exists. 116 * @return the GPS time value 85 117 */ 86 118 public Date getGpsTime() { … … 161 193 162 194 public Double getExifImgDir() { 195 if (tmp != null) 196 return tmp.exifImgDir; 163 197 return exifImgDir; 164 198 } 165 199 200 /** 201 * Determines whether a thumbnail is set 202 * @return {@code true} if a thumbnail is set 203 */ 166 204 public boolean hasThumbnail() { 167 205 return thumbnail != null; … … 169 207 170 208 /** 209 * Returns the thumbnail. 210 * @return the thumbnail 211 */ 212 public Image getThumbnail() { 213 return thumbnail; 214 } 215 216 /** 217 * Sets the thumbnail. 218 * @param thumbnail thumbnail 219 */ 220 public void setThumbnail(Image thumbnail) { 221 this.thumbnail = thumbnail; 222 } 223 224 /** 171 225 * Sets the position. 172 226 * @param pos cached position … … 181 235 */ 182 236 public void setPos(LatLon pos) { 183 setPos( new CachedLatLon(pos));237 setPos(pos != null ? new CachedLatLon(pos) : null); 184 238 } 185 239 … … 241 295 } 242 296 243 public void setExifImgDir( double exifDir) {297 public void setExifImgDir(Double exifDir) { 244 298 this.exifImgDir = exifDir; 245 299 } … … 269 323 270 324 /** 271 * Make a fresh copy and save it in the temporary variable. 272 */ 273 public void cleanTmp() { 325 * Make a fresh copy and save it in the temporary variable. Use 326 * {@link #applyTmp()} or {@link #discardTmp()} if the temporary variable 327 * is not needed anymore. 328 */ 329 public void createTmp() { 274 330 tmp = clone(); 275 tmp.setPos(null);276 331 tmp.tmp = null; 277 332 } 278 333 279 334 /** 280 * Copy the values from the temporary variable to the main instance. 335 * Get temporary variable that is used for real time parameter 336 * adjustments. The temporary variable is created if it does not exist 337 * yet. Use {@link #applyTmp()} or {@link #discardTmp()} if the temporary 338 * variable is not needed anymore. 339 * @return temporary variable 340 */ 341 public ImageEntry getTmp() { 342 if (tmp == null) { 343 createTmp(); 344 } 345 return tmp; 346 } 347 348 /** 349 * Copy the values from the temporary variable to the main instance. The 350 * temporary variable is deleted. 351 * @see #discardTmp() 281 352 */ 282 353 public void applyTmp() { … … 286 357 elevation = tmp.elevation; 287 358 gpsTime = tmp.gpsTime; 359 exifImgDir = tmp.exifImgDir; 288 360 tmp = null; 289 361 } 362 } 363 364 /** 365 * Delete the temporary variable. Temporary modifications are lost. 366 * @see #applyTmp() 367 */ 368 public void discardTmp() { 369 tmp = null; 290 370 } 291 371 … … 336 416 return isNewGpsData; 337 417 } 418 419 /** 420 * Extract GPS metadata from image EXIF. Has no effect if the image file is not set 421 * 422 * If successful, fills in the LatLon, speed, elevation, image direction, and other attributes 423 */ 424 public void extractExif() { 425 426 Metadata metadata; 427 Directory dirExif; 428 GpsDirectory dirGps; 429 430 if (file == null) { 431 return; 432 } 433 434 try { 435 metadata = JpegMetadataReader.readMetadata(file); 436 dirExif = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class); 437 dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class); 438 } catch (CompoundException | IOException p) { 439 setExifCoor(null); 440 setPos(null); 441 return; 442 } 443 444 try { 445 if (dirExif != null) { 446 int orientation = dirExif.getInt(ExifIFD0Directory.TAG_ORIENTATION); 447 setExifOrientation(orientation); 448 } 449 } catch (MetadataException ex) { 450 Main.debug(ex.getMessage()); 451 } 452 453 if (dirGps == null) { 454 setExifCoor(null); 455 setPos(null); 456 return; 457 } 458 459 try { 460 double speed = dirGps.getDouble(GpsDirectory.TAG_SPEED); 461 String speedRef = dirGps.getString(GpsDirectory.TAG_SPEED_REF); 462 if ("M".equalsIgnoreCase(speedRef)) { 463 // miles per hour 464 speed *= SystemOfMeasurement.IMPERIAL.bValue / 1000; 465 } else if ("N".equalsIgnoreCase(speedRef)) { 466 // knots == nautical miles per hour 467 speed *= SystemOfMeasurement.NAUTICAL_MILE.bValue / 1000; 468 } 469 // default is K (km/h) 470 setSpeed(speed); 471 } catch (Exception ex) { 472 Main.debug(ex.getMessage()); 473 } 474 475 try { 476 double ele = dirGps.getDouble(GpsDirectory.TAG_ALTITUDE); 477 int d = dirGps.getInt(GpsDirectory.TAG_ALTITUDE_REF); 478 if (d == 1) { 479 ele *= -1; 480 } 481 setElevation(ele); 482 } catch (MetadataException ex) { 483 Main.debug(ex.getMessage()); 484 } 485 486 try { 487 LatLon latlon = ExifReader.readLatLon(dirGps); 488 setExifCoor(latlon); 489 setPos(getExifCoor()); 490 491 } catch (Exception ex) { // (other exceptions, e.g. #5271) 492 Main.error("Error reading EXIF from file: " + ex); 493 setExifCoor(null); 494 setPos(null); 495 } 496 497 try { 498 Double direction = ExifReader.readDirection(dirGps); 499 if (direction != null) { 500 setExifImgDir(direction); 501 } 502 } catch (Exception ex) { // (CompoundException and other exceptions, e.g. #5271) 503 Main.debug(ex.getMessage()); 504 } 505 506 // Changed to silently cope with no time info in exif. One case 507 // of person having time that couldn't be parsed, but valid GPS info 508 try { 509 setExifTime(ExifReader.readTime(file)); 510 } catch (ParseException ex) { 511 setExifTime(null); 512 } 513 514 // Time and date. We can have these cases: 515 // 1) GPS_TIME_STAMP not set -> date/time will be null 516 // 2) GPS_DATE_STAMP not set -> use EXIF date or set to default 517 // 3) GPS_TIME_STAMP and GPS_DATE_STAMP are set 518 int[] timeStampComps = dirGps.getIntArray(GpsDirectory.TAG_TIME_STAMP); 519 if (timeStampComps != null) { 520 int gpsHour = timeStampComps[0]; 521 int gpsMin = timeStampComps[1]; 522 int gpsSec = timeStampComps[2]; 523 Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); 524 525 // We have the time. Next step is to check if the GPS date stamp is set. 526 // dirGps.getString() always succeeds, but the return value might be null. 527 String dateStampStr = dirGps.getString(GpsDirectory.TAG_DATE_STAMP); 528 if (dateStampStr != null && dateStampStr.matches("^\\d+:\\d+:\\d+$")) { 529 String[] dateStampComps = dateStampStr.split(":"); 530 cal.set(Calendar.YEAR, Integer.parseInt(dateStampComps[0])); 531 cal.set(Calendar.MONTH, Integer.parseInt(dateStampComps[1]) - 1); 532 cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateStampComps[2])); 533 } else { 534 // No GPS date stamp in EXIF data. Copy it from EXIF time. 535 // Date is not set if EXIF time is not available. 536 if (hasExifTime()) { 537 // Time not set yet, so we can copy everything, not just date. 538 cal.setTime(getExifTime()); 539 } 540 } 541 542 cal.set(Calendar.HOUR_OF_DAY, gpsHour); 543 cal.set(Calendar.MINUTE, gpsMin); 544 cal.set(Calendar.SECOND, gpsSec); 545 546 setExifGpsTime(cal.getTime()); 547 } 548 } 338 549 } -
trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java
r9078 r9270 70 70 private JButton btnPrevious; 71 71 private JButton btnCollapse; 72 private JToggleButton tbCentre; 72 73 73 74 private ImageViewerDialog() { … … 150 151 ); 151 152 152 JToggleButtontbCentre = new JToggleButton(new ImageAction(COMMAND_CENTERVIEW,153 tbCentre = new JToggleButton(new ImageAction(COMMAND_CENTERVIEW, 153 154 ImageProvider.get("dialogs", "centreview"), tr("Center view"))); 154 155 tbCentre.setPreferredSize(buttonDim); … … 225 226 currentLayer.showLastPhoto(); 226 227 } else if (COMMAND_CENTERVIEW.equals(action)) { 227 centerView = ((JToggleButton) e.getSource()).isSelected(); 228 final JToggleButton button = (JToggleButton) e.getSource(); 229 centerView = button.isEnabled() && button.isSelected(); 228 230 if (centerView && currentEntry != null && currentEntry.getPos() != null) { 229 231 Main.map.mapView.zoomTo(currentEntry.getPos()); … … 276 278 } 277 279 280 /** 281 * Enables (or disables) the "Center view" button. 282 * @param value {@code true} to enable the button, {@code false} otherwise 283 * @return the old enabled value. Can be used to restore the original enable state 284 */ 285 public static synchronized boolean setCentreEnabled(boolean value) { 286 final ImageViewerDialog instance = getInstance(); 287 final boolean wasEnabled = instance.tbCentre.isEnabled(); 288 instance.tbCentre.setEnabled(value); 289 instance.tbCentre.getAction().actionPerformed(new ActionEvent(instance.tbCentre, 0, null)); 290 return wasEnabled; 291 } 292 278 293 private transient GeoImageLayer currentLayer; 279 294 private transient ImageEntry currentEntry; … … 304 319 StringBuilder osd = new StringBuilder(entry.getFile() != null ? entry.getFile().getName() : ""); 305 320 if (entry.getElevation() != null) { 306 osd.append(tr("\nAltitude: {0} m", entry.getElevation().longValue()));321 osd.append(tr("\nAltitude: {0} m", Math.round(entry.getElevation()))); 307 322 } 308 323 if (entry.getSpeed() != null) { -
trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ThumbsLoader.java
r9078 r9270 33 33 private final boolean cacheOff = Main.pref.getBoolean("geoimage.noThumbnailCache", false); 34 34 35 /** 36 * Constructs a new thumbnail loader that operates on a geoimage layer. 37 * @param layer geoimage layer 38 */ 35 39 public ThumbsLoader(GeoImageLayer layer) { 36 40 this.layer = layer; 37 41 this.data = new ArrayList<>(layer.data); 42 initCache(); 43 } 44 45 /** 46 * Initialize the thumbnail cache. 47 */ 48 private void initCache() { 38 49 if (!cacheOff) { 39 50 try { … … 55 66 56 67 // Do not load thumbnails that were loaded before. 57 if ( entry.thumbnail == null) {58 entry. thumbnail = loadThumb(entry);68 if (!entry.hasThumbnail()) { 69 entry.setThumbnail(loadThumb(entry)); 59 70 60 71 if (Main.isDisplayingMapView()) {
Note:
See TracChangeset
for help on using the changeset viewer.