アクセシビリティ
デベロッパーリソース

Jeff Swartz

Jeff Swartz

シニアテクニカルライター
Adobe

作成日:
2008年2月25日
ユーザレベル:
中級, 上級
製品:
Adobe AIR

JPEG ファイルアップローダの構築

図 1 の PhotoUpload サンプルアプリケーションは、次のような Adobe AIR のファイル操作機能を示します。

  • File オブジェクトで参照する一時ファイルの設定
  • ファイルへのデータの書き込み
  • サーバへのファイルのアップロード
  • ファイルの削除
  • NativeApplication オブジェクトの終了イベントへの応答
  • JavaScript から SWF ファイルの ActionScript クラスへのアクセス
  • 「JavaScript Language Reference for Adobe AIR」に記載されていない高度なランタイムクラス(Camera および Video)の使用

JPEG ファイルアップローダ

図 1. JPEG ファイルのアップロードが可能なサンプルアプリケーション

注意:このサンプルアプリケーションは、説明のためにそのままの状態で提供されています。

要件

この記事に書かれた操作を行うには、次のソフトウェアとファイルが必要です。

Adobe AIR

Adobe AIR SDK

サンプルファイル:

このサンプルアプリケーションには、次のファイルが含まれています。

  • index.html:この記事で説明するメインアプリケーションコンテンツ。
  • application.xml:AIR アプリケーション記述子ファイル。
  • js/Uploader.js:アプリケーションで使用される多数のロジックが含まれている JavaScript ファイル。コードについては、3 ページの「コードの理解」で詳しく説明しています。
  • js/AIRAliases.js:AIR JavaScript エイリアスファイル。
  • swf/JPGEncoderLib.swf:ActionScript 3.0 のクラスが含まれている、JPGEncoder という SWF ファイル。
  • swf_src/com/adobe/images/swf_src/JPGEncoderLib.as:JPGEncoderLib.swf ファイルのコンパイル用の ActionScript 3.0 ソースファイル。このサンプルに用意されている JPGEncoderLib.swf ファイルを使用できます。ただし、セキュリティ上の理由から、ソースコードの SWF ファイルをサードパーティのソースから得る場合は、そのファイルを再コンパイルするとよいでしょう。
  • swf_src/com/adobe/images/JPGEncoder.as:JPGEncoder クラスで使用されるユーティリティクラス。このクラスは、ActionScript 3.0 Corelib プロジェクトでも使用できます。
  • BitString.as:JPGEncoder クラスで使用されるユーティリティクラス。このクラスは、ActionScript 3.0 Corelib プロジェクトでも使用できます。
  • PHP/index.php:PHP 対応の Web サーバの http://localhost/PhotoSyncUpload/ フォルダに格納されるファイル。
  • サンプル AIR アイコンファイル。

その他:

このアプリケーションを使用するには、Web カメラがインストールされている必要があります。また、PHP 対応の Web サーバへのアクセス権も必要です。

前提知識

HTML ベースのアプリケーション構築の経験があることが推奨されます。このクイックスタートの開始方法について詳しくは、「Building the Quick Start sample applications with HTML」を参照してください。

アプリケーションのテスト

このサンプルアプリケーションでは、Web カメラから画像をキャプチャし、その画像(JPEG ファイルとして保存される)を Web サーバにアップロードできます。

