SlideShare a Scribd company logo
Android
  カメラアプリ
   実装のコツ                                          id:TAC


この資料の内容の一部は、Google が作成、提供しているコンテンツをベースに変更したもので、
クリエイティブ・コモンズの表示 3.0 ライセンスに記載の条件に従って使用しています。
自己紹介

 id: TAC, tac0x2a
 Twitter: @tac0x2a
 Androidアプリ作ってます.
 求職中の院生です
Droid Jammer
●   画像中の顔を認識して
    アイコンで隠す

●   簡単な編集ができる

●   インテント連携

●   おまけでカメラ機能を付けた
    おまけで
投稿者: holybible(2010年7月21日)
   Funny idea and easy to use However,
   always got Force to Close on my Froyo device


                         投稿者: Faheem(2010年8月29日)
                         Force closes on taking a pic. Cliq


投稿者: Daniel(2010年9月10日)
Doesn't function. Force close. Eris


              投稿者: Diego(2010年9月27日)
              It keeps on chrashing each time i open it. G1


    投稿者: Eduardo(2010年5月8日)
      Does not work on HTC hero
投稿者: holybible(2010年7月21日)
   Funny idea and easy to use However,
   always got Force to Close on my Froyo device


                         投稿者: Faheem(2010年8月29日)
                         Force closes on taking a pic. Cliq


投稿者: Daniel(2010年9月10日)
Doesn't function. Force close. Eris


              投稿者: Diego(2010年9月27日)
              It keeps on chrashing each time i open it. G1


    投稿者: Eduardo(2010年5月8日)
      Does not work on HTC hero
2つのコツ+α

OutOfMemoryError対策

   takePictureによる
   コールバック
コツその1




OutOfMemoryError
      対策
撮影した画像データを取得する
@Override
public void onPictureTaken(
  byte[] data, Camera camera) {

Bitmap picture =
BitmapFactory.decodeByteArray(
      data,0,data.length,option);

 撮影したデータ( byte[] data ) を Bitmapオブジェクトに変換
@Override
    OutOfMemoryError
public void onPictureTaken(
  byte[] data, Camera camera) {

Bitmap picture =
BitmapFactory.decodeByteArray(
      data,0,data.length,option);

 撮影したデータ( byte[] data ) を Bitmapオブジェクトに変換
OutOfMemoryError
●
    巨大な画像を扱うにはメモリ(ヒープ)が足りない
    ●
        →端末によって異なるが大体16〜32MB程度
●


●
    撮影したデータをBitmapオブジェクトへ変換
    ●
        →メモリ不足で強制終了
読み込みサイズを制限
Bitmap loadSavedSizeBitmap(int maxSize, byte[] data) {

    BitmapFactory.Options opt = new BitmapFactory.Options();
    opt.inJustDecodeBounds = true;

    BitmapFactory.decodeByteArray(data, 0, data.length, opt);
    int srcSize = Math.max(opt.outWidth,opt.outHeight);

    opt.inSampleSize
            = maxSize < srcSize ? (srcSize / maxSize) : 1;

    option.inJustDecodeBounds = false;
    return BitmapFactory.decodeByteArray(
                             data, 0,data.length, opt));
}
読み込みサイズを制限
Bitmap loadSavedSizeBitmap(int maxSize, byte[] data) {

    BitmapFactory.Options opt = new BitmapFactory.Options();
    opt.inJustDecodeBounds = true;

    BitmapFactory.decodeByteArray(data, 0, data.length, opt);
    int srcSize = Math.max(opt.outWidth,opt.outHeight);

    opt.inSampleSize
            = maxSize < srcSize ? (srcSize / maxSize) : 1;
                                    サイズを先読み
    option.inJustDecodeBounds = false;
    return BitmapFactory.decodeByteArray(
                             data, 0,data.length, opt));
}
読み込みサイズを制限
 何倍でロードするか
Bitmap loadSavedSizeBitmap(int maxSize, byte[] data) {
      計算して設定
    (1/inSampleSize)
    BitmapFactory.Options opt = new BitmapFactory.Options();
    opt.inJustDecodeBounds = true;

    BitmapFactory.decodeByteArray(data, 0, data.length, opt);
    int srcSize = Math.max(opt.outWidth,opt.outHeight);

    opt.inSampleSize
            = maxSize < srcSize ? (srcSize / maxSize) : 1;

    option.inJustDecodeBounds = false;
    return BitmapFactory.decodeByteArray(
                             data, 0,data.length, opt));
}
読み込みサイズを制限
Bitmap loadSavedSizeBitmap(int maxSize, byte[] data) {

    BitmapFactory.Options opt = new BitmapFactory.Options();
    opt.inJustDecodeBounds = true;

                               設定した倍率で
    BitmapFactory.decodeByteArray(data, 0, data.length, opt);
    int srcSize = Math.max(opt.outWidth,opt.outHeight);
                                  ロードする
    opt.inSampleSize
            = maxSize < srcSize ? (srcSize / maxSize) : 1;

    option.inJustDecodeBounds = false;
    return BitmapFactory.decodeByteArray(
                             data, 0,data.length, opt));
}
コツその2




