External/Aga.Controls/GifDecoder.cs
author moel.mich
Sun, 23 Sep 2012 18:37:43 +0000
changeset 380 573f1fff48b2
permissions -rw-r--r--
Fixed Issue 387. The new implementation does not try to start a ring 0 driver that already exists, but could not be opened. It tries to delete the driver and install it new. The driver is now stored temporarily in the application folder. The driver is not correctly removed on system shutdown.
moel@345
     1
#pragma warning disable 675 // Bitwise-or operator used on a sign-extended operand
moel@345
     2
moel@345
     3
#region Java Info
moel@345
     4
/**
moel@345
     5
 * Class GifDecoder - Decodes a GIF file into one or more frames.
moel@345
     6
 * <br><pre>
moel@345
     7
 * Example:
moel@345
     8
 *    GifDecoder d = new GifDecoder();
moel@345
     9
 *    d.read("sample.gif");
moel@345
    10
 *    int n = d.getFrameCount();
moel@345
    11
 *    for (int i = 0; i < n; i++) {
moel@345
    12
 *       BufferedImage frame = d.getFrame(i);  // frame i
moel@345
    13
 *       int t = d.getDelay(i);  // display duration of frame in milliseconds
moel@345
    14
 *       // do something with frame
moel@345
    15
 *    }
moel@345
    16
 * </pre>
moel@345
    17
 * No copyright asserted on the source code of this class.  May be used for
moel@345
    18
 * any purpose, however, refer to the Unisys LZW patent for any additional
moel@345
    19
 * restrictions.  Please forward any corrections to kweiner@fmsware.com.
moel@345
    20
 *
moel@345
    21
 * @author Kevin Weiner, FM Software; LZW decoder adapted from John Cristy's ImageMagick.
moel@345
    22
 * @version 1.03 November 2003
moel@345
    23
 *
moel@345
    24
 */
moel@345
    25
#endregion
moel@345
    26
moel@345
    27
using System;
moel@345
    28
using System.Collections;
moel@345
    29
using System.Drawing;
moel@345
    30
using System.Drawing.Imaging;
moel@345
    31
using System.IO;
moel@345
    32
moel@345
    33
