PR

Webカメラで撮影した写真をセピア調に演出するアプリを作る

2013年9月3日(火)
薬師寺 国安

戻る(←)アイコンがタップされた時の処理

ピクチャライブラリにアクセスし、ピクチャライブラリ内にsepiaという文字を含んだファイル名がある場合は、「Folder」アイコンの使用を可能にし、それ以外は不可とします。

myFrameを非表示、「Sepia調に変換」ボタンを使用可、「Attach Camera」アイコンを使用可、GridViewを表示状態にします。
Webカメラのデバイス名が表示されているComboBox内の、先頭のデバイスを選択状態にします。よって、リアカメラを選択していた場合でも、戻る(←)アイコンをタップして、元の画面に戻った際は、フロントカメラが選択されていることになります。これは、どのデバイスが先頭に来るかによって異なります。

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

  Private Async Sub backButton_Click(sender As Object, e As RoutedEventArgs) Handles backButton.Click
    Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
    Dim myPictureFiles = Await myFolder.GetFilesAsync()
    For Each myPhoto In myPictureFiles
      If myPhoto.Path.Contains("sepia") Then
        ichiranButton.IsEnabled = True
      Else
        ichiranButton.IsEnabled = False
      End If
    Next
    myFrame.Visibility = Xaml.Visibility.Collapsed
    changeSepiaButton.IsEnabled = True
    shutterButton.IsEnabled = True
    GridView1.Visibility = Xaml.Visibility.Visible
    cameraComboBox.SelectedIndex = 0
  End Sub

WriteableBitmapExtensions.FromStreamAsyncメソッドを使って、リソース内の画像を読み込む関数

ピクチャライブラリのSepiaSourceImageサブフォルダにアクセスし、GetFilesAsyncメソッドでファイルを取得して、コレクション変数_myPictureFilesに格納します。
メンバ変数fileNameListをクリアしておきます。

ファイル名を格納している_myPictureFilesコレクション変数内のファイルを、変数myPtotoFileに格納しながら、以下の処理を繰り返します。
fileNameListオブジェクトにAddメソッドで、フルパス付のファイル名をPathプロパティで取得し、Path.GetFileNameWithoutExtensionメソッドで、パスと拡張子を除いたファイル名に、文字列「.jpg」を連結して追加していきます。
fileNameListオブジェクト内に格納されたファイル名で、GridView1.SelectedIndexに該当するファイルを、GetFileAsyncメソッドで取得し、imageFileで参照します。
WriteableBitmapExtensions.FromStreamAsyncメソッドでリソース内の画像を読み込み、戻り値とします。非同期処理で行われるため関数の先頭にAsyncを追加します。

  Private Async Function GetTestImageAsync() As Task(Of WriteableBitmap)
    Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
    Dim mySubFolder As StorageFolder = Await myFolder.CreateFolderAsync("SepiaSourceImage", CreationCollisionOption.OpenIfExists)
    Dim _myPictureFiles = Await mySubFolder.GetFilesAsync
    fileNameList.Clear()
    For Each myPhotoFile In _myPictureFiles
      fileNameList.Add(Path.GetFileNameWithoutExtension(myPhotoFile.Path) & ".jpg")
    Next
    Dim imageFile As StorageFile = Await mySubFolder.GetFileAsync(fileNameList(GridView1.SelectedIndex))
    Return Await WriteableBitmapExtensions.FromStreamAsync(Await imageFile.OpenReadAsync)
  End Function

「Sepia調に変換」ボタンがクリックされた時の処理

GetTestImageAsync関数を呼び出し、読み込んだ画像ファイルを、myBmpで参照します。

myBmp.EffectSepiaメソッドでSepia調に変換された画像を、メンバ変数mySourceで参照します。
Image1のSourceプロパティにmySourceを指定します。これで、Image1にセピア調に変換された画像が表示されます。「Save」アイコンの使用を可能にします。

  Private Async Sub changeSepiaButton_Click(sender As Object, e As RoutedEventArgs) Handles changeSepiaButton.Click
    Dim myBmp = Await GetTestImageAsync()
    mySource = myBmp.EffectSepia
    Image1.Source = mySource
    saveButton.IsEnabled = True
  End Sub

