0

I'm trying to insert some location data on an image generated inside my application (i.e. it's not a picture taken from device camera):

This's saveImage method:

public static String saveImage(Context context, ContentResolver contentResolver, Bitmap source,
                                   String title, String description, Location location) {
    File snapshot;
    Uri url;

    try {
        File pictures = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        File rpi = new File(pictures, context.getString(R.string.app_name));

        if (!rpi.exists())
            if (!rpi.mkdirs())
                return null;

        snapshot = new File(rpi, title);
        OutputStream stream = new FileOutputStream(snapshot);
        source.compress(Bitmap.CompressFormat.JPEG, 90, stream);
        stream.flush();
        stream.close();

        if (location != null)
            georeferenceImage(snapshot, location);

        ContentValues values = new ContentValues();
        values.put(MediaStore.Images.Media.TITLE, title);
        values.put(MediaStore.Images.Media.DISPLAY_NAME, title);

        if (description != null) {
            values.put(MediaStore.Images.Media.DESCRIPTION, description);
        }

        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
        values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis());

        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
            values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
            values.put(MediaStore.Images.ImageColumns.BUCKET_ID, snapshot.toString().toLowerCase(Locale.US).hashCode());
            values.put(MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME, snapshot.getName().toLowerCase(Locale.getDefault()));
        }

        values.put("_data", snapshot.getAbsolutePath());

        url = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    } catch (Exception ex) {
        return null;
    }

    return (url != null) ? url.toString() : null;
}

This's georeferenceImage() method:

private static boolean georeferenceImage(@NonNull final File image_file, @NonNull final Location location) {
    try {
        final ExifInterface exif = new ExifInterface(image_file.getAbsolutePath());
        exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, getLat(location));
        exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, location.getLatitude() < 0 ? "S" : "N");
        exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, getLon(location));
        exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, location.getLongitude() < 0 ? "W" : "E");
        //exif.setLatLong(location.getLatitude(), location.getLongitude());
        //exif.setAltitude(location.getAltitude());
        exif.saveAttributes();
    } catch (IOException e) {
        return false;
    }

    return true;
}

And these are lat & lon formatting methods:

private static String getLon(@NonNull final Location location) {
    String[] degMinSec = Location.convert(location.getLongitude(), Location.FORMAT_SECONDS).split(":");
    return degMinSec[0] + "/1," + degMinSec[1] + "/1," + degMinSec[2] + "/1000";
}

private static String getLat(@NonNull final Location location) {
    String[] degMinSec = Location.convert(location.getLatitude(), Location.FORMAT_SECONDS).split(":");
    return degMinSec[0] + "/1," + degMinSec[1] + "/1," + degMinSec[2] + "/1000";
}

Once saved I see no position data (I tried with different tools with the same result). I tried also to use setLatLon() and setAltitude() methods without luck. No exceptions are thrown. Inspecting in debug exif variable prior saveAttributes() call I found only TAG_GPS_LATITUDE_REF and TAG_GPS_LONGITUDE_REF but not TAG_GPS_LATITUDE and TAG_GPS_LONGITUDE.

weirdgyn
  • 886
  • 16
  • 47
  • What are you messing around with the mediastore and values? You dont need that if you write an exif to file so dont confuse us. – blackapps Jul 29 '20 at 16:10
  • only to fully depict the running code handling the image ... I don't think this's the case but maybe following lines (mediastore and so on) are wiping exif data for some reason. Of course the only relevant part of code related to exif handling is `georeferenceImage()` . – weirdgyn Jul 29 '20 at 17:06
  • Is the file size different before and after the georeferenceImage() call? – blackapps Jul 29 '20 at 17:35
  • yes it grows up of 236 bytes. – weirdgyn Jul 29 '20 at 18:55

1 Answers1

0

The problem was hiding around getLat() and getLon() formatters. This's code works better:

private static String toExifFmt(double angle) {
    angle = Math.abs(angle);
    final int degree = (int) angle;
    angle *= 60;
    angle -= (degree * 60.0d);
    final int minute = (int) angle;
    angle *= 60;
    angle -= (minute * 60.0d);
    final int second = (int) (angle*1000.0d);

    final StringBuilder sb = new StringBuilder();

    sb.setLength(0);
    sb.append(degree);
    sb.append("/1,");
    sb.append(minute);
    sb.append("/1,");
    sb.append(second);
    sb.append("/1000");

    return sb.toString();
}

I found it here.

weirdgyn
  • 886
  • 16
  • 47