Adobe AIR for iOSによるiPhone/iPadアプリケーション開発第4回 カメラとカメラロール

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

本記事は工学社月刊I/O 2012年1月号に掲載された記事の原稿をブログ化したものです。本誌の記事の内容とは異なる場合があります。転載に関しては工学社様の許可を得ております。

また、下記記事も併せてご参照ください。

Adobe AIR for iOSによるiPhone/iPadアプリケーション開発 第4回 カメラとカメラロール

■はじめに

スマートフォンにはカメラが必ずと言っていいほどついていると思います。今回はAIR for iOSに用意されているカメラ周りのAPIを用いて、簡単なカメラとそのカメラで撮った画像をiPhoneのカメラロールに保存するアプリケーションを作成していきます。

■Flexモバイルプロジェクトの準備

以下の手順でFlexモバイルプロジェクトを作成していきます。

  • Flexモバイルプロジェクトの作成(記事ではプロジェクト名は「MonethlyIO_04_Camera」)
  • パッケージエクスプローラで(default package)以下のMonthlyIO_04_Camera.mxmlをMain.mxmlに変更します。F2で名前変更が可能です。
  • src\Main-app.xmlを編集します。nameタグを「カメラ」とします。
  • 不要になるMonthlyIO_04_CameraHomeViewを削除しておきます。
  • プロジェクトのプロパティ>Flexビルドのパッケージ化で証明書とプロビジョニングファイルを設定します。

■Viewの実装

画面のロジッククラスであるViewを実装します。メニューからファイル>新規>ActionScriptクラスを選択します。名前を「HomeView」、スーパークラスを「View」とします。スーパークラスは参照ボタンクリックして指定します。

この段階で、Main,mxmlのルートタグにあるfirstViewをviews.HomeViewに変更しておきます。

<s:ViewNavigatorApplication 
	xmlns:fx="http://ns.adobe.com/mxml/2009" 
	xmlns:s="library://ns.adobe.com/flex/spark" firstView="views.HomeView">

(Main.mxmlソースコード前半)

Viewには画面のロジック(イベントハンドラ)を記述していきます。

[SkinState("portrait")]
[SkinState("landscape")]
[SkinState("normal")]
[SkinState("disabled")]
public class HomeView extends View {
	public function HomeView() {
		super();		
		setStyle("skinClass", HomeViewSkin);
	}

	[SkinPart]
	public var cameraUIButton:Button;
		
	[SkinPart]
	public var cameraRollButton:Button;
	
	[SkinPart]
	public var saveButton:Button;
	
	[SkinPart]
	public var cameraImage:Image;
}

(HomeView.asソースコード)

ここで登場する画面コンポーネントは、カメラを起動するcameraUIButton、端末のカメラロール(画像ファイル置き場)を開くcameraRollButton、画像を保存するsaveButton、カメラで撮った写真を表示するcameraImageの4つです。

いったんここでSkinの実装に移ります。

■Skinの実装

先ほど作成したViewに対応した画面を表すクラスであるSkinを作成します。メニューからファイル>新規>MXMLスキンを選択します。

名前を「HomeViewSkin」、ホストコンポーネントに先ほど作成したHomeViewを指定します。このホストコンポーネントの指定によりViewとSkinが関連付けられます。

<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
		xmlns:s="library://ns.adobe.com/flex/spark"
	>
	<!-- host component -->
	<fx:Metadata>
		[HostComponent("views.HomeView")]
	</fx:Metadata>	
	<!-- states -->
	<s:states>
		<s:State name="portrait" />
		<s:State name="landscape" />
		<s:State name="normal" />
		<s:State name="disabled" />
	</s:states>
	<s:VGroup id="myGroup" width="100%" height="100%">
		<s:HGroup width="100%" height="110" paddingBottom="30" paddingLeft="10" paddingRight="10"
			  paddingTop="30" verticalAlign="middle" horizontalAlign="center">
			<s:Button id="cameraUIButton" width="190" height="60" label="カメラ起動" fontSize="18"/>
			<s:Button id="cameraRollButton" width="190" height="60" label="カメラロール開く" fontSize="18"/>
			<s:Button id="saveButton" width="190" height="60" label="カメラロール保存" fontSize="18"/>
		</s:HGroup>
		<s:Image id="cameraImage" width="100%" height="100%" />
	</s:VGroup>
</s:Skin>

(HomeViewSkin.mxmlソースコード前半)

Skin内の各画面コンポーネントとViewのスキンパートを結びつけるためにidが重要ですので注意して下さい。Skinの実装はこれで終わりです。

ここまでで画面ができましたので、エミュレータでも動作を確認できると思います。実際にロジックを実装した後の完成イメージは下記のようになります。

■CameraUIの実装

最後にViewにロジックを記述していきます。

override protected function partAdded(partName:String, instance:Object):void {
	if(instance == cameraUIButton) {
		cameraUIButton.addEventListener(MouseEvent.CLICK, cameraUIButtonClickHandler);
	}
	
	if(instance == cameraRollButton) {
		cameraRollButton.addEventListener(MouseEvent.CLICK, cameraRollButtonClickHandler);
	}
	
	if(instance == saveButton) {
		saveButton.addEventListener(MouseEvent.CLICK, saveButtonClickHandler);
	}
}

最初のpartAddedメソッドはイベントハンドラの設定を行ったりするお決まりのメソッドです。3つのボタンにそれぞれClickイベントのイベントハンドラを設定しています。

