そうめんを利用して画像を保存する

おはようございます。

金曜の会社の飲み会で、のどをやられたようです。
それにしても寒いですね。先日石油ヒーターを出しました。

さて、今日は前回投稿の画像保存を「そうめん」を利用してやってみたいと思います。

■そうめんとは

BeInteractive!のyossyさんが作ったActionScript Thread Library 1.0(そうめん) です。
使ってみた感想は・・・とても便利です。

いか、良いと思ったことです。

  • addEventListenerとさよならできます。
  • 次に行う処理がはっきりし、可読性が上がります。
  • 簡単に待ち(sleep)処理ができます。
  • 割り込み処理ができる

では、前回投稿の画像保存処理がそうめんを利用するとどうなるか見ていきましょう。

■画像をダウンロードするURLLoaderThread

URLLoaderにThreadの機構を追加した拡張クラスです。


var urlRequest:URLRequest = new URLRequest(url);
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.BINARY;
loader.addEventListener(Event.COMPLETE, function(e:Event):void{ onLoadComplete(e, savePath); });
loader.load(urlRequest);

これが、下のように変わります。
URLLoaderThreadは、プライベート変数として宣言しています。


private var _imageLoader:URLLoaderThread;
override protected function run():void
{
_imageLoader = new URLLoaderThread(new URLRequest(_imageUrl));
_imageLoader.loader.dataFormat = URLLoaderDataFormat.BINARY;
//URLのコンテンツダウンロードを開始する
_imageLoader.start();
//ダウンロード完了まで待機
_imageLoader.join();
//ダウンロード完了後にonLoadCompleteメソッドを呼び出す(保存先はコンストラクタでプライベート変数に格納)
next(onLoadComplete);
}

どうでしょうか?
処理の上から順に読めるので分かりやすく、事前にイベントリスナを登録しておく必要もありません。

■画像の保存処理

保存処理は、基本的にほとんど変わりません。

相違点は、

  • イベントに関連したクラスではないので、メソッドの引数にEvent変数を持ちません
  • ダウンロードコンテンツへのアクセスもURLLoaderにキャストする必要がありません


private function onLoadComplete(e:Event, savePath:String):void
{
var file:File = new File(savePath);
var stream:FileStream = new FileStream();
var byteArr:ByteArray = new ByteArray();
stream.open(file, FileMode.WRITE);
stream.writeBytes(URLLoader(e.target).data);
}

これが、下のように変わります。


private function onLoadComplete():void
{
var file:File = new File(_savePath);
var stream:FileStream = new FileStream();
stream.open(file, FileMode.WRITE);
stream.writeBytes(_imageLoader.loader.data);
stream.close();
}

■SerialExecutorを使った拡張

画像のダウンロードを連続して行いたい場合はどうすれば良いでしょうか?
その場合、SerialExecutor(ParallelExecutor)を利用します。

SerialExecutorは、登録したThreadを順番に実行してくれます。並列処理を行いたい場合は、ParallelExecutorを利用します。
以下は、SerialExecutorを利用した順次ダウンロードのサンプルです。


var downloaders:SerialExecutor;
downloaders = new SerialExecutor();
//3つの画像ダウンロードスレッドを登録
downloaders.addThread(new DownloadImageThread(url1, savePath1));
downloaders.addThread(new DownloadImageThread(url2, savePath2));
downloaders.addThread(new DownloadImageThread(url3, savePath3));
//ダウンロード開始
downloaders.start();
downloaders.join();
next(completeDownload);


全ソースと使い方は続きのページに載せます。


ソース

package
{
  import flash.events.Event;
  import flash.filesystem.File;
  import flash.filesystem.FileMode;
  import flash.filesystem.FileStream;
  import flash.net.URLLoaderDataFormat;
  import flash.net.URLRequest;
  import flash.utils.ByteArray;

  import org.libspark.thread.Thread;
  import org.libspark.thread.threads.net.URLLoaderThread;

  public class DownloadImageThread extends Thread
  {
    private var _imageUrl:String;
    private var _savePath:String;
    private var _imageLoader:URLLoaderThread;

    /**
     * コンストラクタ
     */
    public function DownloadImageThread(imageUrl:String, savaPath:String):void
    {
      _imageUrl = imageUrl;
      _savePath = savaPath;
    }

    /**
     * スレッド開始
     */
    override protected function run():void
    {
      _imageLoader = new URLLoaderThread(new URLRequest(_imageUrl));
      _imageLoader.loader.dataFormat = URLLoaderDataFormat.BINARY;
      _imageLoader.start();
      _imageLoader.join();
      next(onLoadComplete);
    }

    /**
     * URLのコンテンツをコンテンツを保存する。
     */
    private function onLoadComplete():void
    {
      var file:File = new File(_savePath);
      var stream:FileStream = new FileStream();
      try {
        stream.open(file, FileMode.WRITE);
        stream.writeBytes(_imageLoader.loader.data);
      } catch (e:Error) {
        trace(e.getStackTrace());
      } finally {
        stream.close();
      }
    }
  }
}

■使い方

Thread.initialize(new EnterFrameThreadExecutor());
var url:String = "http://www.hatena.ne.jp/images/logo_portal_hatena.gif";
var file:File = File.applicationDirectory.resolvePath("hatena.gif");
var downloader:DownloadImageThread = new DownloadImageThread(url, file.nativePath);
downloader.start();