次は、このアプリの肝となる、拡大縮小、移動したクラウディアの画像を合成する処理だ。Nugetで取得したWriteableBitmapExのBiltメソッドを使用する。
Private Async Sub gouseiButton_Click(sender As Object, e As RoutedEventArgs) Handles gouseiButton.Click Try Dim myColor = Colors.White Dim wb1 As WriteableBitmap = New WriteableBitmap(640, 480) Dim wb2 As WriteableBitmap = New WriteableBitmap(81, 249) wb1.SetSource(Await myFile.OpenReadAsync()) ' 合成領域の画像 wb2.SetSource(Await claudiaImage.OpenReadAsync()) ' 合成する画像 Dim myRect1 As Rect = New Rect() myRect1.Width = Math.Round(81 * myTrans.ScaleX) myRect1.Height = Math.Round(249 * myTrans.ScaleY) myRect1.X = myTrans.TranslateX myRect1.Y = myTrans.TranslateY Dim myRect2 As Rect = New Rect(0, 0, 81, 249) ‘ このプログラムの肝。Webカメラからの画像と、拡大縮小、移動されたクラウディアの画像を合成する。 wb1.Blit(myRect1, wb2, myRect2, myColor, WriteableBitmapExtensions.BlendMode.Alpha) wb1.Invalidate() Using myStream As Stream = wb1.PixelBuffer.AsStream Await myStream.FlushAsync() Image1.Source = myBilt1 End Using Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary Dim SubFolder = Await myFolder.CreateFolderAsync("CameraWithClaudia", CreationCollisionOption.OpenIfExists) Dim myID As Guid = Windows.Graphics.Imaging.BitmapEncoder.PngEncoderId Await WriteableBitmapSaveExtensions.SaveToFile(wb1, myFile, myID) Dim saveMessage As New MessageDialog("ピクチャライブラリ―のCameraWithClaudiaフォルダーに保存しました。") Await saveMessage.ShowAsync ichiranButton.IsEnabled = True Canvas1.Children.Clear() Image1.Source = Nothing claudiaListBox.IsEnabled = False gouseiButton.IsEnabled = False Catch Exit Sub End Try End Sub
以降、上記コードの中身を詳細に見ていこう。
まず、非同期処理で行われるためメソッドの先頭にAsyncを追加する。
色はWhiteとしておく。ほかの色にすると、画像自体にその色のフィルターが掛かってしまうためだ。
Webカメラで写した、台紙となる画像サイズが640×480で初期化された、WriteableBitmapオブジェクトのインスタンスwb1を作成する。
次に、クラウディアの画像サイズ81×249で初期化された、新しいWriteableBitmapオブジェクトのインスタンス、wb2を作成する
ストリームにアクセスしてBitmapSourceのソースイメージ(この場合、Await myFile.OPenReadAsync)を設定し、変数wb1で参照する(合成領域の画像)。同じく、変数wb2で合成する画像(クラウディア)を参照する。
四角形の幅、高さ、および原点を示す新しいインスタンスmyRect1を作成する。myRect1の[Width]にクラウディアの拡大したWidthの値を指定する。myRect1の[Height]にクラウディアの拡大したHeightの値を指定する。myRect1の[X]と[Y]プロパティにクラウディアの移動した距離の値を指定する。
クラウディアの幅と高さで初期化した、新しいRectのインスタンスmyRect2を作成する。
WriteableBitmapExのBiltメソッドで合成領域(Webカメラで撮った画像)にクラウディアの画像を合成する。書式は下記の通りだ。
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.Alphaと指定する。
Invalidateメソッドで、ビットマップ全体を再描画する。
合成した画像の、各ピクセルの書き込み先のディレクトリバッファーのアクセスを取得し、Stream型の変数myStreamで参照する。FlushAsyncメソッドで、ストリームに対応する全てのバッファーを非同期にクリアし、バッファー内のデータをデバイスに書き込む。Image1のソースプロパティにクラウディアの画像が合成されたwb1オブジェクトを指定する。これで、Image1にクラウディアが拡大縮小され、任意の位置に配置された画像が合成表示される。
ピクチャライブラリ―の「CameraWithClaudia」サブフォルダーにアクセスする。
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)
保存した旨のメッセージボックスを表示する。
[一覧]アイコンを使用可能にし、Canvas1をクリアし、Image1に表示されていた画像を消去し、クラウディアの画像の表示されているリストボックスを使用不可とし、[合成保存]ボタンの使用を不可とする。
次に、[ソリューション・エクスプローラー]内のImageIchiranpage.xamlを展開して表示される、ImageIchiranPage.xaml.vbをダブルクリックしてコードを記述する。
ここでは、コードが長くなるためコードを全部記載することは省略している。全てのコードを見る場合は、サンプルをダウンロードして「MainWindow.xaml.vb」ファイルを見ていただきたい。
Private Async Function DataShow() As Task GridView1.Items.Clear() Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary Dim mySubFolder = Await myFolder.CreateFolderAsync("CameraWithClaudia", CreationCollisionOption.OpenIfExists) myPictureFiles = Await mySubFolder.GetFilesAsync() If myPictureFiles.Count = 0 Then Dim message As New MessageDialog("画像はありません。戻ってください。") Await message.ShowAsync Exit Function End If For Each myPhotoFile In myPictureFiles Dim bmp As New BitmapImage bmp.SetSource(Await myPhotoFile.OpenSequentialReadAsync) Dim myImage As New Image myImage.Width = 640 myImage.Height = 480 myImage.Source = bmp Dim myFileName As New TextBlock myFileName.Text = myPhotoFile.Name myFileName.FontSize = 20 myFileName.HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center Dim myStackPanel As New StackPanel myStackPanel.Margin = New Thickness(3) myStackPanel.Children.Add(myImage) myStackPanel.Children.Add(myFileName) GridView1.Items.Add(myStackPanel) Next AddHandler GridView1.Loaded, AddressOf Me.GridView1_Loaded End Function
以降、上記コードの中身を詳細に見ていこう。
非同期処理が行われるため、メソッドの先頭にAsyncを追加する。
GridView1内をクリアしておく。
ピクチャライブラリ―の「CameraWithClaudia」サブフォルダーにアクセスする。GetFilesAsyncメソッドでサブフォルダー内の画像を取得し、コレクションメンバー変数「myPictureFiles」に格納しておく。画像がない場合はメッセージボックスを表示し、処理を抜ける。
メンバー変数myPictureFiles内のファイルをmyPhotoFile変数に格納しながら、以下の処理を行う。
新しいBitmapImageのインスタンスbmpオブジェクトを作成する。SetSourceメソッドに、「Await myPhotoFile.OpenSequentialReadAsync」と指定して、順次読み取りアクセス用のストリームを開く。
新しいImageのインスタンスmyImageオブジェクトを作成する。[Width]に「640」、[Height]に「480」を指定し、[Source]プロパティにbmpオブジェクトを指定する。
新しいTextBlockのインスタンスmyFileNameオブジェクトを作成する。[Text]プロパティにmyPhotoFile.Nameを指定し、拡張子を含むファイル名を指定する。文字サイズには「20」を、文字位置は「中央揃え」とする。
StackPanelの新しいインスタンスmyStackPanelオブジェクトを作成する。[Margin]プロパティに「3」を指定して余白を設ける。AddメソッドでmyStackPanelオブジェクトにmyImageオブジェクトとmyFileNameオブジェクトを追加する。GridViewに画像と、ファイル名の追加されたmyStackPanelオブジェクトを追加する。これで、GridView1に画像の一覧が表示される。
今回は、ここまでだ。また次回の記事でお会いしよう。次回は複数画像の中から、選択した画像の拡大・縮小・回転させる方法を紹介する。
本コンテストでは、2013年9月1日〜12月1日に新たにWindowsストアに新規公開されたアプリを募集します。入賞したアプリの製作者には、総額130万円の賞金が授与されますので、ふるってご応募ください。
PROJECT KySS 薬師寺 国安(やくしじ くにやす)
1950年生まれ。フリーVBプログラマ。高級婦人服メーカーの事務職に在職中、趣味でVBやActiveXに取り組み、記事を執筆。2003年よりフリー。.NETやRIAに関する執筆多数。Windowsストアアプリも多数公開中(約270本)。
Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。
Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。
Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。
PROJECT KySSは、1997年に薬師寺聖と結成したコラボレーション・ユニット
Copyright © ITmedia, Inc. All Rights Reserved.