【问题标题】:How to get orientation of image file, which was taken from FileProvider class?如何获取取自 FileProvider 类的图像文件的方向?
【发布时间】:2016-12-11 12:04:44
【问题描述】:

背景

针对 API 24 或更高版本,开发者无需使用简单的“Uri.fromFile”命令,而是需要使用 FileProvider(或自己的 ContentProvider),以便让其他应用访问应用的文件。

问题

我尝试使用以下代码打开一个相机应用程序,让它将文件保存到我的应用程序的私人存储中:

    final Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    final File photoFile = FileHelper.generateTempCameraFile(this);
    mCameraCachedImageURI = FileProvider.getUriForFile(this, getPackageName()+ ".provider", photoFile);
    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCameraCachedImageURI);
    takePictureIntent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    startActivityForResult(takePictureIntent, REQ_CODE_PICK_IMAGE_FROM_CAMERA);

provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path name="external_files" path="."/>
</paths>

清单文件

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths"/>
    </provider>

这开始很好,因为相机应用程序已启动,但在返回的结果中,我无法使用以前正常工作的代码获取图像文件的方向:

@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    int orientation = getOrientation(this,mCameraCachedImageURI );
    ...

public static int getOrientation(final Context context, final Uri photoUri) {
    Cursor cursor = null;
    try {
        cursor = context.getContentResolver().query(photoUri,
                new String[]{MediaStore.Images.ImageColumns.ORIENTATION}, null, null, null);
    } catch (final Exception ignored) {
    }
    if (cursor == null) {
        // fallback
        return getOrientation(photoUri.getPath());
    }
    int result = 0;
    if (cursor.getCount() > 0) {
        cursor.moveToFirst();
        result = cursor.getInt(0);
    }
    cursor.close();
    return result;
}

public static int getOrientation(final String filePath) {
    if (TextUtils.isEmpty(filePath))
        return 0;
    try {
        final ExifInterface exifInterface = new ExifInterface(filePath);
        final int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_NORMAL);
        int rotate = 0;
        switch (orientation) {
            case ExifInterface.ORIENTATION_ROTATE_270:
                rotate = 270;
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                rotate = 180;
                break;
            case ExifInterface.ORIENTATION_ROTATE_90:
                rotate = 90;
                break;
        }
        return rotate;
    } catch (final IOException ignored) {
    }
    return 0;
}

这会崩溃,因为运行此代码时光标没有任何列。

不仅如此,甚至后备功能(在更改代码以使用它时)也不起作用,因为它在文件路径中添加了一个附加部分(在本例中为“外部”)。

我发现了什么

这里的 contentResolver 似乎使用了 FileProvider,而不是以前版本的 Android 上使用的。

问题是,我需要此 URI 的 ContentProvider 才能授予相机应用访问此文件的权限...

问题

如何使用上面的代码(甚至更好的代码),使用新的 FileProvider Uri 获得方向?也许我可以强制 ContentResolver 使用以前的 ContentProvider 来获取光标所需的列数据?

我真的必须在这里创建自己的 ContentProvider 吗?

【问题讨论】:

  • 为什么不使用Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) ?更多here
  • 我不想放公共文件,这些文件也可用于图库应用。这是一个临时文件,应该在应用程序本身中使用,很快就会被删除。
  • 如果它只是一个私人数据(没有其他应用程序看到它),那么你需要FileProvider 做什么?仅限MediaStore.ACTION_IMAGE_CAPTURE
  • @pskink 它足够私密,不应该让用户轻易找到和查看。我只需要拍摄一张相机图像,然后将其用于某事。

标签: android orientation exif android-fileprovider


【解决方案1】:

Uri 不是文件。您在 Uri 上调用 getPath() 并将其视为文件路径。这只适用于Uri 中的方案是file。在你的情况下,它不是。

您已经有一个指向该文件的File 对象。它被称为photoFile。在您的活动字段中保留它,并将其保存在已保存的实例状态Bundle 中(因为当相机应用程序处于前台时,您的进程可能会终止)。然后,使用photoFile。但是不要使用内置的ExifInterface,作为it has security flaws

如何使用上面的代码(甚至更好的代码),使用新的 FileProvider Uri 获得方向?

你没有。使用photoFile

也许我可以强制 ContentResolver 使用以前的 ContentProvider 来获取光标所需列的数据?

我不知道您为什么期望 getOrientation() 需要 Uri 才能工作。您正在查询 MediaStore 以获取有关并非来自 MediaStoreUri 的数据。

我真的必须在这里创建自己的 ContentProvider 吗?

不,因为FileProvider 不是您的问题。您将拥有与您自己的ContentProvider 相同的有缺陷的getOrientation() 方法。

【讨论】:

  • 如果不使用 uri 或 Exif,我应该使用什么来获取捕获的图像文件的方向?我仅将 ExifInterface 用作后备,但现在我不知道该使用什么。
  • @androiddeveloper: "我应该用什么来获取捕获的图像文件的方向?" -- 一个随机数生成器。说真的,如果您不打算在 JPEG EXIF 标头中查看方向,则无法知道方向。 MediaStore 检查 EXIF 标头以查找它在自己的数据库中缓存的方向,以查找已编入索引的图像。
  • 我的意思是如何获得方向?我应该怎么称呼?哪个功能?我有文件路径和从 FileProvider 创建的 Uri。在 uri 上使用 MediaStore 不起作用,无论是 FileProvider 还是“Uri.fromFile”
  • @androiddeveloper:致电getOrientation(final String filePath)。它在你的代码中。但是,filePath 的值不是 Uri 上的 getPath()。它是photoFile.getAbsolutePath()。而且,我建议切换到不同的ExifInterface 实现,如Android SDK 中的has security flaws
  • @androiddeveloper:Android 7.0+ 设备应该打补丁。谷歌为 6.0(可能还有 5.x——我忘了​​)提供了一个补丁。但是,由于操作系统升级的不良记录,许多 5.x/6.x 设备不太可能看到该补丁。如果您的minSdkVersion 是24 或更高,使用SDK 的ExifInterface 应该没问题;否则我会使用其他东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-30
  • 2011-09-21
  • 1970-01-01
相关资源
最近更新 更多