では、次にもう1つのサンプルを紹介します。
カメラで写した写真を保存する
Webカメラで写した画像を保存し、ListBoxに一覧で表示します。ListBoxに表示された画像の一覧から任意の画像を選択すると、実寸の画像が表示されます(図4)。
画面にはWebカメラの画像が表示されています。自分の好きなポーズで[保存]ボタンをタップすると、そのポーズが保存されます。[一覧]ボタンをタップすると、撮ったポーズの画像が表示されます。
画像はピクチャライブラリのPhotoImageというサブフォルダーに保存されます。PhotoImageサブフォルダー内に画像が存在する場合は、[一覧]ボタンの使用は可能ですが、画像が存在していない場合は使用不可となります。
図4:Webカメラで写した画像が一覧でListBoxに表示され、選択した画像が実寸で表示されている(クリックで拡大)
実際に動かした動画は下記のようになります。Windows Store Applicationの動画を撮るアプリケーションが存在していませんので、スマホで撮った動画です。見難い点はご了承願います。
VIDEO
サンプル一式は、会員限定特典としてダウンロードできます。記事末尾をご確認ください。
プロジェクトの作成
VS 2012のメニューから[ファイル(F)/新規作成(N)/プロジェクト(P)]と選択します。次に、「テンプレート」から「Windows ストア」を選択し、右に表示される項目名から「新しいアプリケーション(XAML)」を選択します。「名前(N)」に任意のプロジェクト名を指定します。ここでは「Win8_CaptureElementSave」という名前を付けています。
コントロールの配置
要素のWidthに1920、Heightに1080と指定しておきます。これは、筆者のPCの解像度です。
ツールボックスからデザイン画面上にCaptureElementコントロールを1個、「保存」と「一覧」用のButtonコントロールを2個、ListBoxコントロール1個、Imageコントロールを1個配置します(図5)。CaptureElementコントロールは、カメラや web カメラなどのキャプチャ デバイスからのストリームをレンダリングするコントロールです。
図5:各コントロールを配置した(クリックで拡大)
書き出されるXAMLコードをリスト2のように編集します。
リスト2 書き出され編集されたXAMLコード(MainPage.xaml)
(1)プロパティ要素内に、Key名がListBoxTemplateという要素を配置し、子要素として要素を配置します。Marginプロパティに10を指定して余白を設けます。
要素の子要素として 要素を配置し、WidthとHeightの値を指定します。Sourceプロパティには「画像名」をバインドしておきます。「画像名」はVBコード内で定義されたプロパティ名です。
(2)Webカメラの映像を表示する要素を配置します。
(3)「保存」と「一覧」用の要素を2個配置します。
(4)要素のItemTemplateプロパティにStaticResourceを用いて(1)で定義したListBoxTemplateを参照させます。
(5) 要素を配置し、Widthに640、Heightに480と指定します。画像の実寸のサイズです。
(6)「保存しました。」のメッセージを表示する要素を配置します。
02
x:Class="Win8_CaptureElementSave.MainPage"
05
xmlns:local="using:Win8_CaptureElementSave"
08
mc:Ignorable="d" Width="1920" Height="1080">
10
<DataTemplate x:Key="ListBoxTemplate">■(1)
11
<StackPanel Margin="10">
12
<Image Width="320" Height="240" Source="{Binding 画像名}"/>■(1)
16
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
17
<CaptureElement x:Name="CaptureElement1" HorizontalAlignment="Left" Height="240" Margin="58,83,0,0" VerticalAlignment="Top" Width="320"/>■(2)
18
<Button x:Name="saveButton" Content="保存" HorizontalAlignment="Left" Height="52" Margin="102,337,0,0" VerticalAlignment="Top" Width="208" FontFamily="Meiryo UI" FontSize="24"/>■(3)
19
<Button x:Name="ichiranButton" Content="一覧" HorizontalAlignment="Left" Height="52" Margin="485,10,0,0" VerticalAlignment="Top" Width="208" FontFamily="Meiryo UI" FontSize="24"/>■(3)
20
<ListBox x:Name="ListBox1" HorizontalAlignment="Left" Height="629" Margin="415,83,0,0" VerticalAlignment="Top" Width="351" ItemTemplate="{StaticResource ListBoxTemplate}"/>■(4)
21
<Image x:Name="Image1" HorizontalAlignment="Left" Height="480" Margin="795,67,0,0" VerticalAlignment="Top" Width="640"/>■(5)
22
<TextBlock x:Name="messageTextBlock" HorizontalAlignment="Left" Height="55" Margin="19,417,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="526" FontFamily="Meiryo UI" FontSize="36" Foreground="Red"/>■(6)
ピクチャライブラリとWebカメラ、マイクへのアクセス許可の設定
ソリューションエクスプローラー内のpackage.appxmanifestファイルをダブルクリックして開き、「機能」タブをから、「マイク」、「画像ライブラリ」、「Webカメラ」にチェックを付けて、アクセス可能にしておきます(図6)。
図6:package.appxmanifestの設定を行う(クリックで拡大)
次に、ソリューションエクスプローラー内のMainWindow.xamlを展開して表示される、MainWindow.xaml.vbをダブルクリックしてリスト3のコードを記述します。
ロジックコードを記述する
リスト3 (MainWindow.xaml.vb)
写真、オーディオの録音と、ビデオのキャプチャのためのクラスが含まれる、Windows.Media.Capture名前空間をインポートします。
1
Imports Windows.Media.Capture
クラスやその他のプログラミング要素が、メディア フォーマットを作成するために必要なクラスの含まれる、Windows.Media.MediaProperties名前空間をインポートします。
1
Imports Windows.Media.MediaProperties
ファイル、フォルダー、およびアプリケーションの設定を管理するクラスの含まれる、Windows.Storage名前空間をインポートします。
ImageInfoクラス内にBitmapImageクラスの「画像名」プロパティを定義しておきます。
2
Property 画像名 As BitmapImage
5
Public NotInheritable Class MainPage
IStorageFile型(ファイルを表す)のIReadonlyCollectionメンバ変数myPhotosを宣言します。IReadonlyCollection(of Out T)インターフェースは、要素の厳密に型指定された読み取り専用のコレクションを表します。
1
Dim myPhotos As IReadOnlyCollection(Of IStorageFile)
新しいMediaCaptureクラスのインスタンスmyMediaCaptureオブジェクトメンバ変数を宣言します。MediaCaptureクラスは、フォト、オーディオ録音、およびビデオキャプチャを表すクラスです。
1
Dim myMediaCapture As New MediaCapture
ページがアクティブになった時の処理
InitializeAsyncメソッドでMediaCaptureオブジェクトを初期化します。SourceプロパティにmyMediaCaptureオブジェクトを指定します。StartPreviewAsyncメソッドでMediaCaptureのプレビューを開始します。Webカメラの画像が表示されます。
ピクチャライブラリのPhotoImageサブフォルダーにアクセスします。
GetFileAsyncメソッドでPhotoImageサブフォルダー内のファイルを取得し、コレクション変数myPhotosに格納します。
myPhotosのCountプロパティでファイルの個数を取得し、ファイルが存在する場合は[一覧]ボタンの使用を可能にします。それ以外は使用を不可としておきます。
非同期で処理が行われるため、メソッドの先頭にAsyncを追加します。
01
Protected Overrides Async Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
02
Await myMediaCapture.InitializeAsync()
03
CaptureElement1.Source = myMediaCapture
04
Await myMediaCapture.StartPreviewAsync
05
Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
06
Dim mySubFolder = Await myFolder.CreateFolderAsync("PhotoImage", CreationCollisionOption.OpenIfExists)
07
myPhotos = Await mySubFolder.GetFilesAsync()
08
If myPhotos.Count > 0 Then
09
ichiranButton.IsEnabled = True
11
ichiranButton.IsEnabled = False
[保存]ボタンをクリックした時の処理
ピクチャライブラリフォルダーにアクセスします。CreateFolderAsyncメソッドで、ピクチャライブラリフォルダー内にPhotoImageというサブフォルダーを作成します。CreationCollisionOption.OpenIfExistsと指定し、指定したファイルやフォルダーがすでに存在する場合は、そのフォルダー名やファイル名を返します。そうでない場合は、ファイルやフォルダーを作成します。
CreateFileAsyncメソッドでサブフォルダー内に「年月日時間分秒.png」のファイルを作成します。
イメージストリームの書式を表すImageEncodingPropertiesクラスの新しいインスタンス、myImageEncodingPropertyオブジェクトを作成します。
フォーマットのサブタイプを設定するSubTypeプロパティに「PNG」と指定します。
WidthとHeightの値を指定します。
CapturePhotoToStorageFileAsyncメソッドで、出力イメージのエンコードプロパティ(PNGで640×480)と、保存する画像ファイル名、とを指定してストレージファイルにフォトをキャプチャします。
「保存しました。」と表示します。
非同期処理で行われるためメソッドの先頭にAsyncを追加します。
01
Private Async Sub saveButton_Click(sender As Object, e As RoutedEventArgs) Handles saveButton.Click
02
Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
03
Dim mySubFolder = Await myFolder.CreateFolderAsync("PhotoImage", CreationCollisionOption.OpenIfExists)
04
Dim myFile = Await mySubFolder.CreateFileAsync(DateTime.Now.ToString("yyyyMMddHHmmss") & ".png")
05
Dim myImageEncodingProperty As New ImageEncodingProperties
06
myImageEncodingProperty.Subtype = "PNG"
07
myImageEncodingProperty.Width = 640
08
myImageEncodingProperty.Height = 480
09
Await myMediaCapture.CapturePhotoToStorageFileAsync(myImageEncodingProperty, myFile)
10
messageTextBlock.Text = "保存しました。"
[一覧]ボタンがクリックされた時の処理
ピクチャライブラリのサブフォルダーPhotoImageにアクセスします。
GetFileAsyncメソッドでPhotoImage内のファイルを取得し、読み取り専用のコレクションを表すメンバ変数myPhotosに格納します。
ImageInfoクラス型の新しいリストであるmyImageInfoオブジェクトを作成します。
PhotoImageサブフォルダー内のファイル名を格納しているmyPhotosコレクション内を、変数resultにファイル名を格納しながら、反復処理を行います。
新しいBitmapImageクラスのbmpオブジェクトを作成します。
SetSourceメソッドにAwait result.OpenReadAsyncと指定して、ファイルの内容を読み込むために、現在のファイルを、ランダムアクセスストリームで開きます。
ImageInfoクラスの「画像名」プロパティにbmpオブジェクトを指定し、AddメソッドでmyImageInfoオブジェクトに追加していきます。
ListBoxのItemsSourceプロパティにmyImageInfoオブジェクトを追加します。これで、ListBox内にキャプチャした画像の一覧が表示されます。
非同期処理で行われるため、メソッドの先頭にAsyncを追加します。
01
Private Async Sub ichiranButton_Click(sender As Object, e As RoutedEventArgs) Handles ichiranButton.Click
02
Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
03
Dim mySubFolder = Await myFolder.CreateFolderAsync("PhotoImage", CreationCollisionOption.OpenIfExists)
04
myPhotos = Await mySubFolder.GetFilesAsync()
05
Dim myImageInfo As New List(Of ImageInfo)
06
For Each result In myPhotos
07
Dim bmp As New BitmapImage
08
bmp.SetSource(Await result.OpenReadAsync)
09
myImageInfo.Add(New ImageInfo With {.画像名 = bmp})
11
ListBox1.ItemsSource = myImageInfo
12
messageTextBlock.Text = String.Empty
ListBox内の任意の画像が選択された時の処理
新しいBitmapImageクラスのインスタンスbmpオブジェクトを作成します。
PhotoImageサブフォルダー内のファイル一覧を格納しているmyPhotoコレクションから、ListBoxで選択された画像のインデックスに対応するファイルを開き、SetSourceメソッドに指定します。ImageのSourceにbmpオブジェクトを指定します。これで実寸の画像が表示されます。
非同期処理で行われるため、メソッドの先頭にAsyncを追加します。
01
Private Async Sub ListBox1_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles ListBox1.SelectionChanged
03
Dim bmp As New BitmapImage
04
bmp.SetSource(Await myPhotos(ListBox1.SelectedIndex).OpenReadAsync)
今回はここまでです。ありがとうございました。