PCで撮影した写真を並べて最適な1枚を選べるプログラムをつくる

Webカメラが装備されてなくてエラーが発生した時の処理
警告メッセージを表示し、「Attach Camera」の使用を不可として、処理を抜けます。非同期処理で行われるためメソッドの先頭にAsyncを追加します。
Private Async Sub ErrorShow()
Dim message As New MessageDialog("カメラが装備されておりません。")
Await message.ShowAsync
shutterButton.IsEnabled = False
Exit Sub
End Sub
Webカメラのデバイスの種類が選択された時の処理
デバイスの表示されている選択ボックスから選択したインデックス番号を、メンバ変数CameraNoに格納します。
AppBar1のバーを表示状態にします。
MediaCaptureの新しいインスタンスmyMediaCaptureオブジェクトを作成します。
InitializeAsyncメソッドで、以下の内容でMediaCaptureオブジェクトを初期化します。
新しいMediaCaptureInitializationSettingsクラスのインスタンスを作成します。MediaCaptureInitializationSettingsクラスは、MediaCaptureオブジェクトの初期化設定をするクラスです。VideoDevideIdプロパティにComboBox1より選択されたインデックスに対応する、コレクション変数myCameraのデバイスIDを指定します。
CaptureElement1のSourceプロパティにデバイスIDで初期化されたmyMediaCaptureを指定します。StartPreviewAsyncメソッドでプレビューを開始します。これで、Webカメラの画像が表示されます。マウスの右クリックで表示される、「Attach Camera」アイコンの使用を可能にします。非同期処理で行われるため、メソッドの先頭にAsyncを追加します。
Private Async Sub cameraComboBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles cameraComboBox.SelectionChanged
Try
cameraNo = cameraComboBox.SelectedIndex
AppBar1.Visibility = Xaml.Visibility.Visible
myMediaCapture = New MediaCapture
Await myMediaCapture.InitializeAsync(New MediaCaptureInitializationSettings With {.VideoDeviceId = myCamera(cameraComboBox.SelectedIndex).Id})
CaptureElement1.Source = myMediaCapture
Await myMediaCapture.StartPreviewAsync
shutterButton.IsEnabled = True
Catch
Exit Sub
End Try
End Sub
「Attach Camera」アイコンがタップされた時の処理
MediaElement1を再生します。つまりシャッター音が鳴ります。
ピクチャライブラリにアクセスし、CreateFolderAsyncメソッドで、ピクチャフォルダ内にPhotoAlbumというサブフォルダを作成します。その際、CreationCollisionOption.OpenIfExistsと指定しておくと、同名フォルダやファイルがある場合は、そのフォルダやファイル名を返し、無い場合は新規に作成してくれます。
CreateFileAsyncメソッドで現在の年月日時間分秒.pngファイルを作成します。メンバ変数saveImageFileNameに、このpngファイル名を格納しておきます。
イメージストリームの書式を表す新しい、ImageEncodingPropertiesクラスのインスタンスmyImageEncodingPropertyオブジェクトを作成します。書式のサブタイプを表すSubtypeプロパティにpngを指定し、Widthに640、Heightに480と指定します。
CapturePhotoToStorageFileAsyncメソッドで、ストレージファイルにフォトをキャプチャします。書式は以下の通りです。
CapturePhotoToStorageFileAsync(ImageEncodingProperties,IStorageFile)
GetFilesAsyncメソッドでPhotoAlbumフォルダ内のファイルを取得し、Countプロパティで個数を取得して、メンバ変数Indexに格納します。
新しいBitmapImageのインスタンスsaveBmpオブジェクトを作成します。SetSourceメソッドに、
Await myPictureFiles(Index - 1).OpenReadAsync
と指定し、OpenReadAsyncメソッドで、ランダムアクセスストリームを開き、BitmapSourceのソースイメージに設定します。
新しいImageのインスタンスmyImageオブジェクトを作成します。Widthに320、Heightに240、SourceプロパティにsaveBmpオブジェクトを指定します。
新しいStackPanelのインスタンスmyStackPanelオブジェクトを作成します。UIElementの描画位置に影響する変換情報を設定するRenderTransformプロパティに、1 つのオブジェクトに複数の異なる変換を適用することができるCompositeTransformを指定します。
ジェスチャとともにUIElementの動作および操作に使用される、ManipulationModeに、すべての相互作用モードを有効にする、ManipulationModes.Allを指定します。UIElement. ManipulationModes列挙体については、下記のURLを参考にしてください。
→ http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.input.manipulationmodes
SetValueメソッドでZIndexPropertyの値に1ずつ加算されるメンバ変数noの値を指定します。選択されたStackPanelが前面に表示されます。
新しいButtonのインスタンスdelButtonオブジェクトを作成します。Contentプロパティに「削除」、Tagプロパティに、1ずつ加算されるメンバ変数noの値を文字列にキャストして指定します。どの「削除」ボタンがクリックされたかの判定に使用します。
myStackPanelオブジェクトに、myImage、delButtonオブジェクトを追加し、PhotoAreaという名前を持つCanvas内にAddメソッドでmyStackPanelオブジェクトを追加します。写した写真が同じ位置に重なって表示されます。
AddHandlerステートメントで、操作中に入力デバイスが位置を変更した時に発生するManipulationDeltaイベントにイベントハンドラを追加します。イベントハンドラ内では以下の処理を行います。
TranslateXとTranslateYでx軸とy軸にそって並行移動する距離を設定します。
ScaleXとScaleYでオブジェクトを拡大縮小する値を設定します。
Rotaionプロパティでオブジェクトを回転します。CenterXとCenterYには実寸の画像の半分のWidthとHeightの値を指定します。これで、画像の中心を起点として回転します。
これによって、写された画像は、ピンチで拡大縮小、回転が可能になります。
SetValueメソッドでZIndexPropertyに1ずつ加算されるメンバ変数noの値を指定します。すると、選択された画像が一番手前に配置され、マウスのドラッグで写された画像が、好きな位置に配置できるようになります。
AddHandlerステートメントで、delButtonがクリックされた時のイベントハンドラを追加します。イベントハンドラ内では以下の処理を行います。
Buttonの情報を保持しているdelSenderオブジェクトをDirectCastでButtonにキャストし、そのTagプロパティの値を取得し、数値に変換して変数delIndexに格納しておきます。
コレクションメンバ変数である、myPictureFiles内のdelIndexに該当する画像ファイルを、DeleteAsyncメソッドで削除します。「削除しました。」のメッセージを表示し、画面を再描画するために、DataReadプロシージャを実行します。
非同期処理で行われるためメソッドの先頭にAsyncを追加します。
Private Async Sub shutterButton_Click(sender As Object, e As RoutedEventArgs) Handles shutterButton.Click
MediaElement1.Play()
Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
Dim mySubFolder = Await myFolder.CreateFolderAsync("PhotoAlbum", CreationCollisionOption.OpenIfExists)
Dim myFile As StorageFile = Await mySubFolder.CreateFileAsync(DateTime.Now.ToString("yyyy年MM月dd日HH時mm分ss秒") & ".png")
saveImageFileName = DateTime.Now.ToString("yyyy年MM月dd日HH時mm分ss秒") & ".png"
Dim myImageEncodingProperty As New ImageEncodingProperties
myImageEncodingProperty.Subtype = "png"
myImageEncodingProperty.Width = 640
myImageEncodingProperty.Height = 480
Await myMediaCapture.CapturePhotoToStorageFileAsync(myImageEncodingProperty, myFile)
myPictureFiles = Await mySubFolder.GetFilesAsync()
Index = myPictureFiles.Count
saveBmp = New BitmapImage
saveBmp.SetSource(Await myPictureFiles(Index - 1).OpenReadAsync)
Dim myImage As New Image
With myImage
.Width = 320
.Height = 240
.Source = saveBmp
End With
Dim myStackPanel As New StackPanel
With myStackPanel
.RenderTransform = New CompositeTransform
.ManipulationMode = ManipulationModes.All
.SetValue(Canvas.ZIndexProperty, no)
End With
Dim delButton As New Button
delButton.Content = "削除"
delButton.Tag = no.ToString
myStackPanel.Children.Add(myImage)
myStackPanel.Children.Add(delButton)
PhotoArea.Children.Add(myStackPanel)
AddHandler myStackPanel.ManipulationDelta, Sub(mySender As Object, myArgs As ManipulationDeltaRoutedEventArgs)
Dim myTrans = DirectCast(myStackPanel.RenderTransform, CompositeTransform)
myTrans.TranslateX = myTrans.TranslateX + myArgs.Delta.Translation.X
myTrans.TranslateY = myTrans.TranslateY + myArgs.Delta.Translation.Y
myTrans.ScaleX = myTrans.ScaleX * myArgs.Delta.Scale
myTrans.ScaleY = myTrans.ScaleY * myArgs.Delta.Scale
myTrans.CenterX = 320
myTrans.CenterY = 240
myTrans.Rotation = myTrans.Rotation + myArgs.Delta.Rotation
myStackPanel.SetValue(Canvas.ZIndexProperty, no)
End Sub
AddHandler delButton.Click, Async Sub(delSender As Object, delArgs As RoutedEventArgs)
Dim delIndex = CInt(DirectCast(delSender, Button).Tag)
Await myPictureFiles(delIndex).DeleteAsync
Dim message As New MessageDialog("削除しました。")
Await message.ShowAsync
DataReload()
End Sub
no = no + 1
ichiranButton.IsEnabled = True
End Sub
画像を削除した際に、画面を再描画する処理
PhotoAreaという名前のCanvas内をクリアし、メンバ変数noを0で初期化します。
ピクチャライブラリのサブフォルダPhotoAlbumにアクセスします。GetFilesAsyncメソッドで、ファイルを取得してコレクションメンバ変数myPictureFilesに格納します。
コレクション変数myPictureFiles内のファイルを変数myFileに格納しながら、以下の処理を繰り返します。
新しいBitmapImageのインスタンスsaveBmpオブジェクトを作成します。SetSourceメソッドに、
Await myFile.OpenReadAsync
と指定し、OpenReadAsyncメソッドで、ランダムアクセスストリームを開き、BitmapSourceのソースイメージに設定します。
新しいImageのインスタンスmyImageオブジェクトを作成します。Widthに320、Heightに240、SourceプロパティにsaveBmpオブジェクトを指定します。
新しいStackPanelのインスタンスmyStackPanelオブジェクトを作成します。
UIElementの描画位置に影響する変換情報を設定するRenderTransformプロパティに、1 つのオブジェクトに複数の異なる変換を適用することができるCompositeTransformを指定します。
ジェスチャとともにUIElementの動作および操作に使用される、ManipulationModeに、すべての相互作用モードを有効にする、ManipulationModes.Allを指定します。UIElement. ManipulationModes列挙体については、下記のURLを参考にしてください。
→ http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.input.manipulationmodes
新しいButtonのインスタンスdelButtonオブジェクトを作成します。Contentプロパティに「削除」、Tagプロパティにメンバ変数noの値を文字列にキャストして指定します。どの「削除」ボタンがクリックされたかの判定に使用します。
myStackPanelオブジェクトに、myImage、delButtonオブジェクトを追加し、PhotoAreaという名前を持つCanvas内にAddメソッドでmyStackPanelオブジェクトを追加します。写した写真が同じ位置に重なって表示されます。
AddHandlerステートメントで、操作中に入力デバイスが位置を変更した時に発生するManipulationDeltaイベントにイベントハンドラを追加します。イベントハンドラ内では以下の処理を行います。
TranslateXとTranslateYでx軸とy軸にそって並行移動する距離を設定します。
ScaleXとScaleYでオブジェクトを拡大縮小する値を設定します。
Rotaionプロパティでオブジェクトを回転します。CenterXとCenterYには実寸の画像の半分のWidthとHeightの値を指定します。これで、画像の中心を起点として回転します。
これによって、写された画像は、ピンチで拡大縮小、回転が可能になります。
SetValueメソッドでZIndexPropertyに1ずつ加算されるメンバ変数noの値を指定します。選択された画像が一番手前に配置されます。これで、マウスのドラッグで写された画像が、好きな位置に配置できるようになります。
AddHandlerステートメントで、delButtonがクリックされた時のイベントハンドラを追加します。イベントハンドラ内では以下の処理を行います。
Buttonの情報を保持しているdelSenderオブジェクトをDirectCastでButtonにキャストし、そのTagプロパティの値を取得し、数値に変換して変数delIndexに格納しておきます。
delIndexの値が0より小さい場合、つまり画像ファイルが存在しない場合は、「Folder」アイコンの使用を不可とします。それ以外は使用を可とします。
コレクションメンバ変数である、myPictureFiles内のdelIndexに該当する画像ファイルを、DeleteAsyncメソッドで削除します。「削除しました。」のメッセージを表示し、画面を再描画するために、DataReloadプロシージャを実行します。
非同期処理で行われるためメソッドの先頭にAsyncを追加します。
Private Async Sub DataReload()
PhotoArea.Children.Clear()
no = 0
Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
Dim mySubFolder = Await myFolder.CreateFolderAsync("PhotoAlbum", CreationCollisionOption.OpenIfExists)
myPictureFiles = Await mySubFolder.GetFilesAsync()
For Each myFile As IStorageFile In myPictureFiles
saveBmp = New BitmapImage
saveBmp.SetSource(Await myFile.OpenReadAsync)
Dim myImage As New Image
With myImage
.Width = 320
.Height = 240
.Source = saveBmp
End With
Dim myStackPanel As New StackPanel
With myStackPanel
.RenderTransform = New CompositeTransform
.ManipulationMode = ManipulationModes.All
End With
Dim delButton As New Button
delButton.Content = "削除"
delButton.Tag = no.ToString
myStackPanel.Children.Add(myImage)
myStackPanel.Children.Add(delButton)
PhotoArea.Children.Add(myStackPanel)
AddHandler myStackPanel.ManipulationDelta, Sub(mySender As Object, myArgs As ManipulationDeltaRoutedEventArgs)
Dim myTrans = DirectCast(myStackPanel.RenderTransform, CompositeTransform)
myTrans.TranslateX = myTrans.TranslateX + myArgs.Delta.Translation.X
myTrans.TranslateY = myTrans.TranslateY + myArgs.Delta.Translation.Y
myTrans.ScaleX = myTrans.ScaleX * myArgs.Delta.Scale
myTrans.ScaleY = myTrans.ScaleY * myArgs.Delta.Scale
myTrans.CenterX = 320
myTrans.CenterY = 240
myTrans.Rotation = myTrans.Rotation + myArgs.Delta.Rotation
myStackPanel.SetValue(Canvas.ZIndexProperty, no)
End Sub
AddHandler delButton.Click, Async Sub(delSender As Object, delArgs As RoutedEventArgs)
Dim delIndex = CInt(DirectCast(delSender, Button).Tag)
If delIndex < 0 Then
ichiranButton.IsEnabled = False
Else
ichiranButton.IsEnabled = True
End If
Await myPictureFiles(delIndex).DeleteAsync
Dim message As New MessageDialog("削除しました。")
Await message.ShowAsync
DataReload()
End Sub
no = no + 1
Next
End Sub
戻る(←)アイコンがタップされた時の処理
PhotoAreaという名前のCanvasを表示状態にします。
Webカメラのデバイス名を表示している、camerComboBoxを表示状態にします。
AppBar1を表示状態にします。myFrameを非表示にし、DataShowとDataReloadプロシージャを実行します。
Private Sub backButton_Click(sender As Object, e As RoutedEventArgs) Handles backButton.Click
PhotoArea.Visibility = Xaml.Visibility.Visible
cameraComboBox.Visibility = Xaml.Visibility.Visible
AppBar1.Visibility = Xaml.Visibility.Visible
AppBar1.IsEnabled = True
myFrame.Visibility = Xaml.Visibility.Collapsed
DataShow()
DataReload()
End Sub
撮影した写真から最適な1枚を選ぶサンプルプログラム


