前回のエントリーでカメラやギャラリーから画像を取得する周りまとめを書きましたが、
カメラからの画像取得に関して、国産端末で上手くいかないことが判明しましたので
こちらのエントリーで訂正させていただきます。


■国産の端末のほとんどでonActivityResultのdataパラメタにuriが入ってきません;;
前回エントリーを書いてからアプリを実際につくり、
国内メーカーの機種で試したところdata.getData()でuriが取得できない事が判明。
そこで保存先を明示することにしました。


まずカメラの呼び出しから
Uri uri; ←Activityクラスにプロパティとして置いてonActivityResultで参照できるように


カメラボタン押下などインテントの呼び出しを行う箇所の記述
------------------------------------------------------
//ContentValues
ContentValues values = new ContentValues();

//ファイル名を決めて
String filename = System.currentTimeMillis() + ".jpg";
//必要な情報を詰める
values.put(MediaStore.Images.Media.TITLE, filename);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
//Uriを取得して覚えておく、Intentにも保存先として渡す
uri= getContentResolver().insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

//インテントの設定
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, resourceUri);
startActivityForResult(intent, CAMMERA_IMAGE);
------------------------------------------------------

Manifastへの外部ストレージへの書き出し許可のユーザーパーミッションは忘れないでください。



onActivityResultの修正
------------------------------------------------------
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

     super.onActivityResult(requestCode, resultCode, data);

     if (resultCode != RESULT_OK){
         return;
     }

//uriにnullを詰めるコードを消す

     if (requestCode == GALLERY_IMAGE) {
         resourceUri= data.getData();
     }
     else if(requestCode == CAMMERA_IMAGE){
//カメラからの戻りの場合はuriをdataから取得しない(起動時に指定したUriが入っている)
//         uri =data.getData();
     }
    
     if(uri == null){
         return;
     }

     try {
         InputStream is = getContentResolver().openInputStream(uri);
         Bitmap bitmap = BitmapFactory.decodeStream(is);
        
/*
         //ファイルパスを取得したい場合は下記のようにContentResolverを活用する
         //ContentResolver経由でファイルパスを取得
         ContentResolver cr = getContentResolver();
         String[] columns = {MediaStore.Images.Media.DATA };
         Cursor c = cr.query(uri, columns, null, null, null);
        
         c.moveToFirst();
         File picture = new File(c.getString(0));
*/

     } catch (Exception e){
     // } catch (FileNotFoundException e) {
         // TODO 自動生成された catch ブロック
         e.printStackTrace();
         return;
     }
}
------------------------------------------------------

上記の画像のロードはシンプルな実装ですが、前回も書いた通り下記の関数を噛ませてリサイズしながらロードすることを推奨します。
こちらから飛んでください

これで国産端末でもカメラから画像を取得できると思います。
Androidで大きなサイズの画像をリサイズしながら取得する方法として
先日、どちらかのブログで紹介されていたものです。
BitmapFactoryを活用することで、画像をロードする前に画像の情報だけを取得し、
inSampleSizeへスケーリングサイズを指定することでリサイズした画像を取得しています。

掲載元からコピペ、関数名等を自分好みに修正して活用させていただいていますが、
掲載先のブログが分からなくなってしまったため、
備忘用にメモします。

/**
* リサイズ済み画像を取得する。
* @param file 画像ファイル
* @param view_width 目的のサイズ(幅)
* @param view_height 目的のサイズ(高さ)
* @return
*/
public Bitmap getResizeBitmap(File file, int view_width, int view_height){
     Bitmap ret = null;

         if(file == null){
         }else{
             //画像
             BitmapFactory.Options option = new BitmapFactory.Options();
             Bitmap src = null;
             int sample_size = 0;

             //実際に読み込まないで情報だけ取得する
             option.inJustDecodeBounds = true;
             BitmapFactory.decodeFile(file.getAbsolutePath(), option);
             if((option.outWidth * option.outHeight) > 1048576){
                 //1Mピクセル超えてる
                 double out_area = (double)(option.outWidth * option.outHeight) / 1048576.0;
                 sample_size = (int) (Math.sqrt(out_area) + 1);
             }else{
                 //小さいのでそのまま
                 sample_size = 1;
             }

             //実際に読み込むモード
             option.inJustDecodeBounds = false;
             //スケーリングする係数
             option.inSampleSize = sample_size;
             //画像を読み込む
             src = BitmapFactory.decodeFile(file.getAbsolutePath(), option);
             if(src == null){
             }else{
                 int src_width = src.getWidth();
                 int src_height = src.getHeight();

                 //表示利用域に合わせたサイズを計算
                 float scale = getFitScale(view_width, view_height, src_width, src_height);

                 //リサイズマトリクス
                 Matrix matrix = new Matrix();
                 matrix.postScale(scale, scale);

                 //ビットマップ作成
                 ret = Bitmap.createBitmap(src, 0, 0, src_width, src_height, matrix, true);
             }
         }

         return ret;
}

