2012年6月19日火曜日

[Android] 多様な機種に対応することの難しさ

前回の記事でColor Simperアプリをリリースしたと書いたのですが、公開後に特定の機種での不具合が発覚し、再度リリースすることになりました。

今回はたまたま知り合いにインストールして試してもらった際にわかったのですぐに修正することができたのですが、危うく放置してしまうところでした…

実際Google Play上でいろんなアプリのレビューを見ていると自分の機種では動かなかったという内容の書き込みをたまに見かけます。

Androidの機種数の多さについてこんな記事がありました。

WIRED.jp
機種数3,997:「断片化」を続けるAndroid

以前から言われ続けていることではありますが、Androidはオープンなプラットフォームなので各メーカーがユーザーのニーズに応じて多彩な機種を開発できるというメリットがある一方、機種ごとの差が開きすぎるとアプリ開発者の動作検証の負担が増大し、ユーザーの端末上での不具合発生率も高くなるというデメリットがあります。

特に個人で開発を行う場合はテストできる端末が限られてしまうため機種依存の不具合の発見は難しい問題となるのですが、そういう背景もあってかテストに関する議論が盛り上がっているようですね。

Androidテスト祭り

Androidで開発をしていく以上この問題は避けて通れないので、僕としてもまだこれといった方法は浮かんでいないのですが試行錯誤しながら対策を考えていこうと思います。

2012年6月13日水曜日

[Android] Color SimplerアプリをGoogle Playへリリースしました

先日、Color Simplerという画像処理アプリをGoogle Playに登録しました。

リンクはこちらになります。
https://play.google.com/store/apps/details?id=net.starrow.colorsimpler

このアプリは画像から特定の色だけ残して他をグレーアウトするという、いわゆるパートカラーを実現するためのもので、「プレミアムモルツ画像が簡単につくれる」をコンセプトに開発しました。

できる限り手順を簡単にしたつもりなので、気軽に使ってみてください。

開発中なかなか時間が取れなかったりメモリの問題ではまったりして思いの外時間がかかってしまい、ブログの更新が滞ってしまったので、はまったポイントなどを今後書いていこうと思っています。


ところで、今回アプリを登録するためにGoogle Playへ開発者登録をしたのですが、その際にちょっとしたトラブルがありました。

はじめ「Google Play への登録はまだ処理中です。」の画面が消えず、結局2日後くらいにキャンセルされてしまったのです。

このままではアプリを公開できないので、クレジットカード情報を再度記入して登録したところ2回目は1日くらいで受理されました。

詳しいことはわからないのですが、1回目はカード情報を間違えていたのかもしれません。
何はともあれ、無事アプリをリリースすることができてよかったです。

これからアップデートや別のアプリの開発も続けていこうと思いますのでよろしくお願いします。

2012年3月24日土曜日

[Android] intentでカメラアプリを呼び出し画像を取得する

前回は端末内の画像を読み込む処理について書きましたが、今回はカメラアプリを起動して撮影した画像を取得する処理についてです。

まずはカメラを起動するところから。

        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        startActivityForResult(intent, 0);

これでカメラアプリが立ち上がり、撮影すると呼び出し元のアプリへ戻りonActivityResultが呼ばれます。

カメラアプリが複数登録されている場合はどれを起動するか選択できるのですが、ここからは標準のカメラアプリを起動した場合について扱っていきます。

カメラを起動するということは画像を取得したい場合がほとんどだと思うのですが、標準のカメラアプリではintentのExtraDataにMediaStore.EXTRA_OUTPUTを指定したかどうかによって画像の取得の仕方が変わります。


MediaStore.EXTRA_OUTPUTなしの場合

こちらは簡単で、下記のようにすれば取得できます。

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == Activity.RESULT_OK) {
            Bitmap bitmap = (Bitmap)data.getExtras().get("data");
        }
    }

ただし、このやり方で取得できるBitmapは縮小されていて、ソースを読むと50 * 1024ピクセルまでに制限されています。(android-2.3.7_r1.0時点)

これはAndroidの作法としてintentのExtraDataにはあまり大きなデータを入れるべきではないからだと思います。


MediaStore.EXTRA_OUTPUTありの場合

こちらの場合は、自分で指定したUriに画像を書き込ませることができます。
サイズはオリジナルのままです。

あらかじめ

        mSaveUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/tmp.jpg"));
        intent.putExtra(MediaStore.EXTRA_OUTPUT, mSaveUri);

のように指定してカメラを立ち上げると、mSaveUriのパスにJPEG画像として保存してくれます。
mSaveUriは自分で定義したUriのオブジェクト変数です。

