我有一个 Android 应用程序,我想在其中显示 ImageView 的 GPS 坐标,这是我从用户上传的图像中获得的。我的代码如下所示:
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;
}
}
我现在遇到的问题是,“extractGPSData(String filePath)”函数不会返回 GPS 坐标,因为如果您查看上传图像的 logcats 元数据,您会发现,图片是0.0。这是我这边的问题吗?或者我如何提取上传图像的 GPS 坐标。非常感谢!
我尝试了目前提取GPS坐标的方法。我还尝试从另一个 stackoverflow 帖子中获取纬度和经度:
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);
我有点困惑。
这是我这边的问题吗
是的。您需要使用原始图像。相反,您正在通过
saveBitmapToFile()
方法制作浪费的副本。然后你尝试使用该副本。除其他问题外,副本没有 EXIF 标头。
所以,首先删除
saveBitmapToFile()
。
我还尝试从另一个 stackoverflow 帖子中获取纬度和经度
这种方法与您所能得到的一样好,但是您需要使用与 ExifInterface()
InputStream
,来自 androidx.exifinterface:exifinterface
库:
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);
请注意,任何图像都不需要具有 GPS EXIF 标头。