source: josm/trunk/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java@ 19387

Last change on this file since 19387 was 19387, checked in by stoecker, 7 days ago

see #24238 - support more EXIF data in image correlation

  • Property svn:eol-style set to native
File size: 25.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.gpx;
3
4import java.awt.Dimension;
5import java.awt.image.BufferedImage;
6import java.io.File;
7import java.io.IOException;
8import java.io.InputStream;
9import java.net.URI;
10import java.nio.file.Files;
11import java.time.Instant;
12import java.util.Date;
13import java.util.List;
14import java.util.Objects;
15
16import javax.imageio.IIOParam;
17
18import org.openstreetmap.josm.data.IQuadBucketType;
19import org.openstreetmap.josm.data.coor.CachedLatLon;
20import org.openstreetmap.josm.data.coor.ILatLon;
21import org.openstreetmap.josm.data.coor.LatLon;
22import org.openstreetmap.josm.data.imagery.street_level.Projections;
23import org.openstreetmap.josm.data.osm.BBox;
24import org.openstreetmap.josm.gui.layer.geoimage.ImageMetadata;
25
26/**
27 * Stores info about each image
28 * @since 14205 (extracted from gui.layer.geoimage.ImageEntry)
29 */
30public class GpxImageEntry implements Comparable<GpxImageEntry>, IQuadBucketType, ImageMetadata {
31 private File file;
32 private Integer exifOrientation;
33 private LatLon exifCoor;
34 private Double exifImgDir;
35 private Double exifGpsTrack;
36 private Double exifHPosErr;
37 private Double exifGpsDop;
38 private Instant exifTime;
39 private Projections cameraProjection = Projections.UNKNOWN;
40 /**
41 * Flag isNewGpsData indicates that the GPS data of the image is new or has changed.
42 * GPS data includes the position, speed, elevation, time (e.g. as extracted from the GPS track).
43 * The flag can used to decide for which image file the EXIF GPS data is (re-)written.
44 */
45 private boolean isNewGpsData;
46 /** Temporary source of GPS time if not correlated with GPX track. */
47 private Instant exifGpsTime;
48
49 private String iptcCaption;
50 private String iptcHeadline;
51 private List<String> iptcKeywords;
52 private String iptcObjectName;
53
54 /**
55 * The following values are computed from the correlation with the gpx track
56 * or extracted from the image EXIF data.
57 */
58 private CachedLatLon pos;
59 /** Speed in kilometer per hour */
60 private Double speed;
61 /** Elevation (altitude) in meters */
62 private Double elevation;
63 /** GPS Differential mode */
64 private Integer gpsDiffMode;
65 /** GPS Measure mode */
66 private Integer gps2d3dMode;
67 /** GPS Datum */
68 private String exifGpsDatum;
69 /** GPS processing method */
70 private String exifGpsProcMethod;
71 /** The time after correlation with a gpx track */
72 private Instant gpsTime;
73
74 private int width;
75 private int height;
76
77 /**
78 * When the correlation dialog is open, we like to show the image position
79 * for the current time offset on the map in real time.
80 * On the other hand, when the user aborts this operation, the old values
81 * should be restored. We have a temporary copy, that overrides
82 * the normal values if it is not null. (This may be not the most elegant
83 * solution for this, but it works.)
84 */
85 private GpxImageEntry tmp;
86
87 /**
88 * Constructs a new {@code GpxImageEntry}.
89 */
90 public GpxImageEntry() {}
91
92 /**
93 * Constructs a new {@code GpxImageEntry} from an existing instance.
94 * @param other existing instance
95 * @since 14624
96 */
97 public GpxImageEntry(GpxImageEntry other) {
98 file = other.file;
99 exifOrientation = other.exifOrientation;
100 exifCoor = other.exifCoor;
101 exifImgDir = other.exifImgDir;
102 exifGpsTrack = other.exifGpsTrack;
103 exifHPosErr = other.exifHPosErr;
104 gpsDiffMode = other.gpsDiffMode;
105 gps2d3dMode = other.gps2d3dMode;
106 exifGpsDop = other.exifGpsDop;
107 exifGpsDatum = other.exifGpsDatum;
108 exifGpsProcMethod = other.exifGpsProcMethod;
109 exifTime = other.exifTime;
110 isNewGpsData = other.isNewGpsData;
111 exifGpsTime = other.exifGpsTime;
112 pos = other.pos;
113 speed = other.speed;
114 elevation = other.elevation;
115 gpsTime = other.gpsTime;
116 width = other.width;
117 height = other.height;
118 tmp = other.tmp;
119 }
120
121 /**
122 * Constructs a new {@code GpxImageEntry}.
123 * @param file Path to image file on disk
124 */
125 public GpxImageEntry(File file) {
126 setFile(file);
127 }
128
129 @Override
130 public URI getImageURI() {
131 return this.getFile().toURI();
132 }
133
134 /**
135 * Returns width of the image this GpxImageEntry represents.
136 * @return width of the image this GpxImageEntry represents
137 * @since 13220
138 */
139 @Override
140 public int getWidth() {
141 return width;
142 }
143
144 /**
145 * Returns height of the image this GpxImageEntry represents.
146 * @return height of the image this GpxImageEntry represents
147 * @since 13220
148 */
149 @Override
150 public int getHeight() {
151 return height;
152 }
153
154 /**
155 * Returns the position value. The position value from the temporary copy
156 * is returned if that copy exists.
157 * @return the position value
158 */
159 @Override
160 public CachedLatLon getPos() {
161 if (tmp != null)
162 return tmp.pos;
163 return pos;
164 }
165
166 /**
167 * Returns the speed value. The speed value from the temporary copy is
168 * returned if that copy exists.
169 * @return the speed value
170 */
171 @Override
172 public Double getSpeed() {
173 if (tmp != null)
174 return tmp.speed;
175 return speed;
176 }
177
178 /**
179 * Returns the elevation value. The elevation value from the temporary
180 * copy is returned if that copy exists.
181 * @return the elevation value
182 */
183 @Override
184 public Double getElevation() {
185 if (tmp != null)
186 return tmp.elevation;
187 return elevation;
188 }
189
190 /**
191 * Return the GPS Differential mode value. The GPS Differential mode value from the temporary
192 * copy is returned if that copy exists.
193 * @return the differential mode value
194 * @since 19387
195 */
196 @Override
197 public Integer getGpsDiffMode() {
198 if (tmp != null)
199 return tmp.gpsDiffMode;
200 return gpsDiffMode;
201 }
202
203 /**
204 * Return the GPS 2d or 3d mode value. The GPS mode value form the temporary
205 * copy is returned if that copy exists.
206 * @return the GPS 2d/3d mode value
207 * @since 19387
208 */
209 @Override
210 public Integer getGps2d3dMode() {
211 if (tmp != null)
212 return tmp.gps2d3dMode;
213 return gps2d3dMode;
214 }
215
216 /**
217 * Return the GPS DOP value. The GPS DOP value from the temporary
218 * copy is returned if that copy exists.
219 * @return the DOP value
220 * @since 19387
221 */
222 @Override
223 public Double getExifGpsDop() {
224 if (tmp != null)
225 return tmp.exifGpsDop;
226 return exifGpsDop;
227 }
228
229 /**
230 * Return the exif GPS coordinates datum value.
231 * @return The datum value
232 * @since 19387
233 */
234 @Override
235 public String getExifGpsDatum() {
236 if (tmp != null)
237 return tmp.exifGpsDatum;
238 return exifGpsDatum;
239 }
240
241 /**
242 * Return the exif GPS processing method string
243 * @return the processing method string
244 * @since 19387
245 */
246 @Override
247 public String getExifGpsProcMethod() {
248 if (tmp != null)
249 return tmp.exifGpsProcMethod;
250 return exifGpsProcMethod;
251 }
252
253 /**
254 * Returns the GPS time value. The GPS time value from the temporary copy
255 * is returned if that copy exists.
256 * @return the GPS time value
257 */
258 @Override
259 public Instant getGpsInstant() {
260 return tmp != null ? tmp.gpsTime : gpsTime;
261 }
262
263 /**
264 * Convenient way to determine if this entry has a GPS time, without the cost of building a defensive copy.
265 * @return {@code true} if this entry has a GPS time
266 * @since 6450
267 */
268 @Override
269 public boolean hasGpsTime() {
270 return (tmp != null && tmp.gpsTime != null) || gpsTime != null;
271 }
272
273 /**
274 * Returns associated file.
275 * @return associated file
276 */
277 public File getFile() {
278 return file;
279 }
280
281 /**
282 * Returns a display name for this entry
283 * @return a display name for this entry
284 */
285 @Override
286 public String getDisplayName() {
287 return file == null ? "" : file.getName();
288 }
289
290 /**
291 * Returns EXIF orientation
292 * @return EXIF orientation
293 */
294 @Override
295 public Integer getExifOrientation() {
296 return exifOrientation != null ? exifOrientation : 1;
297 }
298
299 /**
300 * Returns EXIF time
301 * @return EXIF time
302 * @since 17715
303 */
304 @Override
305 public Instant getExifInstant() {
306 return exifTime;
307 }
308
309 /**
310 * Convenient way to determine if this entry has a EXIF time, without the cost of building a defensive copy.
311 * @return {@code true} if this entry has a EXIF time
312 * @since 6450
313 */
314 @Override
315 public boolean hasExifTime() {
316 return exifTime != null;
317 }
318
319 /**
320 * Returns the EXIF GPS time.
321 * @return the EXIF GPS time
322 * @since 17715
323 */
324 @Override
325 public Instant getExifGpsInstant() {
326 return exifGpsTime;
327 }
328
329 /**
330 * Convenient way to determine if this entry has a EXIF GPS time, without the cost of building a defensive copy.
331 * @return {@code true} if this entry has a EXIF GPS time
332 * @since 6450
333 */
334 @Override
335 public boolean hasExifGpsTime() {
336 return exifGpsTime != null;
337 }
338
339 private static Date getDefensiveDate(Instant date) {
340 if (date == null)
341 return null;
342 return Date.from(date);
343 }
344
345 @Override
346 public LatLon getExifCoor() {
347 return exifCoor;
348 }
349
350 @Override
351 public Double getExifImgDir() {
352 if (tmp != null)
353 return tmp.exifImgDir;
354 return exifImgDir;
355 }
356
357 /**
358 * Convenient way to determine if this entry has a EXIF GPS track angle value,
359 * without the cost of building a defensive copy.
360 * @return {@code true} if this entry has a EXIF track angle value
361 * @since 19387
362 */
363 @Override
364 public Double getExifGpsTrack() {
365 if (tmp != null)
366 return tmp.exifGpsTrack;
367 return exifGpsTrack;
368 }
369
370 /**
371 * Convenient way to determine if this entry has a EXIF GPS horizontal positionning error value,
372 * without the cost of building a defensive copy.
373 * @return {@code true} if this entry has a EXIF GPS horizontal positionning error value
374 * @since 19387
375 */
376 @Override
377 public Double getExifHPosErr() {
378 if (tmp != null)
379 return tmp.exifHPosErr;
380 return exifHPosErr;
381 }
382
383 @Override
384 public Instant getLastModified() {
385 return Instant.ofEpochMilli(this.getFile().lastModified());
386 }
387
388 /**
389 * Sets the width of this GpxImageEntry.
390 * @param width set the width of this GpxImageEntry
391 * @since 13220
392 */
393 @Override
394 public void setWidth(int width) {
395 this.width = width;
396 }
397
398 /**
399 * Sets the height of this GpxImageEntry.
400 * @param height set the height of this GpxImageEntry
401 * @since 13220
402 */
403 @Override
404 public void setHeight(int height) {
405 this.height = height;
406 }
407
408 /**
409 * Sets the position.
410 * @param pos cached position
411 */
412 public void setPos(CachedLatLon pos) {
413 this.pos = pos;
414 }
415
416 /**
417 * Sets the position.
418 * @param pos position (will be cached)
419 */
420 public void setPos(LatLon pos) {
421 setPos(pos != null ? new CachedLatLon(pos) : null);
422 }
423
424 @Override
425 public void setPos(ILatLon pos) {
426 if (pos instanceof CachedLatLon) {
427 this.setPos((CachedLatLon) pos);
428 } else if (pos instanceof LatLon) {
429 this.setPos((LatLon) pos);
430 } else if (pos != null) {
431 this.setPos(new LatLon(pos));
432 } else {
433 this.setPos(null);
434 }
435 }
436
437 /**
438 * Sets the speed.
439 * @param speed speed
440 */
441 @Override
442 public void setSpeed(Double speed) {
443 this.speed = speed;
444 }
445
446 /**
447 * Sets the elevation.
448 * @param elevation elevation
449 */
450 @Override
451 public void setElevation(Double elevation) {
452 this.elevation = elevation;
453 }
454
455 /**
456 * Sets GPS Differential mode.
457 * @param gpsDiffMode GPS Differential mode
458 * @since 19387
459 */
460 @Override
461 public void setGpsDiffMode(Integer gpsDiffMode) {
462 this.gpsDiffMode = gpsDiffMode;
463 }
464
465 /**
466 * Sets GPS 2d/3d mode.
467 * @param gps2d3dMode GPS 2d/3d mode value
468 * @since 19387
469 */
470 @Override
471 public void setGps2d3dMode(Integer gps2d3dMode) {
472 this.gps2d3dMode = gps2d3dMode;
473 }
474
475 /**
476 * Sets GPS DOP value.
477 * @param exifGpsDop GPS DOP value
478 * @since 19387
479 */
480 @Override
481 public void setExifGpsDop(Double exifGpsDop) {
482 this.exifGpsDop = exifGpsDop;
483 }
484
485 /**
486 * Sets the GPS Datum.
487 * @param exifGpsDatum GPS Datum
488 * @since 19387
489 */
490 @Override
491 public void setExifGpsDatum(String exifGpsDatum) {
492 this.exifGpsDatum = exifGpsDatum;
493 }
494
495 /**
496 * Sets the GPS Processing Method.
497 * @param exifGpsProcMethod GPS Processing Method
498 * @since 19387
499 */
500 @Override
501 public void setExifGpsProcMethod(String exifGpsProcMethod) {
502 this.exifGpsProcMethod = exifGpsProcMethod;
503 }
504
505 /**
506 * Sets associated file.
507 * @param file associated file
508 */
509 public void setFile(File file) {
510 this.file = file;
511 }
512
513 /**
514 * Sets EXIF orientation.
515 * @param exifOrientation EXIF orientation
516 */
517 @Override
518 public void setExifOrientation(Integer exifOrientation) {
519 this.exifOrientation = exifOrientation;
520 }
521
522 /**
523 * Sets EXIF time.
524 * @param exifTime EXIF time
525 * @since 17715
526 */
527 @Override
528 public void setExifTime(Instant exifTime) {
529 this.exifTime = exifTime;
530 }
531
532 /**
533 * Sets the EXIF GPS time.
534 * @param exifGpsTime the EXIF GPS time
535 * @since 17715
536 */
537 @Override
538 public void setExifGpsTime(Instant exifGpsTime) {
539 this.exifGpsTime = exifGpsTime;
540 }
541
542 /**
543 * Sets the GPS time.
544 * @param gpsTime the GPS time
545 * @since 17715
546 */
547 @Override
548 public void setGpsTime(Instant gpsTime) {
549 this.gpsTime = gpsTime;
550 }
551
552 public void setExifCoor(LatLon exifCoor) {
553 this.exifCoor = exifCoor;
554 }
555
556 @Override
557 public void setExifCoor(ILatLon exifCoor) {
558 if (exifCoor instanceof LatLon) {
559 this.exifCoor = (LatLon) exifCoor;
560 } else if (exifCoor != null) {
561 this.exifCoor = new LatLon(exifCoor);
562 } else {
563 this.exifCoor = null;
564 }
565 }
566
567 @Override
568 public void setExifImgDir(Double exifDir) {
569 this.exifImgDir = exifDir;
570 }
571
572 /**
573 * Sets the exif GPS track (move direction angle)
574 * @param exifGpsTrack the exif GPS track angle
575 * @since 19387
576 */
577 @Override
578 public void setExifGpsTrack(Double exifGpsTrack) {
579 this.exifGpsTrack = exifGpsTrack;
580 }
581
582 /**
583 * Sets the exif horizontal positioning error
584 * @param exifHposErr the Exif horizontal positionning error
585 * @since 19387
586 */
587 @Override
588 public void setExifHPosErr(Double exifHPosErr) {
589 this.exifHPosErr = exifHPosErr;
590 }
591
592 /**
593 * Sets the IPTC caption.
594 * @param iptcCaption the IPTC caption
595 * @since 15219
596 */
597 @Override
598 public void setIptcCaption(String iptcCaption) {
599 this.iptcCaption = iptcCaption;
600 }
601
602 /**
603 * Sets the IPTC headline.
604 * @param iptcHeadline the IPTC headline
605 * @since 15219
606 */
607 @Override
608 public void setIptcHeadline(String iptcHeadline) {
609 this.iptcHeadline = iptcHeadline;
610 }
611
612 /**
613 * Sets the IPTC keywords.
614 * @param iptcKeywords the IPTC keywords
615 * @since 15219
616 */
617 @Override
618 public void setIptcKeywords(List<String> iptcKeywords) {
619 this.iptcKeywords = iptcKeywords;
620 }
621
622 /**
623 * Sets the IPTC object name.
624 * @param iptcObjectName the IPTC object name
625 * @since 15219
626 */
627 @Override
628 public void setIptcObjectName(String iptcObjectName) {
629 this.iptcObjectName = iptcObjectName;
630 }
631
632 /**
633 * Returns the IPTC caption.
634 * @return the IPTC caption
635 * @since 15219
636 */
637 @Override
638 public String getIptcCaption() {
639 return iptcCaption;
640 }
641
642 /**
643 * Returns the IPTC headline.
644 * @return the IPTC headline
645 * @since 15219
646 */
647 @Override
648 public String getIptcHeadline() {
649 return iptcHeadline;
650 }
651
652 /**
653 * Returns the IPTC keywords.
654 * @return the IPTC keywords
655 * @since 15219
656 */
657 @Override
658 public List<String> getIptcKeywords() {
659 return iptcKeywords;
660 }
661
662 /**
663 * Returns the IPTC object name.
664 * @return the IPTC object name
665 * @since 15219
666 */
667 @Override
668 public String getIptcObjectName() {
669 return iptcObjectName;
670 }
671
672 @Override
673 public int compareTo(GpxImageEntry image) {
674 if (exifTime != null && image.exifTime != null)
675 return exifTime.compareTo(image.exifTime);
676 else if (exifTime == null && image.exifTime == null)
677 return 0;
678 else if (exifTime == null)
679 return -1;
680 else
681 return 1;
682 }
683
684 @Override
685 public int hashCode() {
686 return Objects.hash(height, width, isNewGpsData,
687 elevation, exifCoor, exifGpsTime, exifImgDir, exifGpsTrack, exifHPosErr,
688 exifGpsDop, gpsDiffMode, gps2d3dMode, exifGpsDatum, exifGpsProcMethod,
689 exifOrientation, exifTime, iptcCaption, iptcHeadline, iptcKeywords,
690 iptcObjectName, file, gpsTime, pos, speed, tmp, cameraProjection);
691 }
692
693 @Override
694 public boolean equals(Object obj) {
695 if (this == obj)
696 return true;
697 if (obj == null || getClass() != obj.getClass())
698 return false;
699 GpxImageEntry other = (GpxImageEntry) obj;
700 return height == other.height
701 && width == other.width
702 && isNewGpsData == other.isNewGpsData
703 && Objects.equals(elevation, other.elevation)
704 && Objects.equals(exifCoor, other.exifCoor)
705 && Objects.equals(exifGpsTime, other.exifGpsTime)
706 && Objects.equals(exifImgDir, other.exifImgDir)
707 && Objects.equals(exifGpsTrack, other.exifGpsTrack)
708 && Objects.equals(exifHPosErr, other.exifHPosErr)
709 && Objects.equals(gpsDiffMode, other.gpsDiffMode)
710 && Objects.equals(gps2d3dMode, other.gps2d3dMode)
711 && Objects.equals(exifGpsDop, other.exifGpsDop)
712 && Objects.equals(exifGpsDatum, other.exifGpsDatum)
713 && Objects.equals(exifGpsProcMethod, other.exifGpsProcMethod)
714 && Objects.equals(exifOrientation, other.exifOrientation)
715 && Objects.equals(exifTime, other.exifTime)
716 && Objects.equals(iptcCaption, other.iptcCaption)
717 && Objects.equals(iptcHeadline, other.iptcHeadline)
718 && Objects.equals(iptcKeywords, other.iptcKeywords)
719 && Objects.equals(iptcObjectName, other.iptcObjectName)
720 && Objects.equals(file, other.file)
721 && Objects.equals(gpsTime, other.gpsTime)
722 && Objects.equals(pos, other.pos)
723 && Objects.equals(speed, other.speed)
724 && Objects.equals(tmp, other.tmp)
725 && cameraProjection == other.cameraProjection;
726 }
727
728 /**
729 * Make a fresh copy and save it in the temporary variable. Use
730 * {@link #applyTmp()} or {@link #discardTmp()} if the temporary variable
731 * is not needed anymore.
732 * @return the fresh copy.
733 */
734 public GpxImageEntry createTmp() {
735 tmp = new GpxImageEntry(this);
736 tmp.tmp = null;
737 return tmp;
738 }
739
740 /**
741 * Get temporary variable that is used for real time parameter
742 * adjustments. The temporary variable is created if it does not exist
743 * yet. Use {@link #applyTmp()} or {@link #discardTmp()} if the temporary
744 * variable is not needed anymore.
745 * @return temporary variable
746 */
747 public GpxImageEntry getTmp() {
748 if (tmp == null) {
749 createTmp();
750 }
751 return tmp;
752 }
753
754 /**
755 * Copy the values from the temporary variable to the main instance. The
756 * temporary variable is deleted.
757 * @see #discardTmp()
758 * @since 19387 exifGpsTrack, exifHPosErr, gpsDiffMode, gps2d3dMode, exifGpsDop, exifGpsDatum, exifGpsProcMethod added
759 */
760 public void applyTmp() {
761 if (tmp != null) {
762 pos = tmp.pos;
763 speed = tmp.speed;
764 elevation = tmp.elevation;
765 gpsTime = tmp.gpsTime;
766 exifImgDir = tmp.exifImgDir;
767 exifGpsTrack = tmp.exifGpsTrack;
768 exifHPosErr = tmp.exifHPosErr;
769 gpsDiffMode = tmp.gpsDiffMode;
770 gps2d3dMode = tmp.gps2d3dMode;
771 exifGpsDop = tmp.exifGpsDop;
772 exifGpsDatum = tmp.exifGpsDatum;
773 exifGpsProcMethod = tmp.exifGpsProcMethod;
774 isNewGpsData = isNewGpsData || tmp.isNewGpsData;
775 tmp = null;
776 }
777 tmpUpdated();
778 }
779
780 /**
781 * Delete the temporary variable. Temporary modifications are lost.
782 * @see #applyTmp()
783 */
784 public void discardTmp() {
785 tmp = null;
786 tmpUpdated();
787 }
788
789 /**
790 * If it has been tagged i.e. matched to a gpx track or retrieved lat/lon from exif
791 * @return {@code true} if it has been tagged
792 */
793 public boolean isTagged() {
794 return pos != null;
795 }
796
797 /**
798 * String representation. (only partial info)
799 */
800 @Override
801 public String toString() {
802 return file.getName()+": "+
803 "pos = "+pos+" | "+
804 "exifCoor = "+exifCoor+" | "+
805 (tmp == null ? " tmp==null" :
806 " [tmp] pos = "+tmp.pos);
807 }
808
809 /**
810 * Indicates that the image has new GPS data.
811 * That flag is set by new GPS data providers. It is used e.g. by the photo_geotagging plugin
812 * to decide for which image file the EXIF GPS data needs to be (re-)written.
813 * @since 6392
814 */
815 public void flagNewGpsData() {
816 isNewGpsData = true;
817 }
818
819 /**
820 * Indicate that the temporary copy has been updated. Mostly used to prevent UI issues.
821 * By default, this is a no-op. Override when needed in subclasses.
822 * @since 17579
823 */
824 protected void tmpUpdated() {
825 // No-op by default
826 }
827
828 @Override
829 public BBox getBBox() {
830 // new BBox(LatLon) is null safe.
831 // Use `getPos` instead of `getExifCoor` since the image may be correlated against a GPX track
832 return new BBox(this.getPos());
833 }
834
835 /**
836 * Remove the flag that indicates new GPS data.
837 * The flag is cleared by a new GPS data consumer.
838 */
839 public void unflagNewGpsData() {
840 isNewGpsData = false;
841 }
842
843 /**
844 * Queries whether the GPS data changed. The flag value from the temporary
845 * copy is returned if that copy exists.
846 * @return {@code true} if GPS data changed, {@code false} otherwise
847 * @since 6392
848 */
849 public boolean hasNewGpsData() {
850 if (tmp != null)
851 return tmp.isNewGpsData;
852 return isNewGpsData;
853 }
854
855 /**
856 * Extract GPS metadata from image EXIF. Has no effect if the image file is not set
857 *
858 * If successful, fills in the LatLon, speed, elevation, image direction, and other attributes
859 * @since 9270
860 */
861 @Override
862 public void extractExif() {
863 ImageMetadata.super.extractExif();
864 }
865
866 @Override
867 public InputStream getInputStream() throws IOException {
868 return Files.newInputStream(this.getFile().toPath());
869 }
870
871 /**
872 * Reads the image represented by this entry in the given target dimension.
873 * @param target the desired dimension used for {@linkplain IIOParam#setSourceSubsampling subsampling} or {@code null}
874 * @return the read image, or {@code null}
875 * @throws IOException if any I/O error occurs
876 * @since 18246
877 */
878 public BufferedImage read(Dimension target) throws IOException {
879 throw new UnsupportedOperationException("read not implemented for " + this.getClass().getSimpleName());
880 }
881
882 /**
883 * Get the projection type for this entry
884 * @return The projection type
885 * @since 18246
886 */
887 @Override
888 public Projections getProjectionType() {
889 return this.cameraProjection;
890 }
891
892 @Override
893 public void setProjectionType(Projections newProjection) {
894 this.cameraProjection = newProjection;
895 }
896
897 /**
898 * Returns a {@link WayPoint} representation of this GPX image entry.
899 * @return a {@code WayPoint} representation of this GPX image entry (containing position, instant and elevation)
900 * @since 18065
901 */
902 public WayPoint asWayPoint() {
903 CachedLatLon position = getPos();
904 WayPoint wpt = null;
905 if (position != null) {
906 wpt = new WayPoint(position);
907 wpt.setInstant(exifTime);
908 Double ele = getElevation();
909 if (ele != null) {
910 wpt.put(GpxConstants.PT_ELE, ele.toString());
911 }
912 }
913 return wpt;
914 }
915}
Note: See TracBrowser for help on using the repository browser.