External/Aga.Controls/GifDecoder.cs
author sl
Sun, 03 Feb 2013 19:06:01 +0100
changeset 392 8af90fa0940f
permissions -rw-r--r--
Now fetching some of our Sound Graph DLL function pointers.
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
}