このトピックは、ここで多くの質問で議論されてきましたが、ほとんどが結果が異なり、APIの変更とさまざまな種類のURIにより、決定的な答えはありません。
自分には答えがありませんが、それについて話しましょう。 ExifInterface
には、filePath
を受け入れる単一のコンストラクターがあります。パス自体に依存することは現在推奨されていないので、それ自体は面倒です-代わりにUri
sとContentResolver
を使用する必要があります。 OK。
Uri
という名前のuri
は、onActivityResult
のインテントから取得できます(_ACTION_GET_CONTENT
_を使用してギャラリーから画像を選択した場合)またはUri
以前(カメラから画像を選択してintent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
を呼び出した場合)。
uri
は2つの異なるスキーマを持つことができます:
file://
_スキーマを持ちます。それらはパスを保持しているため、扱いやすいです。 new ExifInterface(uri.getPath())
を呼び出すと完了です。content://
_インターフェイスがあります。私は個人的にそれが何であるかを知りませんが、私を怒らせています。私が理解している限り、この2番目のケースはContext.getContentResolver()
で取得できるContentResolver
で処理する必要があります。次のworksは、私がテストしたすべてのアプリで、いずれの場合でも:
_public static ExifInterface getPictureData(Context context, Uri uri) {
String[] uriParts = uri.toString().split(":");
String path = null;
if (uriParts[0].equals("content")) {
// we can use ContentResolver.
// let’s query the DATA column which holds the path
String col = MediaStore.Images.ImageColumns.DATA;
Cursor c = context.getContentResolver().query(uri,
new String[]{col},
null, null, null);
if (c != null && c.moveToFirst()) {
path = c.getString(c.getColumnIndex(col));
c.close();
return new ExifInterface(path);
}
} else if (uriParts[0].equals("file")) {
// it's easy to get the path
path = uri.getEncodedPath();
return new ExifInterface(path);
}
return null;
}
_
_content://
_ URIを使用したKitKat以降の問題が発生します。 KitKatでは、_Storage Access Framework
_( here を参照)と新しいインテント、_ACTION_OPEN_DOCUMENT
_、およびプラットフォームピッカーが導入されています。しかし、それは言われています
Android 4.4以降では、システムが制御するピッカーUIを表示するACTION_OPEN_DOCUMENTインテントを使用する追加オプションがあり、ユーザーは他のアプリが利用可能にしたすべてのファイルを閲覧できます。この単一のUIから、ユーザーはサポートされているアプリのいずれかからファイルを選択できます。
ACTION_OPEN_DOCUMENTは、ACTION_GET_CONTENTの代替となることを意図したものではありません。使用すべきものは、アプリのニーズによって異なります。
これを非常にシンプルに保つために、古い_ACTION_GET_CONTENT
_で大丈夫だとしましょう:ギャラリーアプリを選択できる選択ダイアログが起動します。
ただし、コンテンツアプローチはもう機能しません。 KitKatで動作することもありますが、たとえば、Lollipopでは動作しないなどです。何が正確に変わったのかわかりません。
私は多くのことを検索して試しました。 KitKatで特に採用されている別のアプローチは次のとおりです。
_String wholeId = DocumentsContract.getDocumentId(uri);
String[] parts = wholeId.split(“:”);
String numberId = parts[1];
Cursor c = context.getContentResolver().query(
// why external and not internal ?
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[]{ col },
MediaStore.Images.Media._ID + “=?”,
new String[]{ numberId },
null);
_
これは時々機能しますが、他の機能は機能しません。具体的には、wholeId
が_image:2839
_のような場合に機能しますが、wholeId
が単なる数字の場合は明らかに壊れます。
システムピッカーを使用してこれを試すことができます(つまり、_ACTION_OPEN_DOCUMENT
_を使用してギャラリーを起動します)。「最近」から画像を選択すると、動作します。 「ダウンロード」から画像を選択すると、破損します。
即時の答えはありません、OSの新しいバージョンではコンテンツURIからのファイルパスは見つかりません。すべてのコンテンツURIが写真やファイルを指すわけではないと言うことができます。
それは私にはまったく問題ありません。最初はこれを避けるために働きました。しかし、その後、パスを使用すべきではない場合、ExifInterfaceクラスをどのように使用することになっていますか?
最新のアプリがこれをどのように行うか理解できません。向きとメタデータを見つけることはすぐに直面する問題であり、ContentResolver
はその意味でAPIを提供しません。 ContentResolver.openFileDescriptor()
などがありますが、メタデータを読み取るAPIはありません(これはそのファイルにあります)。ストリームからExif
を読み込む外部ライブラリがあるかもしれませんが、これを解決するための共通/プラットフォームの方法について疑問に思っています。
Googleのオープンソースアプリで同様のコードを検索しましたが、何も見つかりませんでした。
以下は、私がテストしたすべてのアプリで動作します。
Uri
がたまたまMediaStore
からのものである場合にのみ機能します。 Uri
が他の何かから来た場合、失敗します。
即時の答えは、「しません。新しいバージョンのOSではコンテンツURIからのファイルパスは見つかりません」です。すべてのコンテンツURIが写真やファイルを指すわけではないと言うことができます。
正しい。 here など、多くの場合にこれを指摘しました。
パスを使用しない場合、ExifInterfaceクラスをどのように使用するのですか?
あなたはしません。他のコードを使用してEXIFヘッダーを取得します。
Exifをストリームから読み込む外部ライブラリがあるかもしれませんが、これを解決するための一般的な/プラットフォームの方法について疑問に思っています。
外部ライブラリを使用します。
Googleのオープンソースアプリで同様のコードを検索しましたが、何も見つかりませんでした。
Mmsアプリ にいくつかあります。
Alex.dorokhovの回答をいくつかのサンプルコードで展開します。サポートライブラリは最適な方法です。
build.gradle
dependencies {
...
compile "com.Android.support:exifinterface:25.0.1"
...
}
サンプルコード:
import Android.support.media.ExifInterface;
...
try (InputStream inputStream = context.getContentResolver().openInputStream(uri)) {
ExifInterface exif = new ExifInterface(inputStream);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
} catch (IOException e) {
e.printStackTrace();
}
Api 25をターゲットにした後(24+でも問題になる可能性があります)にこの方法でやらなければならなかった理由は、API 19にAndroid 7ファイルを参照しているだけのカメラにURIで渡されるため、このようにカメラインテントに渡すURIを作成する必要がありました。
FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".fileprovider", tempFile);
そこに問題があるのは、そのファイルがURIを実際のファイルパスに変換できないことです(一時ファイルパスを保持する以外)。
コンテンツURI(実際にはInputStream)からEXIFを取得することが、サポートライブラリで利用可能になりました。参照: https://Android-developers.googleblog.com/2016/12/introducing-the-exifinterface-support-library.html