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

Last change on this file since 7109 was 7004, checked in by Don-vip, 10 years ago

see #8465 - use multi-catch where applicable

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