「Save」アイコンがタップされた時の処理

Image1.Sourceの値をDirectCastでWriteableBitmapにキャストして、myBmpオブジェクトで参照します。

SaveAsyncメソッドで、保存する場所をピクチャライブラリ内、保存する画像形式をPngに指定し、保存するファイル名を、文字列「sepia」を先頭に追加した「yyyy年MM月dd日HH時mm分ss秒」形式とし、Widthを640、Heightを480として保存します。

「sepia2013年01月01日10時10分10秒.png」といった形式の画像ファイルが保存されます。

「ピクチャフォルダー内に保存しました。」のメッセージを表示し、「Folder」アイコンの使用を可能に、「Save」アイコンの使用を不可とします。非同期処理で行われるためメソッドの先頭にAsyncを追加します。

  Private Async Sub saveButton_Click(sender As Object, e As RoutedEventArgs) Handles saveButton.Click
    Dim myBmp = DirectCast(Image1.Source, WriteableBitmap)
    Await myBmp.SaveAsync(ImageDirectories.PicturesLibrary, ImageFormat.Png, "sepia" & DateTime.Now.ToString("yyyy年MM月dd日HH時mm分ss秒"), 640, 480)
    Dim message As New MessageDialog("ピクチャフォルダ内に保存しました。")
    Await message.ShowAsync
    ichiranButton.IsEnabled = True
    saveButton.IsEnabled = False
  End Sub

「Folder」アイコンがタップされた時の処理

myFrameを表示状態にします。「Sepia調に変換」ボタンの使用を不可、「AttachCamera」アイコンの使用を不可、GridView1を非表示状態にします。

NavigateメソッドでIchiranShowPageに遷移します。値は何も渡さないのでNothingを指定します。

  Private Sub ichiranButton_Click(sender As Object, e As RoutedEventArgs) Handles ichiranButton.Click
    myFrame.Visibility = Xaml.Visibility.Visible
    changeSepiaButton.IsEnabled = False
    shutterButton.IsEnabled = False
    GridView1.Visibility = Xaml.Visibility.Collapsed
    myFrame.Navigate(GetType(IchiranShowPage), Nothing)
  End Sub
End Class

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

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

リスト4 (IchiranShowPage.xaml.vb)

Option Strict On

Imports Windows.Storage
Imports Windows.UI
Imports Windows.UI.Popups
Public NotInheritable Class IchiranShowPage
  Inherits Page

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

「ファイル名」と「削除」ボタンの付いたセピア調に変換された画像を一覧表示する、DataShowプロシージャを実行します。

  Protected Overrides Async Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
    DataShow()
  End Sub

「ファイル名」と「削除」ボタンの付いたセピア調に変換された画像を一覧表示する処理

ピクチャライブラリにアクセスします。GetFilesAsyncメソッドでピクチャライブラリ内の画像を取得して、コレクション変数myPictureFilesに格納します。

ファイルを格納しているmyPictureFilesコレクション内のファイルを、変数myPhotoに格納しながら、以下の処理を繰り返します。ファイル名に「sepia」という文字列が含まれている場合の処理です。

新しいBitmapImageのインスタンスbmpオブジェクトを作成します。SetSourceメソッドに、

Await myPhoto.OpenReadAsync

と指定し、OpenReadAsyncメソッドで、現在のファイルのランダムアクセスストリームを開きBitmapSourceのソースイメージに設定します。
新しいImageのインスタンスmyImageを作成します。Widthに640、Heightに480、StretchにNone、Sourceプロパティにbmpオブジェクトを指定します。

新しいTextBlockのインスタンスmyTextBlockオブジェクトを作成します。
文字サイズに20、文字色にBeige、Textプロパティに、パスと拡張子を除いたファイル名から、SubStringメソッドで6文字目から20文字取り出し、指定します。