フォトアップローダでは、SWF ファイルの JPGEncoder クラスを使用してデータが JPEG 形式に変換されます。JPGEncoder クラスは、ActionScript 3.0 Corelib プロジェクト(http://code.google.com/p/as3corelib)でパブリッシュされます。

アプリケーション(PhotoUploadHTML.air)を実行する前に、index.php ファイル(PHP ディレクトリのソースファイルに付属している)を PHP 対応の Web サーバの http://localhost/PhotoSyncUpload/ フォルダにインストールします。また、Web カメラがコンピュータにインストールされていることを確認します。

アプリケーションをテストするには:

  1. 用意されている AIR ファイルをダブルクリックしてアプリケーションをインストールし、実行します。
  2. 被写体に Web カメラを向けます。
  3. 「Preview」ボタンをクリックします。次に、「保存」ボタンをクリックして画像を保存します。
  4. この手順を繰り返して複数の画像を保存します。
  5. 「Upload」ボタンをクリックして、ファイルを Web サーバにアップロードします。

コードの理解

AIR クラスの使用方法について詳しくは、「Adobe AIR Language Reference for HTML Developers」を参照してください。

Web カメラの画像のプレビュー

Uploader.js ファイル内の appInit() メソッドは、ActionScript 3.0 ドキュメントの Camera クラスと Video クラスセクションに記載されている 2 つのクラスを使用しています。カメラオブジェクト(Camera クラスのインスタンス)をユーザのコンピュータの Web カメラに割り当てるために、Camera クラスの getCamera() メソッドが呼び出されます。カメラがない場合は、ユーザに通知するために alert() 関数が呼び出されます。ビデオオブジェクト(Video クラスのインスタンス)は、カメラでキャプチャした画像を表示するために割り当てられた ActionScript 3.0 表示オブジェクトです。

camera = window.runtime.flash.media.Camera.getCamera();
if (camera)
{
    video = new window.runtime.flash.media.Video();
    video.attachCamera(camera);
    camera.addEventListener(air.ActivityEvent.ACTIVITY, setSize);
}
else
{
    alert("No cameras are available.");
}

setSize() 関数では、ビデオの高さと幅が設定され、次に shoot() 関数が呼び出されます。

function setSize() 
{
    video.width = camera.width * 2;
    video.height = camera.height * 2;
    shoot(false);
}

shoot() 関数では、不透明な白い NativeWindow を短時間画面いっぱいに表示してカメラのフラッシュをシミュレートする flasher() 関数が呼び出されます。

function shoot(flash) 
{
    if (flash)
    {
        flasher();
    }
    bmd = new window.runtime.flash.display.BitmapData(video.width, video.height);
    bmd.draw(video);
    saveTemp();
}
function flasher() 
{
    var windowInitOpts = new air.NativeWindowInitOptions();
    windowInitOpts.systemChrome = air.NativeWindowSystemChrome.NONE;
    windowInitOpts.type = air.NativeWindowType.LIGHTWEIGHT;
    var flashCube = new air.NativeWindow(windowInitOpts);
    flashCube.x = 0;
    flashCube.y = 0;
    flashCube.width = air.Capabilities.screenResolutionX;
    flashCube.height = air.Capabilities.screenResolutionY;
    flashCube.visible = true;
    setTimeout(closeFlash, 100, flashCube);
}
function closeFlash(flashCube) {
    flashCube.close();
}

appInit() メソッドでの初期化中にアプリケーションから初めて shoot メソッドを呼び出す場合、このメソッドの flash パラメータには false が設定されます。

次に、shoot() メソッドでビデオオブジェクトに画像がキャプチャされ、BitmapData オブジェクト bmd に保存されます。flash.display.BitmapData クラスについては、ActionScript 3.0 のドキュメントを参照してください。

bmd = new window.runtime.flash.display.BitmapData(video.width, video.height);
bmd.draw(video);

ファイルの保存

アプリケーションの初期化時および「Preview」ボタンのクリック時には、saveTemp() メソッドで画像が JPEG ファイルに保存されます。その後は、このファイルが img 画像に読み込まれます。

bmd オブジェクトに格納されている BitmapData データは、JPEG 形式に変換する必要があります。この変換は、corelib プロジェクト(http://code.google.com/p/as3corelib)でパブリッシュされた JPGEncoder ActionScript 3.0 クラスで行われます。swf ディレクトリ内のソースファイルで提供される JPGEncoderLib.swf ファイルには、該当する JPGEncoder クラスが含まれています。また、この HTML ベースのアプリケーションでは、次のスクリプトタグ(index.html ファイル内)を使用して SWF ファイルを読み込むことによって、その SWF ファイル内のクラスが JavaScript コードで使用可能になります。

<script src="swf/JPGEncoderLib.swf" type="application/x-shockwave-flash"></script>

saveTemp() 関数を使用すると、JPEG データが一時ファイルに保存されます。この一時ファイルは、air.File.createTempFile() を呼び出すことによって作成されます。データをファイルに保存するために、FileStream オブジェクトが作成され、そのオブジェクトの writeBytes() メソッドが呼び出されます。次に、一時ファイルがドキュメント内の img 画像に読み込まれます。JPGEncoder オブジェクトの encode() メソッドを呼び出すことにより、画像データを JPEG エンコード形式のデータが格納される ByteArray に変換しています。

function saveTemp()
{
    tempFile = air.File.createTempFile();
    temps.push(tempFile);
    saveJPEG(tempFile);
    img.src = "";
    img = window.document.getElementById("img");
    img.src = tempFile.url;
    img.width = 320;
    img.height = 240;
}
function saveJPEG(file) {
    stream = new air.FileStream();
    stream.open(file, air.FileMode.WRITE);
    var data = getJPEGData(bmd);
    stream.writeBytes(data, 0, data.length);
    stream.close();
    return file;
}
function getJPEGData(bmd) {
    var jpegEncoder = new window.runtime.com.adobe.images.JPGEncoder();
    return jpegEncoder.encode(bmd);
}

ユーザが「保存」ボタンをクリックすると、画像は、save() メソッドによってアプリケーションリソースディレクトリの images サブディレクトリに JPEG ファイルとして保存されます。ファイルの名前は、Date オブジェクトの time プロパティで設定されるタイムスタンプに基づきます。

function save() 
{
    var timestamp = new Date().getTime().toString();
    var path = "images/" + timestamp + ".jpg";
    file = air.File.applicationStorageDirectory.resolvePath(path);
    saveJPEG(file);
}

Web サーバへのファイルのアップロード

Uploader.as ファイルには、ファイルを Web サーバにアップロードするコードが含まれています。保存したファイルのリストは、files 配列(File オブジェクトの配列)に格納されます。upload() メソッドでは、アプリケーションストレージディレクトリの images サブディレクトリでファイルのリストの検索が行われます。

function upload()
{
    totalSize = 0;
    files = new Array();
    var dir = air.File.applicationStorageDirectory.resolvePath("images");
    var allNodes = dir.getDirectoryListing();
    for (var i = 0; i < allNodes.length; i++)
    {
        file = allNodes[i];
        if (!file.isDirectory)
        {
            files.push(file);
            totalSize += file.size;
        }
    }
    url = UPLOAD_URL
    uploadedSoFar = 0;
    uploadNext();
}

uploadNext() 関数では files 配列から 1 つの File オブジェクトが抽出され、ファイルをアップロードする uploadFile() 関数が呼び出されます。

function uploadNext()
{
    if (files.length > 0)
    {
        currentFile = files.pop();
        uploadFile(currentFile);
    }
}
function uploadFile(file)
{
    var urlRequest = new air.URLRequest(url);
    urlRequest.method = air.URLRequestMethod.POST;
    file.addEventListener(air.ProgressEvent.PROGRESS, uploadProgress);
    file.addEventListener(air.Event.COMPLETE, uploadComplete);
    file.addEventListener(air.SecurityErrorEvent.SECURITY_ERROR, uploadError);
    file.addEventListener(air.HTTPStatusEvent.HTTP_STATUS, uploadError); 
    file.addEventListener(air.IOErrorEvent.IO_ERROR, uploadError);
    file.upload(urlRequest, "uploadfile");
}

ploadFile() 関数では アップロード対象の File オブジェクトの様々なイベントリスナーが設定されます。

function uploadProgress(event) 
{
    var uploadedAmt = uploadedSoFar + event.bytesLoaded;
    event.bytesLoaded = uploadedAmt;
    event.bytesTotal = totalSize;
    air.trace("Progress", event.bytesLoaded, event.bytesTotal);
}
function uploadComplete(event)
{
    uploadedSoFar += currentFile.size;
    var newLocation = currentFile.parent.resolvePath("uploaded/" + currentFile.name);
    uploadNext();
}
function uploadError(event)
{
    var errorStr = event.toString();
    air.trace("Error uploading: " + currentFile.nativePath + "\n  Message: " + errorStr);
}

uploadComplete() 関数(ファイルのアップロード時に呼び出されるイベントハンドラ)では、uploadNext() 関数が呼び出され、次のファイル(存在する場合)がアップロードされます。

Web サーバに掲載した PHP ページでは、POST データとして提供されるファイルを、アップロード対象(Web サーバの「uploaded」サブディレクトリに保存)のファイルの形で受け入れるキューとして文字列が認識されます。

アプリケーション終了時の一時ファイルの削除

appInit() 関数では、終了イベントのイベントリスナーが設定されます。このリスナーは、アプリケーションの終了時に NativeApplication オブジェクトによって送出されます。

air.NativeApplication.nativeApplication.addEventListener(air.Event.EXITING, appExiting);

NativeApplication オブジェクトでは、ユーザが main を閉じるときに終了イベントが送出されます。終了イベントは appExiting() 関数で処理され、アプリケーションが実際に終了する前に、セッション中に使用した一時ファイルの配列が保存されます。

function appExiting(event)
{
    for (i = 0; i < temps.length; i++)
    {
        tempFile = temps[i];
        tempFile.deleteFile();
    }
}

著者について

Jeff Swartzは、1992年にMacromedia(現Adobe Systems)に入社し、現在はAdobe AIR担当のテクニカルライターを務めています。Jeffは、University of Illinois at Urbana-Champaignのコンピュータサイエンス学学士号と、Edinburgh University人工知能学部での就学経験を有しています。サンフランシスコベイエリアのファンは、Jeffのトロンボーン演奏を寛大に許容しています。また、Vienna Beef Ltd.のダンシングホットドッグ、Big Frankとして活躍した経験もあります。