42

ACTION_IMAGE_CAPTUREアクティビティで作業するときに向きの問題がありました。を使用して、TAG_ORIENTATIONそれに応じて画像を回転させました。しかし、一部の新しいデバイスではこれが機能しないことがわかりました。実際、すべての方向に対して 1 を返します。

これが確認されたデバイスのリストです。

  • サムスン インフューズ 4G (2.3.3)
  • サムスン ギャラクシー SII X (2.3.5)
  • ソニー Xperia アーク (2.3.3)

興味深いことに、この画像をギャラリーにすると適切に表示され、それを選択するとTAG_ORIENTATION適切に入力されます。したがって、どういうわけか はOSこの情報を適切に埋めますが、 ではありませんActivityResult

方向を把握する最も信頼できる方法は何ですか? 別の質問で誰かが高さと幅を比較することを提案しましたが、これらを取得すると、方向に基づいて適切に切り替えられます(別の謎)

編集: これは、OS がギャラリーで撮影した画像を複製する別のバグに関連しているようです (私たちが指定した URL に画像を保存することのみが想定されています) ORIENTATION。指定された場所にあるものはそうではありません。

これがバグです。http://code.google.com/p/android/issues/detail?id=19268

EDIT-2: Android の新しいバグを報告しました。これは、前述のバグに関連する OS のバグであると確信しています。 http://code.google.com/p/android/issues/detail?id=22822

4

5 に答える 5

56

わかりました、Android のこのバグはしばらく修正されないようです。ExifInformation を実装して、両方のデバイス (適切な Exif タグと不適切な exif タグを持つデバイス) が連携する方法を見つけましたが..

したがって、問題は一部の(新しい)デバイスにあり、適切に回転された画像がAndroidのデフォルトフォルダーに保存されている間に、適切なexifタグなしでアプリフォルダーに保存された写真を作成するバグがあります(そうすべきではありません)。 .

今私がしていることは、アプリからカメラアプリを起動している時間を記録することです。次に、アクティビティの結果について、メディア プロバイダーに問い合わせて、保存したこのタイムスタンプの後に画像が保存されているかどうかを確認します。つまり、ほとんどの場合、OS は適切に回転された画像を既定のフォルダーに保存し、もちろんメディア ストアにエントリを配置し、この行から回転情報を使用できます。正しい画像が表示されていることを確認するために、このファイルのサイズを、アクセスできるファイル (自分のアプリ フォルダーに保存されている) と比較します。

    int rotation =-1;
    long fileSize = new File(filePath).length();

    Cursor mediaCursor = content.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[] {MediaStore.Images.ImageColumns.ORIENTATION, MediaStore.MediaColumns.SIZE }, MediaStore.MediaColumns.DATE_ADDED + ">=?", new String[]{String.valueOf(captureTime/1000 - 1)}, MediaStore.MediaColumns.DATE_ADDED + " desc");

    if (mediaCursor != null && captureTime != 0 && mediaCursor.getCount() !=0 ) {
        while(mediaCursor.moveToNext()){
            long size = mediaCursor.getLong(1);
            //Extra check to make sure that we are getting the orientation from the proper file
            if(size == fileSize){
                rotation = mediaCursor.getInt(0);
                break;
            }
        }
    }

この時点での回転がまだ -1 の場合、これは適切な回転情報を持つ電話機の 1 つであることを意味します。この時点で、onActivityResult に返されるファイルで通常の exif 方向を使用できます。

    else if(rotation == -1){
        rotation = getExifOrientationAttribute(filePath);
    }

この質問の答えのようなexifの向きを見つける方法を簡単に見つけることができますAndroidのカメラの向きの問題

また、ExifInterface は Api レベル 5 以降でしかサポートされていないことにも注意してください。したがって、2.0 より前の電話をサポートしたい場合は、Drew Noakes の厚意により Java 用に見つけたこの便利なライブラリを使用できます。http://www.drewnoakes.com/code/exif/

画像の回転を頑張ってください!

EDIT:聞かれたので使った意図と始め方はこんな感じでした

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//mediaFile is where the image will be saved
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mediaFile));
startActivityForResult(intent, 1);
于 2012-01-14T18:28:47.897 に答える
7

確かに問題のあるバグです!提案された回避策が気に入るかどうかわからないので、別の回避策を示します:)

重要なのはEXTRA_OUTPUT、画像がキャプチャされたときにそれを使用してクエリすることです! 明らかに、これはファイル名を指定できる場合にのみ機能します。

protected void takePictureSequence() {      
    try {
        ContentValues values = new ContentValues();  
        values.put(MediaStore.Images.Media.TITLE, UUID.randomUUID().toString() + ".jpg");  
        newPhotoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

        Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, newPhotoUri);

        startActivityForResult(intent, ActivityResults.TAKE_NEW_PICTURE_RESULT);
    } catch (Exception e) {
        Toast.makeText(this, R.string.could_not_initalize_camera, Toast.LENGTH_LONG).show();
    }
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == ActivityResults.TAKE_NEW_PICTURE_RESULT) {
        if (resultCode == RESULT_OK) {
            try {
                String[] projection = { MediaStore.Images.Media.DATA }; 
                CursorLoader loader = new CursorLoader(this, newPhotoUri, projection, null, null, null);
                Cursor cursor = loader.loadInBackground();

                int column_index_data = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                cursor.moveToFirst();

                // Rotation is stored in an EXIF tag, and this tag seems to return 0 for URIs.
                // Hence, we retrieve it using an absolute path instead!
                int rotation = 0;
                String realPath = cursor.getString(column_index_data);
                if (realPath != null) {
                    rotation = ImageHelper.getRotationForImage(realPath);
                }

                // Now we can load the bitmap from the Uri, using the correct rotation.
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public int getRotationForImage(String path) {
    int rotation = 0;

    try {
        ExifInterface exif = new ExifInterface(path);
        rotation = (int)exifOrientationToDegrees(exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL));
    } catch (IOException e) {
        e.printStackTrace();
    }

    return rotation;
}
于 2013-10-26T18:05:13.143 に答える
7

あなたもこの方法で行くことができます:

Matrix matrix = new Matrix();
// rotate the Bitmap (there a problem with exif so we'll query the mediaStore for orientation
Cursor cursor = getApplicationContext().getContentResolver().query(selectedImage,
      new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
if (cursor.getCount() == 1) {
cursor.moveToFirst();
    int orientation =  cursor.getInt(0);
    matrix.preRotate(orientation);
    }
于 2012-08-26T22:28:54.463 に答える
2

私が最近学んだことは、画像のサイズを変更すると、通常は EXIF 情報が失われるということです。したがって、新しいファイルに古い EXIF 情報を与える必要があります。

ソース。

于 2014-10-16T18:43:53.003 に答える