次に、[ソリューション・エクスプローラー内]の「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.