ピクチャライブラリ内の画像を指定して表示する+1つのサンプル

2012年12月4日(火)
薬師寺 国安

では、次にもう1つのサンプルを紹介します。

カメラで写した写真を保存する

Webカメラで写した画像を保存し、ListBoxに一覧で表示します。ListBoxに表示された画像の一覧から任意の画像を選択すると、実寸の画像が表示されます(図4)。

画面にはWebカメラの画像が表示されています。自分の好きなポーズで[保存]ボタンをタップすると、そのポーズが保存されます。[一覧]ボタンをタップすると、撮ったポーズの画像が表示されます。

画像はピクチャライブラリのPhotoImageというサブフォルダーに保存されます。PhotoImageサブフォルダー内に画像が存在する場合は、[一覧]ボタンの使用は可能ですが、画像が存在していない場合は使用不可となります。

図4:Webカメラで写した画像が一覧でListBoxに表示され、選択した画像が実寸で表示されている(クリックで拡大)

実際に動かした動画は下記のようになります。Windows Store Applicationの動画を撮るアプリケーションが存在していませんので、スマホで撮った動画です。見難い点はご了承願います。

サンプル一式は、会員限定特典としてダウンロードできます。記事末尾をご確認ください。

プロジェクトの作成

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)「保存」と「一覧」用の
  • (4)要素のItemTemplateプロパティにStaticResourceを用いて(1)で定義したListBoxTemplateを参照させます。
  • (5)要素を配置し、Widthに640、Heightに480と指定します。画像の実寸のサイズです。
  • (6)「保存しました。」のメッセージを表示する要素を配置します。
<Page
  x:Class="Win8_CaptureElementSave.MainPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="using:Win8_CaptureElementSave"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="d" Width="1920" Height="1080">
  <Page.Resources>■(1)
    <DataTemplate x:Key="ListBoxTemplate">■(1)
      <StackPanel Margin="10">
        <Image Width="320" Height="240" Source="{Binding 画像名}"/>■(1)
      </StackPanel>
    </DataTemplate>■(1)
  </Page.Resources>■(1)
  <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <CaptureElement x:Name="CaptureElement1" HorizontalAlignment="Left" Height="240" Margin="58,83,0,0" VerticalAlignment="Top" Width="320"/>■(2)
    <Button x:Name="saveButton" Content="保存" HorizontalAlignment="Left" Height="52" Margin="102,337,0,0" VerticalAlignment="Top" Width="208" FontFamily="Meiryo UI" FontSize="24"/>■(3)
    <Button x:Name="ichiranButton" Content="一覧" HorizontalAlignment="Left" Height="52" Margin="485,10,0,0" VerticalAlignment="Top" Width="208" FontFamily="Meiryo UI" FontSize="24"/>■(3)
    <ListBox x:Name="ListBox1" HorizontalAlignment="Left" Height="629" Margin="415,83,0,0" VerticalAlignment="Top" Width="351" ItemTemplate="{StaticResource ListBoxTemplate}"/>■(4)
    <Image x:Name="Image1" HorizontalAlignment="Left" Height="480" Margin="795,67,0,0" VerticalAlignment="Top" Width="640"/>■(5)
<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)
  </Grid>
</Page>

ピクチャライブラリとWebカメラ、マイクへのアクセス許可の設定

ソリューションエクスプローラー内のpackage.appxmanifestファイルをダブルクリックして開き、「機能」タブをから、「マイク」、「画像ライブラリ」、「Webカメラ」にチェックを付けて、アクセス可能にしておきます(図6)。

図6:package.appxmanifestの設定を行う(クリックで拡大)

次に、ソリューションエクスプローラー内のMainWindow.xamlを展開して表示される、MainWindow.xaml.vbをダブルクリックしてリスト3のコードを記述します。

ロジックコードを記述する

リスト3 (MainWindow.xaml.vb)

Option Strict On

写真、オーディオの録音と、ビデオのキャプチャのためのクラスが含まれる、Windows.Media.Capture名前空間をインポートします。

Imports Windows.Media.Capture

クラスやその他のプログラミング要素が、メディア フォーマットを作成するために必要なクラスの含まれる、Windows.Media.MediaProperties名前空間をインポートします。

