root/as3/ICODecoder/src/com/voidelement/images/ico/ICOImageData.as

リビジョン 244, 12.5 kB (コミッタ: munegon, コミット時期: 1 年 前)

--

Line 
1 /**
2  * com.voidelement.images.ico.ICODecoder  Class for ActionScript 3.0
3  * 
4  * @author       Copyright (c) 2008 munegon
5  * @version      1.0
6  * 
7  * @link         http://www.voidelement.com/
8  * @link         http://void.heteml.jp/blog/
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  * 
14  * http://www.apache.org/licenses/LICENSE-2.0
15  * 
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
19  * either express or implied. See the License for the specific language
20  * governing permissions and limitations under the License.
21  */
22
23
24
25 package com.voidelement.images.ico {
26         import flash.display.BitmapData;
27         import flash.display.BitmapDataChannel;
28         import flash.display.BlendMode;
29         import flash.errors.IOError;
30         import flash.utils.ByteArray;
31         import flash.utils.Endian;
32        
33         public class ICOImageData {
34                 private const COMP_RGB      :int = 0;
35                 private const COMP_RLE8     :int = 1;
36                 private const COMP_RLE4     :int = 2;
37                 private const COMP_BITFIELDS:int = 3;
38                
39                 private const BIT1 :int = 1;
40                 private const BIT4 :int = 4;
41                 private const BIT8 :int = 8;
42                 private const BIT16:int = 16;
43                 private const BIT24:int = 24;
44                 private const BIT32:int = 32;
45                
46                
47                 private var _image:BitmapData;
48                 public function get image():BitmapData { return _image; }
49                
50                 private var _mask:BitmapData;
51                 public function get mask():BitmapData { return _mask; }
52                
53                 private var _info:BitmapInfoHeader;
54                 public function get info():BitmapInfoHeader { return _info; }
55                
56                 private var _palette:Array;
57                 public function get palette():Array { return _palette; }
58                
59                
60                 private var nRMask:uint;
61                 private var nGMask:uint;
62                 private var nBMask:uint;
63                 private var nRPos:uint = 0;
64                 private var nGPos:uint = 0;
65                 private var nBPos:uint = 0;
66                 private var nRMax:uint;
67                 private var nGMax:uint;
68                 private var nBMax:uint;
69                
70                
71                 public function ICOImageData( stream:ByteArray ) {
72                         _info = new BitmapInfoHeader( stream );
73                         _image = new BitmapData( info.width, info.height, true );
74                        
75                         stream.endian = Endian.LITTLE_ENDIAN;
76                        
77                         ICODecoder.log("bpp: " + info.bitsPerPixel );
78                         ICODecoder.log("comp: " + info.compression );
79                         ICODecoder.log("used: " + info.colorUsed );
80                         ICODecoder.log("impo: " + info.colorImportant );
81                        
82                         switch ( info.bitsPerPixel ){
83                                 case BIT1:
84                                         readColorPalette( stream );
85                                         decode1BitBMP( stream );
86                                         decodeMaskData( stream );
87                                         break;
88                                 case BIT4:
89                                         readColorPalette( stream );
90                                         if ( info.compression == COMP_RLE4 ){
91                                                 decode4bitRLE( stream );
92                                         } else {
93                                                 decode4BitBMP( stream );
94                                         }
95                                         decodeMaskData( stream );
96                                         break;
97                                 case BIT8:
98                                         readColorPalette( stream );
99                                         if ( info.compression == COMP_RLE8 ){
100                                                 decode8BitRLE( stream );
101                                         } else {
102                                                 decode8BitBMP( stream );
103                                         }
104                                         decodeMaskData( stream );
105                                         break;
106                                 case BIT16:
107                                         readBitFields( stream );
108                                         checkColorMask();
109                                         decode16BitBMP( stream );
110                                         decodeMaskData( stream );
111                                         break;
112                                 case BIT24:
113                                         decode24BitBMP( stream );
114                                         decodeMaskData( stream );
115                                         break;
116                                 case BIT32:
117                                         readBitFields( stream );
118                                         checkColorMask();
119                                         decode32BitBMP( stream );
120                                         decodeMaskData( stream );
121                                         break;
122                                 default:
123                                         throw new VerifyError("invalid bits per pixel : " + info.bitsPerPixel );
124                         }
125                 }
126                
127                 /**
128                  * ビットフィールド読み込み
129                  */
130                 private function readBitFields( stream:ByteArray ):void {
131                         if ( info.compression == COMP_RGB ){
132                                 if ( info.bitsPerPixel == BIT16 ){
133                                         // RGB555
134                                         nRMask = 0x00007c00;
135                                         nGMask = 0x000003e0;
136                                         nBMask = 0x0000001f;
137                                 } else {
138                                         //RGB888;
139                                         nRMask = 0x00ff0000;
140                                         nGMask = 0x0000ff00;
141                                         nBMask = 0x000000ff;
142                                 }
143                         } else if ( info.compression == COMP_BITFIELDS ){
144                                 try {
145                                         nRMask = stream.readUnsignedInt();
146                                         nGMask = stream.readUnsignedInt();
147                                         nBMask = stream.readUnsignedInt();
148                                 } catch ( e:IOError ) {
149                                         throw new VerifyError("invalid bit fields");
150                                 }
151                         }
152                 }
153                
154                
155                 /**
156                  * カラーパレット読み込み
157                  */
158                 private function readColorPalette( stream:ByteArray ):void {
159                         var i:int;
160                         var len:int = ( info.colorUsed > 0 ) ? info.colorUsed : Math.pow( 2, info.bitsPerPixel );
161                        
162                         _palette = new Array( len );
163                        
164                         for ( i = 0; i < len; ++i ){
165                                 palette[ i ] = stream.readUnsignedInt();
166                         }
167                 }
168                
169                
170                 /**
171                  * 1bitのBMPデコード
172                  */
173                 private function decode1BitBMP( stream:ByteArray ):void {
174                         var x:int;
175                         var y:int;
176                         var i:int;
177                         var col:int;
178                         var buf:ByteArray = new ByteArray();
179                         var line:int = info.width / 8;
180                        
181                         if ( line % 4 > 0 ){
182                                 line = ( ( line / 4 | 0 ) + 1 ) * 4;
183                         }
184                        
185                         try {
186                                 for ( y = info.height - 1; y >= 0; --y ){
187                                         buf.length = 0;
188                                         stream.readBytes( buf, 0, line );
189                                        
190                                         for ( x = 0; x < info.width; x += 8 ){
191                                                 col = buf.readUnsignedByte();
192                                                
193                                                 for ( i = 0; i < 8; ++i ){
194                                                         image.setPixel( x + i, y, palette[ col >> ( 7 - i ) & 0x01 ] );
195                                                 }
196                                         }
197                                 }
198                         } catch ( e:IOError ) {
199                                 throw new VerifyError("invalid image data");
200                         }
201                 }
202                
203                
204                 /**
205                  * 4bitのRLE圧縮BMPデコード
206                  */
207                 private function decode4bitRLE( stream:ByteArray ):void {
208                         var x:int;
209                         var y:int;
210                         var i:int;
211                         var n:int;
212                         var col:int;
213                         var data:uint;
214                         var buf:ByteArray = new ByteArray();
215                        
216                         try {
217                                 for ( y = info.height - 1; y >= 0; --y ){
218                                         buf.length = 0;
219                                        
220                                         while ( stream.bytesAvailable > 0 ){
221                                                 n = stream.readUnsignedByte();
222                                                
223                                                 if ( n > 0 ){
224                                                         // エンコードデータ
225                                                         data = stream.readUnsignedByte();
226                                                         for ( i = 0; i < n/2; ++i ){
227                                                                 buf.writeByte( data );
228                                                         }
229                                                 } else {
230                                                         n = stream.readUnsignedByte();
231                                                        
232                                                         if ( n > 0 ){
233                                                                 // 絶対モードデータ
234                                                                 stream.readBytes( buf, buf.length, n/2 );
235                                                                 buf.position += n/2;
236                                                                
237                                                                 if ( n/2 + 1 >> 1 << 1 != n/2 ){
238                                                                         stream.readUnsignedByte();
239                                                                 }
240                                                         } else {
241                                                                 // EOL
242                                                                 break;
243                                                         }
244                                                 }
245                                         }
246                                        
247                                         buf.position = 0;
248                                        
249                                         for ( x = 0; x < info.width; x += 2 ){
250                                                 col = buf.readUnsignedByte();
251                                                
252                                                 image.setPixel( x, y, palette[ col >> 4 ] );
253                                                 image.setPixel( x + 1, y, palette[ col & 0x0f ] );
254                                         }
255                                 }
256                         } catch ( e:IOError ) {
257                                 throw new VerifyError("invalid image data");
258                         }
259                 }
260                
261                
262                 /**
263                  * 4bitの非圧縮BMPデコード
264                  */
265                 private function decode4BitBMP( stream:ByteArray ):void {
266                         var x:int;
267                         var y:int;
268                         var i:int;
269                         var col:int;
270                         var buf:ByteArray = new ByteArray();
271                         var line:int = info.width / 2;
272                        
273                         if ( line % 4 > 0 ){
274                                 line = ( ( line / 4 | 0 ) + 1 ) * 4;
275                         }
276                        
277                         try {
278                                 for ( y = info.height - 1; y >= 0; --y ){
279                                         buf.length = 0;
280                                         stream.readBytes( buf, 0, line );
281                                        
282                                         for ( x = 0; x < info.width; x += 2 ){
283                                                 col = buf.readUnsignedByte();
284                                                
285                                                 image.setPixel( x, y, palette[ col >> 4 ] );
286                                                 image.setPixel( x + 1, y, palette[ col & 0x0f ] );
287                                         }
288                                 }
289                         } catch ( e:IOError ) {
290                                 throw new VerifyError("invalid image data");
291                         }
292                 }
293                
294                
295                 /**
296                  * 8bitのRLE圧縮BMPデコード
297                  */
298                 private function decode8BitRLE( stream:ByteArray ):void {
299                         var x:int;
300                         var y:int;
301                         var i:int;
302                         var n:int;
303                         var col:int;
304                         var data:uint;
305                         var buf:ByteArray = new ByteArray();
306                        
307                         try {
308                                 for ( y = info.height - 1; y >= 0; --y ){
309                                         buf.length = 0;
310                                        
311                                         while ( stream.bytesAvailable > 0 ){
312                                                 n = stream.readUnsignedByte();
313                                                
314                                                 if ( n > 0 ){
315                                                         // エンコードデータ
316                                                         data = stream.readUnsignedByte();
317                                                         for ( i = 0; i < n; ++i ){
318                                                                 buf.writeByte( data );
319                                                         }
320                                                 } else {
321                                                         n = stream.readUnsignedByte();
322                                                        
323                                                         if ( n > 0 ){
324                                                                 // 絶対モードデータ
325                                                                 stream.readBytes( buf, buf.length, n );
326                                                                 buf.position += n;
327                                                                 if ( n + 1 >> 1 << 1 != n ){
328                                                                         stream.readUnsignedByte();
329                                                                 }
330                                                         } else {
331                                                                 // EOL
332                                                                 break;
333                                                         }
334                                                 }
335                                         }
336                                        
337                                         buf.position = 0;
338                                        
339                                         for ( x = 0; x < info.width; ++x ){
340                                                 image.setPixel( x, y, palette[ buf.readUnsignedByte() ] );
341                                         }
342                                 }
343                         } catch ( e:IOError ) {
344                                 throw new VerifyError("invalid image data");
345                         }
346                 }
347                
348                 /**
349                  * 8bitの非圧縮BMPデコード
350                  */
351                 private function decode8BitBMP( stream:ByteArray ):void {
352                         var x:int;
353                         var y:int;
354                         var i:int;
355                         var col:int;
356                         var buf:ByteArray = new ByteArray();
357                         var line:int = info.width;
358                        
359                         if ( line % 4 > 0 ){
360                                 line = ( ( line / 4 | 0 ) + 1 ) * 4;
361                         }
362                        
363                         try {
364                                 for ( y = info.height - 1; y >= 0; --y ){
365                                         buf.length = 0;
366                                         stream.readBytes( buf, 0, line );
367                                        
368                                         for ( x = 0; x < info.width; ++x ){
369                                                 image.setPixel( x, y, palette[ buf.readUnsignedByte() ] );
370                                         }
371                                 }
372                         } catch ( e:IOError ) {
373                                 throw new VerifyError("invalid image data");
374                         }
375                 }
376                
377                 /**
378                  * 16bitのBMPデコード
379                  */
380                 private function decode16BitBMP( stream:ByteArray ):void {
381                         var x:int;
382                         var y:int;
383                         var col:int;
384                        
385                         try {
386                                 for ( y = info.height - 1; y >= 0; --y ){
387                                         for ( x = 0; x < info.width; ++x ){
388                                                 col = stream.readUnsignedShort();
389                                                 image.setPixel( x, y, ( ( ( col & nRMask ) >> nRPos )*0xff/nRMax << 16 ) + ( ( ( col & nGMask ) >> nGPos )*0xff/nGMax << 8 ) + ( ( ( col & nBMask ) >> nBPos )*0xff/nBMax << 0 ) );
390                                         }
391                                 }
392                         } catch ( e:IOError ) {
393                                 throw new VerifyError("invalid image data");
394                         }
395                 }
396                
397                 /**
398                  * 24bitのBMPデコード
399                  */
400                 private function decode24BitBMP( stream:ByteArray ):void {
401                         var x:int;
402                         var y:int;
403                         var col:int;
404                         var buf:ByteArray = new ByteArray();
405                         var line:int = info.width * 3;
406                        
407                         if ( line % 4 > 0 ){
408                                 line = ( ( line / 4 | 0 ) + 1 ) * 4;
409                         }
410                        
411                         try {
412                                 for ( y = info.height - 1; y >= 0; --y ){
413                                         buf.length = 0;
414                                         stream.readBytes( buf, 0, line );
415                                        
416                                         for ( x = 0; x < info.width; ++x ){
417                                                 image.setPixel( x, y, buf.readUnsignedByte() + ( buf.readUnsignedByte() << 8 ) + ( buf.readUnsignedByte() << 16 ) );
418                                         }
419                                 }
420                         } catch ( e:IOError ) {
421                                 throw new VerifyError("invalid image data");
422                         }
423                 }
424                
425                 /**
426                  * 32bitのBMPデコード
427                  */
428                 private function decode32BitBMP( stream:ByteArray ):void {
429                         var x:int;
430                         var y:int;
431                         var col:int;
432                        
433                         try {
434                                 for ( y = info.height - 1; y >= 0; --y ){
435                                         for ( x = 0; x < info.width; ++x ){
436                                                 col = stream.readUnsignedInt();
437                                                 image.setPixel( x, y, ( ( ( col & nRMask ) >> nRPos )*0xff/nRMax << 16 ) | ( ( ( col & nGMask ) >> nGPos )*0xff/nGMax << 8 ) | ( ( ( col & nBMask ) >> nBPos )*0xff/nBMax << 0 ) );
438                                         }
439                                 }
440                         } catch ( e:IOError ) {
441                                 throw new VerifyError("invalid image data");
442                         }
443                 }
444                
445                
446                 /**
447                  * 透過マスクデコード
448                  */
449                 private function decodeMaskData( stream:ByteArray ):void {
450                         _mask = new BitmapData( info.width, info.height, false, 0xffffff );
451                        
452                         stream.endian = Endian.BIG_ENDIAN;
453                        
454                         try {
455                                 for ( var y:int = info.height - 1; y >= 0; --y ) {
456                                         var alpha:uint = stream.readUnsignedInt() >>> ( 32 - info.width );
457                                        
458                                         for ( var x:int = 0; x < info.width; ++x ) {
459                                                 if ( ( alpha >>> ( info.width - 1 - x ) ) & 1 ) {
460                                                         mask.setPixel( x, y, 0x000000 );
461                                                 }
462                                         }
463                                 }
464                         } catch ( e:IOError ) {
465                                 throw new VerifyError("invalid mask data");
466                         }
467                        
468                         image.copyChannel( mask, mask.rect, mask.rect.topLeft, BitmapDataChannel.BLUE, BitmapDataChannel.ALPHA );
469                 }
470                
471                
472                 /**
473                  * カラーマスクチェック
474                  */
475                 private function checkColorMask():void {
476                         if ( ( nRMask & nGMask ) | ( nGMask & nBMask ) | ( nBMask & nRMask ) ){
477                                 throw new VerifyError("invalid bit fields");
478                         }
479                        
480                         while ( ( ( nRMask >> nRPos ) & 0x00000001 ) == 0 ){
481                                 nRPos++;
482                         }
483                         while ( ( ( nGMask >> nGPos ) & 0x00000001 ) == 0 ){
484                                 nGPos++;
485                         }
486                         while ( ( ( nBMask >> nBPos ) & 0x00000001 ) == 0 ){
487                                 nBPos++;
488                         }
489                        
490                         nRMax = nRMask >> nRPos;
491                         nGMax = nGMask >> nGPos;
492                         nBMax = nBMask >> nBPos;
493                 }
494         }
495 }
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。