カメラの向きを取得し、縦横の位置を合わせて表示させる

2012年1月13日(金)
PROJECT KySS

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

リスト2 (MainPage.xaml.vb)

01Option Strict On
02 
03ランチャーやチューザーに関するクラスの含まれる、Microsoft.Phone.Tasks名前空間をインポートします。
04Imports Microsoft.Phone.Tasks
05 
06CameraCaptureTask を使って取得した写真や画像を、ExifLib を使って正しい方向に回転して表示させるため、ExifLibをインポートしておきます。
07Imports ExifLib
08 
09JPEG ファイルを WriteableBitmap オブジェクトにデコードするPictureDecorderクラスの含まれる、Microsoft.Phone名前空間をインポートします。
10Imports Microsoft.Phone
11 
12Imports System.IO
13 
14曲、アルバム、再生リスト、およびピクチャを列挙、再生、および表示するためのクラスの含まれる、Microsoft.Xna.Framework.Media名前空間をインポートします。ピクチャへのアクセスを提供するMediaLibrayクラスを使用するため、この名前空間のインポートが必要です。
15Imports Microsoft.Xna.Framework.Media
16 
17Imports System.Windows.Media.Imaging
18 
19Partial Public Class MainPage
20  Inherits PhoneApplicationPage
21 
22  ' コンストラクター
23  Public Sub New()
24    InitializeComponent()
25  End Sub
26 
27CameraCaptureTaskクラス型のメンバ変数myCameraCaptureTaskを宣言します。
28  Dim myCameraCaptureTask As CameraCaptureTask
29 
30Exifの情報を元にして画像を回転するExifLib.ExifOrientaion型のメンバ変数myOrientationを宣言します。
31  Dim myOrientation As ExifLib.ExifOrientation
32 
33バイト型の配列、imageByteをメンバ変数として宣言します。
34  Dim imageBytes As Byte()
35 
36ストリーム型のmyCaptureImageメンバ変数を宣言します。
37  Dim myCaptureImage As Stream

ページがアクティブになった時呼び出されるメソッド

01AddHandlerステートメントで、チューザータスクが完了した時に発生するCompletedイベントにイベントハンドラを追加します。イベントハンドラ内では以下の処理が実行されます。
02カメラアプリケーションが起動して、写真がきちんと撮れた場合の処理です。
03ストリーム型のmyCaptureImageメンバ変数に、写真のデータ(ChosenPhoto)を含むストリームを格納します。ChosenPhoto.Positionプロパティに0を指定し、写真データの、現在のストリーム内の位置を設定します。
04ExifLibに属するJpegInfo型のinfo変数を宣言し、ExifReader.ReadJpegメソッドで、写真のEXIF データから向きを取得します。Exifの情報を元にして画像を回転するExifLib.ExifOrientaion型のメンバ変数myOrientationに、カメラの向きを格納します。カメラの向きがTopLeft、つまり横撮影であった場合は360画像を回転させます。カメラの向きがToRight、つまり縦撮影であった場合は90度画像を回転させます。
05写真のデータを含む、ストリームのバイトの長さを取得し、バイト配列を作成します。Readメソッドで、現在のストリームからバイトシーケンスを読み取ります。
06ChosenPhoto.Readの書式は以下の通りです。
07 
08ChosenPhoto.Read(バイト配列,0ベースのバイトオフセット(現在のストリームから読み取ったデータの格納を開始します), 現在のストリームから読み取るバイトの最大数)
09 
10Seekメソッドで、現在のストリーム内の位置を設定します。書式は以下の通りです。
11 
12ChosePhoto.Seek(基点のパラメーターのバイト オフセット, 参照ポイントを示すSeekOrigin型の値)
13 
14SeekOriginにはBeginを指定し、ストリームの先頭を指定しています。
15 
16WriteableBitmap型の変数imageSourceを宣言し、PictureDecoder.DecodeJpeg(resultArgs.ChosenPhoto)で、撮った写真をJPEGファイルとしてWriteableBitmapオブジェクトにデコードします。PictureDecoder.DecodeJpegメソッドはMicrosof.Phone名前空間に属しています。WriteableBitmapクラスは書き込み更新することのできるBitmapSourceを提供するクラスです。
17 
18Image2のSourceプロパティにデコードされたJPEGファイルを格納しているimageSourceオブジェクトを指定します。これでImage内に、撮った写真が表示されます。縦撮影の場合は縦向きで、横撮影の場合は横向きで表示されます。
19カメラを起動している状態で撮影を中止した場合は、saveButton(フロッピーのアイコン)は使用不可のままで処理を抜けます。
20 
21  Protected Overrides Sub OnNavigatedTo(e As System.Windows.Navigation.NavigationEventArgs)
22    myCameraCaptureTask = New CameraCaptureTask
23    AddHandler myCameraCaptureTask.Completed, Sub(resultSender As Object, resultArgs As PhotoResult)
24          If resultArgs.TaskResult = TaskResult.OK Then
25              myCaptureImage = resultArgs.ChosenPhoto
26              resultArgs.ChosenPhoto.Position = 0
27              Dim info As JpegInfo = ExifReader.ReadJpeg(resultArgs.ChosenPhoto, resultArgs.OriginalFileName)
28              myOrientation = info.Orientation
29              Dim myAngle As Integer = 0
30              Select Case info.Orientation
31                     Case ExifOrientation.TopLeft 'カメラ横向き
32                           myAngle = 0
33                           Exit Select
34                     Case ExifOrientation.TopRight 'カメラ縦向き
35                           myAngle = 90
36                           Exit Select
37                     End Select
38                     myComposite.Rotation = myAngle
39                     imageBytes = New Byte(CInt(resultArgs.ChosenPhoto.Length)) {}
40                     resultArgs.ChosenPhoto.Read(imageBytes, 0, imageBytes.Length)
41                     resultArgs.ChosenPhoto.Seek(0, SeekOrigin.Begin)
42                     Dim imageSource As WriteableBitmap = PictureDecoder.DecodeJpeg(resultArgs.ChosenPhoto)
43                     Image2.Source = imageSource
44              Else
45                     saveButton.IsEnabled = False
46                     Exit Sub
47              End If
48          End Sub
49    MyBase.OnNavigatedTo(e)
50  End Sub