Imports Windows.Media.MediaProperties

ファイル、フォルダー、およびアプリケーションの設定を管理するクラスの含まれる、Windows.Storage名前空間をインポートします。

Imports Windows.Storage

ImageInfoクラス内にBitmapImageクラスの「画像名」プロパティを定義しておきます。

Public Class ImageInfo
  Property 画像名 As BitmapImage
End Class

Public NotInheritable Class MainPage
  Inherits Page

IStorageFile型(ファイルを表す)のIReadonlyCollectionメンバ変数myPhotosを宣言します。IReadonlyCollection(of Out T)インターフェースは、要素の厳密に型指定された読み取り専用のコレクションを表します。

  Dim myPhotos As IReadOnlyCollection(Of IStorageFile)

新しいMediaCaptureクラスのインスタンスmyMediaCaptureオブジェクトメンバ変数を宣言します。MediaCaptureクラスは、フォト、オーディオ録音、およびビデオキャプチャを表すクラスです。

  Dim myMediaCapture As New MediaCapture

ページがアクティブになった時の処理

InitializeAsyncメソッドでMediaCaptureオブジェクトを初期化します。SourceプロパティにmyMediaCaptureオブジェクトを指定します。StartPreviewAsyncメソッドでMediaCaptureのプレビューを開始します。Webカメラの画像が表示されます。

ピクチャライブラリのPhotoImageサブフォルダーにアクセスします。
GetFileAsyncメソッドでPhotoImageサブフォルダー内のファイルを取得し、コレクション変数myPhotosに格納します。
myPhotosのCountプロパティでファイルの個数を取得し、ファイルが存在する場合は[一覧]ボタンの使用を可能にします。それ以外は使用を不可としておきます。
非同期で処理が行われるため、メソッドの先頭にAsyncを追加します。

  Protected Overrides Async Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
    Await myMediaCapture.InitializeAsync()
    CaptureElement1.Source = myMediaCapture
    Await myMediaCapture.StartPreviewAsync
    Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
    Dim mySubFolder = Await myFolder.CreateFolderAsync("PhotoImage", CreationCollisionOption.OpenIfExists)
    myPhotos = Await mySubFolder.GetFilesAsync()
    If myPhotos.Count > 0 Then
      ichiranButton.IsEnabled = True
    Else
      ichiranButton.IsEnabled = False
    End If
  End Sub

[保存]ボタンをクリックした時の処理

ピクチャライブラリフォルダーにアクセスします。CreateFolderAsyncメソッドで、ピクチャライブラリフォルダー内にPhotoImageというサブフォルダーを作成します。CreationCollisionOption.OpenIfExistsと指定し、指定したファイルやフォルダーがすでに存在する場合は、そのフォルダー名やファイル名を返します。そうでない場合は、ファイルやフォルダーを作成します。

CreateFileAsyncメソッドでサブフォルダー内に「年月日時間分秒.png」のファイルを作成します。

イメージストリームの書式を表すImageEncodingPropertiesクラスの新しいインスタンス、myImageEncodingPropertyオブジェクトを作成します。

フォーマットのサブタイプを設定するSubTypeプロパティに「PNG」と指定します。

WidthとHeightの値を指定します。

CapturePhotoToStorageFileAsyncメソッドで、出力イメージのエンコードプロパティ(PNGで640×480)と、保存する画像ファイル名、とを指定してストレージファイルにフォトをキャプチャします。

「保存しました。」と表示します。

非同期処理で行われるためメソッドの先頭にAsyncを追加します。

  Private Async Sub saveButton_Click(sender As Object, e As RoutedEventArgs) Handles saveButton.Click
    Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
    Dim mySubFolder = Await myFolder.CreateFolderAsync("PhotoImage", CreationCollisionOption.OpenIfExists)
    Dim myFile = Await mySubFolder.CreateFileAsync(DateTime.Now.ToString("yyyyMMddHHmmss") & ".png")
    Dim myImageEncodingProperty As New ImageEncodingProperties
    myImageEncodingProperty.Subtype = "PNG"
    myImageEncodingProperty.Width = 640
    myImageEncodingProperty.Height = 480
    Await myMediaCapture.CapturePhotoToStorageFileAsync(myImageEncodingProperty, myFile)
    messageTextBlock.Text = "保存しました。"
  End Sub

