撮影した写真を分離ストレージとPicturesHUBに保存する

2012年2月13日(月)
PROJECT KySS

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

リスト4 (MainPage.xaml.vb)

    Option Strict On
    Imports System.Xml.Linq
    Imports System.IO
    Imports System.IO.IsolatedStorage
    Imports System.Windows.Media.Imaging
    Imports Microsoft.Phone

ImageInfoクラス内にWriteableBitmapクラス型のimageFileNameを定義しておきます。
    Public Class ImageInfo
      Property imageFileName As WriteableBitmap
    End Class

    Partial Public Class DataShowPage
      Inherits PhoneApplicationPage
 
      Public Sub New()
        InitializeComponent()
      End Sub

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

変数storageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。Path.CombineでImageというフォルダとimageFileList.xmlというXMLファイル名と連結します。
分離ストレージ内のファイルを表すIsolatedStorageFileStreamクラス用オブジェクト変数myStreamを用意し、IsolatedStorageFileクラスのOpenFileメソッドでImageフォルダ内のimageFileList.xmlファイルを、指定したファイルアクセスを使用して指定したモードでファイルを開きます。開いたファイルをStreamReaderで読み込みます。ReadToEndメソッドでファイルの最後まで読み取り変数readXmldoc変数に格納しておきます。
読み込んだXMLテキストをParseメソッドでXElementとして読み込みます。ImageInfoクラス型の新しいリストであるmyImageInfoオブジェクトを作成します。
Descendantsメソッドで、子孫要素であるすべての <fileName> 要素のコレクションを選択し、各要素を、変数resultに格納しながら、以下の処理を繰り返します。
Path.CombineでImageフォルダと、<fileName>要素の属性”imageFileName”の値を連結して、変数imageFilePathに格納しておきます。変数imageStorageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。IsolatedStorageFileクラスのOpenFileメソッドでImageフォルダ内のimageFileList.xmlファイルを、指定したファイルアクセスを使用して指定したモードでファイルを開きます。WriteableBitmap型の変数imageSourceを宣言し、PictureDecoder.DecodeJpegメソッドで、開いたストリームをJPEGファイルとしてWriteableBitmapオブジェクトにデコードします。PictureDecoder.DecodeJpegメソッドはMicrosof.Phone名前空間に属しています。WriteableBitmapクラスは書き込み更新することのできるBitmapSourceを提供するクラスです。
ImageInfoクラスのimageFileNameプロパティに、読み込んだWriteableBitmapオブジェクトのimageSourceオブジェクトを指定し、AddメソッドでmyImageInfoオブジェクトに追加していきます。ListBox1のItemsSourceプロパティにmyImageInfoオブジェクトを指定します。これで、撮った画像の一覧が表示されます。
  Protected Overrides Sub OnNavigatedTo(e As System.Windows.Navigation.NavigationEventArgs)
    Dim storage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
    Dim filePath As String = Path.Combine("Image", "imageFileList.xml")
    Using myStream As IsolatedStorageFileStream = storage.OpenFile(filePath, FileMode.Open, FileAccess.Read)
      Using reader As StreamReader = New StreamReader(myStream)
        Dim readXmldoc As String = reader.ReadToEnd
        Dim doc As XElement = XElement.Parse(readXmldoc)
        Dim myImageInfo As New List(Of ImageInfo)
 
        For Each result In From c In doc.Descendants("fileName") Select c
          Dim imageFilePath As String = Path.Combine("Image", result.Attribute("imageFileName").Value)
          Dim imageStorage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
          Using stream As IsolatedStorageFileStream = imageStorage.OpenFile(imageFilePath, FileMode.Open, FileAccess.Read)
            Dim imageSource As WriteableBitmap = PictureDecoder.DecodeJpeg(stream)
            With myImageInfo
              .Add(New ImageInfo With {.imageFileName = imageSource})
            End With
            'stream.Close()
          End Using
        Next
        ListBox1.ItemsSource = myImageInfo
      End Using
    End Using
 
    MyBase.OnNavigatedTo(e)
  End Sub

一覧の画像から任意の画像を選択した時の処理

選択された画像のIndexを引数に、SavePicturesHUBに遷移します。
    Private Sub ListBox1_SelectionChanged(sender As Object, e As System.Windows.Controls.SelectionChangedEventArgs) Handles ListBox1.SelectionChanged
      NavigationService.Navigate(New Uri(String.Format("/SavePicturesHUB.xaml?Index={0}", ListBox1.SelectedIndex.ToString), UriKind.Relative))
    End Sub
  End Class

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

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

リスト5 (SavePicturesHUB.xaml.vb)

    Option Strict On
    Imports System.Xml.Linq
    Imports System.IO
    Imports System.IO.IsolatedStorage
    Imports System.Windows.Media.Imaging
    Imports Microsoft.Phone
    Imports Microsoft.Xna.Framework.Media

    Partial Public Class AddEyeMaskPage
      Inherits PhoneApplicationPage
 
      Public Sub New()
        InitializeComponent()
      End Sub
      Dim myIndex As Integer
      Dim imageName As String
      Dim imageFileName As String

