]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/load/JpegLoader.java
Version 12, December 2010
[GpsPrune.git] / tim / prune / load / JpegLoader.java
index 08b29fad02e6b32ec2cfc6bafa663869d76cbefa..a6a45c60b5d1ffe56c8257ac29b9f5e3f31e4a3b 100644 (file)
@@ -21,15 +21,14 @@ import tim.prune.I18nManager;
 import tim.prune.config.Config;
 import tim.prune.data.Altitude;
 import tim.prune.data.DataPoint;
+import tim.prune.data.Field;
 import tim.prune.data.LatLonRectangle;
 import tim.prune.data.Latitude;
 import tim.prune.data.Longitude;
 import tim.prune.data.Photo;
 import tim.prune.data.Timestamp;
-import tim.prune.drew.jpeg.ExifReader;
-import tim.prune.drew.jpeg.JpegData;
-import tim.prune.drew.jpeg.JpegException;
-import tim.prune.drew.jpeg.Rational;
+import tim.prune.jpeg.ExifGateway;
+import tim.prune.jpeg.JpegData;
 
 /**
  * Class to manage the loading of Jpegs and dealing with the GPS data from them
@@ -60,8 +59,7 @@ public class JpegLoader implements Runnable
        {
                _app = inApp;
                _parentFrame = inParentFrame;
-               String[] fileTypes = {"jpg", "jpe", "jpeg"};
-               _fileFilter = new GenericFileFilter("filetype.jpeg", fileTypes);
+               _fileFilter = new JpegFileFilter();
        }
 
 
@@ -151,8 +149,8 @@ public class JpegLoader implements Runnable
        public void run()
        {
                // Initialise arrays, errors, summaries
-               _fileCounts = new int[4]; // files, jpegs, exifs, gps
-               _photos = new TreeSet<Photo>(new PhotoSorter());
+               _fileCounts = new int[3]; // files, jpegs, gps
+               _photos = new TreeSet<Photo>(new MediaSorter());
                File[] files = _fileChooser.getSelectedFiles();
                // Loop recursively over selected files/directories to count files
                int numFiles = countFileList(files, true, _subdirCheckbox.isSelected());
@@ -167,8 +165,6 @@ public class JpegLoader implements Runnable
                _progressDialog.dispose(); // Sometimes dialog doesn't disappear without this dispose
                if (_cancelled) {return;}
 
-               //System.out.println("Finished - counts are: " + _fileCounts[0] + ", " + _fileCounts[1]
-               //  + ", " + _fileCounts[2] + ", " + _fileCounts[3]);
                if (_fileCounts[0] == 0)
                {
                        // No files found at all
@@ -180,11 +176,6 @@ public class JpegLoader implements Runnable
                        _app.showErrorMessage("error.jpegload.dialogtitle", "error.jpegload.nojpegsfound");
                }
                else if (!_noExifCheckbox.isSelected() && _fileCounts[2] == 0)
-               {
-                       // Need coordinates but no exif found
-                       _app.showErrorMessage("error.jpegload.dialogtitle", "error.jpegload.noexiffound");
-               }
-               else if (!_noExifCheckbox.isSelected() && _fileCounts[3] == 0)
                {
                        // Need coordinates but no gps information found
                        _app.showErrorMessage("error.jpegload.dialogtitle", "error.jpegload.nogpsfound");
@@ -248,51 +239,67 @@ public class JpegLoader implements Runnable
                if (!_fileFilter.acceptFilename(inFile.getName())) {return;}
                // If it's a Jpeg, we can use ExifReader to get coords, otherwise we could try exiftool (if it's installed)
 
+               if (inFile.exists() && inFile.canRead()) {
+                       _fileCounts[1]++; // jpeg found
+               }
+               Photo photo = createPhoto(inFile);
+               if (photo.getDataPoint() != null) {
+                       _fileCounts[2]++; // photo has coordinates
+               }
+               // Check the criteria for adding the photo - check whether the photo has coordinates and if so if they're within the rectangle
+               if ( (photo.getDataPoint() != null || _noExifCheckbox.isSelected())
+                       && (photo.getDataPoint() == null || !_outsideAreaCheckbox.isEnabled()
+                               || _outsideAreaCheckbox.isSelected() || _trackRectangle.containsPoint(photo.getDataPoint())))
+               {
+                       _photos.add(photo);
+               }
+       }
+
+       /**
+        * Create a Photo object for the given file, including reading exif information
+        * @param inFile file object
+        * @return Photo object
+        */
+       public static Photo createPhoto(File inFile)
+       {
                // Create Photo object
                Photo photo = new Photo(inFile);
                // Try to get information out of exif
-               try
+               JpegData jpegData = ExifGateway.getJpegData(inFile);
+               Timestamp timestamp = null;
+               if (jpegData != null)
                {
-                       JpegData jpegData = new ExifReader(inFile).extract();
-                       _fileCounts[1]++; // jpeg found (no exception thrown)
-                       if (jpegData.getExifDataPresent())
-                               {_fileCounts[2]++;} // exif found
-                       if (jpegData.isValid())
+                       if (jpegData.isGpsValid())
                        {
-                               if (jpegData.getGpsDatestamp() != null && jpegData.getGpsTimestamp() != null)
-                               {
-                                       photo.setTimestamp(createTimestamp(jpegData.getGpsDatestamp(), jpegData.getGpsTimestamp()));
-                               }
+                               timestamp = createTimestamp(jpegData.getGpsDatestamp(), jpegData.getGpsTimestamp());
                                // Make DataPoint and attach to Photo
                                DataPoint point = createDataPoint(jpegData);
                                point.setPhoto(photo);
                                point.setSegmentStart(true);
                                photo.setDataPoint(point);
                                photo.setOriginalStatus(Photo.Status.TAGGED);
-                               _fileCounts[3]++;
                        }
                        // Use exif timestamp if gps timestamp not available
-                       if (photo.getTimestamp() == null && jpegData.getOriginalTimestamp() != null)
-                       {
-                               photo.setTimestamp(createTimestamp(jpegData.getOriginalTimestamp()));
+                       if (timestamp == null && jpegData.getOriginalTimestamp() != null) {
+                               timestamp = createTimestamp(jpegData.getOriginalTimestamp());
+                       }
+                       if (timestamp == null && jpegData.getDigitizedTimestamp() != null) {
+                               timestamp = createTimestamp(jpegData.getDigitizedTimestamp());
                        }
                        photo.setExifThumbnail(jpegData.getThumbnailImage());
                        // Also extract orientation tag for setting rotation state of photo
                        photo.setRotation(jpegData.getRequiredRotation());
                }
-               catch (JpegException jpe) { // don't list errors, just count them
-               }
                // Use file timestamp if exif timestamp isn't available
-               if (photo.getTimestamp() == null) {
-                       photo.setTimestamp(new Timestamp(inFile.lastModified()));
+               if (timestamp == null) {
+                       timestamp = new Timestamp(inFile.lastModified());
                }
-               // Check the criteria for adding the photo - check whether the photo has coordinates and if so if they're within the rectangle
-               if ( (photo.getDataPoint() != null || _noExifCheckbox.isSelected())
-                       && (photo.getDataPoint() == null || !_outsideAreaCheckbox.isEnabled()
-                               || _outsideAreaCheckbox.isSelected() || _trackRectangle.containsPoint(photo.getDataPoint())))
-               {
-                       _photos.add(photo);
+               // Apply timestamp to photo and its point (if any)
+               photo.setTimestamp(timestamp);
+               if (photo.getDataPoint() != null) {
+                       photo.getDataPoint().setFieldValue(Field.TIMESTAMP, timestamp.getText(Timestamp.FORMAT_ISO_8601), false);
                }
+               return photo;
        }
 
 
@@ -350,26 +357,25 @@ public class JpegLoader implements Runnable
                        inData.getLongitudeRef() == 'E' || inData.getLongitudeRef() == 'e');
                Longitude longitude = new Longitude(lonval, Longitude.FORMAT_DEG_MIN_SEC);
                Altitude altitude = null;
-               if (inData.getAltitude() != null)
-               {
-                       altitude = new Altitude(inData.getAltitude().intValue(), Altitude.Format.METRES);
+               if (inData.hasAltitude()) {
+                       altitude = new Altitude(inData.getAltitude(), Altitude.Format.METRES);
                }
                return new DataPoint(latitude, longitude, altitude);
        }
 
 
        /**
-        * Convert an array of 3 Rational numbers into a double coordinate value
-        * @param inRationals array of three Rational objects
+        * Convert an array of 3 doubles (deg-min-sec) into a double coordinate value
+        * @param inValues array of three doubles for deg-min-sec
         * @param isPositive true for positive hemisphere, for positive double value
         * @return double value of coordinate, either positive or negative
         */
-       private static double getCoordinateDoubleValue(Rational[] inRationals, boolean isPositive)
+       private static double getCoordinateDoubleValue(double[] inValues, boolean isPositive)
        {
-               if (inRationals == null || inRationals.length != 3) return 0.0;
-               double value = inRationals[0].doubleValue()        // degrees
-                       + inRationals[1].doubleValue() / 60.0          // minutes
-                       + inRationals[2].doubleValue() / 60.0 / 60.0;  // seconds
+               if (inValues == null || inValues.length != 3) return 0.0;
+               double value = inValues[0]        // degrees
+                       + inValues[1] / 60.0          // minutes
+                       + inValues[2] / 60.0 / 60.0;  // seconds
                // make sure it's the correct sign
                value = Math.abs(value);
                if (!isPositive) value = -value;
@@ -378,15 +384,18 @@ public class JpegLoader implements Runnable
 
 
        /**
-        * Use the given Rational values to create a timestamp
-        * @param inDate rationals describing date
-        * @param inTime rationals describing time
+        * Use the given int values to create a timestamp
+        * @param inDate ints describing date
+        * @param inTime ints describing time
         * @return Timestamp object corresponding to inputs
         */
-       private static Timestamp createTimestamp(Rational[] inDate, Rational[] inTime)
+       private static Timestamp createTimestamp(int[] inDate, int[] inTime)
        {
-               return new Timestamp(inDate[0].intValue(), inDate[1].intValue(), inDate[2].intValue(),
-                       inTime[0].intValue(), inTime[1].intValue(), inTime[2].intValue());
+               if (inDate == null || inTime == null || inDate.length != 3 || inTime.length != 3) {
+                       return null;
+               }
+               return new Timestamp(inDate[0], inDate[1], inDate[2],
+                       inTime[0], inTime[1], inTime[2]);
        }