namespace Aga.Controls
moel@345
    34
{
moel@345
    35
	public class GifFrame
moel@345
    36
	{
moel@345
    37
		private Image _image;
moel@345
    38
		public Image Image
moel@345
    39
		{
moel@345
    40
			get { return _image; }
moel@345
    41
		}
moel@345
    42
moel@345
    43
		private int _delay;
moel@345
    44
		public int Delay
moel@345
    45
		{
moel@345
    46
			get { return _delay; }
moel@345
    47
		}
moel@345
    48
moel@345
    49
		public GifFrame(Image im, int del)
moel@345
    50
		{
moel@345
    51
			_image = im;
moel@345
    52
			_delay = del;
moel@345
    53
		}
moel@345
    54
	}
moel@345
    55
moel@345
    56
	public class GifDecoder 
moel@345
    57
	{
moel@345
    58
		public const int StatusOK = 0;//File read status: No errors.
moel@345
    59
		public const int StatusFormatError = 1; //File read status: Error decoding file (may be partially decoded)
moel@345
    60
		public const int StatusOpenError = 2; //Unable to open source.
moel@345
    61
moel@345
    62
		private Stream inStream;
moel@345
    63
		private int status;
moel@345
    64
moel@345
    65
		private int width; // full image width
moel@345
    66
		private int height; // full image height
moel@345
    67
		private bool gctFlag; // global color table used
moel@345
    68
		private int gctSize; // size of global color table
moel@345
    69
		private int loopCount = 1; // iterations; 0 = repeat forever
moel@345
    70
moel@345
    71
		private int[] gct; // global color table
moel@345
    72
		private int[] lct; // local color table
moel@345
    73
		private int[] act; // active color table
moel@345
    74
moel@345
    75
		private int bgIndex; // background color index
moel@345
    76
		private int bgColor; // background color
moel@345
    77
		private int lastBgColor; // previous bg color
moel@345
    78
		private int pixelAspect; // pixel aspect ratio
moel@345
    79
moel@345
    80
		private bool lctFlag; // local color table flag
moel@345
    81
		private bool interlace; // interlace flag
moel@345
    82
		private int lctSize; // local color table size
moel@345
    83
moel@345
    84
		private int ix, iy, iw, ih; // current image rectangle
moel@345
    85
		private Rectangle lastRect; // last image rect
moel@345
    86
		private Image image; // current frame
moel@345
    87
		private Bitmap bitmap;
moel@345
    88
		private Image lastImage; // previous frame
moel@345
    89
moel@345
    90
		private byte[] block = new byte[256]; // current data block
moel@345
    91
		private int blockSize = 0; // block size
moel@345
    92
moel@345
    93
		// last graphic control extension info
moel@345
    94
		private int dispose = 0;
moel@345
    95
		// 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev
moel@345
    96
		private int lastDispose = 0;
moel@345
    97
		private bool transparency = false; // use transparent color
moel@345
    98
		private int delay = 0; // delay in milliseconds
moel@345
    99
		private int transIndex; // transparent color index
moel@345
   100
moel@345
   101
		private const int MaxStackSize = 4096;
moel@345
   102
		// max decoder pixel stack size
moel@345
   103
moel@345
   104
		// LZW decoder working arrays
moel@345
   105
		private short[] prefix;
moel@345
   106
		private byte[] suffix;
moel@345
   107
		private byte[] pixelStack;
moel@345
   108
		private byte[] pixels;
moel@345
   109
moel@345
   110
		private ArrayList frames; // frames read from current file
moel@345
   111
		private int frameCount;
moel@345
   112
		private bool _makeTransparent;
moel@345
   113
moel@345
   114
		/**
moel@345
   115
		 * Gets the number of frames read from file.
moel@345
   116
		 * @return frame count
moel@345
   117
		 */
moel@345
   118
		public int FrameCount
moel@345
   119
		{
moel@345
   120
			get
moel@345
   121
			{
moel@345
   122
				return frameCount;
moel@345
   123
			}
moel@345
   124
		}
moel@345
   125
moel@345
   126
		/**
moel@345
   127
		 * Gets the first (or only) image read.
moel@345
   128
		 *
moel@345
   129
		 * @return BufferedImage containing first frame, or null if none.
moel@345
   130
		 */
moel@345
   131
		public Image Image
moel@345
   132
		{
moel@345
   133
			get
moel@345
   134
			{
moel@345
   135
				return GetFrame(0).Image;
moel@345
   136
			}
moel@345
   137
		}
moel@345
   138
moel@345
   139
		/**
moel@345
   140
		 * Gets the "Netscape" iteration count, if any.
moel@345
   141
		 * A count of 0 means repeat indefinitiely.
moel@345
   142
		 *
moel@345
   143
		 * @return iteration count if one was specified, else 1.
moel@345
   144
		 */
moel@345
   145
		public int LoopCount
moel@345
   146
		{
moel@345
   147
			get
moel@345
   148
			{
moel@345
   149
				return loopCount;
moel@345
   150
			}
moel@345
   151
		}
moel@345
   152
moel@345
   153
		public GifDecoder(Stream stream, bool makeTransparent)
moel@345
   154
		{
moel@345
   155
			_makeTransparent = makeTransparent;
moel@345
   156
			if (Read(stream) != 0)
moel@345
   157
				throw new InvalidOperationException();
moel@345
   158
		}
moel@345
   159
moel@345
   160
		/**
moel@345
   161
		 * Creates new frame image from current data (and previous
moel@345
   162
		 * frames as specified by their disposition codes).
moel@345
   163
		 */
moel@345
   164
		private int[] GetPixels(Bitmap bitmap)
moel@345
   165
		{
moel@345
   166
			int [] pixels = new int [ 3 * image.Width * image.Height ];
moel@345
   167
			int count = 0;
moel@345
   168
			for (int th = 0; th < image.Height; th++)
moel@345
   169
			{
moel@345
   170
				for (int tw = 0; tw < image.Width; tw++)
moel@345
   171
				{
moel@345
   172
					Color color = bitmap.GetPixel(tw, th);
moel@345
   173
					pixels[count] = color.R;
moel@345
   174
					count++;
moel@345
   175
					pixels[count] = color.G;
moel@345
   176
					count++;
moel@345
   177
					pixels[count] = color.B;
moel@345
   178
					count++;
moel@345
   179
				}
moel@345
   180
			}
moel@345
   181
			return pixels;
moel@345
   182
		}
moel@345
   183
moel@345
   184
		private void SetPixels(int[] pixels)
moel@345
   185
		{
moel@345
   186
			int count = 0;
moel@345
   187
			for (int th = 0; th < image.Height; th++)
moel@345
   188
			{
moel@345
   189
				for (int tw = 0; tw < image.Width; tw++)
moel@345
   190
				{
moel@345
   191
					Color color = Color.FromArgb( pixels[count++] );
moel@345
   192
					bitmap.SetPixel( tw, th, color );
moel@345
   193
				}
moel@345
   194
			}
moel@345
   195
			if (_makeTransparent)
moel@345
   196
				bitmap.MakeTransparent(bitmap.GetPixel(0, 0));
moel@345
   197
		}
moel@345
   198
moel@345
   199
		private void SetPixels() 
moel@345
   200
		{
moel@345
   201
			// expose destination image's pixels as int array
moel@345
   202
			//		int[] dest =
moel@345
   203
			//			(( int ) image.getRaster().getDataBuffer()).getData();
moel@345
   204
			int[] dest = GetPixels( bitmap );
moel@345
   205
moel@345
   206
			// fill in starting image contents based on last image's dispose code
moel@345
   207
			if (lastDispose > 0) 
moel@345
   208
			{
moel@345
   209
				if (lastDispose == 3) 
moel@345
   210
				{
moel@345
   211
					// use image before last
moel@345
   212
					int n = frameCount - 2;
moel@345
   213
					if (n > 0) 
moel@345
   214
					{
moel@345
   215
						lastImage = GetFrame(n - 1).Image;
moel@345
   216
					} 
moel@345
   217
					else 
moel@345
   218
					{
moel@345
   219
						lastImage = null;
moel@345
   220
					}
moel@345
   221
				}
moel@345
   222
moel@345
   223
				if (lastImage != null) 
moel@345
   224
				{
moel@345
   225
					//				int[] prev =
moel@345
   226
					//					((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData();
moel@345
   227
					int[] prev = GetPixels( new Bitmap( lastImage ) );
moel@345
   228
					Array.Copy(prev, 0, dest, 0, width * height);
moel@345
   229
					// copy pixels
moel@345
   230
moel@345
   231
					if (lastDispose == 2) 
moel@345
   232
					{
moel@345
   233
						// fill last image rect area with background color
moel@345
   234
						Graphics g = Graphics.FromImage( image );
moel@345
   235
						Color c = Color.Empty;
moel@345
   236
						if (transparency) 
moel@345
   237
						{
moel@345
   238
							c = Color.FromArgb( 0, 0, 0, 0 ); 	// assume background is transparent
moel@345
   239
						} 
moel@345
   240
						else 
moel@345
   241
						{
moel@345
   242
							c = Color.FromArgb( lastBgColor ) ;
moel@345
   243
							//						c = new Color(lastBgColor); // use given background color
moel@345
   244
						}
moel@345
   245
						Brush brush = new SolidBrush( c );
moel@345
   246
						g.FillRectangle( brush, lastRect );
moel@345
   247
						brush.Dispose();
moel@345
   248
						g.Dispose();
moel@345
   249
					}
moel@345
   250
				}
moel@345
   251
			}
moel@345
   252
moel@345
   253
			// copy each source line to the appropriate place in the destination
moel@345
   254
			int pass = 1;
moel@345
   255
			int inc = 8;
moel@345
   256
			int iline = 0;
moel@345
   257
			for (int i = 0; i < ih; i++) 
moel@345
   258
			{
moel@345
   259
				int line = i;
moel@345
   260
				if (interlace) 
moel@345
   261
				{
moel@345
   262
					if (iline >= ih) 
moel@345
   263
					{
moel@345
   264
						pass++;
moel@345
   265
						switch (pass) 
moel@345
   266
						{
moel@345
   267
							case 2 :
moel@345
   268
								iline = 4;
moel@345
   269
								break;
moel@345
   270
							case 3 :
moel@345
   271
								iline = 2;
moel@345
   272
								inc = 4;
moel@345
   273
								break;
moel@345
   274
							case 4 :
moel@345
   275
								iline = 1;
moel@345
   276
								inc = 2;
moel@345
   277
								break;
moel@345
   278
						}
moel@345
   279
					}
moel@345
   280
					line = iline;
moel@345
   281
					iline += inc;
moel@345
   282
				}
moel@345
   283
				line += iy;
moel@345
   284
				if (line < height) 
moel@345
   285
				{
moel@345
   286
					int k = line * width;
moel@345
   287
					int dx = k + ix; // start of line in dest
moel@345
   288
					int dlim = dx + iw; // end of dest line
moel@345
   289
					if ((k + width) < dlim) 
moel@345
   290
					{
moel@345
   291
						dlim = k + width; // past dest edge
moel@345
   292
					}
moel@345
   293
					int sx = i * iw; // start of line in source
moel@345
   294
					while (dx < dlim) 
moel@345
   295
					{
moel@345
   296
						// map color and insert in destination
moel@345
   297
						int index = ((int) pixels[sx++]) & 0xff;
moel@345
   298
						int c = act[index];
moel@345
   299
						if (c != 0) 
moel@345
   300
						{
moel@345
   301
							dest[dx] = c;
moel@345
   302
						}
moel@345
   303
						dx++;
moel@345
   304
					}
moel@345
   305
				}
moel@345
   306
			}
moel@345
   307
			SetPixels( dest );
moel@345
   308
		}
moel@345
   309
moel@345
   310
		/**
moel@345
   311
		 * Gets the image contents of frame n.
moel@345
   312
		 *
moel@345
   313
		 * @return BufferedImage representation of frame.
moel@345
   314
		 */
moel@345
   315
		public GifFrame GetFrame(int n) 
moel@345
   316
		{
moel@345
   317
			if ((n >= 0) && (n < frameCount))
moel@345
   318
				return (GifFrame)frames[n];
moel@345
   319
			else
moel@345
   320
				throw new ArgumentOutOfRangeException();
moel@345
   321
		}
moel@345
   322
moel@345
   323
		/**
moel@345
   324
		 * Gets image size.
moel@345
   325
		 *
moel@345
   326
		 * @return GIF image dimensions
moel@345
   327
		 */
moel@345
   328
		public Size FrameSize
moel@345
   329
		{
moel@345
   330
			get
moel@345
   331
			{
moel@345
   332
				return new Size(width, height);
moel@345
   333
			}
moel@345
   334
		}
moel@345
   335
moel@345
   336
		/**
moel@345
   337
		 * Reads GIF image from stream
moel@345
   338
		 *
moel@345
   339
		 * @param BufferedInputStream containing GIF file.
moel@345
   340
		 * @return read status code (0 = no errors)
moel@345
   341
		 */
moel@345
   342
		private int Read( Stream inStream ) 
moel@345
   343
		{
moel@345
   344
			Init();
moel@345
   345
			if ( inStream != null) 
moel@345
   346
			{
moel@345
   347
				this.inStream = inStream;
moel@345
   348
				ReadHeader();
moel@345
   349
				if (!Error()) 
moel@345
   350
				{
moel@345
   351
					ReadContents();
moel@345
   352
					if (frameCount < 0) 
moel@345
   353
					{
moel@345
   354
						status = StatusFormatError;
moel@345
   355
					}
moel@345
   356
				}
moel@345
   357
				inStream.Close();
moel@345
   358
			} 
moel@345
   359
			else 
moel@345
   360
			{
moel@345
   361
				status = StatusOpenError;
moel@345
   362
			}
moel@345
   363
			return status;
moel@345
   364
		}
moel@345
   365
moel@345
   366
moel@345
   367
		/**
moel@345
   368
		 * Decodes LZW image data into pixel array.
moel@345
   369
		 * Adapted from John Cristy's ImageMagick.
moel@345
   370
		 */
moel@345
   371
		private void DecodeImageData() 
moel@345
   372
		{
moel@345
   373
			int NullCode = -1;
moel@345
   374
			int npix = iw * ih;
moel@345
   375
			int available, 
moel@345
   376
				clear,
moel@345
   377
				code_mask,
moel@345
   378
				code_size,
moel@345
   379
				end_of_information,
moel@345
   380
				in_code,
moel@345
   381
				old_code,
moel@345
   382
				bits,
moel@345
   383
				code,
moel@345
   384
				count,
moel@345
   385
				i,
moel@345
   386
				datum,
moel@345
   387
				data_size,
moel@345
   388
				first,
moel@345
   389
				top,
moel@345
   390
				bi,
moel@345
   391
				pi;
moel@345
   392
moel@345
   393
			if ((pixels == null) || (pixels.Length < npix)) 
moel@345
   394
			{
moel@345
   395
				pixels = new byte[npix]; // allocate new pixel array
moel@345
   396
			}
moel@345
   397
			if (prefix == null) prefix = new short[MaxStackSize];
moel@345
   398
			if (suffix == null) suffix = new byte[MaxStackSize];
moel@345
   399
			if (pixelStack == null) pixelStack = new byte[MaxStackSize + 1];
moel@345
   400
moel@345
   401
			//  Initialize GIF data stream decoder.
moel@345
   402
moel@345
   403
			data_size = Read();
moel@345
   404
			clear = 1 << data_size;
moel@345
   405
			end_of_information = clear + 1;
moel@345
   406
			available = clear + 2;
moel@345
   407
			old_code = NullCode;
moel@345
   408
			code_size = data_size + 1;
moel@345
   409
			code_mask = (1 << code_size) - 1;
moel@345
   410
			for (code = 0; code < clear; code++) 
moel@345
   411
			{
moel@345
   412
				prefix[code] = 0;
moel@345
   413
				suffix[code] = (byte) code;
moel@345
   414
			}
moel@345
   415
moel@345
   416
			//  Decode GIF pixel stream.
moel@345
   417
moel@345
   418
			datum = bits = count = first = top = pi = bi = 0;
moel@345
   419
moel@345
   420
			for (i = 0; i < npix;) 
moel@345
   421
			{
moel@345
   422
				if (top == 0) 
moel@345
   423
				{
moel@345
   424
					if (bits < code_size) 
moel@345
   425
					{
moel@345
   426
						//  Load bytes until there are enough bits for a code.
moel@345
   427
						if (count == 0) 
moel@345
   428
						{
moel@345
   429
							// Read a new data block.
moel@345
   430
							count = ReadBlock();
moel@345
   431
							if (count <= 0)
moel@345
   432
								break;
moel@345
   433
							bi = 0;
moel@345
   434
						}
moel@345
   435
						datum += (((int) block[bi]) & 0xff) << bits;
moel@345
   436
						bits += 8;
moel@345
   437
						bi++;
moel@345
   438
						count--;
moel@345
   439
						continue;
moel@345
   440
					}
moel@345
   441
moel@345
   442
					//  Get the next code.
moel@345
   443
moel@345
   444
					code = datum & code_mask;
moel@345
   445
					datum >>= code_size;
moel@345
   446
					bits -= code_size;
moel@345
   447
moel@345
   448
					//  Interpret the code
moel@345
   449
moel@345
   450
					if ((code > available) || (code == end_of_information))
moel@345
   451
						break;
moel@345
   452
					if (code == clear) 
moel@345
   453
					{
moel@345
   454
						//  Reset decoder.
moel@345
   455
						code_size = data_size + 1;
moel@345
   456
						code_mask = (1 << code_size) - 1;
moel@345
   457
						available = clear + 2;
moel@345
   458
						old_code = NullCode;
moel@345
   459
						continue;
moel@345
   460
					}
moel@345
   461
					if (old_code == NullCode) 
moel@345
   462
					{
moel@345
   463
						pixelStack[top++] = suffix[code];
moel@345
   464
						old_code = code;
moel@345
   465
						first = code;
moel@345
   466
						continue;
moel@345
   467
					}
moel@345
   468
					in_code = code;
moel@345
   469
					if (code == available) 
moel@345
   470
					{
moel@345
   471
						pixelStack[top++] = (byte) first;
moel@345
   472
						code = old_code;
moel@345
   473
					}
moel@345
   474
					while (code > clear) 
moel@345
   475
					{
moel@345
   476
						pixelStack[top++] = suffix[code];
moel@345
   477
						code = prefix[code];
moel@345
   478
					}
moel@345
   479
					first = ((int) suffix[code]) & 0xff;
moel@345
   480
moel@345
   481
					//  Add a new string to the string table,
moel@345
   482
moel@345
   483
					if (available >= MaxStackSize)
moel@345
   484
						break;
moel@345
   485
					pixelStack[top++] = (byte) first;
moel@345
   486
					prefix[available] = (short) old_code;
moel@345
   487
					suffix[available] = (byte) first;
moel@345
   488
					available++;
moel@345
   489
					if (((available & code_mask) == 0)
moel@345
   490
						&& (available < MaxStackSize)) 
moel@345
   491
					{
moel@345
   492
						code_size++;
moel@345
   493
						code_mask += available;
moel@345
   494
					}
moel@345
   495
					old_code = in_code;
moel@345
   496
				}
moel@345
   497
moel@345
   498
				//  Pop a pixel off the pixel stack.
moel@345
   499
moel@345
   500
				top--;
moel@345
   501
				pixels[pi++] = pixelStack[top];
moel@345
   502
				i++;
moel@345
   503
			}
moel@345
   504
moel@345
   505
			for (i = pi; i < npix; i++) 
moel@345
   506
			{
moel@345
   507
				pixels[i] = 0; // clear missing pixels
moel@345
   508
			}
moel@345
   509
moel@345
   510
		}
moel@345
   511
moel@345
   512
		/**
moel@345
   513
		 * Returns true if an error was encountered during reading/decoding
moel@345
   514
		 */
moel@345
   515
		private bool Error() 
moel@345
   516
		{
moel@345
   517
			return status != StatusOK;
moel@345
   518
		}
moel@345
   519
moel@345
   520
		/**
moel@345
   521
		 * Initializes or re-initializes reader
moel@345
   522
		 */
moel@345
   523
		private void Init() 
moel@345
   524
		{
moel@345
   525
			status = StatusOK;
moel@345
   526
			frameCount = 0;
moel@345
   527
			frames = new ArrayList();
moel@345
   528
			gct = null;
moel@345
   529
			lct = null;
moel@345
   530
		}
moel@345
   531
moel@345
   532
		/**
moel@345
   533
		 * Reads a single byte from the input stream.
moel@345
   534
		 */
moel@345
   535
		private int Read() 
moel@345
   536
		{
moel@345
   537
			int curByte = 0;
moel@345
   538
			try 
moel@345
   539
			{
moel@345
   540
				curByte = inStream.ReadByte();
moel@345
   541
			} 
moel@345
   542
			catch (IOException) 
moel@345
   543
			{
moel@345
   544
				status = StatusFormatError;
moel@345
   545
			}
moel@345
   546
			return curByte;
moel@345
   547
		}
moel@345
   548
moel@345
   549
		/**
moel@345
   550
		 * Reads next variable length block from input.
moel@345
   551
		 *
moel@345
   552
		 * @return number of bytes stored in "buffer"
moel@345
   553
		 */
moel@345
   554
		private int ReadBlock() 
moel@345
   555
		{
moel@345
   556
			blockSize = Read();
moel@345
   557
			int n = 0;
moel@345
   558
			if (blockSize > 0) 
moel@345
   559
			{
moel@345
   560
				try 
moel@345
   561
				{
moel@345
   562
					int count = 0;
moel@345
   563
					while (n < blockSize) 
moel@345
   564
					{
moel@345
   565
						count = inStream.Read(block, n, blockSize - n);
moel@345
   566
						if (count == -1) 
moel@345
   567
							break;
moel@345
   568
						n += count;
moel@345
   569
					}
moel@345
   570
				} 
moel@345
   571
				catch (IOException) 
moel@345
   572
				{
moel@345
   573
				}
moel@345
   574
moel@345
   575
				if (n < blockSize) 
moel@345
   576
				{
moel@345
   577
					status = StatusFormatError;
moel@345
   578
				}
moel@345
   579
			}
moel@345
   580
			return n;
moel@345
   581
		}
moel@345
   582
moel@345
   583
		/**
moel@345
   584
		 * Reads color table as 256 RGB integer values
moel@345
   585
		 *
moel@345
   586
		 * @param ncolors int number of colors to read
moel@345
   587
		 * @return int array containing 256 colors (packed ARGB with full alpha)
moel@345
   588
		 */
moel@345
   589
		private int[] ReadColorTable(int ncolors) 
moel@345
   590
		{
moel@345
   591
			int nbytes = 3 * ncolors;
moel@345
   592
			int[] tab = null;
moel@345
   593
			byte[] c = new byte[nbytes];
moel@345
   594
			int n = 0;
moel@345
   595
			try 
moel@345
   596
			{
moel@345
   597
				n = inStream.Read(c, 0, c.Length );
moel@345
   598
			} 
moel@345
   599
			catch (IOException) 
moel@345
   600
			{
moel@345
   601
			}
moel@345
   602
			if (n < nbytes) 
moel@345
   603
			{
moel@345
   604
				status = StatusFormatError;
moel@345
   605
			} 
moel@345
   606
			else 
moel@345
   607
			{
moel@345
   608
				tab = new int[256]; // max size to avoid bounds checks
moel@345
   609
				int i = 0;
moel@345
   610
				int j = 0;
moel@345
   611
				while (i < ncolors) 
moel@345
   612
				{
moel@345
   613
					int r = ((int) c[j++]) & 0xff;
moel@345
   614
					int g = ((int) c[j++]) & 0xff;
moel@345
   615
					int b = ((int) c[j++]) & 0xff;
moel@345
   616
					tab[i++] = ( int ) ( 0xff000000 | (r << 16) | (g << 8) | b );
moel@345
   617
				}
moel@345
   618
			}
moel@345
   619
			return tab;
moel@345
   620
		}
moel@345
   621
moel@345
   622
		/**
moel@345
   623
		 * Main file parser.  Reads GIF content blocks.
moel@345
   624
		 */
moel@345
   625
		private void ReadContents() 
moel@345
   626
		{
moel@345
   627
			// read GIF file content blocks
moel@345
   628
			bool done = false;
moel@345
   629
			while (!(done || Error())) 
moel@345
   630
			{
moel@345
   631
				int code = Read();
moel@345
   632
				switch (code) 
moel@345
   633
				{
moel@345
   634
moel@345
   635
					case 0x2C : // image separator
moel@345
   636
						ReadImage();
moel@345
   637
						break;
moel@345
   638
moel@345
   639
					case 0x21 : // extension
moel@345
   640
						code = Read();
moel@345
   641
					switch (code) 
moel@345
   642
					{
moel@345
   643
						case 0xf9 : // graphics control extension
moel@345
   644
							ReadGraphicControlExt();
moel@345
   645
							break;
moel@345
   646
moel@345
   647
						case 0xff : // application extension
moel@345
   648
							ReadBlock();
moel@345
   649
							String app = "";
moel@345
   650
							for (int i = 0; i < 11; i++) 
moel@345
   651
							{
moel@345
   652
								app += (char) block[i];
moel@345
   653
							}
moel@345
   654
							if (app.Equals("NETSCAPE2.0")) 
moel@345
   655
							{
moel@345
   656
								ReadNetscapeExt();
moel@345
   657
							}
moel@345
   658
							else
moel@345
   659
								Skip(); // don't care
moel@345
   660
							break;
moel@345
   661
moel@345
   662
						default : // uninteresting extension
moel@345
   663
							Skip();
moel@345
   664
							break;
moel@345
   665
					}
moel@345
   666
						break;
moel@345
   667
moel@345
   668
					case 0x3b : // terminator
moel@345
   669
						done = true;
moel@345
   670
						break;
moel@345
   671
moel@345
   672
					case 0x00 : // bad byte, but keep going and see what happens
moel@345
   673
						break;
moel@345
   674
moel@345
   675
					default :
moel@345
   676
						status = StatusFormatError;
moel@345
   677
						break;
moel@345
   678
				}
moel@345
   679
			}
moel@345
   680
		}
moel@345
   681
moel@345
   682
		/**
moel@345
   683
		 * Reads Graphics Control Extension values
moel@345
   684
		 */
moel@345
   685
		private void ReadGraphicControlExt() 
moel@345
   686
		{
moel@345
   687
			Read(); // block size
moel@345
   688
			int packed = Read(); // packed fields
moel@345
   689
			dispose = (packed & 0x1c) >> 2; // disposal method
moel@345
   690
			if (dispose == 0) 
moel@345
   691
			{
moel@345
   692
				dispose = 1; // elect to keep old image if discretionary
moel@345
   693
			}
moel@345
   694
			transparency = (packed & 1) != 0;
moel@345
   695
			delay = ReadShort() * 10; // delay in milliseconds
moel@345
   696
			transIndex = Read(); // transparent color index
moel@345
   697
			Read(); // block terminator
moel@345
   698
		}
moel@345
   699
moel@345
   700
		/**
moel@345
   701
		 * Reads GIF file header information.
moel@345
   702
		 */
moel@345
   703
		private void ReadHeader() 
moel@345
   704
		{
moel@345
   705
			String id = "";
moel@345
   706
			for (int i = 0; i < 6; i++) 
moel@345
   707
			{
moel@345
   708
				id += (char) Read();
moel@345
   709
			}
moel@345
   710
			if (!id.StartsWith("GIF")) 
moel@345
   711
			{
moel@345
   712
				status = StatusFormatError;
moel@345
   713
				return;
moel@345
   714
			}
moel@345
   715
moel@345
   716
			ReadLSD();
moel@345
   717
			if (gctFlag && !Error()) 
moel@345
   718
			{
moel@345
   719
				gct = ReadColorTable(gctSize);
moel@345
   720
				bgColor = gct[bgIndex];
moel@345
   721
			}
moel@345
   722
		}
moel@345
   723
moel@345
   724
		/**
moel@345
   725
		 * Reads next frame image
moel@345
   726
		 */
moel@345
   727
		private void ReadImage() 
moel@345
   728
		{
moel@345
   729
			ix = ReadShort(); // (sub)image position & size
moel@345
   730
			iy = ReadShort();
moel@345
   731
			iw = ReadShort();
moel@345
   732
			ih = ReadShort();
moel@345
   733
moel@345
   734
			int packed = Read();
moel@345
   735
			lctFlag = (packed & 0x80) != 0; // 1 - local color table flag
moel@345
   736
			interlace = (packed & 0x40) != 0; // 2 - interlace flag
moel@345
   737
			// 3 - sort flag
moel@345
   738
			// 4-5 - reserved
moel@345
   739
			lctSize = 2 << (packed & 7); // 6-8 - local color table size
moel@345
   740
moel@345
   741
			if (lctFlag) 
moel@345
   742
			{
moel@345
   743
				lct = ReadColorTable(lctSize); // read table
moel@345
   744
				act = lct; // make local table active
moel@345
   745
			} 
moel@345
   746
			else 
moel@345
   747
			{
moel@345
   748
				act = gct; // make global table active
moel@345
   749
				if (bgIndex == transIndex)
moel@345
   750
					bgColor = 0;
moel@345
   751
			}
moel@345
   752
			int save = 0;
moel@345
   753
			if (transparency) 
moel@345
   754
			{
moel@345
   755
				save = act[transIndex];
moel@345
   756
				act[transIndex] = 0; // set transparent color if specified
moel@345
   757
			}
moel@345
   758
moel@345
   759
			if (act == null) 
moel@345
   760
			{
moel@345
   761
				status = StatusFormatError; // no color table defined
moel@345
   762
			}
moel@345
   763
moel@345
   764
			if (Error()) return;
moel@345
   765
moel@345
   766
			DecodeImageData(); // decode pixel data
moel@345
   767
			Skip();
moel@345
   768
moel@345
   769
			if (Error()) return;
moel@345
   770
moel@345
   771
			frameCount++;
moel@345
   772
moel@345
   773
			// create new image to receive frame data
moel@345
   774
			//		image =
moel@345
   775
			//			new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
moel@345
   776
moel@345
   777
			bitmap = new Bitmap( width, height );
moel@345
   778
			image = bitmap;
moel@345
   779
			SetPixels(); // transfer pixel data to image
moel@345
   780
moel@345
   781
			frames.Add(new GifFrame(bitmap, delay)); // add image to frame list
moel@345
   782
moel@345
   783
			if (transparency) 
moel@345
   784
			{
moel@345
   785
				act[transIndex] = save;
moel@345
   786
			}
moel@345
   787
			ResetFrame();
moel@345
   788
moel@345
   789
		}
moel@345
   790
moel@345
   791
		/**
moel@345
   792
		 * Reads Logical Screen Descriptor
moel@345
   793
		 */
moel@345
   794
		private void ReadLSD() 
moel@345
   795
		{
moel@345
   796
moel@345
   797
			// logical screen size
moel@345
   798
			width = ReadShort();
moel@345
   799
			height = ReadShort();
moel@345
   800
moel@345
   801
			// packed fields
moel@345
   802
			int packed = Read();
moel@345
   803
			gctFlag = (packed & 0x80) != 0; // 1   : global color table flag
moel@345
   804
			// 2-4 : color resolution
moel@345
   805
			// 5   : gct sort flag
moel@345
   806
			gctSize = 2 << (packed & 7); // 6-8 : gct size
moel@345
   807
moel@345
   808
			bgIndex = Read(); // background color index
moel@345
   809
			pixelAspect = Read(); // pixel aspect ratio
moel@345
   810
		}
moel@345
   811
moel@345
   812
		/**
moel@345
   813
		 * Reads Netscape extenstion to obtain iteration count
moel@345
   814
		 */
moel@345
   815
		private void ReadNetscapeExt() 
moel@345
   816
		{
moel@345
   817
			do 
moel@345
   818
			{
moel@345
   819
				ReadBlock();
moel@345
   820
				if (block[0] == 1) 
moel@345
   821
				{
moel@345
   822
					// loop count sub-block
moel@345
   823
					int b1 = ((int) block[1]) & 0xff;
moel@345
   824
					int b2 = ((int) block[2]) & 0xff;
moel@345
   825
					loopCount = (b2 << 8) | b1;
moel@345
   826
				}
moel@345
   827
			} while ((blockSize > 0) && !Error());
moel@345
   828
		}
moel@345
   829
moel@345
   830
		/**
moel@345
   831
		 * Reads next 16-bit value, LSB first
moel@345
   832
		 */
moel@345
   833
		private int ReadShort() 
moel@345
   834
		{
moel@345
   835
			// read 16-bit value, LSB first
moel@345
   836
			return Read() | (Read() << 8);
moel@345
   837
		}
moel@345
   838
moel@345
   839
		/**
moel@345
   840
		 * Resets frame state for reading next image.
moel@345
   841
		 */
moel@345
   842
		private void ResetFrame() 
moel@345
   843
		{
moel@345
   844
			lastDispose = dispose;
moel@345
   845
			lastRect = new Rectangle(ix, iy, iw, ih);
moel@345
   846
			lastImage = image;
moel@345
   847
			lastBgColor = bgColor;
moel@345
   848
			//		int dispose = 0;
moel@345
   849
			lct = null;
moel@345
   850
		}
moel@345
   851
moel@345
   852
		/**
moel@345
   853
		 * Skips variable length blocks up to and including
moel@345
   854
		 * next zero length block.
moel@345
   855
		 */
moel@345
   856
		private void Skip() 
moel@345
   857
		{
moel@345
   858
			do 
moel@345
   859
			{
moel@345
   860
				ReadBlock();
moel@345
   861
			} while ((blockSize > 0) && !Error());
moel@345
   862
		}
moel@345
   863
	}
moel@345
   864
}