カメラボタンがタップされた時の処理

1カメラ機能を起動し、保存ボタン(フロッピーのアイコン)の使用を可能にします。
2  Private Sub cameraButton_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles cameraButton.Click
3    MessageBox.Show("カメラの解像度を低く設定し、設定の保存を行って、写真を撮ってください。")
4    myCameraCaptureTask.Show()
5    saveButton.IsEnabled = True
6  End Sub

保存(フロッピーのアイコン)ボタンがタップされた時の処理

01保存する画像のファイル名を作成します。現在の日付と時間(秒を含む)を連結したファイル名にします。日付の/を-に、時間の:を-にReplace関数で書き換えます。このファイル名を変数imageFileNameに格納しておきます。
02Stream.Seek メソッドで、写真データの現在のストリーム内の位置を0に設定します。
03ピクチャへのアクセスを提供する新しいMediaLibrayクラスのインスタンス、myLibrayを作成します。
04MediaLibrary.SavePictureメソッドで、ストリームオブジェクトに含まれる画像を、指定したファイル名で、メディアライブラリーに保存し、その保存した画像をピクチャオブジェクトとして返します。保存した旨のメッセージを表示します。
05  Private Sub saveButton_Click(sender As Object, e As System.Windows.RoutedEventArgs) Handles saveButton.Click
06    Dim imageFileName As String = DateTime.Now.ToString("yyyyMMddHHmmss") &".jpg"
07     
08    myCaptureImage.Seek(0, 0)
09    Dim myLibray As New MediaLibrary
10    myLibray.SavePicture(imageFileName, myCaptureImage)
11    MessageBox.Show("PicturesHubに保存しました。")
12  End Sub
13End Class

今回でWindows Phone Tips集第2弾は終了です。いかがですか?「基本編」、「応用編」、「Tips」、「Tips第2弾」と、いろいろなサンプルを見てきましたが、Windows Phoneでのサンプルの作成方法は理解できましたでしょうか?とにかく自分で手を動かして作ってみることが重要です。今までのサンプルをヒントに自分なりのWindows Phoneアプリを作って、ぜひMarketplaceに申請していただきたいと思います。また機会があれば、Marketplaceへのアプリの申請方法についても紹介したいと思います。

この連載に引き続き、次回からはTips集の第3弾を公開しますのでご期待ください。では、どうもありがとうございました。

  • 「撮った写真をカメラの向きに応じて表示させる」のサンプルファイル

四国の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メルマガ会員のサービス内容を見る

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