次に、カメラを起動するロジックを実装していきます。AIR for iOSではCameraUIを用いてiPhone/iPad標準のカメラアプリケーションを起動し、写真を撮影し、その写真をアプリケーションで取得する事が可能です。CameraUIオブジェクトに適切なイベントハンドラを設定してカメラアプリケーションを起動します。

private function cameraUIButtonClickHandler(event:MouseEvent):void {
	if(CameraUI.isSupported) {
		var cameraUI:CameraUI = new CameraUI();
		cameraUI.addEventListener(MediaEvent.COMPLETE, cameraUI_completeHandler);
		cameraUI.addEventListener(Event.CANCEL, cameraUI_cancelHandler);
		cameraUI.addEventListener(ErrorEvent.ERROR, cameraUI_errorHandler);
		cameraUI.launch(MediaType.IMAGE);
	}
}

MediaEvent.COMPLETEに対するイベントハンドラが写真を撮り終わった際のイベントハンドラになります。最後の行のlaunchメソッドの引数のMediaType.IMAGEで静止画カメラをしていしています。MediaType.VIDEOにすると動画カメラを起動する事も可能です。

次に、撮影完了イベントハンドラを実装していきます(撮影キャンセル、エラー用のハンドラは省略します)

private var myLoader:Loader;

private function cameraUI_completeHandler(event:MediaEvent):void {		
	var mediaPromise:MediaPromise = event.data;
	this.myLoader = new Loader();
	this.myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadFilePromiseCompleteHandler);
	this.myLoader.loadFilePromise(mediaPromise);		
}

このイベントハンドラのeventオブジェクトのdataプロパティにはMediaPromiseオブジェクトが格納されています。プロミスというのが独特ではありますが、このオブジェクトに撮影したメディアに関する各種情報が格納されています。iOSの場合、カメラで撮影した画像がカメラロールには保存されず、このMediaPromiseから直接取り出すことが出来ません。そのため、上記のようにいったんLoaderオブジェクトを利用してファイルを読み込む必要があります。イベントハンドラをLoaderオブジェクトのcontentLoaderInfoに設定しています。そして、MediaPromiseからのファイル読み込み処理は下記になります。

private function onLoadFilePromiseCompleteHandler(event:Event):void {
	var myLoaderInfo:LoaderInfo = event.target as LoaderInfo;
	myLoaderInfo.removeEventListener(Event.COMPLETE, onLoadFilePromiseCompleteHandler);
		
	cameraImage.source = Bitmap(myLoaderInfo.content);
}

ここでLoaderInfoオブジェクトにBitmapデータが格納されているので、それを画面のImageオブジェクト(cameraImage)のsourceに設定しています。

これでカメラで撮影を行って、その画像をiPhone上に表示する事が出来ました。

■CameraRollの実装

次に、カメラロールを開いて写真をアプリケーションに取り込む処理を書いて行きます。カメラを起動する処理と流れは同じです。

private function cameraRollButtonClickHandler(event:MouseEvent):void {
	if(CameraRoll.supportsBrowseForImage) {
		var cameraRoll:CameraRoll = new CameraRoll();
		cameraRoll.addEventListener(MediaEvent.SELECT, cameraRoll_selectHandler);
		cameraRoll.addEventListener(Event.CANCEL, cameraRoll_cancelHandler);
		cameraRoll.browseForImage(); 
	}
}

カメラロールの利用可否を確認して、cameraRoll.browseForImageメソッドでカメラロールを開きます。カメラロールで写真を選択した際のイベントハンドラは下記になります。

private function cameraRoll_selectHandler(event:MediaEvent):void {
	var mediaPromise:MediaPromise = event.data;
	this.myLoader = new Loader();
	this.myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadFilePromiseCompleteHandler);
	this.myLoader.loadFilePromise(mediaPromise);		
}

このイベントハンドラはCameraUIの場合のものと同じです。MediaPromiseオブジェクトが取得できているので、そこから画像イメージをロードします。この際のイベントハンドラはCameraUIの場合と同じイベントハンドラを参照しています。

これで、先ほどのCameraUIの場合同様にカメラロールで選択した画像が画面に表示されると思います。

最後に、カメラロールに画像を保存するボタンの処理を書いてみましょう。

private function saveButtonClickHandler(event:MouseEvent):void {
	if(CameraRoll.supportsAddBitmapData) {
		if(cameraImage.source != null) {				
			var cameraRoll:CameraRoll = new CameraRoll();
			var bitmap:Bitmap = Bitmap(cameraImage.source);
			cameraRoll.addBitmapData(bitmap.bitmapData);		
		}
	}
}

カメラロールへの画像の保存はcameraRoll.addBitmapDataで簡単にできます。

実装がすべて終わりましたので、実機でテストしてみて下さい。

■最後に

AIR for iOSでのカメラアプリはいかがでしたでしょうか。この後、画面の縦横の判定やファイルのFlickrへのアップロードなどを実装していくのも面白いかもしれません。次回もAIR for iOSでミニアプリを作っていきたいと思います。

■自己紹介

福田寅成
クラスメソッド株式会社(https://classmethod.jp/
RIAエバンジェリスト
RIAやクラウドに関するセミナーの開催や技術記事執筆を通じて、先進技術の啓蒙を行う日々。Flex/AIR/Silverlight/AWS/Azure/Android/iOS/Windows Phone/UXと幅広い分野を担当。

EOF