画像を円形にトリミングして表示・保存するプログラムを作る
円形上でドラッグした時の処理
円形の位置をドラッグした移動量分だけ動かします。e.Delta.Translation.X、e.Delta.Translation.Yでx-y画面座標の変化を取得しています。
e.Handled=Trueと指定して、Gridにイベントが伝わらないようにします。
Private Sub Ellipse1_ManipulationDelta(sender As Object, e As ManipulationDeltaRoutedEventArgs) Handles Ellipse1.ManipulationDelta Ellipse1.Margin = New Thickness(Ellipse1.Margin.Left + e.Delta.Translation.X, Ellipse1.Margin.Top + e.Delta.Translation.Y, 0, 0) e.Handled = True End Sub
円形をタッチした時の処理
e.Handled=Trueと指定して、Gridにイベントが伝わらないようにします。
Private Sub Ellipse1_ManipulationStarted(sender As Object, e As ManipulationStartedRoutedEventArgs) Handles Ellipse1.ManipulationStarted e.Handled = True End Sub
[切り出す]ボタンがクリックされた時の処理
Ellipse1(円形)のWidthとHeightで初期化された、新しいWriteableBitmapのインスタンスmyWriteableBitmapオブジェクトを作成します。
イメージデータやファイルからデータを読み取る、FromStreamメソッドで、FileOpenPickerで指定したファイルのデータを読み取り、myEllipseメンバ変数で参照しておきます。
円形の周囲の色をBlackに指定します。
矩形の上に円形の型を重ねますので、重ねる型の色をTransparentに指定して、背景の画像が見えるようにします。
Ellipse1のxとy座標とEllipse1の幅と高さで切り抜かれた画像を、myCropで参照します。同様にmyCrop2でも参照しておきます。
切り抜かれた画像を表示するresultEllipseの幅をEllipse1の幅と同じにします。同様に高さも同じにします。
ImageBrushのImageSourceプロパティにmyCropオブジェクトを指定します。円形で切り抜かれた画像が表示されます。
切り抜かれた画像にDrawEllipseメソッドで、x、y、width、height の各パラメーターで示された外接する四角形によって定義される楕円を、Blackで描画します。
次に、FillEllipseCenteredメソッドで円を黒で塗りつぶします。次に、FillEllipseメソッドで、楕円の内部をTransparent(透明色)で塗りつぶします。これで、矩形の中に選択した範囲の円が表示され、その周囲は黒で塗りつぶされます。円の中は透明色で塗りつぶされますので、選択した範囲の画像が表示されます。
[保存]ボタンの使用を可能にします。円形で切り抜かれた画像であるmyCropとmyCrop2オブジェクトを再描画します。
非同期処理で行われるため、メソッドの先頭にAsyncを追加します。Asyncが追加されていると、その処理が非同期で行われることを意味します。
Private Async Sub Button1_Click(sender As Object, e As RoutedEventArgs) Handles Button1.Click Dim myWriteableBitmap = New WriteableBitmap(CUInt(Ellipse1.Width), CUInt(Ellipse1.Height)) myEllipse = Await myWriteableBitmap.FromStream(Await myFile.OpenReadAsync) myColor = Colors.Black Dim myColor2 = Colors.Transparent myCrop = myEllipse.Crop(CUInt(Ellipse1.Margin.Left), CUInt(Ellipse1.Margin.Top), CUInt(Ellipse1.Width), CUInt(Ellipse1.Height)) myCrop2 = myEllipse.Crop(CUInt(Ellipse1.Margin.Left), CUInt(Ellipse1.Margin.Top), CUInt(Ellipse1.Width), CUInt(Ellipse1.Height)) resultEllipse.Width = Ellipse1.Width resultEllipse.Height = Ellipse1.Height resultImage.ImageSource = myCrop myCrop2.DrawEllipse(0, 0, CUInt(Ellipse1.Width), CUInt(Ellipse1.Height), myColor) myCrop2.FillEllipseCentered(CUInt(Ellipse1.Margin.Left), CUInt(Ellipse1.Margin.Top), CUInt(Ellipse1.Width * 2), CUInt(Ellipse1.Height * 2), myColor) myCrop2.FillEllipse(0, 0, CUInt(myCrop.PixelWidth), CUInt(myCrop.PixelHeight), myColor2) saveButton.IsEnabled = True myCrop.Invalidate() myCrop2.Invalidate() End Sub
[ファイル選択]ボタンがクリックされた時の処理
[切り出す]ボタンを使用不可にして。画像を選択するSelectImageプロシージャ—を実行します。
Private Sub backButton_Click(sender As Object, e As RoutedEventArgs) Handles backButton.Click ImageSelect() Button1.IsEnabled = True End Sub
[保存]ボタンがクリックされた時の処理
WriteableBitmap型のmyCrop3オブジェクトで、円形で指定された範囲の画像を取得します。
Rect型の新しいインスタンスmyRectオブジェクトで描画領域を設定します。Rect構造体は四角形の幅、高さ、および原点を示します。
BiltメソッドでmyCrop3にmyCrop2の画像を合成します。Biltの書式は下記の通りです。myCrop3をmyCrop2で、myRectの領域に、色をBlackに指定して、BlendModeをAlphaで合成します。アルファブレンディングは、ソースと宛先を結合するアルファチャネルを使用しています。ColorをRedに指定すると、周囲の色が赤で書き出されます。
WriteableBitmap.Bilt(destRect As Rect,source As WriteableBitmap,sourceRect As Rect,color As Color,BlendMode As WriteableBitmapExtension.BlendMode)
切り出された画像(myCrop3)のストリームを取得し、FlushAsyncメソッドで、ストリームに対応する全てのバッファを非同期にクリアし、バッファ内のデータを基となるデバイスに書き込みます。
切り出された画像のストリームの長さで初期化された、バイト配列のオブジェクトmyPixelを作成します。ReadAsyncメソッドで、現在のストリームからバイトシーケンスを非同期的に読み取り、読み取ったバイト数だけストリームの位置を進めます。
インデックスとなる変数offSetを宣言します。切り出された画像の高さ(PixelHeight)と幅(PixelWidth)に対して、反復処理を行います。offSet変数には、4ビットを乗算したバイト型の配列変数myPixelの、インデックスになる値を格納します。
バイト型のBRGA(青、赤、緑、アルファ)変数に、ピクセルのバイト数を転送し、offSetに対応するmyPixelバイト変数にRGBAの値を指定します。この画像処理を行わないと、保存する画像が実際の画像の色と異なって保存されますので、注意してください。
ピクチャライブラリのサブフォルダCutImageにアクセスします。CreateFileAsyncメソッドで、「年月日時間分秒.png」ファイルを作成します。CreateFileAsyncメソッドは、フォルダまたはファイルグループに新規ファイルを作成するメソッドです。
OpenAsyncメソッドで読み取りと書き込み可能な状態で、作成したPNG画像を開きます。OpenAsyncメソッドは、ファイルのランダムアクセスストリームを開くメソッドです。
イメージデータの作成、編集、保存に使用されるイメージエンコーダーを含む、BitmapEncoderクラス用の変数myEncoderを宣言します。
CreateAsyncメソッドで、指定済みコーデックのために新しいBitmapEncoderを非同期的に作成し、ストリーム上でこれを初期化します。CreateAsyncメソッドには、「指定したエンコーダーのCLSID」と「ストリームのイメージファイルが書き込まれる場所」を指定します。ここでは、「指定したエンコーダーのCLSID」には、BitmapEncoder.PngEncoderIdを、「ストリームのイメージファイルが書き込まれる場所」にはmyFileStreamを指定しています。
BitmapEncoderクラスのSetPixelDataメソッドで、引数で指定されたパラメーターを使用して、フレームビットマップピクセルデータを指定します。SetPixelDataの書式は下記の通りです。
BitmapEncoder.SetPixelData(ピクセルデータのピクセル形式,ピクセルデータのアルファモード,ピクセルの幅,ピクセルの高さ, 水平方向の解像度のドット/インチ、ピクセルデータ(通常96), 垂直方向の解像度のドット/インチ、ピクセルデータ(通常96),ピクセルデータ)
BitmapEncoderのFlushAsyncメソッドで、非同期的に現在のフレームデータをコミットし、イメージファイルのデータ全てをフラッシュします。切り出された画像が保存されます。
保存した旨のメッセージを表示します。
非同期処理で行われるため、メソッドの先頭にAsyncを追加します。Asyncが追加されていると、その処理が非同期で行われることを意味します。
Private Async Sub saveButton_Click(sender As Object, e As RoutedEventArgs) Handles saveButton.Click Dim myCrop3 = myEllipse.Crop(CUInt(Ellipse1.Margin.Left), CUInt(Ellipse1.Margin.Top), CUInt(Ellipse1.Width), CUInt(Ellipse1.Height)) Dim myRect As New Rect(0, 0, myCrop.PixelWidth, myCrop.PixelHeight) myCrop3.Blit(myRect, myCrop2, myRect, myColor, WriteableBitmapExtensions.BlendMode. Alpha) myCrop3.Invalidate() Using myStream As Stream = myCrop3.PixelBuffer.AsStream Await myStream.FlushAsync() Dim myPixel As Byte() = New Byte(myStream.Length - 1) {} Await myStream.ReadAsync(myPixel, 0, myPixel.Length - 1) Dim offSet As Integer For row As Integer = 0 To CUInt(myCrop3.PixelHeight) - 1 For col As Integer = 0 To CUInt(myCrop3.PixelWidth) - 1 offSet = (row * CUInt(myCrop3.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("CutImage", 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(myCrop3.PixelWidth), CUInt(myCrop3.PixelHeight), 96, 96, myPixel) Await myEncoder.FlushAsync 'Await myFileStream.GetOutputStreamAt(0).FlushAsync() End Using Dim myMessageAs New MessageDialog("保存しました。") Await myMessage.ShowAsync End Using End Sub End Class
今回はここまでです。ありがとうございました。
画像を円形にトリミングして表示・保存するプログラム
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- 画像の任意の部分をトリミングして保存するプログラムを作る
- 撮影した写真と手持ちの画像を合成して保存するサンプルアプリ
- 顔認識APIを使って写真に黒縁メガネをかける
- お気に入りの写真に登場する、仲良しクラウディアちゃん
- お花とクラウディアさんを合成して表示するプログラムを作る
- 時刻とともに、その日の出来事をキャラクターが音声で教えてくれるアプリを作る
- 撮影した写真の管理ができるマイフォトアプリを作る
- Kinectで得た人体情報を転送して、Windows Phoneの画面上に関節の位置を表示してみる
- 読み込んだ画像に落書きをし、PictureHUBに保存する
- ピクチャライブラリ内の画像を指定して表示する+1つのサンプル