[一覧]ボタンがクリックされた時の処理

ピクチャライブラリのサブフォルダーPhotoImageにアクセスします。

GetFileAsyncメソッドでPhotoImage内のファイルを取得し、読み取り専用のコレクションを表すメンバ変数myPhotosに格納します。

ImageInfoクラス型の新しいリストであるmyImageInfoオブジェクトを作成します。

PhotoImageサブフォルダー内のファイル名を格納しているmyPhotosコレクション内を、変数resultにファイル名を格納しながら、反復処理を行います。

新しいBitmapImageクラスのbmpオブジェクトを作成します。
SetSourceメソッドにAwait result.OpenReadAsyncと指定して、ファイルの内容を読み込むために、現在のファイルを、ランダムアクセスストリームで開きます。

ImageInfoクラスの「画像名」プロパティにbmpオブジェクトを指定し、AddメソッドでmyImageInfoオブジェクトに追加していきます。

ListBoxのItemsSourceプロパティにmyImageInfoオブジェクトを追加します。これで、ListBox内にキャプチャした画像の一覧が表示されます。

非同期処理で行われるため、メソッドの先頭にAsyncを追加します。

  Private Async Sub ichiranButton_Click(sender As Object, e As RoutedEventArgs) Handles ichiranButton.Click
    Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
    Dim mySubFolder = Await myFolder.CreateFolderAsync("PhotoImage", CreationCollisionOption.OpenIfExists)
    myPhotos = Await mySubFolder.GetFilesAsync()
    Dim myImageInfo As New List(Of ImageInfo)
    For Each result In myPhotos
      Dim bmp As New BitmapImage
      bmp.SetSource(Await result.OpenReadAsync)
      myImageInfo.Add(New ImageInfo With {.画像名 = bmp})
    Next
    ListBox1.ItemsSource = myImageInfo
    messageTextBlock.Text = String.Empty
  End Sub

ListBox内の任意の画像が選択された時の処理

新しいBitmapImageクラスのインスタンスbmpオブジェクトを作成します。

PhotoImageサブフォルダー内のファイル一覧を格納しているmyPhotoコレクションから、ListBoxで選択された画像のインデックスに対応するファイルを開き、SetSourceメソッドに指定します。ImageのSourceにbmpオブジェクトを指定します。これで実寸の画像が表示されます。

非同期処理で行われるため、メソッドの先頭にAsyncを追加します。

  Private Async Sub ListBox1_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles ListBox1.SelectionChanged
    Try
      Dim bmp As New BitmapImage
      bmp.SetSource(Await myPhotos(ListBox1.SelectedIndex).OpenReadAsync)
      Image1.Source = bmp
    Catch
      Exit Sub
    End Try
  End Sub
End Class

今回はここまでです。ありがとうございました。

  • ピクチャライブラリ内の画像を指定して表示するサンプルアプリ

  • Webカメラで写した画像を保存してListBoxに一覧表示するサンプル

薬師寺国安事務所

薬師寺国安事務所代表。Visual Basic プログラミングと、マイクロソフト系の技術をテーマとした、書籍や記事の執筆を行う。
1950年生まれ。事務系のサラリーマンだった40歳から趣味でプログラミングを始め、1996年より独学でActiveXに取り組む。1997年に薬師寺聖とコラボレーション・ユニット PROJECT KySS を結成。2003年よりフリーになり、PROJECT KySS の活動に本格的に参加、.NETやRIAに関する書籍や記事を多数執筆する傍ら、受託案件のプログラミングも手掛ける。Windows Phoneアプリ開発を経て、現在はWindows ストア アプリを多数公開中

Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。Microsoft MVP for Development Platforms - Windows Phone Development(Oct 2012-Sep 2013)。Microsoft MVP for Development Platforms - Client Development(Oct 2013-Sep 2014)。Microsoft MVP for Development Platforms-Windows Platform Development (Oct 2014-Sep 2015)。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています