web-dev-qa-db-ja.com

ACTION_IMAGE_CAPTUREで撮影された画像は、一部のGingerbreadデバイスでExifInterface.TAG_ORIENTATIONに対して常に1を返します

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

これを確認したデバイスのリストは次のとおりです。

  • Samsung Infuse 4G(2.3.3)
  • Samsung Galaxy SII X(2.3.5)
  • Sony Xperia Arc(2.3.3)

おもしろいのは、この画像がギャラリーになると適切に表示され、それを選択すると、TAG_ORIENTATIONが適切に表示されることです。どういうわけかOSActivityResultではなく、この情報を適切に埋めます。

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

編集:これは、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

40
Tolga E

みんな、OK 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より前の携帯電話をサポートしたい場合は、Java Drew Noakesのご厚意により; http://www.drewnoakes.com/code/exif/

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

編集:それが尋ねられたので、私が使用した意図と私が始めた方法はこのようなものでした

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);
53
Tolga E

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

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

確かに問題のあるバグです!私は提案された回避策が好きかどうかわからないので、ここに別のものがあります:)

重要なのは、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;
}
7
l33t

最近学んだことは、画像のサイズを変更すると、通常、EXIF情報が失われるということです。そのため、新しいファイルに古いEXIF情報を提供します。

ソース

2
Rohit Sharma

これに対する私の解決策。テスト済みLG G2モバイル。カメラを使用して新しい写真を撮ると、すべてが正常に機能することに気付きました。ExifInterfaceは正しい方向を返します。コード行:

exif = new ExifInterface(path);

しかし、絶対パスを使用すると、アプリがクラッシュします。しかし、解決策は、sdkのバージョンに依存するため、以下のこの方法です。もう1つ注意すべき点は、ギャラリー画像を選択するためだけに絶対パスを使用したことです。カメラに使用した場合、アプリがクラッシュしました。プログラミングの初心者で、これを解決するために2日を失いました。それが誰かを助けることを願っています。

   public String getRealPathFromURI(Uri uri) {
        if(Build.VERSION.SDK_INT >= 19){
            String id = uri.getLastPathSegment().split(":")[1];
            final String[] imageColumns = {MediaStore.Images.Media.DATA };
            final String imageOrderBy = null;
            Uri tempUri = getUri();
            Cursor imageCursor = getContentResolver().query(tempUri, imageColumns,
                    MediaStore.Images.Media._ID + "="+id, null, imageOrderBy);
            if (imageCursor.moveToFirst()) {
                return imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
            }else{
                return null;
            }
        }else{
            String[] projection = { MediaStore.MediaColumns.DATA };
            Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
            if (cursor != null) {
                int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
                cursor.moveToFirst();
                return cursor.getString(column_index);
            } else
                return null;
        }
    }

そのため、onActivityResultメソッドでExifInterfaceを取得します

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

    if (requestCode == GALLERY_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) {
        try {
            exif = new ExifInterface(getRealPathFromURI(data.getData()));
        } catch (IOException e) {
            e.printStackTrace();
        }
        showImage(data.getData());
    } else if (requestCode == CAMERA_IMAGE_REQUEST && resultCode == RESULT_OK) {
        try {
            exif = new ExifInterface(Uri.fromFile(getCameraFile()).getPath());
        } catch (IOException e) {
            e.printStackTrace();
        }
        showImage(Uri.fromFile(getCameraFile()));
    }
}

私のショーイメージメソッドは次のようになります

public void showImage(Uri uri) {
    if (uri != null) {
        try {

            Bitmap bitmap = scaleBitmapDown(MediaStore.Images.Media.getBitmap(getContentResolver(), uri), IMAGE_SIZE);

            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

            bitmap = rotateBitmap(bitmap, orientation);



            if (whatPlayer.equals("Player1")) {
                mImagePlayer1.setImageBitmap(bitmap);

                bitmapPlayer1 = bitmap; //*save picture in static variable so other activity can use this
            }
            if (whatPlayer.equals("Player2")) {
                mImagePlayer2.setImageBitmap(bitmap);

                bitmapPlayer2 = bitmap;
            }

        } catch (IOException e) {
            Log.d(TAG, "Image picking failed because " + e.getMessage());
            Toast.makeText(this, R.string.image_picker_error, Toast.LENGTH_LONG).show();
        }
    } else {
        Log.d(TAG, "Image picker gave us a null image.");
        Toast.makeText(this, R.string.image_picker_error, Toast.LENGTH_LONG).show();
    }
}
0
Lantus