Androidアプリ開発 画像選択 外部アプリで選択した画像をcropする

2017年01月22日(編集2017年01月22日)
このエントリーをはてなブックマークに追加

Androidアプリ開発では、外部アプリと連携して画像を取得できます。また、取得した画像は、cropして保存やサーバーにアップロードしたい場合があります。
この記事は、外部アプリと連携して取得した画像をcropする方法を記載した記事です。

環境はAndroid 7.1 (API level 25) です。

環境

  • OS X El Capitan
  • android sdk 25
  • Oracle jdk version 1.8.0_72
  • Android Studio 2.2.3

難易度

中級者向け

サンプルコード

Android-Media-Demo

Crop

Cropとは、画像の必要な部分だけを切り抜くことです。Androidアプリでは、Intentの機能を使って、crop機能を呼び出すことができます。

画像crop

実装

外部アプリから取得した画像でcropアプリを立ち上げる処理を実装します。
外部アプリから画像を取得する方法がわからない場合は、この記事を参照してください。

{project_folder}/ImageSelectionCropDemo.java

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case (ImageSelectionCropDemo.REQUEST_CODE_CHOOSER):
                if (resultCode != RESULT_OK) {
                    Toast.makeText(this, getString(R.string.image_unselected_message), Toast.LENGTH_LONG).show();
                    return;
                }
                startCrop(data.getData());
                break;
            default:
                break;
        }
    }

    /**
     * start Crop
     *
     * @param uri image uri
     */
    private void startCrop(Uri uri) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("aspectX", 16);
        intent.putExtra("aspectY", 9);
        intent.putExtra("scaleUpIfNeeded", true);
        intent.putExtra("scale", "true");
        intent.putExtra("return-data", false);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.name());
        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getExternalStorageTempStoreFilePath()));
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        startActivityForResult(intent, ImageSelectionCropDemo.REQUEST_CODE_CROP);
    }
          

■ 実装の解説

1. onActivityResult

onActivityResultメソッドはstartActivityForResultメソッドの結果を受け取ります。
このメソッドで外部アプリ立ち上げ時に設定したリクエストコード(ImageSelectionCropDemo.REQUEST_CODE_CHOOSER)を受け取った時、クラップを起動します。

            case (ImageSelectionCropDemo.REQUEST_CODE_CHOOSER):
                if (resultCode != RESULT_OK) {
                    Toast.makeText(this, getString(R.string.image_unselected_message), Toast.LENGTH_LONG).show();
                    return;
                }
                startCrop(data.getData());
                break;
        

2. startCrop

クラップアプリを起動します。Intentにcom.android.camera.action.CROPを設定します。

Intent intent = new Intent("com.android.camera.action.CROP");
        

起動するcropアプリのアスペクト比は任意に設定することができます。アスペクト比は縦横比のことです。例えば映像なら、ワイド(16:9)とスタンダード(4:3)の2つが基本になります。

まず、アスペクト比を16:9に設定します。

intent.putExtra("aspectX", 16);
intent.putExtra("aspectY", 9);
        
アスペクト比を16:9に設定

次に、アスペクト比の設定をコメントアウトします。

//intent.putExtra("aspectX", 16);
//intent.putExtra("aspectY", 9);
        
アスペクト比の設定なし

crop画像のアスペクト比が手動で変更できるようになりました。このように、アスペクト比は、アプリに応じた設定が可能です。

また、crop画像の出力画像タイプと画像出力フォルダの設定も可能です。

intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.name());
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getExternalStorageTempStoreFilePath()));
        

出力画像タイプの設定とcrop画像出力フォルダの設定は任意です。画像出力フォルダを指定しない場合は、選択した画像のあるフォルダと同じフォルダにcropファイルが保存されます。
なので、cropした画像をサーバーアップロード後に削除する等の場合は、画像出力フォルダを指定するべきです。

また、Android6.0以降の場合、cropした画像の保存をするためにWRITE_EXTERNAL_STORAGEの権限処理実装が必要です。
権限処理の実装がわからない場合は、この記事を参考にしてください。

crop画像取得の実装

上記のcropした画像を取得する処理を記載します。

{project_folder}/ImageSelectionCropDemo.java

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case (ImageSelectionCropDemo.REQUEST_CODE_CHOOSER):
                if (resultCode != RESULT_OK) {
                    Toast.makeText(this, getString(R.string.image_unselected_message), Toast.LENGTH_LONG).show();
                    return;
                }
                startCrop(data.getData());
                break;
           +case (REQUEST_CODE_CROP):
                if (resultCode != RESULT_OK) {
                    Toast.makeText(this, getString(R.string.crop_image_failure_message), Toast.LENGTH_LONG).show();
                    return;
                }
                selectedImage.setImageURI(data.getData());
                deleteExternalStoragePublicPicture();
                break;
            default:
                break;
        }
    }
          

■ 実装の解説

1. onActivityResult

onActivityResultメソッドはstartActivityForResultの結果を受け取ります。
cropアプリ立ち上げ時に設定したリクエストコード(ImageSelectionCropDemo.REQUEST_CODE_CROP)を受け取ります。

case (REQUEST_CODE_CROP):
    break;
        

cropされた画像はintentを使ってuriで取得します。

selectedImage.setImageURI(data.getData());
        

画像はUriからbitmapに変換して画面に表示するべきですが、ここでは省略します。

最後に、受け取ったcrop画像が不要になった場合は、ファイルを削除します。

deleteExternalStoragePublicPicture();
        

ビルド

上記のコードの動作を確認してみましょう。

sample app

cropした画像が表示されました。

結論

Androidはデフォルトでcrop処理が実装可能になっています。
しかし、デフォルトのcom.android.camera.action.CROPはうまく動作しない端末があるので、アプリの容量に制限がないのであればライブラリを組み込むことを考えると良いでしょう。

関連記事

タグ検索で調べてみよう

Android7.1