撮影した写真と手持ちの画像を合成して保存するサンプルアプリ
[合成]ボタンをクリックした時の処理
画像を合成するBiltメソッドのColorに指定する色をWhiteにしています。
Image1(元画像)のWidthとHeightで初期化された、新しいWriteableBitmapのインスタンスwb1オブジェクトを作成します。
Image2(テクスチャ)のWidthとHeightで初期化された、新しいWriteableBitmapのインスタンスw2オブジェクトを作成します。
イメージデータやファイルからデータを読み取る、FromStreamメソッドで「元画像」のデータを読み取り、myBilt1変数で参照しておきます。
同じく、「テクスチャ」の画像データを読み取りmyBilt2変数で参照しておきます。
表示領域を指定するRect構造体の新しいインスタンス、myRectオブジェクトを作成します。
Biltメソッドで2枚の画像を合成します。Biltの書式は下記の通りです。myBilt1をmyBilt2で、myRectの領域に、色をWhiteに指定して、BlendModeをMultiplyで合成します。Multiplyはデスティネーションカラーとソースカラーを乗算するモードです。ColorをRedに指定すると、全体が、赤味がかって表示されます。
WriteableBitmap.Bilt(destRect As Rect,source As WriteableBitmap,sourceRect As Rect,color As Color,BlendMode As WriteableBitmapExtension.BlendMode)
Image3にmyBilt1オブジェクトを指定します。2枚の画像が合成されて表示されます。
Invalidateメソッドで、ビットマップ全体の再描画を行います。[保存]ボタンの使用を可能にします。
非同期処理で行われるため、メソッドの先頭にAsyncを追加します。
Private Async Sub makeButton_Click(sender As Object, e As RoutedEventArgs) Handles makeButton.Click Dim myColor = Colors.White wb1 = New WriteableBitmap(CInt(Image1.Width), CInt(Image1.Height)) Dim wb2 As WriteableBitmap = New WriteableBitmap(CInt(Image2.Width), CInt(Image2.Height)) myBilt1 = Await wb1.FromStream(Await myFile.OpenReadAsync) Dim myBilt2 = Await wb2.FromStream(Await myFile2.OpenReadAsync) Dim myRect As New Rect(0, 0, Image1.Width, Image1.Height) myBilt1.Blit(myRect, myBilt2, myRect, myColor, WriteableBitmapExtensions.BlendMode.Multiply) Image3.Source = myBilt1 myBilt1.Invalidate() saveButton.IsEnabled = True End Sub
[保存]ボタンがクリックされた時の処理
合成された画像(myBilt1)のストリームを取得し、FlushAsyncメソッドで、ストリームに対応する全てのバッファを非同期にクリアし、バッファ内のデータを基となるデバイスに書き込みます。
合成された画像(myBilt1)のストリームの長さで初期化された、バイト配列のオブジェクトmyPixelを作成します。ReadAsyncメソッドで、現在のストリームからバイトシーケンスを非同期的に読み取り、読み取ったバイト数だけストリームの位置を進めます。
インデックスとなる変数offSetを宣言します。合成された画像(myBilt1)の高さと幅に対して、反復処理を行います。offSet変数には、4ビットを乗算したバイト型の配列変数myPixelの、インデックスになる値を格納します。
バイト型のBRGA(青、赤、緑、アルファ)変数に、ピクセルのバイト数を転送し、offSetに対応するmyPixelバイト変数にRGBAの値を指定します。
ピクチャライブラリのサブフォルダーTextureにアクセスします。CreateFileAsyncメソッドで、「年月日時間分秒.png」ファイルを作成します。CreateAsyncメソッドは、フォルダーまたはファイルグループに新規ファイルを作成するメソッドです。
OpenAsyncメソッドで読み取りと書き込み可能な状態で、作成したPNG画像を開きます。OpenAsyncメソッドは、ファイルのランダムアクセスストリームを開くメソッドです。
イメージデータの作成、編集、保存に使用されるイメージエンコーダーを含む、BitmapEncoderクラス用の変数myEncoderを宣言します。
CreateAsyncメソッドで、指定済みコーデックのために新しいBitmapEncoderを非同期的に作成し、ストリーム上でこれを初期化します。
CreateAsyncメソッドには、「指定したエンコーダーのCLSID」と「ストリームのイメージファイルが書き込まれる場所」を指定します。ここでは、「指定したエンコーダーのCLSID」には、BitmapEncoder.PngEncoderIdを、「ストリームのイメージファイルが書き込まれる場所」にはmyFileStreamを指定しています。
BitmapEncoderクラスのSetPixelDataメソッドで、引数で指定されたパラメーターを使用して、フレームビットマップピクセルデータを指定します。SetPixelDataの書式は下記の通りです。
BitmapEncoder.SetPixelData(ピクセルデータのピクセル形式,ピクセルデータのアルファモード,ピクセルの幅,ピクセルの高さ, 水平方向の解像度のドット/インチ、ピクセル データ(通常96), 垂直方向の解像度のドット/インチ、ピクセル データ(通常96),ピクセルデータ)
BitmapEncoderのFlushAsyncメソッドで、非同期的に現在のフレームデータをコミットし、イメージファイルのデータ全てをフラッシュします。合成した画像が保存されます。
保存した旨のメッセージを表示します。
非同期処理で行われるため、メソッドの先頭にAsyncを追加します。
Private Async Sub saveButton_Click(sender As Object, e As RoutedEventArgs) Handles saveButton.Click Using myStream As Stream = myBilt1.PixelBuffer.AsStream Await myStream.FlushAsync() Dim myPixel As Byte() = New Byte(CInt(myStream.Length - 1)) {} Await myStream.ReadAsync(myPixel, 0, myPixel.Length - 1) Dim offSet As Integer For row As Integer = 0 To CInt(CUInt(myBilt1.PixelHeight) - 1) For col As Integer = 0 To CInt(CUInt(myBilt1.PixelWidth) - 1) offSet = CInt((row * CUInt(myBilt1.PixelWidth) * 4) + (col * 4)) Dim B As Byte = myPixel(offSet) Dim G As Byte = myPixel(offSet + 1) Dim R As Byte = myPixel(offSet + 2) Dim A As Byte = myPixel(offSet + 3) myPixel(offSet) = R myPixel(offSet + 1) = G myPixel(offSet + 2) = B myPixel(offSet + 3) = A Next Next Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary Dim SubFolder = Await myFolder.CreateFolderAsync("Texture", CreationCollisionOption.OpenIfExists) Dim mySaveFile As StorageFile = Await SubFolder.CreateFileAsync(DateTime.Now.ToString("yyyyMMddHHmmss") & ".png") Using myFileStream As IRandomAccessStream = Await mySaveFile.OpenAsync(FileAccessMode.ReadWrite) Dim myEncoder As BitmapEncoder = Await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, myFileStream) myEncoder.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Premultiplied, CUInt(myBilt1.PixelWidth), CUInt(myBilt1.PixelHeight), 96, 96, myPixel) Await myEncoder.FlushAsync 'Await myFileStream.GetOutputStreamAt(0).FlushAsync() End Using End Using Dim message As New MessageDialog("保存しました。") Await message.ShowAsync End Sub End Class
今回はここまでです。ありがとうございました。
2枚の画像を合成して保存するサンプルアプリ