次に、[ソリューション・エクスプローラー内]の「MainWindow.xaml」を展開して表示される、「MainWindow.xaml.vb」のコードを記述する。
ここではコードが長くなるため今回のテーマと肝となる「画像の合成」「データの一覧表示」部分の解説にとどめている。名前空間の読み込み、メンバー変数の宣言も省略している。全てのコードを見る場合は、サンプルをダウンロードして「MainWindow.xaml.vb」ファイルを見ていただきたい。
Protected Overrides Async Sub OnNavigatedTo(e As Navigation.NavigationEventArgs) ichiranButton.Visibility = Xaml.Visibility.Visible Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary Dim SubFolder = Await myFolder.CreateFolderAsync("BiltImage", CreationCollisionOption.OpenIfExists) Dim myPictureFile = Await SubFolder.GetFilesAsync If myPictureFile.Count > 0 Then ichiranButton.IsEnabled = True Else ichiranButton.IsEnabled = False End If MyBase.OnNavigatedTo(e) End Sub
以降、上記コードの中身を詳細に見ていこう。
まず、非同期処理で行われるためメソッドの先頭にAsyncを追加している。
ピクチャライブラリーにアクセスし、CreateFolderAsyncメソッドで「BiltImage」というフォルダーを作成する。その際、「CreationCollisionOption.OpenIfExists」を指定すると、同名フォルダーがあるときは、そのフォルダー名を返し、ない時は新規に作成する。「CreationCollisionOption Enumeration」の詳細については、下記のURLを参照してほしい。
GetFilesAsyncメソッドでは、「BiltImage」フォルダー内のファイルを取得し、変数myPictureFileで参照しておく。
Countプロパティでは、そのフォルダー内のファイルの数を取得し、ファイルが存在する場合は、「データ一覧」ボタンの使用を可能にする。それ以外は使用を不可とする。
Private Async Sub readButton1_Click(sender As Object, e As RoutedEventArgs) Handles readButton1.Click resultImage.Source = Nothing Image1.Source = Nothing Dim myFileOpenPicker As New FileOpenPicker myFileOpenPicker.ViewMode = PickerViewMode.Thumbnail myFileOpenPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary myFileOpenPicker.FileTypeFilter.Add(".png") myFileOpenPicker.FileTypeFilter.Add(".jpg") myFile = Await myFileOpenPicker.PickSingleFileAsync() If myFile Is Nothing = False Then Dim myBmp As New BitmapImage myBmp.SetSource(Await myFile.OpenReadAsync) If myBmp.PixelWidth <> 640 OrElse myBmp.PixelHeight <> 480 Then Dim message As New MessageDialog("640×480サイズの画像を指定してください") Await message.ShowAsync Exit Sub Else Image1.Source = myBmp End If readButton2.IsEnabled = True Else readButton2.IsEnabled = False End If End Sub
以降、上記コードの中身を詳細に見ていこう。
まず、非同期処理で行われるためメソッドの先頭にAsyncを追加している。
FileOpenPickerクラスの新しいインスタンスmyFileOpenPickerオブジェクトを作成する。FileOpenPickerクラスは、ユーザーが選択し、ファイルを開くことのできるUI要素を表すクラスだ。
ファイルの表示モードを指定するViewModeプロパティにサムネイル表示を指定する。サムネイル表示の他にリスト(List)表示がある。ファイルを開く最初の場所を設定するSuggestedStartLocationプロパティに、ピクチャライブラリーを指定しておく。開くファイルタイプを指定するFileTypeFilter.Addで「.png」と「.jpg」を指定しておく。
PNGファイルを指定する場合は、FileTyleFilter.Add(".png")と指定する。"*.pn"ではないので注意してほしい。
PickSingleFileAsynメソッドで、ユーザーが1つのファイルを選択できるようにファイルピッカーを表示し、変数myFileで参照する。
変数myFileがファイルを参照している場合は、新しいBitmapImageクラスのインスタンスmyBmpオブジェクトに、SetSourceメソッドで「Await myFile.OpenReadAsync」と指定する。そして、ファイルの内容を読み込むために、現在のファイルをランダムアクセスストリームで開く。
もし指定したファイルの画像サイズが640×480より大きかった場合は、メッセージを表示して処理を抜ける。それ以外の場合は、Image1のSourceプロパティにmyBmpオブジェクトを指定する。これで、ファイルピッカーで指定したファイルが表示される。
また、画像を選択する際、選択をやめてキャンセルした場合も、「合成画像」ボタンの使用は不可としておく。それ以外の場合は使用可とする。
以下の処理は、『「元画像」ボタンがタップされた時の処理(readButton1_Clickメソッド処理)』と同じであるため、そちらを参照してほしい。
Private Async Sub readButton2_Click(sender As Object, e As RoutedEventArgs) Handles readButton2.Click Image2.Source = Nothing Dim myFileOpenPicker As New FileOpenPicker myFileOpenPicker.ViewMode = PickerViewMode.Thumbnail myFileOpenPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary myFileOpenPicker.FileTypeFilter.Add(".png") myFileOpenPicker.FileTypeFilter.Add(".jpg") myFile2 = Await myFileOpenPicker.PickSingleFileAsync() If myFile2 Is Nothing = False Then Dim myBmp As New BitmapImage myBmp.SetSource(Await myFile2.OpenReadAsync) If myBmp.PixelWidth <> 640 OrElse myBmp.PixelHeight <> 480 Then Dim message As New MessageDialog("640×480サイズの画像を指定してください") Await message.ShowAsync Exit Sub Else Image2.Source = myBmp End If makeButton.IsEnabled = True Else makeButton.IsEnabled = False End If End Sub
このアプリの肝となる、2枚の画像を合成する処理だ。Nugetで取得したWriteableBitmapEのBiltメソッドを使用する。
Private Async Sub makeButton_Click(sender As Object, e As RoutedEventArgs) Handles makeButton.Click Dim myColor = Colors.White Dim wb1 As WriteableBitmap = New WriteableBitmap(CInt(Image1.Width), CInt(Image1.Height)) Dim wb2 As WriteableBitmap = New WriteableBitmap(CInt(Image2.Width), CInt(Image2.Height)) wb1.SetSource(Await myFile.OpenReadAsync) wb2.SetSource(Await myFile2.OpenReadAsync) Dim myRect As New Rect(0, 0, Image1.Width, Image1.Height) ‘ このアプリの肝。2枚の画像をBiltメソッドで合成する。 wb1.Blit(myRect, wb2, myRect, myColor, WriteableBitmapExtensions.BlendMode.Multiply) wb1.Invalidate() Using myStream As Stream = wb1.PixelBuffer.AsStream Await myStream.FlushAsync() End Using Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary Dim SubFolder = Await myFolder.CreateFolderAsync("BiltImage", CreationCollisionOption.OpenIfExists) myFile = Await SubFolder.CreateFileAsync(DateTime.Now.ToString("yyyy年MM月dd日HH時mm分ss秒") & ".png") mySaveFile = myFile FileName = DateTime.Now.ToString("yyyy年MM月dd日HH時mm分ss秒") & ".png" Dim myID As Guid = Windows.Graphics.Imaging.BitmapEncoder.PngEncoderId Await WriteableBitmapSaveExtensions.SaveToFile(wb1, myFile, myID) ichiranButton.IsEnabled = True Image1.Source = Nothing Image2.Source = Nothing resultImage.Source = wb1 makeButton.IsEnabled = False readButton2.IsEnabled = False End Sub
以降、上記コードの中身を詳細に見ていこう。まず、非同期処理で行われるためメソッドの先頭にAsyncを追加している。
次に、色をWhiteとしておく。他の色にすると画像自体にその色のフィルターが掛かってしまう。
「元画像」ボタンで取り込んだ、台紙となる画像サイズが640×480で初期化された、WriteableBitmapオブジェクトのインスタンスwb1を作成する。
続いて、「合成画像」ボタンで取り込んだ、合成する画像サイズが640×480で初期化された、新しいWriteableBitmapオブジェクトのインスタンス、wb2を作成する。
ストリームにアクセスしてBitmapSourceのソースイメージ(この場合、Await myFile.OPenReadAsync)を設定し、変数wb1で参照する(合成元の画像)。同じく、変数wb2で合成する画像を参照する。
四角形の幅、高さ、および原点を示す新しいインスタンスmyRectを作成する。myRectのWidthに「元画像」ボタンで取り込んで表示されたImage1の「Widthの値」を、HeightにはImage1の「Heightの値」を指定する。
WriteableBitmapEx のBiltメソッドで「元画像」と「合成画像」を合成する。書式は下記の通りだ。
Wb.Bilt(destRect As Rect,Source As Media.Imaging.WritableBitMap,sourceRect As Rect,color As Windows.UI.Color,BlendMode as Media.Imaging.WriteableBitmapExtensions.BlendMode)
BlendModeには、必ずWriteableBitmapExtensions.BlendMode.Multiplyと指定する。Invalidateメソッドで、ビットマップ全体を再描画する。
合成された画像の、各ピクセルの書き込み先のディレクトリバッファーのアクセスを取得し、Stream型の変数myStreamで参照する。FlushAsyncメソッドで、ストリームに対応する全てのバッファーを非同期にクリアし、バッファー内のデータをデバイスに書き込む。ピクチャライブラリーの「BiltImage」サブフォルダーにアクセスする。
CreateFileAsyncメソッドで、「BiltImage」フォルダー内に「yyyy年MM月dd日HH時mm分ss秒.png」形式のファイルを作成する。
Windows.Graphics.Imaging.BitmapEncoder.PngEncoderIdで、PNG画像のグローバル一意識別子を取得して、変数myIDに格納しておく。
WinRTXamlToolkit.ImagingのWriteableBitmapSaveExtensions.SaveToFileメソッドで、合成した画像(wb1)を「yyyy年MM月dd日HH時mm分ss秒.png」形式に書き出す。WriteableBitmapSaveExtensions.SaveToFileメソッドの書式は、下記の通りだ。
WriteableBitmapSaveExtensions.SaveToFile(writeableBitmap as Windows.UI.Xaml.Media.Imageing.WriteableBitmap,output as Windows.Storages.StorageFile,encodeId as System.GUID)
「データ一覧」アイコンを使用可能にし、Image1とImage2をクリアし、resultImageに合成された画像を表示する。「合成」ボタンと「合成画像」ボタンの使用を不可とする。
Copyright © ITmedia, Inc. All Rights Reserved.