酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

WindowsストアアプリでWriteableBitmapExを使ってクリッピング処理する

SilverlightやWindows Phoneで使用できるWriteableBitmapクラスは、機能が削られており画像処理するにはかなり不向きな状態になっています。WriteableBitmapExはその辺りを解決してくれるオープンソースのプロジェクトです。

僕が作っている「WriteableBitmapEffector」も「WriteableBitmapEx」を結構意識しています。*1

今日は、WriteableBitmapExを使ってクリッピング処理する方法をご紹介します。

事前準備(WriteableBitmapExのインストール)

NuGetで「WriteableBitmapEx」を検索して、インストールしておいてください。

事前準備(WriteableBitmapオブジェクトの生成)

Asset配下の画像ファイルからWriteableBitmapオブジェクトを生成させます。

CreateBitmapAsyncメソッドの仕組みは、以前「WindowsストアアプリでIRandomAccessStream型のストリームからWriteableBitmapオブジェクトへ変換する - 酢ろぐ!」で紹介したWriteableBitmapExtensions.FromStreamAsyncメソッドと同じものです。拡張メソッドではなくMainPage.xaml.csの中に処理を埋め込みたかったのでメソッド名を変更しています。

IRandomAccessStreamのファイルストリームからWriteableBitmapオブジェクトを生成していましょう。

下記のコードを説明します。Windows ストア アプリではWriteableBitmapオブジェクトにストリームを食べさせることができません。JPEGやPNGファイルはエンコードされて圧縮されたファイル形式です。ARGB形式のピクセルデータを得ます。

GetPixelDataAsyncメソッドでピクセルデータを取得します。

private async Task<WriteableBitmap> CreateBitmapAsync(IRandomAccessStream stream)
{
    // 非同期で新しいデコーダーを生成し、ストリームからピクセルデータをデコードする
    var decoder = await BitmapDecoder.CreateAsync(stream);
    var pixelData = await decoder.GetPixelDataAsync();
    var bytes = pixelData.DetachPixelData();

    // WriteableBitmapオブジェクトを生成し、デコード済みのピクセルデータを上書きする
    var bitmap = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
    using (var pixelStream = bitmap.PixelBuffer.AsStream())
    {
        await pixelStream.WriteAsync(bytes, 0, bytes.Length);
    }

    return bitmap;
}

WriteableBitmapExを使ってクリッピング処理をする

ここからが本題です。

画面遷移時のOnNavigatedToメソッドで、アプリケーション内に「コンテンツ」として存在している画像ファイルを、先ほど紹介したCreateBitmapAsyncメソッドを使って、WriteableBitmapオブジェクトとして読み込みます。

読み込んだ画像を左上から(50,50)の位置からサイズ(50,50)をクリッピングして、Imageコントロールに表示させています。

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    // アプリ内に含まれている画像ファイルをWriteableBitmapオブジェクトとして読み込む
    var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/eyes0176.jpg"));
    var bitmap = await CreateBitmapAsync(await file.OpenReadAsync());

    // 画像をクリッピングして、Imageコントロールに表示させる
    image.Source = bitmap.Crop(50, 50, 50, 50);
}

関連記事

WindowsランタイムAPI(Windows Runtime API, WinRT API)を使ってアプリ開発する際に逆引きとしてお使いください。

*1:今日久しぶりに使ったら、一部クラス名が被っていたのでEffectorの方を修正しなきゃいけない……