画像に各種フィルタを適用して保存するWindowsアプリを作る

2013年1月28日(月)
薬師寺 国安

ピクチャライブラリへのアクセス許可の設定

今回のサンプルはピクチャライブラリにアクセスするため、「画像ライブラリ」へのアクセス許可が必要になります。ソリューションエクスプローラー内にpackage.appxmanifestというファイルがありますので、このファイルをダブルクリックします。「機能」タブをクリックし、「画像ライブラリ」にチェックを付けます(図7)。

図7:「画像ライブラリ」にチェックを付ける(クリックで拡大)

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

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

リスト2 (MainWindow.xaml.vb)

Option Strict On

エフェクトを使用可能にするSoftBuild.Media名前空間をインポートします。WriteableBitmapEffectorに含まれる名前空間です。

Imports Softbuild.Media

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

Imports Windows.Storage

Public NotInheritable Class MainPage
  Inherits Page

BitmapImageクラス型である新しいリストのインスタンス、myImageListメンバ変数を宣言します。

  Dim myImageList As New List(Of BitmapImage)

ファイルを表すIstorageFileインターフェース型の、インデックスによってアクセスできる読み取り専用のコレクションを表す、IReadOnlyList(Of Out T)インターフェース型のメンバ変数myPictureFilesを宣言します。

  Dim myPictureFiles As IReadOnlyList(Of IStorageFile)

文字列型の新しいリストであるmySubFolderメンバ変数を宣言します。

  Dim fileNameList As New List(Of String)

フォルダとその内容を操作し、その情報を提供するクラスである、StorageFolder型のメンバ変数mySubFolderを宣言します。

  Dim mySubFolder As StorageFolder

WriteableBitmapクラス型のメンバ変数mySourceを宣言します。WriteableBitmapクラスは、書き込みおよび更新が可能な、BitmapSourceを提供するクラスです。

   Dim mySource As WriteableBitmap

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

ピクチャライブラリにアクセスします。GetFileAsyncメソッドで、ピクチャライブラリ内のファイルを取得し、コレクション変数myPictureFilesに格納しておきます。CountプロパティでmyPictureFiles内のファイルの個数を取得し、ファイルが存在する場合は[一覧]ボタンの使用を可能にし、それ以外の場合は使用を不可とします。

CreateFolderAsyncメソッドで、ピクチャライブラリ内にageRecordというサブフォルダを作成します。
CreationCollisionOption.OpenIfExistsと指定します。すでに同名フォルダが存在する場合はそのフォルダ名を返し、ない場合はフォルダを作成してくれます。
GetFileAsyncメソッドでageRecordsサブフォルダ内のファイルを取得して、コレクション変数mySubPictureFiles変数に格納します。

コレクション変数mySubPictureFiles変数内のファイル名を変数myFileで取得しながら、反復処理を行います。
BitmapImageクラスの新しいインスタンスbmpオブジェクトを作成します。
SetSourceメソッドにAwait myFile.OpenReadAsyncと指定して、ランダムアクセス用のストリームを開きます。
BitmapImage型のリストであるmyImageListにAddメソッドでbmpオブジェクトを追加していきます。
文字列型のリストであるfileNameListにGetFileNameメソッドでファイル名を取得して追加していきます。

Imageの新しいインスタンスmyImageオブジェクトを作成し、Marginには0を指定し、WidthとHeightの値を指定します。
Sourceプロパティにbmpオブジェクトを指定し、GridViewコントロールにAddメソッドでmyImageオブジェクトを追加します。
GridViewコントロールに横一列でageRecordsサブフォルダ内の画像が一覧で表示されます。

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

  Protected Overrides Async Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
      Dim pictureFolder As StorageFolder = KnownFolders.PicturesLibrary
      Dim myPictureFiles As IReadOnlyList(Of IStorageFile) = Await pictureFolder.GetFilesAsync()
      If myPictureFiles.Count> 0 Then
        ichiranButton.IsEnabled = True
      Else
        ichiranButton.IsEnabled = False
      End If
      mySubFolder = Await pictureFolder.CreateFolderAsync("ageRecords", CreationCollisionOption.OpenIfExists)
      Dim mySubPictureFiles As IReadOnlyList(Of IStorageFile) = Await mySubFolder.GetFilesAsync()
      For Each myFile In mySubPictureFiles
        Dim bmp As New BitmapImage
        bmp.SetSource(Await myFile.OpenReadAsync)
        myImageList.Add(bmp)
        fileNameList.Add(Path.GetFileName(myFile.Path))
        Dim myImage As New Image
        myImage.Width = 320
        myImage.Height = 240
        myImage.Source = bmp
      GridView1.Items.Add(myImage)
    Next
  End Sub

