PR

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

2012年1月13日(金)
PROJECT KySS

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

リスト2 (MainPage.xaml.vb)

Option Strict On

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

CameraCaptureTask を使って取得した写真や画像を、ExifLib を使って正しい方向に回転して表示させるため、ExifLibをインポートしておきます。
Imports ExifLib

JPEG ファイルを WriteableBitmap オブジェクトにデコードするPictureDecorderクラスの含まれる、Microsoft.Phone名前空間をインポートします。
Imports Microsoft.Phone 

Imports System.IO

曲、アルバム、再生リスト、およびピクチャを列挙、再生、および表示するためのクラスの含まれる、Microsoft.Xna.Framework.Media名前空間をインポートします。ピクチャへのアクセスを提供するMediaLibrayクラスを使用するため、この名前空間のインポートが必要です。
Imports Microsoft.Xna.Framework.Media

Imports System.Windows.Media.Imaging

Partial Public Class MainPage
  Inherits PhoneApplicationPage

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

CameraCaptureTaskクラス型のメンバ変数myCameraCaptureTaskを宣言します。
  Dim myCameraCaptureTask As CameraCaptureTask

Exifの情報を元にして画像を回転するExifLib.ExifOrientaion型のメンバ変数myOrientationを宣言します。
  Dim myOrientation As ExifLib.ExifOrientation

バイト型の配列、imageByteをメンバ変数として宣言します。
  Dim imageBytes As Byte()

ストリーム型のmyCaptureImageメンバ変数を宣言します。
  Dim myCaptureImage As Stream

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

AddHandlerステートメントで、チューザータスクが完了した時に発生するCompletedイベントにイベントハンドラを追加します。イベントハンドラ内では以下の処理が実行されます。
カメラアプリケーションが起動して、写真がきちんと撮れた場合の処理です。
ストリーム型のmyCaptureImageメンバ変数に、写真のデータ(ChosenPhoto)を含むストリームを格納します。ChosenPhoto.Positionプロパティに0を指定し、写真データの、現在のストリーム内の位置を設定します。
ExifLibに属するJpegInfo型のinfo変数を宣言し、ExifReader.ReadJpegメソッドで、写真のEXIF データから向きを取得します。Exifの情報を元にして画像を回転するExifLib.ExifOrientaion型のメンバ変数myOrientationに、カメラの向きを格納します。カメラの向きがTopLeft、つまり横撮影であった場合は360画像を回転させます。カメラの向きがToRight、つまり縦撮影であった場合は90度画像を回転させます。
写真のデータを含む、ストリームのバイトの長さを取得し、バイト配列を作成します。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を提供するクラスです。

Image2のSourceプロパティにデコードされたJPEGファイルを格納しているimageSourceオブジェクトを指定します。これでImage内に、撮った写真が表示されます。縦撮影の場合は縦向きで、横撮影の場合は横向きで表示されます。
カメラを起動している状態で撮影を中止した場合は、saveButton(フロッピーのアイコン)は使用不可のままで処理を抜けます。

  Protected Overrides Sub OnNavigatedTo(e As System.Windows.Navigation.NavigationEventArgs)
    myCameraCaptureTask = New CameraCaptureTask
    AddHandler myCameraCaptureTask.Completed, Sub(resultSender As Object, resultArgs As PhotoResult)
          If resultArgs.TaskResult = TaskResult.OK Then
              myCaptureImage = resultArgs.ChosenPhoto
              resultArgs.ChosenPhoto.Position = 0
              Dim info As JpegInfo = ExifReader.ReadJpeg(resultArgs.ChosenPhoto, resultArgs.OriginalFileName)
              myOrientation = info.Orientation
              Dim myAngle As Integer = 0
              Select Case info.Orientation
                     Case ExifOrientation.TopLeft 'カメラ横向き
                           myAngle = 0
                           Exit Select
                     Case ExifOrientation.TopRight 'カメラ縦向き
                           myAngle = 90
                           Exit Select
                     End Select
                     myComposite.Rotation = myAngle
                     imageBytes = New Byte(CInt(resultArgs.ChosenPhoto.Length)) {}
                     resultArgs.ChosenPhoto.Read(imageBytes, 0, imageBytes.Length)
                     resultArgs.ChosenPhoto.Seek(0, SeekOrigin.Begin)
                     Dim imageSource As WriteableBitmap = PictureDecoder.DecodeJpeg(resultArgs.ChosenPhoto)
                     Image2.Source = imageSource
              Else
                     saveButton.IsEnabled = False
                     Exit Sub
              End If
          End Sub
    MyBase.OnNavigatedTo(e)
  End Sub

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

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

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

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

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

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

Think IT会員限定特典
  • 「撮った写真をカメラの向きに応じて表示させる」のサンプルファイル

四国の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のWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

Think IT会員サービスの概要とメリットをチェック

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