ちなみに、標準のカメラアプリは撮影した際の時刻をもとにファイル名をつけてsdcardに保存している(android-2.3.7_r1.0時点)のですが、これと同じディレクトリ、同じ命名ルールで保存させたい場合は下記のように指定してやるとできます。

        final Date date = new Date(System.currentTimeMillis());
        final SimpleDateFormat dataFormat = new SimpleDateFormat("'IMG'_yyyyMMdd_HHmmss");
        final String filename = dataFormat.format(date) + ".jpg";
        mSaveUri =
                Uri.fromFile(new File(Environment.getExternalStorageDirectory().toString()
                        + "/DCIM/Camera", filename));

注意点としては、mSaveUriはそのままではMediaStoreのDBに登録されないため、何もしないと撮った画像がギャラリーなどの画像閲覧アプリに表示されません。

ここに関しては、下記のサイトが参考になると思います。

インテントでカメラを呼び出す方法の補足

今回と前回の内容を合わせると、画像を読み込む際にギャラリーとカメラのどちらからでも読み込めるようになります。

2012年3月1日木曜日

[Android] 端末内の画像を読み込みViewに合わせて回転・縮小する

現在開発中のAndroidアプリで端末内の画像をBitmapとして読み込む際に、回転や縮小といった処理を実装したのでそのことについて書きたいと思います。

今回のコードで行なっていることは以下の4つです。
  1. 端末内の画像のUriを取得
  2. Uriから画像データをBitmapとして読み込み
  3. Exifの回転情報を反映
  4. BitmapをセットするViewに合わせてサイズを縮小

まず端末内の画像を選択しそのUriを取得する部分ですが、これは以下の方法が非常に便利でした。

【Android】Galleryを使ってSDカード内の画像をリスト表示する | cozzbox

        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");
        startActivityForResult(intent, 0); 

こうするとonActivityResultのdataにUriが格納されて返ってきます。
画像を選択するGridView等を自前で実装しなくて済むので助かりますね。

続いて得られたUriを用いてBitmapを作成し、回転・縮小する部分(上記の2.~4.の処理)のコードです。

    private Bitmap loadBitmap(Uri uri, int viewWidth, int viewHeight) {
        // Uriから画像を読み込みBitmapを作成
        Bitmap originalBitmap = null;
        try {
            originalBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // MediaStoreから回転情報を取得
        final int orientation;
        Cursor cursor = MediaStore.Images.Media.query(getContentResolver(), uri, new String[] {
            MediaStore.Images.ImageColumns.ORIENTATION
        });
        if (cursor != null) {
            cursor.moveToFirst();
            orientation = cursor.getInt(0);
        } else {
            orientation = 0;
        }

        final int originalWidth = originalBitmap.getWidth();
        final int originalHeight = originalBitmap.getHeight();

        // 縮小割合を計算
        final float scale;
        if (orientation == 90 || orientation == 270) {
            scale = Math.min((float)viewWidth / originalHeight, (float)viewHeight / originalWidth);
        } else {
            scale = Math.min((float)viewWidth / originalWidth, (float)viewHeight / originalHeight);
        }

        // 変換行列の作成
        final Matrix matrix = new Matrix();
        if (orientation != 0) {
            matrix.postRotate(orientation);
        }
        if (scale < 1.0f) {
            matrix.postScale(scale, scale);
        }

        // 行列によって変換されたBitmapを返す
        return Bitmap.createBitmap(originalBitmap, 0, 0, originalWidth, originalHeight, matrix,
                true);
    }

回転情報の取得に関しては、下記の記事を参考にさせて頂きました。

画像の向き(Orientation)を取得 | ゆーすけぶろぐ
ヒビノアワ: andoridでサムネイル画像を正しい向きで表示する


ここでのポイントは、回転方向によって縮小割合の計算の仕方が変わるという点です。
  • 画像が90度, もしくは270度(横向き)の場合
    →Viewの幅と画像の高さ、Viewの高さと画像の幅の割合を計算
  • 上記以外(縦向き)の場合
    →Viewの幅と画像の幅、Viewの高さと画像の高さの割合を計算

Bitmapの貼り付け先としてImageViewを用いず、自前でCanvasに描画する場合などに使えるかなと思いますので、もしよければ参考にしてみてください。

2012年2月29日水曜日

ブログ開設しました

初めまして、当ブログ管理人のstarrowです。

現在メーカーでソフトウェアエンジニアとして勤務しています。

僕は文章を書くことがものすごく苦手で、ブログなんて絶対に無理と思っていたのですが、そんな自分を克服するため、また自分の知識を他人と共有するため一念発起してブログを開設することにしました。

ところどころ言い回しがおかしいところがあるかと思いますが大目に見てやってくださいw

内容としては、主にプログラミングやコンピュータ関係のことについて自分用の備忘録も兼ねて書いていきたいと思っています。

さしあたっては現在Androidアプリを開発中ですので、Androidに関連した記事を書いていくつもりです。

役に立つ記事を書いていくよう心掛けていきますので、よろしくお願いします!