カメラの向きを取得し、縦横の位置を合わせて表示させる
2012年1月13日(金)

ロジックコードを記述する
リスト2 (MainPage.xaml.vb)
01 | Option Strict On |
02 |
03 | ランチャーやチューザーに関するクラスの含まれる、Microsoft.Phone.Tasks名前空間をインポートします。 |
04 | Imports Microsoft.Phone.Tasks |
05 |
06 | CameraCaptureTask を使って取得した写真や画像を、ExifLib を使って正しい方向に回転して表示させるため、ExifLibをインポートしておきます。 |
07 | Imports ExifLib |
08 |
09 | JPEG ファイルを WriteableBitmap オブジェクトにデコードするPictureDecorderクラスの含まれる、Microsoft.Phone名前空間をインポートします。 |
10 | Imports Microsoft.Phone |
11 |
12 | Imports System.IO |
13 |
14 | 曲、アルバム、再生リスト、およびピクチャを列挙、再生、および表示するためのクラスの含まれる、Microsoft.Xna.Framework.Media名前空間をインポートします。ピクチャへのアクセスを提供するMediaLibrayクラスを使用するため、この名前空間のインポートが必要です。 |
15 | Imports Microsoft.Xna.Framework.Media |
16 |
17 | Imports System.Windows.Media.Imaging |
18 |
19 | Partial Public Class MainPage |
20 | Inherits PhoneApplicationPage |
21 |
22 | ' コンストラクター |
23 | Public Sub New() |
24 | InitializeComponent() |
25 | End Sub |
26 |
27 | CameraCaptureTaskクラス型のメンバ変数myCameraCaptureTaskを宣言します。 |
28 | Dim myCameraCaptureTask As CameraCaptureTask |
29 |
30 | Exifの情報を元にして画像を回転する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 |
ページがアクティブになった時呼び出されるメソッド
01 | AddHandlerステートメントで、チューザータスクが完了した時に発生するCompletedイベントにイベントハンドラを追加します。イベントハンドラ内では以下の処理が実行されます。 |
02 | カメラアプリケーションが起動して、写真がきちんと撮れた場合の処理です。 |
03 | ストリーム型のmyCaptureImageメンバ変数に、写真のデータ(ChosenPhoto)を含むストリームを格納します。ChosenPhoto.Positionプロパティに0を指定し、写真データの、現在のストリーム内の位置を設定します。 |
04 | ExifLibに属するJpegInfo型のinfo変数を宣言し、ExifReader.ReadJpegメソッドで、写真のEXIF データから向きを取得します。Exifの情報を元にして画像を回転するExifLib.ExifOrientaion型のメンバ変数myOrientationに、カメラの向きを格納します。カメラの向きがTopLeft、つまり横撮影であった場合は360画像を回転させます。カメラの向きがToRight、つまり縦撮影であった場合は90度画像を回転させます。 |
05 | 写真のデータを含む、ストリームのバイトの長さを取得し、バイト配列を作成します。Readメソッドで、現在のストリームからバイトシーケンスを読み取ります。 |
06 | ChosenPhoto.Readの書式は以下の通りです。 |
07 |
08 | ChosenPhoto.Read(バイト配列,0ベースのバイトオフセット(現在のストリームから読み取ったデータの格納を開始します), 現在のストリームから読み取るバイトの最大数) |
09 |
10 | Seekメソッドで、現在のストリーム内の位置を設定します。書式は以下の通りです。 |
11 |
12 | ChosePhoto.Seek(基点のパラメーターのバイト オフセット, 参照ポイントを示すSeekOrigin型の値) |
13 |
14 | SeekOriginにはBeginを指定し、ストリームの先頭を指定しています。 |
15 |
16 | WriteableBitmap型の変数imageSourceを宣言し、PictureDecoder.DecodeJpeg(resultArgs.ChosenPhoto)で、撮った写真をJPEGファイルとしてWriteableBitmapオブジェクトにデコードします。PictureDecoder.DecodeJpegメソッドはMicrosof.Phone名前空間に属しています。WriteableBitmapクラスは書き込み更新することのできるBitmapSourceを提供するクラスです。 |
17 |
18 | Image2の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に格納しておきます。 |
02 | Stream.Seek メソッドで、写真データの現在のストリーム内の位置を0に設定します。 |
03 | ピクチャへのアクセスを提供する新しいMediaLibrayクラスのインスタンス、myLibrayを作成します。 |
04 | MediaLibrary.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 |
13 | End Class |
今回でWindows Phone Tips集第2弾は終了です。いかがですか?「基本編」、「応用編」、「Tips」、「Tips第2弾」と、いろいろなサンプルを見てきましたが、Windows Phoneでのサンプルの作成方法は理解できましたでしょうか?とにかく自分で手を動かして作ってみることが重要です。今までのサンプルをヒントに自分なりのWindows Phoneアプリを作って、ぜひMarketplaceに申請していただきたいと思います。また機会があれば、Marketplaceへのアプリの申請方法についても紹介したいと思います。
この連載に引き続き、次回からはTips集の第3弾を公開しますのでご期待ください。では、どうもありがとうございました。
「撮った写真をカメラの向きに応じて表示させる」のサンプルファイル
連載バックナンバー
Think ITメルマガ会員登録受付中
Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。