/**
* 最適なスケールを求める
* @param dest_width 目的のサイズ(幅)
* @param dest_height 目的のサイズ(高さ)
* @param src_width 元のサイズ(幅)
* @param src_height 元のサイズ(高さ)
* @return
*/
public static float getFitScale(int dest_width, int dest_height
           , int src_width, int src_height){
   float ret = 0;

   if(dest_width < dest_height){
       //縦が長い
       if(src_width < src_height){
           //縦が長い
           ret = (float)dest_height / (float)src_height;

           if((src_width * ret) > dest_width){
               //縦に合わせると横がはみ出る
               ret = (float)dest_width / (float)src_width;
           }
       }else{
           //横が長い
           ret = (float)dest_width / (float)src_width;
       }
   }else{
       //横が長い
       if(src_width < src_height){
           //縦が長い
           ret = (float)dest_height / (float)src_height;
       }else{
           //横が長い
           ret = (float)dest_width / (float)src_width;

           if((src_height * ret) > dest_height){
               //横に合わせると縦がはみ出る
               ret = (float)dest_height / (float)src_height;
           }
       }
   }

   return ret;
}
■ギャラリーピッカーやカメラからの画像取得周りまとめ


2011/5/18追記
2.3.のソースコード修正版をこちらに記載しましたので合わせて読んでください。


AndroidSDKでの開発中にギャラリー機能やカメラ機能を活用して画像を取り込みたいと思う要件はさまざまなシーンで発生しますが、
やり方をど忘れした上に、どこのブログに情報が載っていたかまで忘れることがあるので、ギャラリーからの画像取得周りについて簡単にまとめます。

やりたい事としては以下の2つです。
1.ギャラリーから画像を取り込む
2.標準カメラから撮影した画像を取得する

これを実現する方法を3点にわけて説明します。
1.ギャラリーから画像を選択して戻ってくる画面の呼び出し
2.撮影したらアプリに戻ってくる標準カメラの呼び出し
3.1、2からのコールバックに対しての処理方法

1.ギャラリーから画像を選択して戻ってくる画面の呼び出し

Intentを用いてActivity呼び出す際に、startActivityForResultを使用することで、
自ActivityのonActivityResultへコールバックを得られます。
ギャラリー、カメラ両方ともこの仕組みを活用することで、
画像へのUriを取得する事が可能です。

1、2の内容はギャラリーorカメラボタンの押下イベント等に適切に実装してください。

まずはギャラリー画面の呼び出しを説明します。


IntentにsetActionでACTION_PICKを指定してあげることで、一発で標準ギャラリーが呼び出されます。

try{
     Intent intent = new Intent();
     intent.setType("image/*");
     intent.setAction(Intent.ACTION_PICK);
     //GALLARERY_IMAGEは適当なintです。onActivityResultでどこからの戻りか識別する必要がある場合に有効です
     startActivityForResult(intent,GALLERY_IMAGE);
}catch(Exception e){

}

※2、3はこちらに訂正版のエントリーがありますので、ソースコードはそちらを参照してください。
説明は一読されることをお奨めします。


2.撮影したらアプリに戻ってくる標準カメラの呼び出し

try{
     Intent intent = new Intent();
     intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
/*
     //putExtraでEXTRA_OUTPUTを設定すると、カメラに画像の保存パスを指定することができます。指定しない場合は標準のファイル名で保存されます。
     File mTmpFile = new File(Environment.getExternalStorageDirectory(), "tmp_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
     intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTmpFile));
*/

     // ギャラリーと同じく判別用のintです
     startActivityForResult(intent, CAMMERA_IMAGE);

}catch(Exception e){

}

3.1、2からのコールバックに対しての処理方法


protected void onActivityResult(int requestCode, int resultCode, Intent data) {

     super.onActivityResult(requestCode, resultCode, data);

     if (resultCode != RESULT_OK){
         return;
     }

     Uri uri = null;
     if (requestCode == GALLERY_IMAGE) {
         uri = data.getData();
     }
     else if(requestCode == CAMMERA_IMAGE){
         uri =data.getData();
     }
    
     if(uri == null){
         return;
     }

     try {
         InputStream is = getContentResolver().openInputStream(uri);
         Bitmap bitmap = BitmapFactory.decodeStream(is);
        
/*
         //ファイルパスを取得したい場合は下記のようにContentResolverを活用する
         //ContentResolver経由でファイルパスを取得
         ContentResolver cr = getContentResolver();
         String[] columns = {MediaStore.Images.Media.DATA };
         Cursor c = cr.query(uri, columns, null, null, null);
        
         c.moveToFirst();
         File picture = new File(c.getString(0));
*/

     } catch (Exception e){
     // } catch (FileNotFoundException e) {
         // TODO 自動生成された catch ブロック
         e.printStackTrace();
         return;
     }
}

以上で、標準カメラおよび標準ギャラリーから画像を取得することができると思います。

【カメラから撮影画像を取得する場合のout of memory対策】

カメラから撮影画像を取得する場合ですが、
カメラの撮影サイズが5M等、非常に大きいサイズの画像だとoutofmemory例外が発生しやすくなります。
そこでBitmapFactoryのOptionsを駆使して画像のサイズ事前に調べた上でリサイズした画像をBitmapとして取得することでメモリー使用を抑えます。

以前どちらかのブログで紹介されていたもので、私のアプリにほぼコピペ移植させていただいた関数を下記URLにメモしています。
どちらのブログだったか覚えておらず出展を表記できず申し訳ありません。

http://ameblo.jp/yolluca/entry-10888432114.html


先ほどのカメラで撮影した画像を活用する場合はこちらのような処理を噛ませ画像の大きさをコントロールすることをお薦めいたします。