This is an automated email from the ASF dual-hosted git repository.

tballison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git


The following commit(s) were added to refs/heads/main by this push:
     new d7a6d413e8 [TIKA-4781] Map EXIF GPS altitude to the existing geo:alt 
property (#2941)
d7a6d413e8 is described below

commit d7a6d413e812f2b2a6222fa2245eaa82a45e8a52
Author: Dominik Schmidt <[email protected]>
AuthorDate: Fri Jul 10 20:45:52 2026 +0200

    [TIKA-4781] Map EXIF GPS altitude to the existing geo:alt property (#2941)
    
    The GeotagHandler mapped latitude, longitude and the GPS timestamp from
    the EXIF GpsDirectory, but not the altitude, although tika-core defines
    Geographic.ALTITUDE and metadata-extractor exposes the value in the same
    directory. Consumers only got the raw description string
    ("GPS:GPS Altitude" = "227.4 metres").
    
    Set geo:alt as a signed value honoring GPSAltitudeRef (1 = below sea
    level = negative), formatted with the same DecimalFormat as latitude
    and longitude. Analogous to TIKA-4425, which added the normalized GPS
    timestamp from the same directory; see TIKA-2861 for the corresponding
    ISO 6709 altitude handling in MP4/QuickTime.
    
    The existing IMG_1034.heic fixture already carries an altitude, so
    HeifParserTest now asserts it end to end; handler-level tests cover the
    above and below sea level cases.
---
 .../tika/parser/image/ImageMetadataExtractor.java  | 15 ++++++++++++--
 .../apache/tika/parser/image/HeifParserTest.java   |  1 +
 .../parser/image/ImageMetadataExtractorTest.java   | 24 ++++++++++++++++++++++
 3 files changed, 38 insertions(+), 2 deletions(-)

diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/main/java/org/apache/tika/parser/image/ImageMetadataExtractor.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/main/java/org/apache/tika/parser/image/ImageMetadataExtractor.java
index 30140ec677..900c4d3f55 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/main/java/org/apache/tika/parser/image/ImageMetadataExtractor.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/main/java/org/apache/tika/parser/image/ImageMetadataExtractor.java
@@ -684,10 +684,10 @@ public class ImageMetadataExtractor {
         }
 
         public void handle(Directory directory, Metadata metadata) throws 
MetadataException {
+            DecimalFormat geoDecimalFormat = new 
DecimalFormat(GEO_DECIMAL_FORMAT_STRING,
+                    new DecimalFormatSymbols(Locale.ENGLISH));
             GeoLocation geoLocation = ((GpsDirectory) 
directory).getGeoLocation();
             if (geoLocation != null) {
-                DecimalFormat geoDecimalFormat = new 
DecimalFormat(GEO_DECIMAL_FORMAT_STRING,
-                        new DecimalFormatSymbols(Locale.ENGLISH));
                 metadata.set(TikaCoreProperties.LATITUDE,
                         geoDecimalFormat.format(geoLocation.getLatitude()));
                 metadata.set(TikaCoreProperties.LONGITUDE,
@@ -697,6 +697,17 @@ public class ImageMetadataExtractor {
             if (gpsDate != null) {
                 metadata.set(Geographic.TIMESTAMP, gpsDate);
             }
+            Rational altitude = ((GpsDirectory) 
directory).getRational(GpsDirectory.TAG_ALTITUDE);
+            if (altitude != null) {
+                double metres = altitude.doubleValue();
+                //GPSAltitudeRef 1 means below sea level
+                Integer altitudeRef =
+                        ((GpsDirectory) 
directory).getInteger(GpsDirectory.TAG_ALTITUDE_REF);
+                if (altitudeRef != null && altitudeRef == 1) {
+                    metres = -metres;
+                }
+                metadata.set(TikaCoreProperties.ALTITUDE, 
geoDecimalFormat.format(metres));
+            }
         }
     }
 
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/test/java/org/apache/tika/parser/image/HeifParserTest.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/test/java/org/apache/tika/parser/image/HeifParserTest.java
index 2f9a80960d..107f408620 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/test/java/org/apache/tika/parser/image/HeifParserTest.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/test/java/org/apache/tika/parser/image/HeifParserTest.java
@@ -51,6 +51,7 @@ public class HeifParserTest extends TikaTest {
             assertEquals("image/heic", metadata.get(Metadata.CONTENT_TYPE));
             assertEquals("23.177917", metadata.get(Metadata.LATITUDE));
             assertEquals("113.394317", metadata.get(Metadata.LONGITUDE));
+            assertEquals("42.810337", metadata.get(Geographic.ALTITUDE));
 
             assertEquals("2018-02-05T07:11:43Z", 
metadata.get(Geographic.TIMESTAMP));
         }
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/test/java/org/apache/tika/parser/image/ImageMetadataExtractorTest.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/test/java/org/apache/tika/parser/image/ImageMetadataExtractorTest.java
index 267659c005..4db12e8b71 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/test/java/org/apache/tika/parser/image/ImageMetadataExtractorTest.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-image-module/src/test/java/org/apache/tika/parser/image/ImageMetadataExtractorTest.java
@@ -28,11 +28,13 @@ import java.util.List;
 import java.util.Locale;
 import java.util.TimeZone;
 
+import com.drew.lang.Rational;
 import com.drew.metadata.Directory;
 import com.drew.metadata.MetadataException;
 import com.drew.metadata.Tag;
 import com.drew.metadata.exif.ExifIFD0Directory;
 import com.drew.metadata.exif.ExifSubIFDDirectory;
+import com.drew.metadata.exif.GpsDirectory;
 import com.drew.metadata.jpeg.JpegCommentDirectory;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
@@ -85,6 +87,28 @@ public class ImageMetadataExtractorTest {
                 "Should be ISO date without time zone");
     }
 
+    @Test
+    public void testGeotagHandlerAltitude() throws MetadataException {
+        GpsDirectory gps = Mockito.mock(GpsDirectory.class);
+        
Mockito.when(gps.getRational(GpsDirectory.TAG_ALTITUDE)).thenReturn(new 
Rational(2274, 10));
+        
Mockito.when(gps.getInteger(GpsDirectory.TAG_ALTITUDE_REF)).thenReturn(0);
+        Metadata metadata = new Metadata();
+
+        new ImageMetadataExtractor.GeotagHandler().handle(gps, metadata);
+        assertEquals("227.4", metadata.get(TikaCoreProperties.ALTITUDE));
+    }
+
+    @Test
+    public void testGeotagHandlerAltitudeBelowSeaLevel() throws 
MetadataException {
+        GpsDirectory gps = Mockito.mock(GpsDirectory.class);
+        
Mockito.when(gps.getRational(GpsDirectory.TAG_ALTITUDE)).thenReturn(new 
Rational(2274, 10));
+        
Mockito.when(gps.getInteger(GpsDirectory.TAG_ALTITUDE_REF)).thenReturn(1);
+        Metadata metadata = new Metadata();
+
+        new ImageMetadataExtractor.GeotagHandler().handle(gps, metadata);
+        assertEquals("-227.4", metadata.get(TikaCoreProperties.ALTITUDE));
+    }
+
     @Test
     public void testExifHandlerParseDateFallback() throws MetadataException {
         ExifIFD0Directory exif = Mockito.mock(ExifIFD0Directory.class);

Reply via email to