WriteableBitmapクラス型のメンバ変数、imageSourceを宣言します。
      Dim imageSource As WriteableBitmap

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

DataShowPage.xamlから渡された文字データを受け取ります。文字データはNavigationContextのQueryStringにDictionary として提供されます。送信時のキーワード(この場合Index)を基に渡された文字列情報の値(myParam(“Index”))を取得します。取得した値をInteger.Parseメソッドで数値に変換し、変数myIndexに格納しておきます。
変数storageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。Path.CombineでImageというフォルダとimageFileList.xmlというXMLファイル名と連結し、変数filePathに格納します。
分離ストレージ内のファイルを表すIsolatedStorageFileStreamクラス用オブジェクト変数myStreamを用意し、IsolatedStorageFileクラスのOpenFileメソッドでImageフォルダ内のimageFileList.xmlファイルを、指定したファイルアクセスを使用して指定したモードでファイルを開きます。開いたファイルをStreamReaderで読み込みます。ReadToEndメソッドでファイルの最後まで読み取り変数readXmldoc変数に格納しておきます。
読み込んだXMLテキストをParseメソッドでXElementとして読み込みます。DataShowPageで選択されたインデック該当する<fileName>要素の属性”imageFileName”の値を、変数imageNameに格納します。Path.CombineでImageというフォルダと、変数imageNameに格納されている画像名を連結し、imageFileNameに格納します。

変数imageStorageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。IsolatedStorageFileクラスのOpenFileメソッドで変数imageFileNameに格納されている画像ファイルを、指定したファイルアクセスを使用して指定したモードでファイルを開きます。PictureDecoder.DecodeJpegメソッドで、開いたストリームをJPEGファイルとしてWriteableBitmapオブジェクトにデコードし、imageSource変数で参照します。PictureDecoder.DecodeJpegメソッドはMicrosof.Phone名前空間に属しています。WriteableBitmapクラスは書き込み更新することのできるBitmapSourceを提供するクラスです。Image1のSourceプロパティにimageSourceオブジェクトを指定します。DataShowPage.xamlで選択された画像が表示されます。
    Protected Overrides Sub OnNavigatedTo(e As System.Windows.Navigation.NavigationEventArgs)
      Dim myParam As IDictionary(Of String, String) = NavigationContext.QueryString
      myIndex = Integer.Parse(myParam("Index"))
 
      Dim storage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
      Dim filePath As String = Path.Combine("Image", "imageFileList.xml")
      Using myStream As IsolatedStorageFileStream = storage.OpenFile(filePath, FileMode.Open, FileAccess.Read)
        Using reader As StreamReader = New StreamReader(myStream)
          Dim readXmldoc As String = reader.ReadToEnd
          Dim doc As XElement = XElement.Parse(readXmldoc)
          imageName = doc.Descendants("fileName")(myIndex).Attribute("imageFileName").Value
          imageFileName = Path.Combine("Image", imageName)
            Dim imageStorage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication
          Using stream As IsolatedStorageFileStream = imageStorage.OpenFile(imageFileName, FileMode.Open, FileAccess.Read)
            imageSource  = PictureDecoder.DecodeJpeg(stream)
            Image1.Source = imageSource
          End Using
        End Using
      End Using
      MyBase.OnNavigatedTo(e)
    End Sub

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

保存する画像のファイル名を作成します。現在の「年月日時間分秒.jpg」ファイルを作成し、変数imageFileNameに格納しておきます。
書き込みおよび更新が可能な BitmapSourceを提供する、WriteableBitmapクラス型のmyWriteableBitmap変数を宣言します。Image1で初期化された、新しいWriteableBitmapのインスタンスmyWriteableBitmapオブジェクトを作成します。WriteableBitmapクラスの第2引数には、ビットマップに特定の変換を適用するTransformを指定できますが、ここではNothingを指定します。
変数storageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。FileExistsメソッドで、imageNameに格納されている画像ファイルが存在しているかどうかをチェックし、存在している場合は、DeleteFileメソッドで同名ファイルを削除します。
分離ストレージ内のファイルを表すIsolatedStorageFileStreamクラス用オブジェクト変数myStream変数を用意し、IsolatedStorageFile.CreateFileメソッドで、分離ストレージ内にimageFileName変数(Image\年月日時間分秒.jpgが格納されている)の持っているファイルを作成します。
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メソッドで、ストリームオブジェクトに含まれる画像を、メディアライブラリーに保存し、その保存した画像をピクチャオブジェクトとして返します。保存した旨のメッセージを表示します。
    Private Sub saveButton_Click(sender As System.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(imageName) = True Then
        storage.DeleteFile(imageName)
      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, IO.FileMode.Open, IO.FileAccess.Read)
          myLibray.SavePicture(imageFileName, Stream)
          MessageBox.Show("PicturesHubに保存しました。")
        End Using
      End Sub
    End Class
  • 「撮影した写真を分離ストレージと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メルマガ会員のサービス内容を見る

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