撮影した写真を分離ストレージとPicturesHUBに保存する
2012年2月13日(月)
「Windows Phone 縦向きのページ」(SavePicturesHUB.xaml)の作成
VS2010メニューの[プロジェクト(P)/新しい項目の追加(W)]と選択し、「Windows Phone 縦向きのページ」を選択します。「名前(N)」にはSavePicturesHUB.xamlと入力します。
SavePicturesHUB.xamlの編集とコントロールの追加
x:NameがPageTitleというTextBlockのTextプロパティに「PicturesHUBに保存」と指定します。名前がPageTitleのTextBlockのStyleプロパティに指定されているPhoneTextTitle1Styleでは、文字サイズが大きすぎるので、PhoneTextTitle2Styleを指定します。文字サイズが小さくなって表示されます。これらのスタイルは前述の「Theme Resources for Windows Phone」で定義されています。{StaticResource}を使用して、これらのテーマリソースを参照します。
ツールボックスからImageコントロールを1個、Buttonコントロールを1個配置します。ImageコントロールのWidthに400、Heightに360を指定します(図7)。
図7:ImageとButtonコントロールを配置した(クリックで拡大) |
書き出されるXAMLは省略します。
次に、MainPage.xamlを展開して表示される、MainPage.xaml.vbをダブルクリックしてリスト3のコードを記述します。
ロジックコードを記述する
リスト3 (MainPage.xaml.vb)
Option Strict On ランチャーやチューザーに関するクラスの含まれる、Microsoft.Phone.Tasks名前空間をインポートします。 Imports Microsoft.Phone.Tasks Imports System.Windows.Media.Imaging Imports Microsoft.Phone 仮想ファイルシステムを作成および使用するための型が含まれている、System.IO.IsolatedStorage名前空間をインポートします。分離ストレージによって、安全なクライアント側のストレージが提供されます。 Imports System.IO.IsolatedStorage Imports System.IO Imports System.Xml.Linq Partial Public Class MainPage Inherits PhoneApplicationPage ' コンストラクター Public Sub New() InitializeComponent() End Sub 数値型の定数変数ImageWidthに400、ImageHeightに360を格納しておきます。 Const ImageWidth As Integer= 400 Const ImageHeight As Integer= 360 バイト型の配列、imageByteをメンバ変数として宣言します。 Dim imageByte As Byte() カメラアプリケーションを起動するCameraCaptureTaskクラス用メンバ変数、myCameraTaskを宣言します。 Dim myCameraTask As CameraCaptureTask
ページがアクティブになった時の処理
新しいCameraCaptureTaskクラスのインスタンス、myCameraTaskオブジェクトを作成します。 AddHandlerステートメントで、チューザータスクが完了した時に発生するCompletedイベントに、イベントハンドラを追加します。イベントハンドラ内では以下の処理が実行されます。 カメラアプリケーションが起動して、写真がきちんと撮れた場合は、写真のデータを含むストリームのバイトの長さを取得し、バイト配列を作成します。Readメソッドで、現在のストリームからバイトシーケンスを読み取り、読み取ったバイト数でストリーム内の位置を進めます。 ChosenPhoto.Readの書式は以下の通りです。 ChosenPhoto.Read(バイト配列,0ベースのバイトオフセット(現在のストリームから読み取ったデータの格納を開始します), 現在のストリームから読み取るバイトの最大数) Seekメソッドで、現在のストリーム内の位置を設定します。書式は以下の通りです。 ChosePhoto.Seek(基点のパラメーターのバイト オフセット, 参照ポイントを示すSeekOrigin型の値) SeekOriginにはBeginを指定し、ストリームの先頭を指定しています。 WriteableBitmap型の変数imageSourceを宣言し、PictureDecoder.DecodeJpeg(resultArgs.ChosenPhoto)で、撮った写真をJPEGファイルとしてWriteableBitmapオブジェクトにデコードします。PictureDecoder.DecodeJpegメソッドはMicrosof.Phone名前空間に属しています。WriteableBitmapクラスは書き込み更新することのできるBitmapSourceを提供するクラスです。 Image1のSourceプロパティにimageSourceオブジェクトを指定します。これでImage内に撮った写真が表示されます。 カメラを起動している状態で撮影を中止した場合は、saveButtonは使用不可のままで処理を抜けます。 変数storageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。分離ストレージ内にImageというフォルダが存在しない場合は、CreateDirectoryメソッドでImageというフォルダを作成します。 Path.Combineメソッドで、2つの文字列を1つのパスに結合します。ここでは、ImageフォルダとimageFileList.xmlを結合しています。Image\imageFileList.xmlとなります。この値をxmlFilePath変数に格納します。FileExistsメソッドでxmlFilePathに格納したファイルが存在する場合は、ichiranButton(データ一覧)の使用を可能にします。そうでない場合は、不可のままです。 Protected Overrides Sub OnNavigatedTo(e As System.Windows.Navigation.NavigationEventArgs) myCameraTask = New CameraCaptureTask AddHandler myCameraTask.Completed, Sub(resultSender As Object, resultArgs As PhotoResult) If resultArgs.TaskResult = TaskResult.OK Then imageByte = New Byte(CInt(resultArgs.ChosenPhoto.Length)) {} resultArgs.ChosenPhoto.Read(imageByte, 0, imageByte.Length) resultArgs.ChosenPhoto.Seek(0, IO.SeekOrigin.Begin) Dim imageSource As WriteableBitmap = PictureDecoder.DecodeJpeg(resultArgs.ChosenPhoto) Image1.Source = imageSource Else saveButton.IsEnabled = False Exit Sub End If End Sub Dim storage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication If storage.DirectoryExists("Image") = False Then storage.CreateDirectory("Image") End If Dim xmlFilePath As String = Path.Combine("Image", "imageFileList.xml") If storage.FileExists(xmlFilePath) = True Then ichiranButton.IsEnabled = True Else ichiranButton.IsEnabled = False End If MyBase.OnNavigatedTo(e) End Sub
[カメラ]ボタンがタップされた時の処理
Showメソッドでカメラアプリケーションを起動します。saveButtonの使用を可能にします。 Private Sub cameraButton_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles cameraButton.Click myCameraTask.Show() saveButton.IsEnabled = True End Sub
[保存]ボタンがタップされた時の処理
保存する画像のファイル名を作成します。現在の「年月日時間分秒.jpg」というファイル名を作成し、変数imageFileNameに格納しておきます。 変数storageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。 Path.CombineでImageというフォルダとimageFileNameに格納されている画像名とを連結し、変数filePathに格納しておきます。 書き込みおよび更新が可能な BitmapSourceを提供する、Image1で初期化された、WriteableBitmapクラス型の新しいインスタンスmyWriteableBitmap変数を宣言します。WriteableBitmapクラスの第2引数には、ビットマップに特定の変換を適用するTransformを指定できますが、ここではNothingを指定します。 分離ストレージ内のファイルを表すIsolatedStorageFileStreamクラス用オブジェクト変数myStream変数を用意し、IsolatedStorageFile.CreateFileメソッドで、分離ストレージ内にfilePath変数の持っているフォルダ内に画像ファイルを作成します。 Extensions.SaveJpegメソッドで、WriteableBitmapオブジェクトを、JPEGストリームにエンコードします。これは、JPEGファイルのターゲットとなる幅と高さを設定するためのパラメーターを持っています。ここで、指定したサイズの画像にエンコードします。書式は下記の通りです。 Extensions.SaveJpeg(WriteableBitmapオブジェクト,イメージデータストリーム,WriteableBitmapオブジェクトのPixelWidth, WriteableBitmapオブジェクトのPixelHeight,0(固定),0~100の間の写真の品質(70以上を指定)) WriteableBitmapオブジェクトのPixelWidthに400を格納している定数変数ImageWidthを指定し、WriteableBitmapオブジェクトのPixelHeightに360を格納している定数変数ImageHeightを指定します。 次に、IsolatedStorageFileStream.Writeメソッドで、バイト配列から読み取ったデータを使用して、IsolatedStorageFileStreamオブジェクトにバイトのブロックを書き込みます。 IsolatedStorageFileStream.Writeメソッドの書式は下記の通りです。 IsolatedStorageFileStream.Write(書き込むバッファ, 開始位置を示すバッファ内のバイト オフセット,書き込む最大バイト数) 変数xmlStorageを、ファイルとディレクトリを格納している分離ストレージ領域を表すIsolateStorageFileクラスとして宣言します。Path.Combineで、Imageというフォルダ名と、imageFileList.xmlという画像ファイル名を記録したXMLファイルを連結し、xmlFilePath変数に格納しておきます。 Imageというフォルダ内にimageFileList.xmlが存在していない場合は、Visual Basic の埋め込み式を用いて、XML宣言とルート要素image、その子要素としてfileName、fileName要素の属性に”imageFileName”を指定し、埋め込み式の構文である <%= expression %>を用いて”imageFileName”属性の値に、imageFileName変数の値を指定します。これは ASP.NET で使用される構文と同じです。 分離ストレージ内のファイルを表すIsolatedStorageFileStreamクラス用オブジェクト変数xmlStreamを用意し、IsolatedStorageFile.CreateFileメソッドで、分離ストレージ内にxmlFilePath変数の持っているフォルダ名付きXMLファイルを作成します。 Imageフォルダ内にimageFileList.xmlファイルが存在すれば、新しいStreamWriter 生成し、IsolatedStorageFile.OpenFileメソッドで、指定したファイルアクセスを使用して指定したモードでファイルを開き、初期化します。Writeメソッドで埋め込み式のXMLをストリームに書き込みます。 次は、既にImageフォルダ内にimageFileList.xmlが存在する場合の処理です。 IsolatedStorageFileクラスのOpenFileメソッドでImageフォルダ内のimageFileList.xmlファイルを、指定したファイルアクセスを使用して指定したモードでファイルを開きます。開いたファイルをStreamReaderで読み込みます。ReadToEndメソッドでファイルの最後まで読み取り変数readXmldoc変数に格納しておきます。読み込んだXMLテキストをParseメソッドでXElementとして読み込みます。 追加するfileName要素を、埋め込み式を用いて生成し、”imageFileName”属性の値を指定します。新しく生成したXML要素を、読み込んだXMLにAddメソッドで追加します。IsolatedStorageFileStreamを閉じます。 imageFileList.xmlファイルが存在する場合は、新しいStreamWriter を生成し、IsolatedStorageFile.OpenFileメソッドで、指定したファイルアクセスを使用して指定したモードでファイルを開き、初期化します。Writeメソッドで、新しいXML要素の追加されたXMLを、ストリームに書き込みます。保存した旨のメッセージを表示します。 [データ一覧]ボタンの使用を可能にし、画像の表示されていた領域をクリアし、[保存]ボタンの使用を不可とします。 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 storage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication Dim filePath As String = Path.Combine("Image", imageFileName) Dim myWriteableBitmap As New WriteableBitmap(Image1, Nothing) Using myStream As IsolatedStorageFileStream = storage.CreateFile(filePath) System.Windows.Media.Imaging.Extensions.SaveJpeg(myWriteableBitmap, myStream, ImageWidth, ImageHeight, 0, 85) myStream.Write(imageByte, 0, imageByte.Length) End Using Dim xmlStorage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication Dim xmlFilePath As String = Path.Combine("Image", "imageFileList.xml") If xmlStorage.FileExists(xmlFilePath) = False Then Dim xmldoc As XDocument = <?xml version="1.0" encoding="utf-8"?> <image> <fileName imageFileName=<%= imageFileName %>></fileName> </image> Using xmlStream As IsolatedStorageFileStream = xmlStorage.CreateFile(xmlFilePath) End Using If xmlStorage.FileExists(xmlFilePath) = True Then Using xmlwriter As StreamWriter = New StreamWriter(xmlStorage.OpenFile(xmlFilePath, FileMode.Open, FileAccess.Write)) xmlwriter.Flush() xmlwriter.Write(xmldoc.ToString) End Using End If Else Dim xmlStream As IsolatedStorageFileStream = xmlStorage.OpenFile(xmlFilePath, FileMode.Open, FileAccess.Read) Using xmlreader As StreamReader = New StreamReader(xmlStream) Dim readXmldoc As String = xmlreader.ReadToEnd Dim doc As XElement = XElement.Parse(readXmldoc) Dim addXml As XElement = <fileName imageFileName=<%= imageFileName %>></fileName> doc.Add(addXml) xmlStream.Close() If xmlStorage.FileExists(xmlFilePath) = True Then Using xmlwriter As StreamWriter = New StreamWriter(storage.OpenFile(xmlFilePath, FileMode.Open, FileAccess.Write)) xmlwriter.Flush() xmlwriter.Write(doc.ToString) MessageBox.Show("画像とXMLファイルを保存しました。") End Using End If End Using End If Image1.Source = Nothing saveButton.IsEnabled = False ichiranButton.IsEnabled = True End Sub
[データ一覧]ボタンがタップされた時の処理
DataShowPage.xamlに遷移します。 Private Sub ichiranButton_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles ichiranButton.Click NavigationService.Navigate(New Uri("/DataShowPage.xaml", UriKind.Relative)) End Sub End Class
次に、DataShowPage.xamlを展開して表示される、DataShowPage.xaml.vbをダブルクリックしてリスト4のコードを記述します。
「撮影した写真を分離ストレージとPicturesHUBに保存する」サンプルプログラム
連載バックナンバー
Think ITメルマガ会員登録受付中
Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。