「sepia2013年01月01日10時10分10秒.png」形式から、sepiaの文字と拡張子を除いたファイル名になります。中央揃えとしておきます。

新しいButtonのいインスタンスmyButtonを作成します。Contentに「削除」、文字サイズに18、Tagプロパティには、パスと拡張子を除いたファイル名に、文字列「.png」を追加した値を指定しておきます。中央揃えとしておきます。

新しいStackPanelのインスタンスmyStackPanelオブジェクトを作成します。
Marginに5を指定して余白を設けます。
Addメソッドで、myStackPanelオブジェクトに、myImage、myTextBlock、myButtonオブジェクトを追加します。

GridView1にAddメソッドでmyStackPanelオブジェクトを追加します。
これで、セピア調の画像にファイル名と削除ボタンの付いた画像の一覧がGridView内に表示されます。

AddHandlerステートメントで「削除」ボタンがクリックされた時のイベントハンドラを追加します。
イベントハンドラ内では以下の処理を行います。

Buttonの情報を格納しているdeSenderオブジェクトをDirectCastでButtonにキャストして、そのTagプロパティの値を取得して、変数myFileNameに格納しておきます。
GetFileAsyncメソッドで、変数myFileNameに格納されている画像ファイルを取得し変数delImageNameで参照します。
DeleteAsyncメソッドで参照していたファイルを削除します。

「削除しました。」のメッセージを表示し、GridView内をクリアします。
画面を再描画するために、DataShowプロシージャを実行します。

  Private Async Sub DataShow()
    Dim myFolder As StorageFolder = Windows.Storage.KnownFolders.PicturesLibrary
    Dim myPictureFiles = Await myFolder.GetFilesAsync()
 
    For Each myPhoto In myPictureFiles
      If myPhoto.Path.Contains("sepia") Then
        Dim bmp As New BitmapImage
        bmp.SetSource(Await myPhoto.OpenReadAsync)
        Dim myImage As New Image
        myImage.Width = 640
        myImage.Height = 480
        myImage.Stretch = Stretch.None
        myImage.Source = bmp
 
        Dim myTextBlock As New TextBlock
        With myTextBlock
          .FontSize = 20
          .Foreground = New SolidColorBrush(Colors.Beige)
          .Text = Path.GetFileNameWithoutExtension(myPhoto.Path).Substring(5, 20)
          .HorizontalAlignment = Xaml.HorizontalAlignment.Center
        End With
 
        Dim myButton As New Button
        With myButton
          .Content = "削除"
          .FontSize = 18
          .Tag = Path.GetFileNameWithoutExtension(myPhoto.Path) & ".png"
          .HorizontalAlignment = Xaml.HorizontalAlignment.Center
        End With
        Dim myStackPanel As New StackPanel
        myStackPanel.Margin = New Thickness(5)
        myStackPanel.Children.Add(myImage)
        myStackPanel.Children.Add(myTextBlock)
        myStackPanel.Children.Add(myButton)
        GridView1.Items.Add(myStackPanel)
 
        AddHandler myButton.Click, Async Sub(delSender As Object, delArgs As RoutedEventArgs)
          Dim myFileName As String = CStr(DirectCast(delSender, Button).Tag)
          Dim delImageName = Await myFolder.GetFileAsync(myFileName)
          Await delImageName.DeleteAsync
          Dim myMessage As New MessageDialog("削除しました。")
          Await myMessage.ShowAsync
          GridView1.Items.Clear()
          DataShow()
          End Sub
          End If
        Next
    End Sub
  End Class

アイコンの作成

詳細については、「自分の現在位置を取得して表示するサンプルプログラム」の記事を参照してください。

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

Think IT会員限定特典
  • セピア調の写真を作るアプリ

薬師寺国安事務所

薬師寺国安事務所代表。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のWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

Think IT会員サービスの概要とメリットをチェック

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