JPGEncoder で画像を JPG に変換するときに、画像が壁紙級のサイズの場合結構時間がかかるようです (10 秒くらい)。

なんとか処理の進捗を見せられぬものかと思って画像を細かく区切って投げてみることにしてみました。ただ単純に縦方向に画像を指定された数に区切ってエンコードして、バイナリ配列につなげて送信するときにクエリーで分割したそれぞれのデータのサイズを一緒に送るイメージです。

サーバでは受け取ったデータをデータのサイズ情報で分割してそれぞれファイルに書き出し。最後にイメージマジックなどでまとめてもらうイメージでしょうか。

ここまで書いたところで、「果たして最後にサーバでつなげるという処理をしてまで進捗状況を見せるべきか??」という疑問にぶち当たってしまいちょっと放置してしましまいましたが、どこかのタイミングで使ってみようと思います (本当はヘッダー情報をいじってサーバでつなげなくても良いようにできればベスト)。

package { public class JPGUpLoader { private var _printBmd:BitmapData; // 送信するイメージ private var _masterbyteArr:ByteArray; private var _partition = 10; // 分割数 private var _encodeCnt = 0; private var _quely:String = "?size="; /** * コンストラクタ * * partition : 分割する数 * mcImg : jpg に変換する MovieClip */ public function JPGUpLoader(partition:Number, mcImg:MovieClip) { _partition = partition; _printBmd = new BitmapData(mcImg.width, mcImg.height); _printBmd.draw(mcImg); _masterbyteArr = new ByteArray(); _encodeCnt = 0; mcImg.addEventListener(Event.ENTER_FRAME, jpgEncoding); } /** * 毎フレームごとに変換処理を実施 */ private function jpgEncoding(evt:Event) { var posy:Number = 0; var h:Number = 0; if (_encodeCnt != _partition - 1) { h = Math.floor(_printBmd.height / _partition); } else { h = _printBmd.height - Math.floor(_printBmd.height / _partition) * (_partition - 1); this.removeEventListener(Event.ENTER_FRAME, jpgEncoding); } var srcBmd:BitmapData = new BitmapData(_printBmd.width, h); srcBmd.copyPixels(_printBmd, new Rectangle(0, 0, _printBmd.width, _printBmd.height), new Point(0, -posy)); var jpgEncoder:JPGEncoder = new JPGEncoder(100); var byteArr:ByteArray = jpgEncoder.encode(srcBmd); if (_encodeCnt == 0) { _quely += byteArr.length; } else { _quely += "," + byteArr.length; } _masterbyteArr.writeBytes(byteArr); _encodeCnt++; if (_encodeCnt == _partition) upImg(); } /** * 画像の送信処理 */ private function upImg() { var strReq:String = "upImg.php" + _quely; var req:URLRequest = new URLRequest(strReq); _imgPostLdr = new URLLoader(); req.contentType = "application/octet-stream"; req.method = URLRequestMethod.POST; req.data = _masterbyteArr; _imgPostLdr.load(req); _imgPostLdr.addEventListener(Event.COMPLETE, onUpLoad); } /** * エンコードの進捗率のゲッター */ public function get encodeCnt():Number { return _encodeCnt; } } }

と思ったら、、プログラマーの Typester さんからこんなアドバイスもらいました。

何で分割してんだろうとおもってJPEGEncoderのソース見てみたのですが、
http://as3corelib.googlecode.com/svn/trunk/src/com/adobe/images/JPGEncoder.as

これってencode関数のEncode 8x8 macroblocksってところをsetTimeoutで切り分けるだけで、進捗も出せるし、固まらなくなると思うけどどうだろう。

なるほど!さっそく試してみようと思います!

HTML5飯