takePictureによる
   コールバック
撮影するメソッド
public final void takePicture(
  ShutterCallback shutter,
  PictureCallback raw,
  PictureCallback postview,
  PictureCallback jpeg
)
 4つのコールバックを設定.
 Android1.xでは引数は3つで, postviewをnullにした場合と同じ
takePictureから
どのコールバックが
   呼ばれるかは
   端末依存です
端末依存なコールバック
public final void takePicture(
  ShutterCallback shutter,
  PictureCallback raw,
  PictureCallback postview,
  PictureCallback jpeg
)
私のx06htではrawは呼ばれたがshutterとpostviewが呼ばれなかった
takePicture
によるコールバックは
   非同期です
takePictureの流れ
 takePicture(
    shutter,
    raw,
    postview,
    jpeg
 );
                shutter


                  raw


                 jpeg
jpeg saved
                                  jpeg
SDK 2.2 emu(1.6) 320x240          raw
                                  shutter
                                  takePicture()




x06ht(2.2.1) 1024x768




ht03a (2.2.1) 1024x768


0        500       1000    1500    2000           2500
takePictureの流れ
       takePicture(
          shutter,
          raw,
          postview,
          jpeg
       );
                            shutter

 まだBitmapが
作られていない!                      raw
                                       ここで
                      約2秒             Bitmapが
                                      作られる
                             jpeg
Bitmapへのアクセスは
jpegのコールバックで
保存されたのを確認し
      てから!
+α
●
    setPictureSize()とsetPreviewSize()を適切に
    設定する.
    ●
        getSupported{Picture|Preview}Sizes()で取得した
        リストからそれぞれ設定.
    ●
        端末によっては特定の組み合わせで落ちる(多分).
    ●


●
    IntentでBitmapオブジェクトを投げない
    ●
        大きなデータをIntentで投げると落ちます
    ●
        とりあえずSDとかに保存、ファイルへのパスのみを
        Intentに乗せて、受ける側でファイルから読み出す
まとめ
●
    メモリやGCを意識して書く
●
    カメラアプリは端末による差が出やすい
●


