1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/External/Aga.Controls/GifDecoder.cs Sun May 27 15:16:19 2012 +0000
1.3 @@ -0,0 +1,864 @@
1.4 +#pragma warning disable 675 // Bitwise-or operator used on a sign-extended operand
1.5 +
1.6 +#region Java Info
1.7 +/**
1.8 + * Class GifDecoder - Decodes a GIF file into one or more frames.
1.9 + * <br><pre>
1.10 + * Example:
1.11 + * GifDecoder d = new GifDecoder();
1.12 + * d.read("sample.gif");
1.13 + * int n = d.getFrameCount();
1.14 + * for (int i = 0; i < n; i++) {
1.15 + * BufferedImage frame = d.getFrame(i); // frame i
1.16 + * int t = d.getDelay(i); // display duration of frame in milliseconds
1.17 + * // do something with frame
1.18 + * }
1.19 + * </pre>
1.20 + * No copyright asserted on the source code of this class. May be used for
1.21 + * any purpose, however, refer to the Unisys LZW patent for any additional
1.22 + * restrictions. Please forward any corrections to kweiner@fmsware.com.
1.23 + *
1.24 + * @author Kevin Weiner, FM Software; LZW decoder adapted from John Cristy's ImageMagick.
1.25 + * @version 1.03 November 2003
1.26 + *
1.27 + */
1.28 +#endregion
1.29 +
1.30 +using System;
1.31 +using System.Collections;
1.32 +using System.Drawing;
1.33 +using System.Drawing.Imaging;
1.34 +using System.IO;
1.35 +
1.36 +namespace Aga.Controls
1.37 +{
1.38 + public class GifFrame
1.39 + {
1.40 + private Image _image;
1.41 + public Image Image
1.42 + {
1.43 + get { return _image; }
1.44 + }
1.45 +
1.46 + private int _delay;
1.47 + public int Delay
1.48 + {
1.49 + get { return _delay; }
1.50 + }
1.51 +
1.52 + public GifFrame(Image im, int del)
1.53 + {
1.54 + _image = im;
1.55 + _delay = del;
1.56 + }
1.57 + }
1.58 +
1.59 + public class GifDecoder
1.60 + {
1.61 + public const int StatusOK = 0;//File read status: No errors.
1.62 + public const int StatusFormatError = 1; //File read status: Error decoding file (may be partially decoded)
1.63 + public const int StatusOpenError = 2; //Unable to open source.
1.64 +
1.65 + private Stream inStream;
1.66 + private int status;
1.67 +
1.68 + private int width; // full image width
1.69 + private int height; // full image height
1.70 + private bool gctFlag; // global color table used
1.71 + private int gctSize; // size of global color table
1.72 + private int loopCount = 1; // iterations; 0 = repeat forever
1.73 +
1.74 + private int[] gct; // global color table
1.75 + private int[] lct; // local color table
1.76 + private int[] act; // active color table
1.77 +
1.78 + private int bgIndex; // background color index
1.79 + private int bgColor; // background color
1.80 + private int lastBgColor; // previous bg color
1.81 + private int pixelAspect; // pixel aspect ratio
1.82 +
1.83 + private bool lctFlag; // local color table flag
1.84 + private bool interlace; // interlace flag
1.85 + private int lctSize; // local color table size
1.86 +
1.87 + private int ix, iy, iw, ih; // current image rectangle
1.88 + private Rectangle lastRect; // last image rect
1.89 + private Image image; // current frame
1.90 + private Bitmap bitmap;
1.91 + private Image lastImage; // previous frame
1.92 +
1.93 + private byte[] block = new byte[256]; // current data block
1.94 + private int blockSize = 0; // block size
1.95 +
1.96 + // last graphic control extension info
1.97 + private int dispose = 0;
1.98 + // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev
1.99 + private int lastDispose = 0;
1.100 + private bool transparency = false; // use transparent color
1.101 + private int delay = 0; // delay in milliseconds
1.102 + private int transIndex; // transparent color index
1.103 +
1.104 + private const int MaxStackSize = 4096;
1.105 + // max decoder pixel stack size
1.106 +
1.107 + // LZW decoder working arrays
1.108 + private short[] prefix;
1.109 + private byte[] suffix;
1.110 + private byte[] pixelStack;
1.111 + private byte[] pixels;
1.112 +
1.113 + private ArrayList frames; // frames read from current file
1.114 + private int frameCount;
1.115 + private bool _makeTransparent;
1.116 +
1.117 + /**
1.118 + * Gets the number of frames read from file.
1.119 + * @return frame count
1.120 + */
1.121 + public int FrameCount
1.122 + {
1.123 + get
1.124 + {
1.125 + return frameCount;
1.126 + }
1.127 + }
1.128 +
1.129 + /**
1.130 + * Gets the first (or only) image read.
1.131 + *
1.132 + * @return BufferedImage containing first frame, or null if none.
1.133 + */
1.134 + public Image Image
1.135 + {
1.136 + get
1.137 + {
1.138 + return GetFrame(0).Image;
1.139 + }
1.140 + }
1.141 +
1.142 + /**
1.143 + * Gets the "Netscape" iteration count, if any.
1.144 + * A count of 0 means repeat indefinitiely.
1.145 + *
1.146 + * @return iteration count if one was specified, else 1.
1.147 + */
1.148 + public int LoopCount
1.149 + {
1.150 + get
1.151 + {
1.152 + return loopCount;
1.153 + }
1.154 + }
1.155 +
1.156 + public GifDecoder(Stream stream, bool makeTransparent)
1.157 + {
1.158 + _makeTransparent = makeTransparent;
1.159 + if (Read(stream) != 0)
1.160 + throw new InvalidOperationException();
1.161 + }
1.162 +
1.163 + /**
1.164 + * Creates new frame image from current data (and previous
1.165 + * frames as specified by their disposition codes).
1.166 + */
1.167 + private int[] GetPixels(Bitmap bitmap)
1.168 + {
1.169 + int [] pixels = new int [ 3 * image.Width * image.Height ];
1.170 + int count = 0;
1.171 + for (int th = 0; th < image.Height; th++)
1.172 + {
1.173 + for (int tw = 0; tw < image.Width; tw++)
1.174 + {
1.175 + Color color = bitmap.GetPixel(tw, th);
1.176 + pixels[count] = color.R;
1.177 + count++;
1.178 + pixels[count] = color.G;
1.179 + count++;
1.180 + pixels[count] = color.B;
1.181 + count++;
1.182 + }
1.183 + }
1.184 + return pixels;
1.185 + }
1.186 +
1.187 + private void SetPixels(int[] pixels)
1.188 + {
1.189 + int count = 0;
1.190 + for (int th = 0; th < image.Height; th++)
1.191 + {
1.192 + for (int tw = 0; tw < image.Width; tw++)
1.193 + {
1.194 + Color color = Color.FromArgb( pixels[count++] );
1.195 + bitmap.SetPixel( tw, th, color );
1.196 + }
1.197 + }
1.198 + if (_makeTransparent)
1.199 + bitmap.MakeTransparent(bitmap.GetPixel(0, 0));
1.200 + }
1.201 +
1.202 + private void SetPixels()
1.203 + {
1.204 + // expose destination image's pixels as int array
1.205 + // int[] dest =
1.206 + // (( int ) image.getRaster().getDataBuffer()).getData();
1.207 + int[] dest = GetPixels( bitmap );
1.208 +
1.209 + // fill in starting image contents based on last image's dispose code
1.210 + if (lastDispose > 0)
1.211 + {
1.212 + if (lastDispose == 3)
1.213 + {
1.214 + // use image before last
1.215 + int n = frameCount - 2;
1.216 + if (n > 0)
1.217 + {
1.218 + lastImage = GetFrame(n - 1).Image;
1.219 + }
1.220 + else
1.221 + {
1.222 + lastImage = null;
1.223 + }
1.224 + }
1.225 +
1.226 + if (lastImage != null)
1.227 + {
1.228 + // int[] prev =
1.229 + // ((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData();
1.230 + int[] prev = GetPixels( new Bitmap( lastImage ) );
1.231 + Array.Copy(prev, 0, dest, 0, width * height);
1.232 + // copy pixels
1.233 +
1.234 + if (lastDispose == 2)
1.235 + {
1.236 + // fill last image rect area with background color
1.237 + Graphics g = Graphics.FromImage( image );
1.238 + Color c = Color.Empty;
1.239 + if (transparency)
1.240 + {
1.241 + c = Color.FromArgb( 0, 0, 0, 0 ); // assume background is transparent
1.242 + }
1.243 + else
1.244 + {
1.245 + c = Color.FromArgb( lastBgColor ) ;
1.246 + // c = new Color(lastBgColor); // use given background color
1.247 + }
1.248 + Brush brush = new SolidBrush( c );
1.249 + g.FillRectangle( brush, lastRect );
1.250 + brush.Dispose();
1.251 + g.Dispose();
1.252 + }
1.253 + }
1.254 + }
1.255 +
1.256 + // copy each source line to the appropriate place in the destination
1.257 + int pass = 1;
1.258 + int inc = 8;
1.259 + int iline = 0;
1.260 + for (int i = 0; i < ih; i++)
1.261 + {
1.262 + int line = i;
1.263 + if (interlace)
1.264 + {
1.265 + if (iline >= ih)
1.266 + {
1.267 + pass++;
1.268 + switch (pass)
1.269 + {
1.270 + case 2 :
1.271 + iline = 4;
1.272 + break;
1.273 + case 3 :
1.274 + iline = 2;
1.275 + inc = 4;
1.276 + break;
1.277 + case 4 :
1.278 + iline = 1;
1.279 + inc = 2;
1.280 + break;
1.281 + }
1.282 + }
1.283 + line = iline;
1.284 + iline += inc;
1.285 + }
1.286 + line += iy;
1.287 + if (line < height)
1.288 + {
1.289 + int k = line * width;
1.290 + int dx = k + ix; // start of line in dest
1.291 + int dlim = dx + iw; // end of dest line
1.292 + if ((k + width) < dlim)
1.293 + {
1.294 + dlim = k + width; // past dest edge
1.295 + }
1.296 + int sx = i * iw; // start of line in source
1.297 + while (dx < dlim)
1.298 + {
1.299 + // map color and insert in destination
1.300 + int index = ((int) pixels[sx++]) & 0xff;
1.301 + int c = act[index];
1.302 + if (c != 0)
1.303 + {
1.304 + dest[dx] = c;
1.305 + }
1.306 + dx++;
1.307 + }
1.308 + }
1.309 + }
1.310 + SetPixels( dest );
1.311 + }
1.312 +
1.313 + /**
1.314 + * Gets the image contents of frame n.
1.315 + *
1.316 + * @return BufferedImage representation of frame.
1.317 + */
1.318 + public GifFrame GetFrame(int n)
1.319 + {
1.320 + if ((n >= 0) && (n < frameCount))
1.321 + return (GifFrame)frames[n];
1.322 + else
1.323 + throw new ArgumentOutOfRangeException();
1.324 + }
1.325 +
1.326 + /**
1.327 + * Gets image size.
1.328 + *
1.329 + * @return GIF image dimensions
1.330 + */
1.331 + public Size FrameSize
1.332 + {
1.333 + get
1.334 + {
1.335 + return new Size(width, height);
1.336 + }
1.337 + }
1.338 +
1.339 + /**
1.340 + * Reads GIF image from stream
1.341 + *
1.342 + * @param BufferedInputStream containing GIF file.
1.343 + * @return read status code (0 = no errors)
1.344 + */
1.345 + private int Read( Stream inStream )
1.346 + {
1.347 + Init();
1.348 + if ( inStream != null)
1.349 + {
1.350 + this.inStream = inStream;
1.351 + ReadHeader();
1.352 + if (!Error())
1.353 + {
1.354 + ReadContents();
1.355 + if (frameCount < 0)
1.356 + {
1.357 + status = StatusFormatError;
1.358 + }
1.359 + }
1.360 + inStream.Close();
1.361 + }
1.362 + else
1.363 + {
1.364 + status = StatusOpenError;
1.365 + }
1.366 + return status;
1.367 + }
1.368 +
1.369 +
1.370 + /**
1.371 + * Decodes LZW image data into pixel array.
1.372 + * Adapted from John Cristy's ImageMagick.
1.373 + */
1.374 + private void DecodeImageData()
1.375 + {
1.376 + int NullCode = -1;
1.377 + int npix = iw * ih;
1.378 + int available,
1.379 + clear,
1.380 + code_mask,
1.381 + code_size,
1.382 + end_of_information,
1.383 + in_code,
1.384 + old_code,
1.385 + bits,
1.386 + code,
1.387 + count,
1.388 + i,
1.389 + datum,
1.390 + data_size,
1.391 + first,
1.392 + top,
1.393 + bi,
1.394 + pi;
1.395 +
1.396 + if ((pixels == null) || (pixels.Length < npix))
1.397 + {
1.398 + pixels = new byte[npix]; // allocate new pixel array
1.399 + }
1.400 + if (prefix == null) prefix = new short[MaxStackSize];
1.401 + if (suffix == null) suffix = new byte[MaxStackSize];
1.402 + if (pixelStack == null) pixelStack = new byte[MaxStackSize + 1];
1.403 +
1.404 + // Initialize GIF data stream decoder.
1.405 +
1.406 + data_size = Read();
1.407 + clear = 1 << data_size;
1.408 + end_of_information = clear + 1;
1.409 + available = clear + 2;
1.410 + old_code = NullCode;
1.411 + code_size = data_size + 1;
1.412 + code_mask = (1 << code_size) - 1;
1.413 + for (code = 0; code < clear; code++)
1.414 + {
1.415 + prefix[code] = 0;
1.416 + suffix[code] = (byte) code;
1.417 + }
1.418 +
1.419 + // Decode GIF pixel stream.
1.420 +
1.421 + datum = bits = count = first = top = pi = bi = 0;
1.422 +
1.423 + for (i = 0; i < npix;)
1.424 + {
1.425 + if (top == 0)
1.426 + {
1.427 + if (bits < code_size)
1.428 + {
1.429 + // Load bytes until there are enough bits for a code.
1.430 + if (count == 0)
1.431 + {
1.432 + // Read a new data block.
1.433 + count = ReadBlock();
1.434 + if (count <= 0)
1.435 + break;
1.436 + bi = 0;
1.437 + }
1.438 + datum += (((int) block[bi]) & 0xff) << bits;
1.439 + bits += 8;
1.440 + bi++;
1.441 + count--;
1.442 + continue;
1.443 + }
1.444 +
1.445 + // Get the next code.
1.446 +
1.447 + code = datum & code_mask;
1.448 + datum >>= code_size;
1.449 + bits -= code_size;
1.450 +
1.451 + // Interpret the code
1.452 +
1.453 + if ((code > available) || (code == end_of_information))
1.454 + break;
1.455 + if (code == clear)
1.456 + {
1.457 + // Reset decoder.
1.458 + code_size = data_size + 1;
1.459 + code_mask = (1 << code_size) - 1;
1.460 + available = clear + 2;
1.461 + old_code = NullCode;
1.462 + continue;
1.463 + }
1.464 + if (old_code == NullCode)
1.465 + {
1.466 + pixelStack[top++] = suffix[code];
1.467 + old_code = code;
1.468 + first = code;
1.469 + continue;
1.470 + }
1.471 + in_code = code;
1.472 + if (code == available)
1.473 + {
1.474 + pixelStack[top++] = (byte) first;
1.475 + code = old_code;
1.476 + }
1.477 + while (code > clear)
1.478 + {
1.479 + pixelStack[top++] = suffix[code];
1.480 + code = prefix[code];
1.481 + }
1.482 + first = ((int) suffix[code]) & 0xff;
1.483 +
1.484 + // Add a new string to the string table,
1.485 +
1.486 + if (available >= MaxStackSize)
1.487 + break;
1.488 + pixelStack[top++] = (byte) first;
1.489 + prefix[available] = (short) old_code;
1.490 + suffix[available] = (byte) first;
1.491 + available++;
1.492 + if (((available & code_mask) == 0)
1.493 + && (available < MaxStackSize))
1.494 + {
1.495 + code_size++;
1.496 + code_mask += available;
1.497 + }
1.498 + old_code = in_code;
1.499 + }
1.500 +
1.501 + // Pop a pixel off the pixel stack.
1.502 +
1.503 + top--;
1.504 + pixels[pi++] = pixelStack[top];
1.505 + i++;
1.506 + }
1.507 +
1.508 + for (i = pi; i < npix; i++)
1.509 + {
1.510 + pixels[i] = 0; // clear missing pixels
1.511 + }
1.512 +
1.513 + }
1.514 +
1.515 + /**
1.516 + * Returns true if an error was encountered during reading/decoding
1.517 + */
1.518 + private bool Error()
1.519 + {
1.520 + return status != StatusOK;
1.521 + }
1.522 +
1.523 + /**
1.524 + * Initializes or re-initializes reader
1.525 + */
1.526 + private void Init()
1.527 + {
1.528 + status = StatusOK;
1.529 + frameCount = 0;
1.530 + frames = new ArrayList();
1.531 + gct = null;
1.532 + lct = null;
1.533 + }
1.534 +
1.535 + /**
1.536 + * Reads a single byte from the input stream.
1.537 + */
1.538 + private int Read()
1.539 + {
1.540 + int curByte = 0;
1.541 + try
1.542 + {
1.543 + curByte = inStream.ReadByte();
1.544 + }
1.545 + catch (IOException)
1.546 + {
1.547 + status = StatusFormatError;
1.548 + }
1.549 + return curByte;
1.550 + }
1.551 +
1.552 + /**
1.553 + * Reads next variable length block from input.
1.554 + *
1.555 + * @return number of bytes stored in "buffer"
1.556 + */
1.557 + private int ReadBlock()
1.558 + {
1.559 + blockSize = Read();
1.560 + int n = 0;
1.561 + if (blockSize > 0)
1.562 + {
1.563 + try
1.564 + {
1.565 + int count = 0;
1.566 + while (n < blockSize)
1.567 + {
1.568 + count = inStream.Read(block, n, blockSize - n);
1.569 + if (count == -1)
1.570 + break;
1.571 + n += count;
1.572 + }
1.573 + }
1.574 + catch (IOException)
1.575 + {
1.576 + }
1.577 +
1.578 + if (n < blockSize)
1.579 + {
1.580 + status = StatusFormatError;
1.581 + }
1.582 + }
1.583 + return n;
1.584 + }
1.585 +
1.586 + /**
1.587 + * Reads color table as 256 RGB integer values
1.588 + *
1.589 + * @param ncolors int number of colors to read
1.590 + * @return int array containing 256 colors (packed ARGB with full alpha)
1.591 + */
1.592 + private int[] ReadColorTable(int ncolors)
1.593 + {
1.594 + int nbytes = 3 * ncolors;
1.595 + int[] tab = null;
1.596 + byte[] c = new byte[nbytes];
1.597 + int n = 0;
1.598 + try
1.599 + {
1.600 + n = inStream.Read(c, 0, c.Length );
1.601 + }
1.602 + catch (IOException)
1.603 + {
1.604 + }
1.605 + if (n < nbytes)
1.606 + {
1.607 + status = StatusFormatError;
1.608 + }
1.609 + else
1.610 + {
1.611 + tab = new int[256]; // max size to avoid bounds checks
1.612 + int i = 0;
1.613 + int j = 0;
1.614 + while (i < ncolors)
1.615 + {
1.616 + int r = ((int) c[j++]) & 0xff;
1.617 + int g = ((int) c[j++]) & 0xff;
1.618 + int b = ((int) c[j++]) & 0xff;
1.619 + tab[i++] = ( int ) ( 0xff000000 | (r << 16) | (g << 8) | b );
1.620 + }
1.621 + }
1.622 + return tab;
1.623 + }
1.624 +
1.625 + /**
1.626 + * Main file parser. Reads GIF content blocks.
1.627 + */
1.628 + private void ReadContents()
1.629 + {
1.630 + // read GIF file content blocks
1.631 + bool done = false;
1.632 + while (!(done || Error()))
1.633 + {
1.634 + int code = Read();
1.635 + switch (code)
1.636 + {
1.637 +
1.638 + case 0x2C : // image separator
1.639 + ReadImage();
1.640 + break;
1.641 +
1.642 + case 0x21 : // extension
1.643 + code = Read();
1.644 + switch (code)
1.645 + {
1.646 + case 0xf9 : // graphics control extension
1.647 + ReadGraphicControlExt();
1.648 + break;
1.649 +
1.650 + case 0xff : // application extension
1.651 + ReadBlock();
1.652 + String app = "";
1.653 + for (int i = 0; i < 11; i++)
1.654 + {
1.655 + app += (char) block[i];
1.656 + }
1.657 + if (app.Equals("NETSCAPE2.0"))
1.658 + {
1.659 + ReadNetscapeExt();
1.660 + }
1.661 + else
1.662 + Skip(); // don't care
1.663 + break;
1.664 +
1.665 + default : // uninteresting extension
1.666 + Skip();
1.667 + break;
1.668 + }
1.669 + break;
1.670 +
1.671 + case 0x3b : // terminator
1.672 + done = true;
1.673 + break;
1.674 +
1.675 + case 0x00 : // bad byte, but keep going and see what happens
1.676 + break;
1.677 +
1.678 + default :
1.679 + status = StatusFormatError;
1.680 + break;
1.681 + }
1.682 + }
1.683 + }
1.684 +
1.685 + /**
1.686 + * Reads Graphics Control Extension values
1.687 + */
1.688 + private void ReadGraphicControlExt()
1.689 + {
1.690 + Read(); // block size
1.691 + int packed = Read(); // packed fields
1.692 + dispose = (packed & 0x1c) >> 2; // disposal method
1.693 + if (dispose == 0)
1.694 + {
1.695 + dispose = 1; // elect to keep old image if discretionary
1.696 + }
1.697 + transparency = (packed & 1) != 0;
1.698 + delay = ReadShort() * 10; // delay in milliseconds
1.699 + transIndex = Read(); // transparent color index
1.700 + Read(); // block terminator
1.701 + }
1.702 +
1.703 + /**
1.704 + * Reads GIF file header information.
1.705 + */
1.706 + private void ReadHeader()
1.707 + {
1.708 + String id = "";
1.709 + for (int i = 0; i < 6; i++)
1.710 + {
1.711 + id += (char) Read();
1.712 + }
1.713 + if (!id.StartsWith("GIF"))
1.714 + {
1.715 + status = StatusFormatError;
1.716 + return;
1.717 + }
1.718 +
1.719 + ReadLSD();
1.720 + if (gctFlag && !Error())
1.721 + {
1.722 + gct = ReadColorTable(gctSize);
1.723 + bgColor = gct[bgIndex];
1.724 + }
1.725 + }
1.726 +
1.727 + /**
1.728 + * Reads next frame image
1.729 + */
1.730 + private void ReadImage()
1.731 + {
1.732 + ix = ReadShort(); // (sub)image position & size
1.733 + iy = ReadShort();
1.734 + iw = ReadShort();
1.735 + ih = ReadShort();
1.736 +
1.737 + int packed = Read();
1.738 + lctFlag = (packed & 0x80) != 0; // 1 - local color table flag
1.739 + interlace = (packed & 0x40) != 0; // 2 - interlace flag
1.740 + // 3 - sort flag
1.741 + // 4-5 - reserved
1.742 + lctSize = 2 << (packed & 7); // 6-8 - local color table size
1.743 +
1.744 + if (lctFlag)
1.745 + {
1.746 + lct = ReadColorTable(lctSize); // read table
1.747 + act = lct; // make local table active
1.748 + }
1.749 + else
1.750 + {
1.751 + act = gct; // make global table active
1.752 + if (bgIndex == transIndex)
1.753 + bgColor = 0;
1.754 + }
1.755 + int save = 0;
1.756 + if (transparency)
1.757 + {
1.758 + save = act[transIndex];
1.759 + act[transIndex] = 0; // set transparent color if specified
1.760 + }
1.761 +
1.762 + if (act == null)
1.763 + {
1.764 + status = StatusFormatError; // no color table defined
1.765 + }
1.766 +
1.767 + if (Error()) return;
1.768 +
1.769 + DecodeImageData(); // decode pixel data
1.770 + Skip();
1.771 +
1.772 + if (Error()) return;
1.773 +
1.774 + frameCount++;
1.775 +
1.776 + // create new image to receive frame data
1.777 + // image =
1.778 + // new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
1.779 +
1.780 + bitmap = new Bitmap( width, height );
1.781 + image = bitmap;
1.782 + SetPixels(); // transfer pixel data to image
1.783 +
1.784 + frames.Add(new GifFrame(bitmap, delay)); // add image to frame list
1.785 +
1.786 + if (transparency)
1.787 + {
1.788 + act[transIndex] = save;
1.789 + }
1.790 + ResetFrame();
1.791 +
1.792 + }
1.793 +
1.794 + /**
1.795 + * Reads Logical Screen Descriptor
1.796 + */
1.797 + private void ReadLSD()
1.798 + {
1.799 +
1.800 + // logical screen size
1.801 + width = ReadShort();
1.802 + height = ReadShort();
1.803 +
1.804 + // packed fields
1.805 + int packed = Read();
1.806 + gctFlag = (packed & 0x80) != 0; // 1 : global color table flag
1.807 + // 2-4 : color resolution
1.808 + // 5 : gct sort flag
1.809 + gctSize = 2 << (packed & 7); // 6-8 : gct size
1.810 +
1.811 + bgIndex = Read(); // background color index
1.812 + pixelAspect = Read(); // pixel aspect ratio
1.813 + }
1.814 +
1.815 + /**
1.816 + * Reads Netscape extenstion to obtain iteration count
1.817 + */
1.818 + private void ReadNetscapeExt()
1.819 + {
1.820 + do
1.821 + {
1.822 + ReadBlock();
1.823 + if (block[0] == 1)
1.824 + {
1.825 + // loop count sub-block
1.826 + int b1 = ((int) block[1]) & 0xff;
1.827 + int b2 = ((int) block[2]) & 0xff;
1.828 + loopCount = (b2 << 8) | b1;
1.829 + }
1.830 + } while ((blockSize > 0) && !Error());
1.831 + }
1.832 +
1.833 + /**
1.834 + * Reads next 16-bit value, LSB first
1.835 + */
1.836 + private int ReadShort()
1.837 + {
1.838 + // read 16-bit value, LSB first
1.839 + return Read() | (Read() << 8);
1.840 + }
1.841 +
1.842 + /**
1.843 + * Resets frame state for reading next image.
1.844 + */
1.845 + private void ResetFrame()
1.846 + {
1.847 + lastDispose = dispose;
1.848 + lastRect = new Rectangle(ix, iy, iw, ih);
1.849 + lastImage = image;
1.850 + lastBgColor = bgColor;
1.851 + // int dispose = 0;
1.852 + lct = null;
1.853 + }
1.854 +
1.855 + /**
1.856 + * Skips variable length blocks up to and including
1.857 + * next zero length block.
1.858 + */
1.859 + private void Skip()
1.860 + {
1.861 + do
1.862 + {
1.863 + ReadBlock();
1.864 + } while ((blockSize > 0) && !Error());
1.865 + }
1.866 + }
1.867 +}