From 297f63756bb849eb8747922358084d756531500a Mon Sep 17 00:00:00 2001 From: Sean Mac Gillicuddy Date: Thu, 19 Mar 2020 10:55:53 +0000 Subject: [PATCH] #3408 Refactoring the FileProcessor and GPSExtractor classes - convert ImageCoordinates to kotlin --- .../nrw/commons/upload/ImageCoordinates.java | 92 ------------------- .../nrw/commons/upload/ImageCoordinates.kt | 72 +++++++++++++++ 2 files changed, 72 insertions(+), 92 deletions(-) delete mode 100644 app/src/main/java/fr/free/nrw/commons/upload/ImageCoordinates.java create mode 100644 app/src/main/java/fr/free/nrw/commons/upload/ImageCoordinates.kt diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ImageCoordinates.java b/app/src/main/java/fr/free/nrw/commons/upload/ImageCoordinates.java deleted file mode 100644 index 64c418f19c..0000000000 --- a/app/src/main/java/fr/free/nrw/commons/upload/ImageCoordinates.java +++ /dev/null @@ -1,92 +0,0 @@ -package fr.free.nrw.commons.upload; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.exifinterface.media.ExifInterface; -import java.io.IOException; -import java.io.InputStream; -import timber.log.Timber; - -/** - * Extracts geolocation to be passed to API for category suggestions. If a picture with geolocation - * is uploaded, extract latitude and longitude from EXIF data of image. - */ -public class ImageCoordinates { - - private double decLatitude; - private double decLongitude; - public boolean imageCoordsExists; - private String decimalCoords; - - /** - * Construct from the file path of the image. - * @param exif exif interface of the image - * - */ - ImageCoordinates(ExifInterface exif){ - //If image has no EXIF data and user has enabled GPS setting, get user's location - //Always return null as a temporary fix for #1599 - if (exif != null && exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE) != null) { - //If image has EXIF data, extract image coords - imageCoordsExists = true; - Timber.d("EXIF data has location info"); - - String latitude = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE); - String latitudeRef = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF); - String longitude = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE); - String longitudeRef = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF); - decLatitude = "N".equals(latitudeRef) ? convertToDegree(latitude) : - 0 - convertToDegree(latitude); - decLongitude = "E".equals(longitudeRef) ? convertToDegree(longitude) - : 0 - convertToDegree(longitude); - - decimalCoords = decLatitude + "|" + decLongitude; - } - } - - /** - * Construct from a stream. - */ - ImageCoordinates(@NonNull InputStream stream) throws IOException { - this(new ExifInterface(stream)); - } - - /** - * Construct from the file path of the image. - * @param path file path of the image - * - */ - ImageCoordinates(@NonNull String path) throws IOException{ - this(new ExifInterface(path)); - } - - /** - * Extracts geolocation (either of image from EXIF data, or of user) - * @return coordinates as string (needs to be passed as a String in API query) - */ - @Nullable - String getDecimalCoords() { - return decimalCoords; - } - - public double getDecLatitude() { - return decLatitude; - } - - public double getDecLongitude() { - return decLongitude; - } - - private double convertToDegree(String stringDMS) { - String[] DMS = stringDMS.split(",", 3); - double degrees = divideComponents(DMS[0]); - double minutes = divideComponents(DMS[1]); - double seconds = divideComponents(DMS[2]); - return degrees + (minutes/60) + (seconds/3600); - } - - private double divideComponents(String dm) { - String[] stringD = dm.split("/", 2); - return Double.parseDouble(stringD[0]) / Double.parseDouble(stringD[1]); - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ImageCoordinates.kt b/app/src/main/java/fr/free/nrw/commons/upload/ImageCoordinates.kt new file mode 100644 index 0000000000..7fb6ce5775 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/upload/ImageCoordinates.kt @@ -0,0 +1,72 @@ +package fr.free.nrw.commons.upload + +import androidx.exifinterface.media.ExifInterface +import timber.log.Timber +import java.io.InputStream + +/** + * Extracts geolocation to be passed to API for category suggestions. If a picture with geolocation + * is uploaded, extract latitude and longitude from EXIF data of image. + */ +class ImageCoordinates internal constructor(exif: ExifInterface?) { + var decLatitude = 0.0 + var decLongitude = 0.0 + var imageCoordsExists = false + /** + * @return string of `"[decLatitude]|[decLongitude]"` or null if coordinates do not exist + */ + var decimalCoords: String? = null + + /** + * Construct from a stream. + */ + internal constructor(stream: InputStream) : this(ExifInterface(stream)) + + /** + * Construct from the file path of the image. + * @param path file path of the image + */ + internal constructor(path: String) : this(ExifInterface(path)) + + + + init { + //If image has no EXIF data and user has enabled GPS setting, get user's location + //Always return null as a temporary fix for #1599 + if (exif != null) { + val latitude = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE) + val latitudeRef = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF) + val longitude = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE) + val longitudeRef = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF) + if (latitude != null && longitude != null && latitudeRef != null && longitudeRef != null) { + //If image has EXIF data, extract image coords + imageCoordsExists = true + Timber.d("EXIF data has location info") + decLatitude = + if (ExifInterface.LATITUDE_NORTH == latitudeRef) convertToDegree(latitude) + else 0 - convertToDegree(latitude) + decLongitude = + if (ExifInterface.LONGITUDE_EAST == longitudeRef) convertToDegree(longitude) + else 0 - convertToDegree(longitude) + decimalCoords = "$decLatitude|$decLongitude" + } + } + } + + /** + * Convert a string to an accurate Degree + * + * @param degreeMinuteSecondString - template string "a/b,c/d,e/f" where the letters represent numbers + * @return the degree accurate to the second + */ + private fun convertToDegree(degreeMinuteSecondString: String) = + degreeMinuteSecondString.split(",").let { + val degrees = evaluateExpression(it[0]) + val minutes = evaluateExpression(it[1]) + val seconds = evaluateExpression(it[2]) + degrees + minutes / 60 + seconds / 3600 + } + + private fun evaluateExpression(dm: String) = + dm.split("/").let { it[0].toDouble() / it[1].toDouble() } +}