root/as3/SiOPM/trunk/src/org/si/utils/ByteArrayExt.as

リビジョン 4540, 15.2 kB (コミッタ: keim, コミット時期: 1 年 前)

SiON v0.63 candidate

Line 
1 //----------------------------------------------------------------------------------------------------
2 // Extended ByteArray
3 //  Copyright (c) 2008 keim All rights reserved.
4 //  Distributed under BSD-style license (see org.si.license.txt).
5 //----------------------------------------------------------------------------------------------------
6
7
8
9
10 package org.si.utils {
11     import flash.net.FileFilter;
12     import flash.net.FileReference;
13     import flash.net.URLRequest;
14     import flash.net.URLLoader;
15     import flash.utils.ByteArray;
16     import flash.events.Event;
17     import flash.display.BitmapData;
18
19
20     /** Extended ByteArray, png image serialize, IFF chunk structure, FileReference operations. */
21     public class ByteArrayExt extends ByteArray {
22     // variables
23     //--------------------------------------------------
24         static private var crc32:Vector.<uint> = null;
25        
26        
27        
28        
29     // constructor
30     //--------------------------------------------------
31         /** constructor */
32         function ByteArrayExt(copyFrom:ByteArray = null)
33         {
34             super();
35             if (copyFrom) {
36                 this.writeBytes(copyFrom);
37                 this.endian = copyFrom.endian;
38                 this.position = 0;
39             }
40         }
41        
42        
43        
44        
45     // bitmap data operations
46     //--------------------------------------------------
47         /** translate from BitmapData
48          *  @param bmd BitmapData translating from.
49          *  @return this instance
50          */
51         public function fromBitmapData(bmd:BitmapData) : ByteArrayExt
52         {
53             var x:int, y:int, i:int, w:int=bmd.width, h:int=bmd.height, len:int, p:int;
54             this.clear();
55             len = bmd.getPixel(w-1, h-1);
56             for (y=0, i=0; y<h && i<len; y++) for (x=0; x<w && i<len; x++, i++) {
57                 p = bmd.getPixel(x, y);
58                 this.writeByte(p>>>16);
59                 if (++i >= len) break;
60                 this.writeByte(p>>>8)
61                 if (++i >= len) break;
62                 this.writeByte(p);
63             }
64             this.position = 0;
65             return this;
66         }
67        
68        
69         /** translate to BitmapData
70          *  @param width same as BitmapData's constructor, set 0 to calculate automatically.
71          *  @param height same as BitmapData's constructor, set 0 to calculate automatically.
72          *  @param transparent same as BitmapData's constructor.
73          *  @param fillColor same as BitmapData's constructor.
74          *  @return translated BitmapData
75          */
76         public function toBitmapData(width:int=0, height:int=0, transparent:Boolean = true, fillColor:uint = 0xFFFFFFFF) : BitmapData
77         {
78             var x:int, y:int, reqh:int, bmd:BitmapData, len:int = this.length, p:uint;
79             if (width == 0) width = ((int(Math.sqrt(len)+65535/65536))+15)&(~15);
80             reqh = ((int(len/width+65535/65536))+15)&(~15);
81             if (height == 0 || reqh > height) height = reqh;
82             bmd = new BitmapData(width, height, transparent, fillColor);
83             this.position = 0;
84             for (y=0; y<height; y++) for (x=0; x<width; x++) {
85                 if (this.bytesAvailable < 3) break;
86                 bmd.setPixel32(x, y, 0xff000000|((this.readUnsignedShort()<<8)|this.readUnsignedByte()));
87             }
88             p = 0xff000000;
89             if (this.bytesAvailable > 0) p |= this.readUnsignedByte() << 16;
90             if (this.bytesAvailable > 0) p |= this.readUnsignedByte() << 8;
91             if (this.bytesAvailable > 0) p |= this.readUnsignedByte();
92             bmd.setPixel32(x, y, p);
93             this.position = 0;
94             bmd.setPixel32(x, y, 0xff000000|(uint(this.length)));
95             return bmd;
96         }
97        
98        
99         /** translate to 24bit png data
100          *  @param width png file width, set 0 to calculate automatically.
101          *  @param height png file height, set 0 to calculate automatically.
102          *  @return ByteArrayExt of PNG data
103          */
104         public function toPNGData(width:int=0, height:int=0) : ByteArrayExt
105         {
106             var i:int, imax:int, reqh:int, pixels:int = (this.length+2)/3, y:int,
107                 png:ByteArrayExt = new ByteArrayExt(),
108                 header:ByteArray = new ByteArray(),
109                 content:ByteArray = new ByteArray();
110             //----- settings
111             if (width == 0) width = ((int(Math.sqrt(pixels)+65535/65536))+15)&(~15);
112             reqh = ((int(pixels/width+65535/65536))+15)&(~15);
113             if (height == 0 || reqh > height) height = reqh;
114             header.writeInt(width);  // width
115             header.writeInt(height); // height
116                 header.writeUnsignedInt(0x08020000); // 24bit RGB
117                 header.writeByte(0);
118             imax = pixels - width;
119             for (y=0, i=0; i<imax; i+=width, y++) {
120                 content.writeByte(0);
121                 content.writeBytes(this, i*3, width*3);
122             }
123             content.writeByte(0);
124             content.writeBytes(this, i*3, this.length-i*3);
125             imax = (i + width) * 3;
126             for (i=this.length; i<imax; i++) content.writeByte(0);
127             imax = width * 3 + 1;
128             for (y++; y<height; y++) for (i=0; i<imax; i++) content.writeByte(0);
129             i = this.length;
130             content.position -= 3;
131             content.writeByte(i>>>16);
132             content.writeByte(i>>>8);
133             content.writeByte(i);
134             content.compress();
135            
136             //----- write png data
137             png.writeUnsignedInt(0x89504e47);
138             png.writeUnsignedInt(0x0D0A1A0A);
139             png_writeChunk(0x49484452, header);
140             png_writeChunk(0x49444154, content);
141             png.writeUnsignedInt(0);
142             png.writeUnsignedInt(0x49454E44);
143             png.position = 0;
144            
145             return png;
146            
147             //----- write png chunk
148             function png_writeChunk(type:uint, data:ByteArray) : void {
149                 png.writeUnsignedInt(data.length);
150                 var crcStartAt:uint = png.position;
151                 png.writeUnsignedInt(type);
152                 png.writeBytes(data);
153                 png.writeUnsignedInt(calculateCRC32(png, crcStartAt, png.position - crcStartAt));
154             }
155         }
156        
157        
158        
159        
160     // IFF chunk operations
161     //--------------------------------------------------
162         /** write IFF chunk */
163         public function writeChunk(chunkID:String, data:ByteArray, listType:String=null) : void
164         {
165             var isList:Boolean = (chunkID == "RIFF" || chunkID == "LIST"),
166                 len:int = ((data) ? data.length : 0) + ((isList) ? 4 : 0);
167             this.writeMultiByte((chunkID+"    ").substr(0,4), "us-ascii");
168             this.writeInt(len);
169             if (isList) {
170                 if (listType) this.writeMultiByte((listType+"    ").substr(0,4), "us-ascii");
171                 else this.writeMultiByte("    ", "us-ascii");
172             }
173             if (data) {
174                 this.writeBytes(data);
175                 if (len & 1) this.writeByte(0);
176             }
177         }
178        
179        
180         /** read (or search) IFF chunk from current position. */
181         public function readChunk(bytes:ByteArray, offset:int=0, searchChunkID:String=null) : *
182         {
183             var id:String, len:int, type:String=null;
184             while (this.bytesAvailable > 0) {
185                 id = this.readMultiByte(4, "us-ascii");
186                 len = this.readInt();
187                 if (searchChunkID == null || searchChunkID == id) {
188                     if (id == "RIFF" || id == "LIST") {
189                         type = this.readMultiByte(4, "us-ascii");
190                         this.readBytes(bytes, offset, len-4);
191                     } else {
192                         this.readBytes(bytes, offset, len);
193                     }
194                     if (len & 1) this.readByte();
195                     bytes.endian = this.endian;
196                     return {"chunkID":id, "length":len, "listType":type};
197                 }
198                 this.position += len + (len & 1);
199             }
200             return null;
201         }
202        
203        
204         /** read all IFF chunks from current position. */
205         public function readAllChunks() : *
206         {
207             var header:*, ret:* = {}, pickup:ByteArrayExt;
208             while (header = readChunk(pickup = new ByteArrayExt())) {
209                 if (header.chunkID in ret) {
210                     if (ret[header.chunkID] is Array) ret[header.chunkID].push(pickup);
211                     else ret[header.chunkID] = [ret[header.chunkID]];
212                 } else {
213                     ret[header.chunkID] = pickup;
214                 }
215             }
216             return ret;
217         }
218        
219        
220        
221        
222     // URL operations
223     //--------------------------------------------------
224         /** load from URL
225          *  @param url URL string to load swf file.
226          *  @param onComplete handler for Event.COMPLETE. The format is function(bae:ByteArrayExt) : void.
227          *  @param onCancel handler for Event.CANCEL. The format is function(e:Event) : void.
228          *  @param onError handler for Event.IO_ERROR. The format is function(e:IOErrorEvent) : void.
229          */
230         public function load(url:String, onComplete:Function=null, onCancel:Function=null, onError:Function=null) : void
231         {
232             var loader:URLLoader = new URLLoader(), bae:ByteArrayExt = this;
233             loader.dataFormat = "binary";
234             loader.addEventListener("complete", _onLoadComplete);
235             loader.addEventListener("cancel", _onLoadCancel);
236             loader.addEventListener("ioError", _onLoadError);
237             loader.load(new URLRequest(url));
238
239             function _removeAllEventListeners(e:Event, callback:Function) : void {
240                 loader.removeEventListener("complete", _onLoadComplete);
241                 loader.removeEventListener("cancel", _onLoadCancel);
242                 loader.removeEventListener("ioError", _onLoadError);
243                 if (callback != null) callback(e);
244             }
245             function _onLoadComplete(e:Event) : void {
246                 bae.clear();
247                 bae.writeBytes(e.target.data);
248                 _removeAllEventListeners(e, null);
249                 bae.position = 0;
250                 if (onComplete != null) onComplete(bae);
251             }
252             function _onLoadCancel(e:Event)   : void { _removeAllEventListeners(e, onCancel); }
253             function _onLoadError(e:Event)    : void { _removeAllEventListeners(e, onError); }
254         }
255        
256        
257        
258        
259     // FileReference operations
260     //--------------------------------------------------
261         /** Call FileReference::browse().
262          *  @param onComplete handler for Event.COMPLETE. The format is function(bae:ByteArrayExt) : void.
263          *  @param onCancel handler for Event.CANCEL. The format is function(e:Event) : void.
264          *  @param onError handler for Event.IO_ERROR. The format is function(e:IOErrorEvent) : void.
265          *  @param fileFilterName name of file filter.
266          *  @param extensions extensions of file filter (like "*.jpg;*.png;*.gif").
267          */
268         public function browse(onComplete:Function=null, onCancel:Function=null, onError:Function=null, fileFilterName:String=null, extensions:String=null) : void
269         {
270             var fr:FileReference = new FileReference(), bae:ByteArrayExt = this;
271             fr.addEventListener("select", function(e:Event) : void {
272                 e.target.removeEventListener(e.type, arguments.callee);
273                 fr.addEventListener("complete", _onBrowseComplete);
274                 fr.addEventListener("cancel", _onBrowseCancel);
275                 fr.addEventListener("ioError", _onBrowseError);
276                 fr.load();
277             });
278             fr.browse((fileFilterName) ? [new FileFilter(fileFilterName, extensions)] : null);
279
280             function _removeAllEventListeners(e:Event, callback:Function) : void {
281                 fr.removeEventListener("complete", _onBrowseComplete);
282                 fr.removeEventListener("cancel", _onBrowseCancel);
283                 fr.removeEventListener("ioError", _onBrowseError);
284                 if (callback != null) callback(e);
285             }
286             function _onBrowseComplete(e:Event) : void {
287                 bae.clear();
288                 bae.writeBytes(e.target.data);
289                 _removeAllEventListeners(e, null);
290                 bae.position = 0;
291                 if (onComplete != null) onComplete(bae);
292             }
293             function _onBrowseCancel(e:Event) : void { _removeAllEventListeners(e, onCancel); }
294             function _onBrowseError(e:Event)  : void { _removeAllEventListeners(e, onError); }
295         }
296        
297        
298         /** Call FileReference::save().
299          *  @param defaultFileName default file name.
300          *  @param onComplete handler for Event.COMPLETE. The format is function(e:Event) : void.
301          *  @param onCancel handler for Event.CANCEL. The format is function(e:Event) : void.
302          *  @param onError handler for Event.IO_ERROR. The format is function(e:IOErrorEvent) : void.
303          */
304         public function save(defaultFileName:String=null, onComplete:Function=null, onCancel:Function=null, onError:Function=null) : void
305         {
306             var fr:FileReference = new FileReference();
307             fr.addEventListener("complete", _onSaveComplete);
308             fr.addEventListener("cancel", _onSaveCancel);
309             fr.addEventListener("ioError", _onSaveError);
310             fr.save(this, defaultFileName);
311
312             function _removeAllEventListeners(e:Event, callback:Function) : void {
313                 fr.removeEventListener("complete", _onSaveComplete);
314                 fr.removeEventListener("cancel", _onSaveCancel);
315                 fr.removeEventListener("ioError", _onSaveError);
316                 if (callback != null) callback(e);
317             }
318             function _onSaveComplete(e:Event) : void { _removeAllEventListeners(e, onComplete); }
319             function _onSaveCancel(e:Event)   : void { _removeAllEventListeners(e, onCancel); }
320             function _onSaveError(e:Event)    : void { _removeAllEventListeners(e, onError); }
321         }
322        
323        
324        
325        
326     // utilities
327     //--------------------------------------------------
328         /** calculate crc32 chuck sum */
329         static public function calculateCRC32(byteArray:ByteArray, offset:int=0, length:int=0) : uint
330         {
331             var i:int, j:int, c:uint, currentPosition:int;
332             if (!crc32) {
333                 crc32 = new Vector.<uint>(256, false);
334                 for (i=0; i<256; i++) {
335                     for (c=i, j=0; j<8; j++) c = uint(((c&1)?0xedb88320:0)^(c>>>1));
336                     crc32[i] = c;
337                 }
338             }
339            
340             if (length==0) length = byteArray.length;
341             currentPosition = byteArray.position;
342             byteArray.position = offset;
343             for (c=0xffffffff, i=0; i<length; i++) {
344                 j = (c ^ byteArray.readUnsignedByte()) & 255;
345                 c >>>= 8;
346                 c ^= crc32[j];
347             }
348             byteArray.position = currentPosition;
349            
350             return c ^ 0xffffffff;
351         }
352     }
353 }
354
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。