場所と写真を記録するプログラムを作って思い出のシーンを保存しよう
[シャッター]ボタンがタップされた時の処理
CountdownControlの秒数を設定するSecondプロパティに5を指定し、カウントダウンを5秒とします。
Private Sub shutterButton_Click(sender As Object, e As RoutedEventArgs) Handles shutterButton.Click CountdownControl1.Visibility = Windows.UI.Xaml.Visibility.Visible messageTextBlock.Text = String.Empty CountdownControl1.Seconds = 5 End Sub
カウントダウンが終わった時の処理。
MediaElementのPlayメソッドでシャッター音を再生します。
messageTextBlock内に保存した旨のメッセージを表示します。
CountdownControlを非表示にします。[写した場所を表示]ボタンの使用を可能にします。
画像を保存するPhotoSaveプロシージャを実行します。
Private Sub CountdownControl1_CountdownComplete(sender As Object, e As RoutedEventArgs) Handles CountdownControl1.CountdownComplete MediaElement1.Play() messageTextBlock.Text = "ピクチャライブラリのMemoryImageフォルダに保存しました。" CountdownControl1.Visibility = Windows.UI.Xaml.Visibility.Collapsed positionButton.IsEnabled = True PhotoSave() End Sub
Webカメラで撮った画像を保存する処理
ピクチャライブラリのMemoryImageというサブフォルダにアクセスします。
CreateFileAsyncで「年月日時間秒分」に「緯度」と「経度」の値を「-」で区切って追加し、”.jpg”という文字列を追加したファイルを作成し、myFile変数で参照しておきます。例えば2012年10月10日10時10分10秒-00.0000-123.3333.jpgといったファイル形式になります。
イメージストリームの書式を表すImageEncodingPropertiesクラスの新しいインスタンス、myImageEncodingPropertyオブジェクトを作成します。
フォーマットのサブタイプを設定するSubTypeプロパティに「Jpeg」と指定します。
WidthとHeightの値を指定します。
CapturePhotoToStorageFileAsyncメソッドで、出力イメージのエンコードプロパティ(Jpgで640×480)と、保存する画像ファイル名、とを指定して、ストレージファイルにフォトをキャプチャします。
メンバ変数Indexに、コレクション変数myPictureFiles内のファイルの個数をCountプロパティで取得し、格納します。
新しいBitmapImageクラスのインスタンスsaveBmpオブジェクトを作成します。
SetSourceメソッドに、Await myPictureFiles(Index - 1).OpenReadAsyncと指定して、ランダムアクセスストリームを開きます。
Image1にsaveBmpオブジェクトを指定します。これで、640×480サイズの画像が表示されます。
[写した場所を表示]ボタンの使用を可能にします。
非同期処理で行われるためメソッドの先頭にAsyncを追加します。
Private Async Sub PhotoSave() Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary Dim mySubFolder = Await myFolder.CreateFolderAsync("MemoryImage", CreationCollisionOption.OpenIfExists) Dim myFile As StorageFile = Await mySubFolder.CreateFileAsync(DateTime.Now.ToString("yyyy年MM月dd日HH時mm分ss秒") & "-" & myLatitude & "-" & myLongitude & ".jpg") Dim myImageEncodingProperty As New ImageEncodingProperties myImageEncodingProperty.Subtype = "jpeg" 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) Image1.Source = saveBmp positionButton.IsEnabled = True End Sub
シャッター音の再生が終わった時の処理
messageTextBoxにメッセージを表示し、メディアの再生の経過時間を示す現在の位置を0とします。
GridView内をクリアし、AddPhotoプロシージャを実行します。
Private Sub MediaElement1_MediaEnded(sender As Object, e As RoutedEventArgs) Handles MediaElement1.MediaEnded Dim myPos As New TimeSpan(0, 0, 0) messageTextBlock.Text = "ピクチャライブラリのMemoryImageフォルダに保存しました。" MediaElement1.Position = myPos GridView1.Items.Clear() AddPhoto() End Sub
GridViewから画像が選択された時の処理
GridViewから選択された画像のインデックスを変数myIndexに格納しておきます。
ピクチャライブラリのMemoryImageサブフォルダにアクセスします。CreationCollisionOption列挙体については下記URLを参照してください。
→ CreationCollisionOption列挙体
GetFilesAsyncメソッドでMemoryImageフォルダ内のファイルを取得し、ファイルのコレクションを表すメンバ変数myPictureFilesに格納しておきます。
新しいBitmapImageのインスタンスsaveBmpオブジェクトを作成し、SetSourceメソッドに、Await myPictureFiles(Index).OpenReadAsyncと指定して、メンバ変数Indexに該当するコレクション変数myPictureFilesに格納されている画像ファイルを読み取って開きます。
ImageのSourceプロパティにsaveBmpオブジェクトを指定します。実寸の画像が表示されます。
非同期処理で行われるためメソッドの先頭にAsyncを追加します。
Private Async Sub GridView1_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles GridView1.SelectionChanged myIndex = GridView1.SelectedIndex If myIndex < 0 Then Exit Sub Else Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary Dim mySubFolder = Await myFolder.CreateFolderAsync("MemoryImage", CreationCollisionOption.OpenIfExists) myPictureFiles = Await mySubFolder.GetFilesAsync() saveBmp = New BitmapImage saveBmp.SetSource(Await myPictureFiles(myIndex).OpenReadAsync) Image1.Source = saveBmp End If End Sub
戻る(←)アイコンがタップされた時の処理
GridViewを表示し、myFrameを非表示にします。
Private Sub backButton_Click(sender As Object, e As RoutedEventArgs) Handles backButton.Click GridView1.Visibility = Xaml.Visibility.Visible myFrame.Visibility = Xaml.Visibility.Collapsed End Sub
[写した場所を表示]ボタンをタップした時の処理
ピクチャライブラリのMemoryImageサブフォルダにアクセスします。CreateFolderAsyncメソッドで、ピクチャライブラリ内にMemoryImage というサブフォルダを作成します。CreationCollisionOption.OpenIfExistsと指定すると、同名フォルダがある場合はフォルダ名を返し、ない場合は新規に作成します。CreationCollisionOption列挙体については下記URLを参照してください。
→ CreationCollisionOption列挙体
GetFilesAsyncメソッドでMemoryImageフォルダ内のファイルを取得し、ファイルのコレクションを表すメンバ変数myImageFilesに格納しておきます。
myImageFiles内のGridViewから選択された画像のインデックスに該当するファイルを変数myImageNameに格納します。この変数を引数にNavigateメソッドでBingMapsShowPageに遷移します。
Private Async Sub positionButton_Click(sender As Object, e As RoutedEventArgs) Handles positionButton.Click myFrame.Visibility = Xaml.Visibility.Visible GridView1.Visibility = Xaml.Visibility.Collapsed Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary Dim mySubFolder = Await myFolder.CreateFolderAsync("MemoryImage", CreationCollisionOption.OpenIfExists) Dim xmlFile = Await mySubFolder.GetFilesAsync Dim myImageName = xmlFile(GridView1.SelectedIndex) myFrame.Navigate(GetType(BingMapsShowPage), myImageName) End Sub End Class
次に、ソリューションエクスプローラー内のBingMapsShowPage.xamlを展開して表示される、BingMapsShowPage.xaml.vbをダブルクリックしてリスト5のコードを記述します。
ロジックコードを記述する
リスト5 (BingMapsShowPage.xaml.vb)
Option Strict On Imports Windows.Storage
Bing Maps APIを提供するクラスを含むBimg.Maps名前空間をインポートします。
Imports Bing.Maps Imports Windows.UI.Popups
最新の HTTP アプリケーション用のプログラミングインターフェイスを提供するクラスの含まれる、System.Net.Http名前空間をインポートします。
Imports System.Net.Http
色の指定に関係するクラスの含まれるWindows.UI名前空間をインポートします。
Imports Windows.UI Public NotInheritable Class BingMapsShowPage Inherits Page
文字列型の定数メンバ変数として宣言した、AppIDに「Yahooで取得したアプリケーションID」を指定します。YahooのIDは下記のURLの「Yahoo!JAPAN IDを新規取得」から取得してください。
→ Yahoo!JAPANログイン・新規ID取得
Const AppID As String = "Yahooで取得したアプリケーションID"
ファイルを表すStorageFile型のメンバ変数myImageNameを宣言します。
Dim myImageName As StorageFile
ページがアクティブになった時の処理
MainPage.xamlから渡された値は、e.Parameterで取得できます。これはObject型であるため、DirectCastでStorageFile型にキャストして、メンバ変数myImageNameで参照します。
Pathプロパティで絶対パス付きファイル名を取得し、変数resultに格納します。
IO.Path.GetFileNameWithoutExtension(result)
で、パスと拡張子を除いた部分のファイル名を取得し、再度、拡張子”.jpg”を連結して変数myResultに格納します。
JPGのファイル名からSubString関数を使って、緯度と経度の部分を抜き出し、変数myLatitudeとmyLongitudeに格納します。ファイル名は
2012年10月21日11時28分22秒-33.835091-132.774902.jpg
という形式になっています。「33.835091」が緯度、「132.774902」が経度になります。この部分をSubString関数で取得します。
緯度、経度を格納した変数、myLatitudeとmyLongitudeを指定して、下記のURL文字列を作成し、変数myUriに格納しておきます。
Dim myUri As String = String.Format("http://reverse.search.olp.yahooapis.jp/OpenLocalPlatform/V1/reverseGeoCoder?lat={0}&lon={1}&appid={2}", myLatitude, myLongitude, AppID)
appidにはYahooで取得したIDを指定します。
このURIで取得できるXMLの構造は、図18のような構造です。赤枠で囲った
要素の値を取得します。新しいHttpClientのオブジェクトmyHttpClientを作成します。
GetStringAsyncメソッドで、指定したURIにGET要求を送信し、非同期操作で応答本体を文字列として受け取り、変数resultAddressに格納します。
ルート要素
置換したXMLをXElement.Parseメソッドで文字列として読み込みます。
ピクチャライブラリのMemoryImageサブフォルダにアクセスします。
GetFileAsyncメソッドで、myResult変数に格納されているファイルを取得します。
OpenReadAsyncメソッドで、読み込んだファイルからアクセスストリームを開きます。
新しいBitmapImageのインスタンスmyBmpオブジェクトを作成し、SetSourceメソッドで、読み込んだファイル名の画像にアクセスして、BitmapSourceのソースイメージを設定します。
新しいPushPinのインスタンスmyPinオブジェクトを作成します。背景色をCrimsonとします。
新しいStackPanelのインスタンスmyStackPanelオブジェクトを作成します。
Marginに5を指定して余白を設けます。背景色にNavyを指定します。
myStackPanelオブジェクトは非表示としておきます。
新しいTextBlockのインスタンスmyTextBlockオブジェクトを作成します。
文字色にRed、文字サイズに24、パディングに10を指定し、Textプロパティに住所を格納しているmyAddress変数の値を指定します。
新しいImageのインスタンスmyImageオブジェクトを作成します。
Widthに160、Heightに120を指定し、SourceプロパティにmyBmpオブジェクトを指定します。
myStackPanelオブジェクトにAddメソッドで、myTextBlock、myImageオブジェクトを追加します。
MapLayerクラスのSetPositionメソッドで、マップレイヤー内に要素の位置を設定します。この場合、myLatitudeとmyLongitudeの位置にmyPinオブジェクトをセットします。MapLayerクラスは、地図上の要素の位置を保持しているマップレイヤーを表すクラスです。
MapにAddメソッドでmyPinオブジェクトを追加します。同様に、MapLayerクラスのSetPositionメソッドで、マップレイヤー内に要素の位置を設定します。この場合、myLatitudeとmyLongitudeの位置にmyStackPanelオブジェクトをセットします。MapLayerクラスは、地図上の要素の位置を保持しているマップレイヤーを表すクラスです。
MapにAddメソッドでmyStackPanelオブジェクトを追加します。
AddHandlerメソッドで、PushPinがタップされた時のイベントハンドラを追加します。
myStackPanelオブジェクトを表示状態にします。おおまかな住所とそこで撮影した画像が表示されます。
表示されたmyStackPanelオブジェクトをタップした際には、myStackPanelオブジェクトを非表示にします。
このサンプルはGPSか位置情報取得機能が装備されていないとエラーになりますので、例外処理を追加しています。例外が発生した際にはErrorShowプロシージャを実行します。
Protected Overrides Async Sub OnNavigatedTo(e As Navigation.NavigationEventArgs) Try myImageName = DirectCast(e.Parameter, StorageFile) Dim result As String = myImageName.Path Dim myResult = IO.Path.GetFileNameWithoutExtension(result) & ".jpg" Dim myLatitude = myResult.Substring(21, 9) Dim myLongitude = myResult.Substring(31, 10) Dim myUri As String = String.Format("http://reverse.search.olp.yahooapis.jp/OpenLocalPlatform/V1/reverseGeoCoder?lat={0}&lon={1}&appid={2}", myLatitude, myLongitude, AppID) Dim myHttpClient As New HttpClient Dim resultAddress = Await myHttpClient.GetStringAsync(myUri) resultAddress = resultAddress.Replace("<YDF firstResultPosition=" & ChrW(34) & "1" & ChrW(34) & " totalResultsAvailable=" & ChrW(34) & "1" & ChrW(34) & " totalResultsReturned=" & ChrW(34) & "1" & ChrW(34) & " xmlns=" & ChrW(34) & "http://olp.yahooapis.jp/ydf/1.0" & ChrW(34) & ">", "<YDF>") Dim httpDoc As XElement = XElement.Parse(resultAddress) Dim myAddress = httpDoc.Descendants("Address").Value Dim myFolder = KnownFolders.PicturesLibrary Dim mySubFolder = Await myFolder.CreateFolderAsync("MemoryImage", CreationCollisionOption.OpenIfExists) Dim myPictureFile = Await mySubFolder.GetFileAsync(myResult) Dim myPicture = Await myPictureFile.OpenReadAsync Dim myBmp As New BitmapImage myBmp.SetSource(myPicture) myMap.Center = New Location(CDbl(myLatitude), CDbl(myLongitude)) Dim myPin As New Pushpin myPin.Background = New SolidColorBrush(Colors.Crimson) Dim myStackPanel As New StackPanel myStackPanel.Margin = New Thickness(5) myStackPanel.Background = New SolidColorBrush(Colors.Navy) myStackPanel.Visibility = Xaml.Visibility.Collapsed Dim myTextBlock As New TextBlock myTextBlock.Foreground = New SolidColorBrush(Colors.Red) myTextBlock.FontSize = 24 myTextBlock.Padding = New Thickness(10) myTextBlock.Text = myAddress & " 辺り" Dim myImage As New Image With myImage .Width = 160 .Height = 120 .Source = myBmp End With myStackPanel.Children.Add(myTextBlock) myStackPanel.Children.Add(myImage) MapLayer.SetPosition(myPin, New Location(CDbl(myLatitude), CDbl(myLongitude))) myMap.Children.Add(myPin) MapLayer.SetPosition(myStackPanel, New Location(CDbl(myLatitude), CDbl(myLongitude))) myMap.Children.Add(myStackPanel) AddHandler myPin.Tapped, Sub() myStackPanel.Visibility = Windows.UI.Xaml.Visibility.Visible End Sub AddHandler myStackPanel.Tapped, Sub() myStackPanel.Visibility = Windows.UI.Xaml.Visibility.Collapsed End Sub Catch ErrorShow() End Try End Sub
エラーが発生した時の処理
警告メッセージを表示して、処理を抜けます。
Private Async Sub ErrorShow() Dim myMessage As New MessageDialog("GPSまたは位置情報取得機能が付いておりません。" & vbCrLf & "写真を撮った位置の表示はできません。" & vbCrLf & "GPSまたは位置情報取得機能の付いたPCでお試しください。") Await myMessage.ShowAsync Exit Sub End Sub End Class
今回はここまでです。ありがとうございました。
筆者からのお知らせ
筆者はWindowsストアでアプリを公開しています。チャームの検索からWindowsストアを選択して、検索欄に、kuniyasuまたはYakushijiKuniyasuと入力すると、公開されているアプリの一覧が表示されます。上記はどちらも私のアカウントですので、興味のある方は是非ダウンロードして使ってみてください。
思い出の写真を記録するサンプルプログラム