26

それは世界で最も単純なことのようです: デフォルトのカメラ アクティビティを使用して、Android アプリ内で写真を撮ります。ただし、たとえば、Null インテントが返される、画像の向きが正しくない、OutOfMemoryErrors など、StackOverflow と Web のいくつかの投稿で取り上げられている多くの落とし穴があります。

私ができる解決策を探しています

  1. カメラ インテントを介してカメラ アクティビティを開始し、
  2. 写真の Uri を取得し、
  3. 写真の正しい向きを取得します。

さらに、デバイス構成 (メーカー、モデル、OS バージョン) 固有の実装はできるだけ避けたいと考えています。だから私は疑問に思っています:これを達成するための最良の方法は何ですか?

4

4 に答える 4

23

更新: 2014 年 1 月 2 日: 私は、デバイスの製造元に基づいて異なる戦略を実装することを避けるために非常に努力しました。残念ながら、私はそれを回避しませんでした。何百もの投稿を調べ、何人かの開発者と話しましたが、デバイス メーカー固有のコードを実装せずにすべてのデバイスで動作するソリューションを見つけた人はいませんでした。

このソリューションを StackOverflow に投稿した後、何人かの開発者から私のコードを github に公開するように依頼されました。だから今ここにあります: github の AndroidCameraUtil

このコードは、Android API レベル >= 8 のさまざまなデバイスで正常にテストされました。完全なリストについては、github の Readme ファイルを参照してください。

CameraIntentHelperActivityは主な機能を提供します。これについては、以下で詳しく説明します。

デフォルトのカメラ アクティビティの呼び出し:

  • Samsung および Sony デバイスの場合: startActivityForResult へのメソッド呼び出しでカメラ アクティビティを呼び出します。定数 CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE のみを設定しました。他のインテント エクストラは設定しません。
  • 他のすべてのデバイスの場合: 以前と同様に、startActivityForResult へのメソッド呼び出しでカメラ アクティビティを呼び出します。ただし、今回は追加でインテントを追加して MediaStore.EXTRA_OUTPUT を設定し、画像を保存する場所に URI を指定します。

どちらの場合も、カメラ アクティビティが開始された時刻を覚えています。


カメラ アクティビティの結果:

  1. Mediastore:まず、MediaStore からキャプチャされた写真を読み取ろうとします。MediaStore コンテンツに対して mangedQuery を使用して、撮影中の最新の画像と、その方向プロパティおよびタイムスタンプを取得します。カメラ インテントが呼び出される前に撮影されたものではない画像が見つかった場合、それは私が探していた画像です。それ以外の場合は、結果を破棄して、次のアプローチのいずれかを試します。
  2. インテント エクストラ: 2 番目に、返されるインテントのインテント.getData() から画像 Uri を取得しようとします。これも成功しない場合は、ステップ 3 に進みます。
  3. デフォルトの写真 Uri : 上記の手順がすべてうまくいかなかった場合は、カメラ アクティビティに渡した画像 Uri を使用します。

この時点で、UploadPhotoActivity に渡す写真の Uri とその向きを取得しました。


画像処理

私の BitmapHelper クラスをよく見てください。これは、そのチュートリアルで詳しく説明されているコードに基づいています。

さらに、shrinkBitmap メソッドは、必要に応じて、以前に抽出された方向情報に基づいて画像を回転させます。


これがあなたの一部に役立つことを願っています。

于 2013-04-30T08:10:22.170 に答える
0

CM 10.1 を搭載した Galaxy S3 では、BitmapHelper で nullpointer 例外が発生します。

bm = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, オプション);

その後、私の UploadPhotoActivity は次の場所で失敗します:

    try {
        photo = BitmapHelper.readBitmap(this, cameraPicUri);
        if (photo != null) {
            photo = BitmapHelper.shrinkBitmap(photo, 600, rotateXDegrees);
            thumbnail = BitmapHelper.shrinkBitmap(photo, 100);
            ImageView imageView = (ImageView) findViewById(R.id.sustainable_action_photo);
            imageView.setImageBitmap(photo);                
        } else {
            Log.e(TAG,"IMAGE ERROR 1");
        }
    } catch (Exception e) {
            Log.e(TAG,"IMAGE ERROR 2");
        e.printStackTrace();
    }

2 番目のログ (画像エラー 2)。数回試行した後、カメラが壊れ、「カメラに接続できませんでした」というエラーが表示されました。

nexus 7 でテストしたところ、問題なく動作しました。

編集:これに絞り込みました:

fileDescriptor = context.getContentResolver().openAssetFileDescriptor(selectedImage, "r");

selectedImageにはこれが含まれていますが:

file:///storage/emulated/0/DCIM/Camera/IMG_20131023_183343.jpg

fileDescriptor は FileNotFoundException を返します。ファイル システムを確認しましたが、画像がこの場所に保存されていません。TakePhotoActivity の cameraPicUri が、存在しない画像を指しています。現在、どこが悪いのか確認中です。

Edit2: エラーを見つけました: デバイスは Samsung であり、Samsung デバイスであることをアプリに伝えるため、Samsung 固有の修正が適用されます。ただし、Cyanogenmod はこれらの修正を必要とせず、最終的にコードが壊れます。取り外したら

(manufacturer.contains("samsung")) &&

できます。これはカスタム ROM であるため、もちろんそれを計画することはできません。デバイスが cyanogenmod を実行しているかどうかを検出し、これをコードに含める方法を見つけようとしています。

素敵なカメラ修理をありがとう!

Edit3:コードを次のように変更して、Galaxy S3 の Cyanogenmod で実行するように修正しました 。変。

if (getPackageManager().hasSystemFeature("com.cyanogenmod.android") || (!(manufacturer.contains("samsung")) && !(manufacturer.contains("sony")) && !(manufacturer.contains(") lge"))))

于 2013-10-23T16:06:23.217 に答える