2015年3月19日木曜日

Canvasとmatrixの組み合わせの応用


イトナブ石巻の紅白こと白出達彦です。

イトナブ開発合宿in滝沢市のまとめを紹介します。

イトナブ開発合宿について、概要を知りたい方はこちらをご覧ください。
今回は滝沢市でイトナブ石巻開発合宿in滝沢市を開催しました。

■開発テーマ
Canvasの静的な描画とmatrixメソッドの組み合わせで、
どのような応用が出来るか

■開発環境
Mac OS 10.9.2
Android Studio 1.1.0

■ソースコード
①layoutファイルにButtonとImageViewを追加
【hanten.xml】

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

        <Button
            android:id="@+id/button1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="画像を開く" />

        <ImageView
            android:id="@+id/imageView1"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </LinearLayout>

②MainActivity
【HantenActivity】
ギャラリーで取得した画像をリサイズして反転、下に行くに連れて白の
グラデーションを濃くしていきます。

public class HantenActiviy extends Activity implements OnClickListener {

    private static final int REQ_SELECT_GALLERY = 100;
    private static final int REFLECTIONGAP = 4;
    private static final int MAX_IMAGE_SIZE = 1024;

    private ImageView mImageView1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.hanten);

        mImageView1 = (ImageView) findViewById(R.id.imageView1);

        findViewById(R.id.button1).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.button1) {
            Intent intent = new Intent();
            intent.setType("image/*");
            intent.setAction(Intent.ACTION_GET_CONTENT);
            startActivityForResult(intent, REQ_SELECT_GALLERY);
        }

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQ_SELECT_GALLERY && resultCode == RESULT_OK) {
            setMirrorBitmap(data.getData());
        }
    }

    private void setMirrorBitmap(Uri imageuri) {
        // Bitmap画像を読み込む
        Bitmap bitmapOriginal = loadBitmap(imageuri);
        // 反転された画像を作成するMatrixを生成
        Matrix matrix = new Matrix();
        matrix.preScale(1, -1);
        int height = bitmapOriginal.getHeight();
        int width = bitmapOriginal.getWidth();
        // 反転された画像を書き込むBitmapを生成
        Bitmap reflectionImage = Bitmap.createBitmap(bitmapOriginal, 0, height / 2, width, height / 2, 
matrix, false);
        // オリジナルの画像に反転した画像を合成したイメージを書き込むBitmapを生成
        Bitmap bitmapWithReflection = Bitmap.createBitmap(width,
                (height + height / 2), Bitmap.Config.ARGB_8888);

        // 最終的なイメージへ書き込むCanvasを生成
        Canvas canvas = new Canvas(bitmapWithReflection);
        // オリジナルの画像を描画
        canvas.drawBitmap(bitmapOriginal, 0, 0, null);
        // オリジナルの画像を描画
        Paint deafaultPaint = new Paint();
        // 繋ぎ目を目立たなくするためにデフォルトの色を描画
        canvas.drawRect(0, height, width, height + REFLECTIONGAP, deafaultPaint);
        // 反転されたイメージを描画
        canvas.drawBitmap(reflectionImage, 0, height + REFLECTIONGAP, null);
        // 反転された部分に下にいくにつれ白くなるようグラデーションを設定
        Paint paint = new Paint();
        LinearGradient shader = new LinearGradient(0,
                bitmapOriginal.getHeight(), 0, bitmapWithReflection.getHeight()
                + REFLECTIONGAP, 0x70ffffff, 0x00ffffff, Shader.TileMode.CLAMP);
        paint.setShader(shader);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        // グラデーションを描画
        canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()
                + REFLECTIONGAP, paint);

        mImageView1.setImageBitmap(bitmapWithReflection);
    }

    private Bitmap loadBitmap(Uri imageuri) {
        InputStream input = null;
        try {

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

            input = getContentResolver().openInputStream(imageuri);
            BitmapFactory.decodeStream(input, null, options);
            int inSampleSize = calculateInSampleSize(options, MAX_IMAGE_SIZE,
                    MAX_IMAGE_SIZE);
            input.close();
            input = null;

            options.inJustDecodeBounds = false;
            options.inSampleSize = inSampleSize;

            input = getContentResolver().openInputStream(imageuri);
            Bitmap bitmap = BitmapFactory.decodeStream(input, null, options);

            return bitmap;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return null;
    }

    private int calculateInSampleSize(BitmapFactory.Options options,
                                      int reqWidth, int reqHeight) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            if (width > height) {
                inSampleSize = Math.round((float) height / (float) reqHeight);
            } else {
                inSampleSize = Math.round((float) width / (float) reqWidth);
            }
        }
        return inSampleSize;
    }

}

コードは以下のサイトから引用させていただきました。 http://www110.kir.jp/Android/ch0614.html

ギャラリーから選んだ写真が・・・・




このように変化します。

■活用事例と可能性
反転効果の他にグレースケールをかけて写真を表示する事も可能です。 可能性としてはSNSとの連携で、編集した写真を投稿するアプリ等が考えられます。


■総括 matrixメソッドは「リサイズした際の再描画」という固定的なイメージしかなかったのですが、animationと同じような動作やギャラリーとの写真で組み合わせ等、柔軟な組み合わせ方ができる事を学ぶことができました。

0 件のコメント:

コメントを投稿