source: josm/trunk/src/org/openstreetmap/josm/tools/ExifReader.java@ 7835

Last change on this file since 7835 was 7592, checked in by stoecker, 10 years ago

fix JavaDoc

  • Property svn:eol-style set to native
File size: 8.0 KB
RevLine 
[6380]1// License: GPL. For details, see LICENSE file.
[626]2package org.openstreetmap.josm.tools;
3
4import java.io.File;
[6127]5import java.io.IOException;
[626]6import java.text.ParseException;
7import java.util.Date;
8
[6643]9import org.openstreetmap.josm.Main;
[6209]10import org.openstreetmap.josm.data.coor.LatLon;
[7299]11import org.openstreetmap.josm.tools.date.PrimaryDateParser;
[6209]12
[626]13import com.drew.imaging.jpeg.JpegMetadataReader;
[4241]14import com.drew.imaging.jpeg.JpegProcessingException;
[6209]15import com.drew.lang.Rational;
[626]16import com.drew.metadata.Directory;
17import com.drew.metadata.Metadata;
[4241]18import com.drew.metadata.MetadataException;
[626]19import com.drew.metadata.Tag;
[6127]20import com.drew.metadata.exif.ExifIFD0Directory;
21import com.drew.metadata.exif.ExifSubIFDDirectory;
[6209]22import com.drew.metadata.exif.GpsDirectory;
[626]23
24/**
[6209]25 * Read out EXIF information from a JPEG file
[626]26 * @author Imi
[6209]27 * @since 99
[626]28 */
[6362]29public final class ExifReader {
[626]30
[6360]31 private ExifReader() {
32 // Hide default constructor for utils classes
33 }
[6830]34
[6209]35 /**
36 * Returns the date/time from the given JPEG file.
37 * @param filename The JPEG file to read
38 * @return The date/time read in the EXIF section, or {@code null} if not found
[7592]39 * @throws ParseException if {@link PrimaryDateParser#parse} fails to parse date/time
[6209]40 */
41 public static Date readTime(File filename) throws ParseException {
[1169]42 try {
43 Metadata metadata = JpegMetadataReader.readMetadata(filename);
[4772]44 String dateStr = null;
45 OUTER:
[6127]46 for (Directory dirIt : metadata.getDirectories()) {
47 for (Tag tag : dirIt.getTags()) {
48 if (tag.getTagType() == ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL /* 0x9003 */) {
[4772]49 dateStr = tag.getDescription();
50 break OUTER; // prefer this tag
51 }
[6127]52 if (tag.getTagType() == ExifIFD0Directory.TAG_DATETIME /* 0x0132 */ ||
53 tag.getTagType() == ExifSubIFDDirectory.TAG_DATETIME_DIGITIZED /* 0x9004 */) {
[4772]54 dateStr = tag.getDescription();
55 }
[1169]56 }
57 }
[5610]58 if (dateStr != null) {
59 dateStr = dateStr.replace('/', ':'); // workaround for HTC Sensation bug, see #7228
[7299]60 return new PrimaryDateParser().parse(dateStr);
[5610]61 }
[1169]62 } catch (ParseException e) {
63 throw e;
[626]64 } catch (Exception e) {
[6643]65 Main.error(e);
[626]66 }
[4772]67 return null;
[1169]68 }
[4241]69
[6209]70 /**
71 * Returns the image orientation of the given JPEG file.
72 * @param filename The JPEG file to read
[6830]73 * @return The image orientation as an {@code int}. Default value is 1. Possible values are listed in EXIF spec as follows:<br><ol>
74 * <li>The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.</li>
75 * <li>The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.</li>
76 * <li>The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.</li>
77 * <li>The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.</li>
78 * <li>The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.</li>
79 * <li>The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.</li>
80 * <li>The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.</li>
81 * <li>The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.</li></ol>
[6209]82 * @see <a href="http://www.impulseadventure.com/photo/exif-orientation.html">http://www.impulseadventure.com/photo/exif-orientation.html</a>
83 * @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>
84 */
85 public static Integer readOrientation(File filename) {
[4241]86 try {
87 final Metadata metadata = JpegMetadataReader.readMetadata(filename);
[6127]88 final Directory dir = metadata.getDirectory(ExifIFD0Directory.class);
[6209]89 return dir.getInt(ExifIFD0Directory.TAG_ORIENTATION);
[7004]90 } catch (JpegProcessingException | MetadataException | IOException e) {
[6643]91 Main.error(e);
[4241]92 }
[6209]93 return null;
[4241]94 }
95
[6209]96 /**
97 * Returns the geolocation of the given JPEG file.
98 * @param filename The JPEG file to read
99 * @return The lat/lon read in the EXIF section, or {@code null} if not found
100 * @since 6209
101 */
102 public static LatLon readLatLon(File filename) {
103 try {
104 final Metadata metadata = JpegMetadataReader.readMetadata(filename);
105 final GpsDirectory dirGps = metadata.getDirectory(GpsDirectory.class);
106 return readLatLon(dirGps);
107 } catch (JpegProcessingException e) {
[6643]108 Main.error(e);
[6209]109 } catch (IOException e) {
[6643]110 Main.error(e);
[6209]111 } catch (MetadataException e) {
[6643]112 Main.error(e);
[6209]113 }
114 return null;
115 }
116
117 /**
118 * Returns the geolocation of the given EXIF GPS directory.
119 * @param dirGps The EXIF GPS directory
120 * @return The lat/lon read in the EXIF section, or {@code null} if {@code dirGps} is null
[6643]121 * @throws MetadataException
[6209]122 * @since 6209
123 */
124 public static LatLon readLatLon(GpsDirectory dirGps) throws MetadataException {
125 if (dirGps != null) {
126 double lat = readAxis(dirGps, GpsDirectory.TAG_GPS_LATITUDE, GpsDirectory.TAG_GPS_LATITUDE_REF, 'S');
127 double lon = readAxis(dirGps, GpsDirectory.TAG_GPS_LONGITUDE, GpsDirectory.TAG_GPS_LONGITUDE_REF, 'W');
128 return new LatLon(lat, lon);
129 }
130 return null;
131 }
[6830]132
[6209]133 /**
134 * Returns the direction of the given JPEG file.
135 * @param filename The JPEG file to read
136 * @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
137 * @since 6209
138 */
139 public static Double readDirection(File filename) {
140 try {
141 final Metadata metadata = JpegMetadataReader.readMetadata(filename);
142 final GpsDirectory dirGps = metadata.getDirectory(GpsDirectory.class);
143 return readDirection(dirGps);
144 } catch (JpegProcessingException e) {
[6643]145 Main.error(e);
[6209]146 } catch (IOException e) {
[6643]147 Main.error(e);
[6209]148 }
149 return null;
150 }
[6830]151
[6209]152 /**
153 * Returns the direction of the given EXIF GPS directory.
154 * @param dirGps The EXIF GPS directory
155 * @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
156 * @since 6209
157 */
158 public static Double readDirection(GpsDirectory dirGps) {
159 if (dirGps != null) {
160 Rational direction = dirGps.getRational(GpsDirectory.TAG_GPS_IMG_DIRECTION);
161 if (direction != null) {
162 return direction.doubleValue();
163 }
164 }
165 return null;
166 }
167
168 private static double readAxis(GpsDirectory dirGps, int gpsTag, int gpsTagRef, char cRef) throws MetadataException {
169 double value;
170 Rational[] components = dirGps.getRationalArray(gpsTag);
171 if (components != null) {
172 double deg = components[0].doubleValue();
173 double min = components[1].doubleValue();
174 double sec = components[2].doubleValue();
[6830]175
[6209]176 if (Double.isNaN(deg) && Double.isNaN(min) && Double.isNaN(sec))
177 throw new IllegalArgumentException();
[6830]178
[6209]179 value = (Double.isNaN(deg) ? 0 : deg + (Double.isNaN(min) ? 0 : (min / 60)) + (Double.isNaN(sec) ? 0 : (sec / 3600)));
[6830]180
[6209]181 if (dirGps.getString(gpsTagRef).charAt(0) == cRef) {
182 value = -value;
183 }
184 } else {
185 // Try to read lon/lat as double value (Nonstandard, created by some cameras -> #5220)
186 value = dirGps.getDouble(gpsTag);
187 }
188 return value;
189 }
[626]190}
Note: See TracBrowser for help on using the repository browser.