【问题标题】:Android Exif data not stored in picture fileAndroid Exif 数据未存储在图片文件中
【发布时间】:2020-11-19 06:54:01
【问题描述】:

我正在尝试在我的应用程序内生成的图像上插入一些位置数据(即它不是从设备相机拍摄的照片):

这是saveImage 方法:

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;
}

这是georeferenceImage() 方法:

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;
}

这些是 lat & lon 格式化方法:

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";
}

保存后,我看不到任何位置数据(我尝试使用不同的工具得到相同的结果)。 我也尝试使用setLatLon()setAltitude() 方法,但没有运气。 不抛出异常。在调试exif 变量之前检查saveAttributes() 调用我发现只有TAG_GPS_LATITUDE_REFTAG_GPS_LONGITUDE_REF 但不是TAG_GPS_LATITUDETAG_GPS_LONGITUDE

【问题讨论】:

  • 你在搞什么媒体存储和价值观?如果您将 exif 写入文件,则不需要它,所以不要混淆我们。
  • 只是为了完全描述处理图像的运行代码......我不认为是这种情况,但可能以下行(媒体商店等)出于某种原因正在擦除 exif 数据。当然,与 exif 处理相关的代码中唯一相关的部分是 georeferenceImage()
  • georeferenceImage() 调用前后文件大小是否不同?
  • 是的,它增长了 236 个字节。

标签: java android image exif


【解决方案1】:

问题在于 getLat() 和 getLon() 格式化程序。 这段代码效果更好:

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();
}

我找到了here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多