●
    デバッグに協力してくれる人を増やす
    ●
        →Androidを布教しt(ry
最後に
Android2.2以降をお使いの皆様




  バグレポートを
  送ってください
哀れみをこめて押す
願いを込めて書く
ね?簡単でしょ?
Androidカメラアプリ実装のコツ




             おしまい
                     Twitter: @tac0x2a
                     Mail: tac@tac42.net
                     野良: http://goo.gl/k2wk
                     AndroidMarket:

More Related Content

カメラアプリ実装のコツ

  • 1. Android カメラアプリ 実装のコツ id:TAC この資料の内容の一部は、Google が作成、提供しているコンテンツをベースに変更したもので、 クリエイティブ・コモンズの表示 3.0 ライセンスに記載の条件に従って使用しています。
  • 2. 自己紹介 id: TAC, tac0x2a Twitter: @tac0x2a Androidアプリ作ってます. 求職中の院生です
  • 3. Droid Jammer ● 画像中の顔を認識して アイコンで隠す ● 簡単な編集ができる ● インテント連携 ● おまけでカメラ機能を付けた おまけで
  • 4. 投稿者: holybible(2010年7月21日) Funny idea and easy to use However, always got Force to Close on my Froyo device 投稿者: Faheem(2010年8月29日) Force closes on taking a pic. Cliq 投稿者: Daniel(2010年9月10日) Doesn't function. Force close. Eris 投稿者: Diego(2010年9月27日) It keeps on chrashing each time i open it. G1 投稿者: Eduardo(2010年5月8日) Does not work on HTC hero
  • 5. 投稿者: holybible(2010年7月21日) Funny idea and easy to use However, always got Force to Close on my Froyo device 投稿者: Faheem(2010年8月29日) Force closes on taking a pic. Cliq 投稿者: Daniel(2010年9月10日) Doesn't function. Force close. Eris 投稿者: Diego(2010年9月27日) It keeps on chrashing each time i open it. G1 投稿者: Eduardo(2010年5月8日) Does not work on HTC hero
  • 6. 2つのコツ+α OutOfMemoryError対策 takePictureによる コールバック
  • 9. @Override public void onPictureTaken( byte[] data, Camera camera) { Bitmap picture = BitmapFactory.decodeByteArray( data,0,data.length,option); 撮影したデータ( byte[] data ) を Bitmapオブジェクトに変換
  • 10. @Override OutOfMemoryError public void onPictureTaken( byte[] data, Camera camera) { Bitmap picture = BitmapFactory.decodeByteArray( data,0,data.length,option); 撮影したデータ( byte[] data ) を Bitmapオブジェクトに変換
  • 11. OutOfMemoryError ● 巨大な画像を扱うにはメモリ(ヒープ)が足りない ● →端末によって異なるが大体16〜32MB程度 ● ● 撮影したデータをBitmapオブジェクトへ変換 ● →メモリ不足で強制終了
  • 12. 読み込みサイズを制限 Bitmap loadSavedSizeBitmap(int maxSize, byte[] data) { BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(data, 0, data.length, opt); int srcSize = Math.max(opt.outWidth,opt.outHeight); opt.inSampleSize = maxSize < srcSize ? (srcSize / maxSize) : 1; option.inJustDecodeBounds = false; return BitmapFactory.decodeByteArray( data, 0,data.length, opt)); }
  • 13. 読み込みサイズを制限 Bitmap loadSavedSizeBitmap(int maxSize, byte[] data) { BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(data, 0, data.length, opt); int srcSize = Math.max(opt.outWidth,opt.outHeight); opt.inSampleSize = maxSize < srcSize ? (srcSize / maxSize) : 1; サイズを先読み option.inJustDecodeBounds = false; return BitmapFactory.decodeByteArray( data, 0,data.length, opt)); }
  • 14. 読み込みサイズを制限 何倍でロードするか Bitmap loadSavedSizeBitmap(int maxSize, byte[] data) { 計算して設定 (1/inSampleSize) BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(data, 0, data.length, opt); int srcSize = Math.max(opt.outWidth,opt.outHeight); opt.inSampleSize = maxSize < srcSize ? (srcSize / maxSize) : 1; option.inJustDecodeBounds = false; return BitmapFactory.decodeByteArray( data, 0,data.length, opt)); }
  • 15. 読み込みサイズを制限 Bitmap loadSavedSizeBitmap(int maxSize, byte[] data) { BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inJustDecodeBounds = true; 設定した倍率で BitmapFactory.decodeByteArray(data, 0, data.length, opt); int srcSize = Math.max(opt.outWidth,opt.outHeight); ロードする opt.inSampleSize = maxSize < srcSize ? (srcSize / maxSize) : 1; option.inJustDecodeBounds = false; return BitmapFactory.decodeByteArray( data, 0,data.length, opt)); }
  • 17. 撮影するメソッド public final void takePicture( ShutterCallback shutter, PictureCallback raw, PictureCallback postview, PictureCallback jpeg ) 4つのコールバックを設定. Android1.xでは引数は3つで, postviewをnullにした場合と同じ
  • 18. takePictureから どのコールバックが 呼ばれるかは 端末依存です
  • 19. 端末依存なコールバック public final void takePicture( ShutterCallback shutter, PictureCallback raw, PictureCallback postview, PictureCallback jpeg ) 私のx06htではrawは呼ばれたがshutterとpostviewが呼ばれなかった
  • 21. takePictureの流れ takePicture( shutter, raw, postview, jpeg ); shutter raw jpeg
  • 22. jpeg saved jpeg SDK 2.2 emu(1.6) 320x240 raw shutter takePicture() x06ht(2.2.1) 1024x768 ht03a (2.2.1) 1024x768 0 500 1000 1500 2000 2500
  • 23. takePictureの流れ takePicture( shutter, raw, postview, jpeg ); shutter まだBitmapが 作られていない! raw ここで 約2秒 Bitmapが 作られる jpeg
  • 25. +α ● setPictureSize()とsetPreviewSize()を適切に 設定する. ● getSupported{Picture|Preview}Sizes()で取得した リストからそれぞれ設定. ● 端末によっては特定の組み合わせで落ちる(多分). ● ● IntentでBitmapオブジェクトを投げない ● 大きなデータをIntentで投げると落ちます ● とりあえずSDとかに保存、ファイルへのパスのみを Intentに乗せて、受ける側でファイルから読み出す
  • 26. まとめ ● メモリやGCを意識して書く ● カメラアプリは端末による差が出やすい ● ● デバッグに協力してくれる人を増やす ● →Androidを布教しt(ry
  • 32. Androidカメラアプリ実装のコツ おしまい Twitter: @tac0x2a Mail: [email protected] 野良: http://goo.gl/k2wk AndroidMarket: