画像にFilterをかけてPicturesHUBに保存する

2012年1月23日(月)
PROJECT KySS

次に、MainPage.xamlを展開して表示される、MainPage.xaml.vbをダブルクリックしてリスト2のコードを記述します。

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

リスト2 (MainPage.xaml.vb)

Option Strict On

ランチャーやチューザーに関するクラスの含まれる、Microsoft.Phone.Tasks名前空間をインポートします。
Imports Microsoft.Phone.Tasks

Imports System.Windows.Media.Imaging

イメージを読み込んだり、操作したりする、コントロールやクラスの含まれる、基本の名前空間である、ImageToolsをインポートします。ImageTools.Filtering名前空間には、セピア、グレースケール、反転フィルタなどの画像フィルタが含まれています
Imports ImageTools
Imports ImageTools.Filtering
仮想ファイルシステムを作成および使用するための型が含まれている、System.IO.IsolatedStorage名前空間をインポートします。分離ストレージによって、安全なクライアント側のストレージが提供されます。
Imports System.IO.IsolatedStorage

曲、アルバム、再生リスト、およびピクチャを列挙、再生、および表示するためのクラスの含まれる、Microsoft.Xna.Framework.Media名前空間をインポートします。この名前空間をインポートしていないとMediaLibrayクラスが使用できませんので、注意してください。
Imports Microsoft.Xna.Framework.Media

Imports System.IO
Partial Public Class MainPage
  Inherits PhoneApplicationPage

  ' コンストラクター
  Public Sub New()
    InitializeComponent()
  End Sub

PicturesHUB内の写真を選択できる、PhotoChooseTaskクラス用のmyTaskメンバ変数を宣言します。
  Dim myTask As PhotoChooserTask

loadImage、filterImageを、Image クラスのピクセルを格納し、ファイルやストリームのサイズ変更やカッティングのような操作から、イメージを読み込む機能を提供するクラスである、ExtendedImageクラス用メンバ変数として宣言します。
  Dim loadImage As ExtendedImage
  Dim filterImage As ExtendedImage

BitmapImageクラス用メンバ変数として、myImageを宣言します。BitmapImageクラスは、イメージを読み込むためのBitmapSourceを提供するクラスです。
  Dim myImage As BitmapImage

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

新しいPhotoChooserTaskのインスタンスを生成します。AddHandlerステートメントで、タスクが完了した時のCompletedイベントハンドラを追加します。Completedイベント内では、完了イベントがTaskResult.OKで、正常に完了した場合は以下の処理を行います。
新しいBitmapImageのインスタンスを作成します。chooser での選択の結果は引数で渡されますので、SetSourceメソッドで、渡された画像を BitmapImage オブジェクトに格納します。Image1のSourceプロパティに、chooserで選択した画像を格納しているBitmapImageオブジェクトを指定します。Picturesで選択した画像が表示されます。
BitmapImageのインスタンスmyImageで初期化された新しいWriteableBitmapオブジェクトwbを作成します。WriteableBitmapクラスは、書き込みおよび更新が可能な BitmapSource を提供するクラスです。
新しいExtendedImageクラスのインスタンスを作成します。SetPixelsメソッドで、loadImageオブジェクトに画像のピクセル配列を設定します。書式は下記の通りです。

ImageBase.SetPixels(画像の新しいPixelWidth(0より大きい),画像の新しいPixelHeight(0より大きい), 色のバイト配列)

wb.ToByteArrayメソッドは、WriteableBitmap byte()に変換するメソッドです。「参照の追加(R)」から、WriteableBitmapEXWinPhone.dllを追加していなければ、wb.ToByteArrayメソッドが使用できませんので、注意してください。
  Protected Overrides Sub OnNavigatedTo(e As System.Windows.Navigation.NavigationEventArgs)
    myTask = New PhotoChooserTask
    AddHandler myTask.Completed, Sub(resultSender As Object, resultArgs As PhotoResult)
               If resultArgs.TaskResult = TaskResult.OK Then
                  myImage = New BitmapImage
                  myImage.SetSource(resultArgs.ChosenPhoto)
                  Image1.Source = myImage
                  Dim wb As WriteableBitmap = New WriteableBitmap(myImage)
                  loadImage = New ExtendedImage
                  loadImage.SetPixels(myImage.PixelWidth, myImage.PixelHeight, wb.ToByteArray())
               End If
             End Sub
    MyBase.OnNavigatedTo(e)
  End Sub

[画像読み込み]ボタンがタップされた時の処理

Showメソッドで、PhotoChooserTaskを実行します。これで、PicturesHUBより選択した画像が、Image1内に表示されます。ListBoxの使用を可能にします。

  Private Sub imageReadButton_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles imageReadButton.Click
    myTask.Show()
    ListBox1.IsEnabled = True
  End Sub

リストボックスより任意のフィルタが選択された時の処理。

ListBoxより選択されたフィルタ名を変数myItemに格納し、myItemの値によって条件分岐を行います。7つのフィルタの条件分岐を書いていますが、処理は全て同じですので、「セピア」についてのみ解説します。
Sepiaクラスとしてfilter変数を宣言します。新しいSepiaクラスのインスタンスを作成します。画像のピクセル配列が設定され、loadImageで初期化された新しい、ExtendedImageを作成しfilterImageオブジェクトで参照します。Sepia.Applyメソッドで、指定されたRectangleの領域で画像へのフィルタが適用されます。Applyメソッドの書式は下記の通りです。

Sepia.Apply(フィルタを適用するターゲットとなるイメージ,元のイメージ, フィルタが適用されるべき画像の領域を定義するRectangle)

Rectangleは下記の値で初期化されます。

New ImageToos.Rectangle(Rectangleの左上隅のx座標(通常0), Rectangleの左上隅のy座標(通常0),元のイメージのPixelWidth,元のイメージのPixelHeight)

フィルタの適用されたイメージを、ToBitmapメソッドでBitmapに変換し、Image1のSourceプロパティに指定します。[保存]ボタンの使用を可能にします。
プルウィットフィルタは、エッジ検出フィルタの一種で、水平方向と垂直方向があり、組み合わせて用いることもあります。ソーベルフィルタもエッジ検出フィルタの一種です。
  Private Sub ListBox1_SelectionChanged(sender As Object, e As System.Windows.Controls.SelectionChangedEventArgs) Handles ListBox1.SelectionChanged
    Dim myItem As String = DirectCast(ListBox1.SelectedItem, ListBoxItem).Content.ToString
 
    Select Case myItem
      Case "セピア"
        Dim filter As Sepia
        filter = New Sepia
        filterImage = New ExtendedImage(loadImage)
        filter.Apply(filterImage, loadImage, New ImageTools.Rectangle(0, 0, loadImage.PixelWidth, loadImage.PixelHeight))
      Case "インバーター"
        Dim filter As Inverter
        filter = New Inverter
        filterImage = New ExtendedImage(loadImage)
        filter.Apply(filterImage, loadImage, New ImageTools.Rectangle(0, 0, loadImage.PixelWidth, loadImage.PixelHeight))
      Case "白黒"
        Dim filter As Grayscale
        filter = New GrayscaleRMY
        filterImage = New ExtendedImage(loadImage)
        filter.Apply(filterImage, loadImage, New ImageTools.Rectangle(0, 0, loadImage.PixelWidth, loadImage.PixelHeight))
      Case "プルウィットX"
        Dim filter As PrewittX
        filter = New PrewittX
        filterImage = New ExtendedImage(loadImage)
        filter.Apply(filterImage, loadImage, New ImageTools.Rectangle(0, 0, loadImage.PixelWidth, loadImage.PixelHeight))
      Case "プルウィットY"
        Dim filter As PrewittY
        filter = New PrewittY
        filterImage = New ExtendedImage(loadImage)
        filter.Apply(filterImage, loadImage, New ImageTools.Rectangle(0, 0, loadImage.PixelWidth, loadImage.PixelHeight))
      Case "ソーベルX"
        Dim filter As SobelX
        filter = New SobelX
        filterImage = New ExtendedImage(loadImage)
        filter.Apply(filterImage, loadImage, New ImageTools.Rectangle(0, 0, loadImage.PixelWidth, loadImage.PixelHeight))
      Case "ソーベルY"
        Dim filter As SobelY
        filter = New SobelY
        filterImage = New ExtendedImage(loadImage)
        filter.Apply(filterImage, loadImage, New ImageTools.Rectangle(0, 0, loadImage.PixelWidth, loadImage.PixelHeight))
      Case Else
        Exit Select
    End Select
    Dim bitmap As WriteableBitmap= filterImage.ToBitmap
    Image1.Source = bitmap
    saveButton.IsEnabled = True
  End Sub

