javaandroidimageviewandroid-gps

How to extract gps coordinates from an ImageView in Android Studio


I have an android app in which I want to display the GPS Coordinates of an ImageView, that I get from the users image uploads. My Code looks like the following:

package com.example.app;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import androidx.exifinterface.media.ExifInterface;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.lang.Rational;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import com.drew.metadata.exif.GpsDirectory;
import com.example.java_lib.client.Client;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;

public class MainActivity extends AppCompatActivity implements LocationListener {

    private static final String TAG = "MainActivity";
    private static final int REQUEST_LOCATION_PERMISSION = 1;

    Button uploadButton, cameraButton, analyzeButton;
    TextView result;
    ImageView image;
    Bitmap bitmap;
    double[] gpsCoordinates = null;

    private LocationManager locationManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        askForPermission();

        Spinner spinner = findViewById(R.id.spinner_drop);
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
                this,
                R.array.LMMs,
                android.R.layout.simple_spinner_item
        );
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);
        uploadButton = findViewById(R.id.uploadButton);
        cameraButton = findViewById(R.id.cameraButton);
        analyzeButton = findViewById(R.id.analyzeButton);
        result = findViewById(R.id.result);
        image = findViewById(R.id.imageView2);

        uploadButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.setAction(Intent.ACTION_GET_CONTENT);
                intent.setType("image/*");
                startActivityForResult(intent, 1);
            }
        });

        cameraButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION_PERMISSION);
                } else {
                    getLocationAndCaptureImage();
                }
            }
        });

        analyzeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (bitmap != null) {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            sendImageAndCoordinatesToServer(bitmap, gpsCoordinates);
                        }
                    }).start();
                } else {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "No image available. Please select or capture an image first.", Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            }
        });

        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    }

    private void getLocationAndCaptureImage() {
        try {
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(intent, 2);
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onLocationChanged(@NonNull Location location) {
        gpsCoordinates = new double[]{location.getLatitude(), location.getLongitude()};
        locationManager.removeUpdates(this);
    }

    void askForPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
                    checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION}, 2);
            }
        }
    }

    @SuppressLint("MissingSuperCall")
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == 2) {
            if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                this.askForPermission();
            }
        } else if (requestCode == REQUEST_LOCATION_PERMISSION) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                getLocationAndCaptureImage();
            } else {
                Toast.makeText(this, "Location permission is required to capture GPS data", Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (requestCode == 1 && resultCode == RESULT_OK && data != null) {
            Uri uri = data.getData();
            result.setText(uri.toString());
            try {
                bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
                image.setImageBitmap(bitmap);

                // Speichern Sie das Bitmap in einer Datei
                File savedImageFile = saveBitmapToFile(bitmap);
                if (savedImageFile != null) {
                    String filePath = savedImageFile.getAbsolutePath();
                    gpsCoordinates = extractGPSData(filePath);
                    result.setText("Latitude: " + gpsCoordinates[0] + ", Longitude: " + gpsCoordinates[1]);
                } else {
                    result.setText("Failed to save image.");
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } else if (requestCode == 2 && resultCode == RESULT_OK && data != null) {
            bitmap = (Bitmap) data.getExtras().get("data");
            image.setImageBitmap(bitmap);

            // Speichern Sie das Bitmap in einer Datei
            File savedImageFile = saveBitmapToFile(bitmap);
            if (savedImageFile != null) {
                String filePath = savedImageFile.getAbsolutePath();
                try {
                    gpsCoordinates = extractGPSData(filePath);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                result.setText("Latitude: " + gpsCoordinates[0] + ", Longitude: " + gpsCoordinates[1]);
            } else {
                result.setText("Failed to save image.");
            }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }




    private double[] extractGPSData(String filePath) throws IOException {
        File imageFile = new File(filePath);
        Metadata metadata = null;
        try {
            metadata = ImageMetadataReader.readMetadata(imageFile);
        } catch (ImageProcessingException e) {
            throw new RuntimeException(e);
        }

        // Log all metadata for debugging purposes
        for (com.drew.metadata.Directory directory : metadata.getDirectories()) {
            for (com.drew.metadata.Tag tag : directory.getTags()) {
                Log.d("Metadata", directory.getName() + " - " + tag.getTagName() + " - " + tag.getDescription());
            }
        }

        GpsDirectory gpsDirectory = metadata.getFirstDirectoryOfType(GpsDirectory.class);
        double[] gpsCoordinates = new double[2];

        if (gpsDirectory != null) {
            Rational[] latitudes = gpsDirectory.getRationalArray(GpsDirectory.TAG_LATITUDE);
            Rational[] longitudes = gpsDirectory.getRationalArray(GpsDirectory.TAG_LONGITUDE);
            String latRef = gpsDirectory.getString(GpsDirectory.TAG_LATITUDE_REF);
            String lonRef = gpsDirectory.getString(GpsDirectory.TAG_LONGITUDE_REF);

            Log.d("GPS Data", "Latitudes: " + Arrays.toString(latitudes));
            Log.d("GPS Data", "Longitudes: " + Arrays.toString(longitudes));
            Log.d("GPS Data", "Latitude Ref: " + latRef);
            Log.d("GPS Data", "Longitude Ref: " + lonRef);

            if (latitudes != null && longitudes != null && latRef != null && lonRef != null) {
                double latitude = convertToDegree(latitudes);
                if (latRef.equals("S")) {
                    latitude = -latitude;
                }
                double longitude = convertToDegree(longitudes);
                if (lonRef.equals("W")) {
                    longitude = -longitude;
                }
                gpsCoordinates[0] = latitude;
                gpsCoordinates[1] = longitude;
                Log.d("GPS Data", "Latitude: " + latitude + ", Longitude: " + longitude);
            } else {
                Log.d("GPS Data", "GPS data not found or incomplete.");
                result.setText("No GPS data found.");
            }
        } else {
            Log.d("GPS Data", "GPS directory not found.");
            result.setText("No GPS data found.");
        }

        return gpsCoordinates;
    }



    private double convertToDegree(Rational[] rationalArray) {
        double degrees = rationalArray[0].doubleValue();
        double minutes = rationalArray[1].doubleValue();
        double seconds = rationalArray[2].doubleValue();
        return degrees + (minutes / 60.0) + (seconds / 3600.0);
    }



    private double[] extractGPSDataFromBitmap(Bitmap bitmap) throws IOException {
        File file = new File(getExternalFilesDir(null), "temp_image.jpg");
        try (FileOutputStream fos = new FileOutputStream(file)) {
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
        }
        return extractGPSData(String.valueOf(Uri.fromFile(file)));
    }

    private void sendImageAndCoordinatesToServer(Bitmap bitmap, double[] gpsCoordinates) {
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
            byte[] imageBytes = byteArrayOutputStream.toByteArray();
           // new Client(imageBytes, gpsCoordinates).start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getFilePathFromUri(Uri uri) {
        String filePath = null;
        try {
            InputStream inputStream = getContentResolver().openInputStream(uri);
            File tempFile = createTempFileFrom(inputStream);
            filePath = tempFile.getAbsolutePath();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return filePath;
    }

    private File createTempFileFrom(InputStream inputStream) throws IOException {
        File tempFile = File.createTempFile("temp_image", ".jpg", getCacheDir());
        tempFile.deleteOnExit();
        try (FileOutputStream out = new FileOutputStream(tempFile)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
        }
        return tempFile;
    }

    private File saveBitmapToFile(Bitmap bitmap) {
        File tempFile = null;
        try {
            tempFile = File.createTempFile("temp_image", ".jpg", getCacheDir());
            tempFile.deleteOnExit();
            FileOutputStream out = new FileOutputStream(tempFile);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return tempFile;
    }


}

The problem I now have is, that the "extractGPSData(String filePath)" function doesn't return me the GPS Coordinates, because if you look into the logcats metadata of an uploaded image, you'll see, that the metadata for the pictures are 0.0. Is this a problem from my side or how could I extract the GPS Coordinates of an uploaded image. Thank you very much!

I tried the method I currently have to extract the GPS coordinates. I also tried getting the latitude and longtitude from another stackoverflow post:

ExifInterface exif = new ExifInterface(filepath);
exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);

I'm a bit confused.


Solution

  • Is this a problem from my side

    Yes. You need to work with the original image. Instead, you are making a copy via your saveBitmapToFile() method. Then you are trying to work with that copy. Among other problems, the copy does not have EXIF headers.

    So, start by deleting saveBitmapToFile().

    I also tried getting the latitude and longtitude from another stackoverflow post

    That approach is as good as you will get, but you need to use the ExifInterface() that works with an InputStream, from the androidx.exifinterface:exifinterface library:

    ExifInterface exif = new ExifInterface(getContentResolver().openInputStream(uri));
    exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
    exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
    exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
    exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
    

    Note that there is no requirement for any image to have GPS EXIF headers.