GridViewの画像一覧から任意の画像が選択された時の処理

各種フィルタボタンの使用を可能にします。
BitmapImageのリストであるmyImageListオブジェクトで、GridViewの選択されたインデックスに対応する画像を取得して変数selectImageに格納します。
ImageのSourceプロパティにselectImageを指定します。
これで、Imageコントロールに実寸大の画像が表示されます。

  Private Sub GridView1_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles GridView1.SelectionChanged
    bakumatsuButton.IsEnabled = True
    grayButton.IsEnabled = True
    negativeButton.IsEnabled = True
    sepiaButton.IsEnabled = True
    SaturationButton.IsEnabled = True
    VignettingButton.IsEnabled = True
    ToycameraButton.IsEnabled = True
    PosterizeButton.IsEnabled = True
    contrastButton.IsEnabled = True
    Dim selectImage = myImageList(GridView1.SelectedIndex)
    Image1.Source = selectImage
    messageTextBlock.Text = String.Empty
  End Sub

画像を日付で検索する際に、日付を入力して[OK]ボタンをクリックした時の処理

画像のファイル名を格納しているfileNameListコレクション内を、ファイル名を格納していく変数resultで反復処理を行います。
変数selectTextにSubStringメソッドで先頭から10文字を取得します。ファイル名は
「2012-08-20 06-03-57.512.jpg」といった形式になっていますので、先頭から10文字を取得すると、「2012-08-20」という値が取得されます。

この値を格納している変数selectTextの値がsearchTextBoxに入力された値と同じであれば、反復処理を抜け、1ずつ加算されていた変数noの値をGridViewのSelectedIndexの値に指定します。Image1にもGridViewで選択された画像が表示されます。
ScrollIntoViewメソッドでGridViewを指定した画像の位置までスクロールします。

同じファイル名が見つかった時にはExit Forすることが肝心です。Exit Forを書き忘れると、最後の画像ファイル名が取得されます。

  Private Sub okButton_Click(sender As Object, e As RoutedEventArgs) Handles okButton.Click
    Dim no As Integer = 0
    For Each resut In fileNameList.ToList
      Dim selectText = resut.Substring(0, 10)
      If selectText = searchTextBox.Text Then
        GridView1.SelectedIndex = no
        GridView1.ScrollIntoView(GridView1.Items(no))
        Exit For
      End If
      no+=1
    Next
  End Sub

GridViewから選択された画像を取得する関数

GetFileAsyncメソッドで、ageRecordsサブフォルダから、画像ファイル名を格納しているFileNameList内の、GridViewから選択したインデックスに対応するファイル名を取得し、変数imageFileで参照します。

WriteableBitmapExtensions.FromStreamAsyncメソッドを使って、GridViewから選択された画像を読み込み戻り値とします。

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

  Private Async Function GetTestImageAsync() As Task(Of WriteableBitmap)
    Dim imageFile As StorageFile = Await mySubFolder.GetFileAsync(fileNameList(GridView1.SelectedIndex))
    Return Await WriteableBitmapExtensions.FromStreamAsync(Await imageFile.OpenReadAsync)
  End Function

[幕末風]ボタンがクリックされた時の処理

WriteableBitmap変数myBmpで、GetTestImageAsync関数の戻り値を取得します。GridViewから選択された画像ファイルが取得されます。
WriteableBitmap型のメンバ変数mySourceにEffectBakumatsuAsyncを指定します。
ImageのSourceプロパティにmySourceを指定します。幕末風なエフェクトのかかった画像が表示されます。
[Effect適用後の画像保存]ボタンの使用を可能にします。

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

  Private Async Sub bakumatsuButton_Click(sender As Object, e As RoutedEventArgs) Handles bakumatsuButton.Click
    Dim myBmp = Await GetTestImageAsync()
    mySource = Await myBmp.EffectBakumatsuAsync
    Image1.Source = mySource
    saveButton.IsEnabled = True
  End Sub
  • 画像に各種フィルタを適用して保存するWindows8サンプルアプリ

薬師寺国安事務所

薬師寺国安事務所代表。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メルマガ会員のサービス内容を見る

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