[保存]ボタンがタップされた時の処理

PicturesHUBに保存するファイル名を現在の「年月日時間分秒.jpg」とします。
Image1で初期化された、新しいWriteableBitmapのオブジェクト、myWriteableBitmapを作成します。WriteableBitmapクラスの第2引数には、ビットマップに特定の変換を適用するTransformを指定できますが、ここではNothingを指定します。WriteableBitmapクラスは、書き込みおよび更新が可能な BitmapSourceを提供するクラスです。
変数storageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。FileExistsメソッドでimageFileNameに格納しているファイルが存在しているかどうかをチェックし、存在している場合は、DeleteFileメソッドで同名ファイルを削除します。
分離ストレージ内のファイルを表すIsolatedStorageFileStreamクラス用オブジェクト変数myStream変数を用意し、IsolatedStorageFile.CreateFileメソッドで、分離ストレージ内にimageFileName変数の持っているファイルを作成します。
Extensions.SaveJpegメソッドで、WriteableBitmapオブジェクトを、JPEGストリームにエンコードし、画像ファイルを一時分離ストレージに保存します。これは、JPEGファイルのターゲットとなる幅と高さを設定するためのパラメータを持っています。書式は下記の通りです。

Extensions.SaveJpeg(WriteableBitmapオブジェクト,イメージデータストリーム,WriteableBitmapオブジェクトのPixelWidth, WriteableBitmapオブジェクトのPixelHeight,0(固定),0~100の間の写真の品質(70以上を指定))

ピクチャへのアクセスを提供する、新しいMediaLibrayクラスのインスタンス、myLibrayを作成します。分離ストレージ内のファイルを表すIsolatedStorageFileStreamクラス用オブジェクト変数Stream変数を用意し、IsolatedStorageFile.OpenFileメソッドで、imageFileNameに格納されているJPEGファイルを、指定したファイルアクセスを使用して指定したモードで開きます。MediaLibrary.SavePictureメソッドで、ストリームオブジェクトに含まれる画像を、メディアライブラリーに保存し、その保存した画像をピクチャオブジェクトとして返します。保存した旨のメッセージを表示します。これで、分離ストレージの画像ファイルがPicturesHUBに保存されます。
  Private Sub saveButton_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles saveButton.Click
    Dim imageFileName As String = DateTime.Now.ToString("yyyyMMddHHmmss") & ".jpg"
 
    Dim myWriteableBitmap As WriteableBitmap
    myWriteableBitmap = New WriteableBitmap(Image1, Nothing)
 
    Dim storage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
    If storage.FileExists(imageFileName) = True Then
      storage.DeleteFile(imageFileName)
    End If
    Using myStream As IsolatedStorageFileStream = storage.CreateFile(imageFileName)
      System.Windows.Media.Imaging.Extensions.SaveJpeg(myWriteableBitmap, myStream, myWriteableBitmap.PixelWidth, myWriteableBitmap.PixelHeight, 0, 85)
    End Using
 
    Dim myLibray As New MediaLibrary
    Using Stream As IsolatedStorageFileStream = storage.OpenFile(imageFileName, FileMode.Open, FileAccess.Read)
      myLibray.SavePicture(imageFileName, Stream)
      MessageBox.Show("PicturesHubに保存しました。")
    End Using
  End Sub
End Class
  • 「画像にFilterをかけてPicturesHUBに保存する」サンプルプログラム

四国のSOHO。薬師寺国安(VBプログラマ)と、薬師寺聖(デザイナ、エンジニア)によるコラボレーション・ユニット。1997年6月、Dynamic HTMLとDirectAnimationの普及を目的として結成。共同開発やユニット名義での執筆活動を行う。XMLおよび.NETに関する著書や連載多数。最新刊は「Silverlight実践プログラミング」両名とも、Microsoft MVP for Development Platforms - Client App Dev (Oct 2003-Sep 2012)。http://www.PROJECTKySS.NET/

連載バックナンバー

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

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

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

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