moel@345: #pragma warning disable 675 // Bitwise-or operator used on a sign-extended operand
moel@345:
moel@345: #region Java Info
moel@345: /**
moel@345: * Class GifDecoder - Decodes a GIF file into one or more frames.
moel@345: *
moel@345: * Example: moel@345: * GifDecoder d = new GifDecoder(); moel@345: * d.read("sample.gif"); moel@345: * int n = d.getFrameCount(); moel@345: * for (int i = 0; i < n; i++) { moel@345: * BufferedImage frame = d.getFrame(i); // frame i moel@345: * int t = d.getDelay(i); // display duration of frame in milliseconds moel@345: * // do something with frame moel@345: * } moel@345: *moel@345: * No copyright asserted on the source code of this class. May be used for moel@345: * any purpose, however, refer to the Unisys LZW patent for any additional moel@345: * restrictions. Please forward any corrections to kweiner@fmsware.com. moel@345: * moel@345: * @author Kevin Weiner, FM Software; LZW decoder adapted from John Cristy's ImageMagick. moel@345: * @version 1.03 November 2003 moel@345: * moel@345: */ moel@345: #endregion moel@345: moel@345: using System; moel@345: using System.Collections; moel@345: using System.Drawing; moel@345: using System.Drawing.Imaging; moel@345: using System.IO; moel@345: moel@345: namespace Aga.Controls moel@345: { moel@345: public class GifFrame moel@345: { moel@345: private Image _image; moel@345: public Image Image moel@345: { moel@345: get { return _image; } moel@345: } moel@345: moel@345: private int _delay; moel@345: public int Delay moel@345: { moel@345: get { return _delay; } moel@345: } moel@345: moel@345: public GifFrame(Image im, int del) moel@345: { moel@345: _image = im; moel@345: _delay = del; moel@345: } moel@345: } moel@345: moel@345: public class GifDecoder moel@345: { moel@345: public const int StatusOK = 0;//File read status: No errors. moel@345: public const int StatusFormatError = 1; //File read status: Error decoding file (may be partially decoded) moel@345: public const int StatusOpenError = 2; //Unable to open source. moel@345: moel@345: private Stream inStream; moel@345: private int status; moel@345: moel@345: private int width; // full image width moel@345: private int height; // full image height moel@345: private bool gctFlag; // global color table used moel@345: private int gctSize; // size of global color table moel@345: private int loopCount = 1; // iterations; 0 = repeat forever moel@345: moel@345: private int[] gct; // global color table moel@345: private int[] lct; // local color table moel@345: private int[] act; // active color table moel@345: moel@345: private int bgIndex; // background color index moel@345: private int bgColor; // background color moel@345: private int lastBgColor; // previous bg color moel@345: private int pixelAspect; // pixel aspect ratio moel@345: moel@345: private bool lctFlag; // local color table flag moel@345: private bool interlace; // interlace flag moel@345: private int lctSize; // local color table size moel@345: moel@345: private int ix, iy, iw, ih; // current image rectangle moel@345: private Rectangle lastRect; // last image rect moel@345: private Image image; // current frame moel@345: private Bitmap bitmap; moel@345: private Image lastImage; // previous frame moel@345: moel@345: private byte[] block = new byte[256]; // current data block moel@345: private int blockSize = 0; // block size moel@345: moel@345: // last graphic control extension info moel@345: private int dispose = 0; moel@345: // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev moel@345: private int lastDispose = 0; moel@345: private bool transparency = false; // use transparent color moel@345: private int delay = 0; // delay in milliseconds moel@345: private int transIndex; // transparent color index moel@345: moel@345: private const int MaxStackSize = 4096; moel@345: // max decoder pixel stack size moel@345: moel@345: // LZW decoder working arrays moel@345: private short[] prefix; moel@345: private byte[] suffix; moel@345: private byte[] pixelStack; moel@345: private byte[] pixels; moel@345: moel@345: private ArrayList frames; // frames read from current file moel@345: private int frameCount; moel@345: private bool _makeTransparent; moel@345: moel@345: /** moel@345: * Gets the number of frames read from file. moel@345: * @return frame count moel@345: */ moel@345: public int FrameCount moel@345: { moel@345: get moel@345: { moel@345: return frameCount; moel@345: } moel@345: } moel@345: moel@345: /** moel@345: * Gets the first (or only) image read. moel@345: * moel@345: * @return BufferedImage containing first frame, or null if none. moel@345: */ moel@345: public Image Image moel@345: { moel@345: get moel@345: { moel@345: return GetFrame(0).Image; moel@345: } moel@345: } moel@345: moel@345: /** moel@345: * Gets the "Netscape" iteration count, if any. moel@345: * A count of 0 means repeat indefinitiely. moel@345: * moel@345: * @return iteration count if one was specified, else 1. moel@345: */ moel@345: public int LoopCount moel@345: { moel@345: get moel@345: { moel@345: return loopCount; moel@345: } moel@345: } moel@345: moel@345: public GifDecoder(Stream stream, bool makeTransparent) moel@345: { moel@345: _makeTransparent = makeTransparent; moel@345: if (Read(stream) != 0) moel@345: throw new InvalidOperationException(); moel@345: } moel@345: moel@345: /** moel@345: * Creates new frame image from current data (and previous moel@345: * frames as specified by their disposition codes). moel@345: */ moel@345: private int[] GetPixels(Bitmap bitmap) moel@345: { moel@345: int [] pixels = new int [ 3 * image.Width * image.Height ]; moel@345: int count = 0; moel@345: for (int th = 0; th < image.Height; th++) moel@345: { moel@345: for (int tw = 0; tw < image.Width; tw++) moel@345: { moel@345: Color color = bitmap.GetPixel(tw, th); moel@345: pixels[count] = color.R; moel@345: count++; moel@345: pixels[count] = color.G; moel@345: count++; moel@345: pixels[count] = color.B; moel@345: count++; moel@345: } moel@345: } moel@345: return pixels; moel@345: } moel@345: moel@345: private void SetPixels(int[] pixels) moel@345: { moel@345: int count = 0; moel@345: for (int th = 0; th < image.Height; th++) moel@345: { moel@345: for (int tw = 0; tw < image.Width; tw++) moel@345: { moel@345: Color color = Color.FromArgb( pixels[count++] ); moel@345: bitmap.SetPixel( tw, th, color ); moel@345: } moel@345: } moel@345: if (_makeTransparent) moel@345: bitmap.MakeTransparent(bitmap.GetPixel(0, 0)); moel@345: } moel@345: moel@345: private void SetPixels() moel@345: { moel@345: // expose destination image's pixels as int array moel@345: // int[] dest = moel@345: // (( int ) image.getRaster().getDataBuffer()).getData(); moel@345: int[] dest = GetPixels( bitmap ); moel@345: moel@345: // fill in starting image contents based on last image's dispose code moel@345: if (lastDispose > 0) moel@345: { moel@345: if (lastDispose == 3) moel@345: { moel@345: // use image before last moel@345: int n = frameCount - 2; moel@345: if (n > 0) moel@345: { moel@345: lastImage = GetFrame(n - 1).Image; moel@345: } moel@345: else moel@345: { moel@345: lastImage = null; moel@345: } moel@345: } moel@345: moel@345: if (lastImage != null) moel@345: { moel@345: // int[] prev = moel@345: // ((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData(); moel@345: int[] prev = GetPixels( new Bitmap( lastImage ) ); moel@345: Array.Copy(prev, 0, dest, 0, width * height); moel@345: // copy pixels moel@345: moel@345: if (lastDispose == 2) moel@345: { moel@345: // fill last image rect area with background color moel@345: Graphics g = Graphics.FromImage( image ); moel@345: Color c = Color.Empty; moel@345: if (transparency) moel@345: { moel@345: c = Color.FromArgb( 0, 0, 0, 0 ); // assume background is transparent moel@345: } moel@345: else moel@345: { moel@345: c = Color.FromArgb( lastBgColor ) ; moel@345: // c = new Color(lastBgColor); // use given background color moel@345: } moel@345: Brush brush = new SolidBrush( c ); moel@345: g.FillRectangle( brush, lastRect ); moel@345: brush.Dispose(); moel@345: g.Dispose(); moel@345: } moel@345: } moel@345: } moel@345: moel@345: // copy each source line to the appropriate place in the destination moel@345: int pass = 1; moel@345: int inc = 8; moel@345: int iline = 0; moel@345: for (int i = 0; i < ih; i++) moel@345: { moel@345: int line = i; moel@345: if (interlace) moel@345: { moel@345: if (iline >= ih) moel@345: { moel@345: pass++; moel@345: switch (pass) moel@345: { moel@345: case 2 : moel@345: iline = 4; moel@345: break; moel@345: case 3 : moel@345: iline = 2; moel@345: inc = 4; moel@345: break; moel@345: case 4 : moel@345: iline = 1; moel@345: inc = 2; moel@345: break; moel@345: } moel@345: } moel@345: line = iline; moel@345: iline += inc; moel@345: } moel@345: line += iy; moel@345: if (line < height) moel@345: { moel@345: int k = line * width; moel@345: int dx = k + ix; // start of line in dest moel@345: int dlim = dx + iw; // end of dest line moel@345: if ((k + width) < dlim) moel@345: { moel@345: dlim = k + width; // past dest edge moel@345: } moel@345: int sx = i * iw; // start of line in source moel@345: while (dx < dlim) moel@345: { moel@345: // map color and insert in destination moel@345: int index = ((int) pixels[sx++]) & 0xff; moel@345: int c = act[index]; moel@345: if (c != 0) moel@345: { moel@345: dest[dx] = c; moel@345: } moel@345: dx++; moel@345: } moel@345: } moel@345: } moel@345: SetPixels( dest ); moel@345: } moel@345: moel@345: /** moel@345: * Gets the image contents of frame n. moel@345: * moel@345: * @return BufferedImage representation of frame. moel@345: */ moel@345: public GifFrame GetFrame(int n) moel@345: { moel@345: if ((n >= 0) && (n < frameCount)) moel@345: return (GifFrame)frames[n]; moel@345: else moel@345: throw new ArgumentOutOfRangeException(); moel@345: } moel@345: moel@345: /** moel@345: * Gets image size. moel@345: * moel@345: * @return GIF image dimensions moel@345: */ moel@345: public Size FrameSize moel@345: { moel@345: get moel@345: { moel@345: return new Size(width, height); moel@345: } moel@345: } moel@345: moel@345: /** moel@345: * Reads GIF image from stream moel@345: * moel@345: * @param BufferedInputStream containing GIF file. moel@345: * @return read status code (0 = no errors) moel@345: */ moel@345: private int Read( Stream inStream ) moel@345: { moel@345: Init(); moel@345: if ( inStream != null) moel@345: { moel@345: this.inStream = inStream; moel@345: ReadHeader(); moel@345: if (!Error()) moel@345: { moel@345: ReadContents(); moel@345: if (frameCount < 0) moel@345: { moel@345: status = StatusFormatError; moel@345: } moel@345: } moel@345: inStream.Close(); moel@345: } moel@345: else moel@345: { moel@345: status = StatusOpenError; moel@345: } moel@345: return status; moel@345: } moel@345: moel@345: moel@345: /** moel@345: * Decodes LZW image data into pixel array. moel@345: * Adapted from John Cristy's ImageMagick. moel@345: */ moel@345: private void DecodeImageData() moel@345: { moel@345: int NullCode = -1; moel@345: int npix = iw * ih; moel@345: int available, moel@345: clear, moel@345: code_mask, moel@345: code_size, moel@345: end_of_information, moel@345: in_code, moel@345: old_code, moel@345: bits, moel@345: code, moel@345: count, moel@345: i, moel@345: datum, moel@345: data_size, moel@345: first, moel@345: top, moel@345: bi, moel@345: pi; moel@345: moel@345: if ((pixels == null) || (pixels.Length < npix)) moel@345: { moel@345: pixels = new byte[npix]; // allocate new pixel array moel@345: } moel@345: if (prefix == null) prefix = new short[MaxStackSize]; moel@345: if (suffix == null) suffix = new byte[MaxStackSize]; moel@345: if (pixelStack == null) pixelStack = new byte[MaxStackSize + 1]; moel@345: moel@345: // Initialize GIF data stream decoder. moel@345: moel@345: data_size = Read(); moel@345: clear = 1 << data_size; moel@345: end_of_information = clear + 1; moel@345: available = clear + 2; moel@345: old_code = NullCode; moel@345: code_size = data_size + 1; moel@345: code_mask = (1 << code_size) - 1; moel@345: for (code = 0; code < clear; code++) moel@345: { moel@345: prefix[code] = 0; moel@345: suffix[code] = (byte) code; moel@345: } moel@345: moel@345: // Decode GIF pixel stream. moel@345: moel@345: datum = bits = count = first = top = pi = bi = 0; moel@345: moel@345: for (i = 0; i < npix;) moel@345: { moel@345: if (top == 0) moel@345: { moel@345: if (bits < code_size) moel@345: { moel@345: // Load bytes until there are enough bits for a code. moel@345: if (count == 0) moel@345: { moel@345: // Read a new data block. moel@345: count = ReadBlock(); moel@345: if (count <= 0) moel@345: break; moel@345: bi = 0; moel@345: } moel@345: datum += (((int) block[bi]) & 0xff) << bits; moel@345: bits += 8; moel@345: bi++; moel@345: count--; moel@345: continue; moel@345: } moel@345: moel@345: // Get the next code. moel@345: moel@345: code = datum & code_mask; moel@345: datum >>= code_size; moel@345: bits -= code_size; moel@345: moel@345: // Interpret the code moel@345: moel@345: if ((code > available) || (code == end_of_information)) moel@345: break; moel@345: if (code == clear) moel@345: { moel@345: // Reset decoder. moel@345: code_size = data_size + 1; moel@345: code_mask = (1 << code_size) - 1; moel@345: available = clear + 2; moel@345: old_code = NullCode; moel@345: continue; moel@345: } moel@345: if (old_code == NullCode) moel@345: { moel@345: pixelStack[top++] = suffix[code]; moel@345: old_code = code; moel@345: first = code; moel@345: continue; moel@345: } moel@345: in_code = code; moel@345: if (code == available) moel@345: { moel@345: pixelStack[top++] = (byte) first; moel@345: code = old_code; moel@345: } moel@345: while (code > clear) moel@345: { moel@345: pixelStack[top++] = suffix[code]; moel@345: code = prefix[code]; moel@345: } moel@345: first = ((int) suffix[code]) & 0xff; moel@345: moel@345: // Add a new string to the string table, moel@345: moel@345: if (available >= MaxStackSize) moel@345: break; moel@345: pixelStack[top++] = (byte) first; moel@345: prefix[available] = (short) old_code; moel@345: suffix[available] = (byte) first; moel@345: available++; moel@345: if (((available & code_mask) == 0) moel@345: && (available < MaxStackSize)) moel@345: { moel@345: code_size++; moel@345: code_mask += available; moel@345: } moel@345: old_code = in_code; moel@345: } moel@345: moel@345: // Pop a pixel off the pixel stack. moel@345: moel@345: top--; moel@345: pixels[pi++] = pixelStack[top]; moel@345: i++; moel@345: } moel@345: moel@345: for (i = pi; i < npix; i++) moel@345: { moel@345: pixels[i] = 0; // clear missing pixels moel@345: } moel@345: moel@345: } moel@345: moel@345: /** moel@345: * Returns true if an error was encountered during reading/decoding moel@345: */ moel@345: private bool Error() moel@345: { moel@345: return status != StatusOK; moel@345: } moel@345: moel@345: /** moel@345: * Initializes or re-initializes reader moel@345: */ moel@345: private void Init() moel@345: { moel@345: status = StatusOK; moel@345: frameCount = 0; moel@345: frames = new ArrayList(); moel@345: gct = null; moel@345: lct = null; moel@345: } moel@345: moel@345: /** moel@345: * Reads a single byte from the input stream. moel@345: */ moel@345: private int Read() moel@345: { moel@345: int curByte = 0; moel@345: try moel@345: { moel@345: curByte = inStream.ReadByte(); moel@345: } moel@345: catch (IOException) moel@345: { moel@345: status = StatusFormatError; moel@345: } moel@345: return curByte; moel@345: } moel@345: moel@345: /** moel@345: * Reads next variable length block from input. moel@345: * moel@345: * @return number of bytes stored in "buffer" moel@345: */ moel@345: private int ReadBlock() moel@345: { moel@345: blockSize = Read(); moel@345: int n = 0; moel@345: if (blockSize > 0) moel@345: { moel@345: try moel@345: { moel@345: int count = 0; moel@345: while (n < blockSize) moel@345: { moel@345: count = inStream.Read(block, n, blockSize - n); moel@345: if (count == -1) moel@345: break; moel@345: n += count; moel@345: } moel@345: } moel@345: catch (IOException) moel@345: { moel@345: } moel@345: moel@345: if (n < blockSize) moel@345: { moel@345: status = StatusFormatError; moel@345: } moel@345: } moel@345: return n; moel@345: } moel@345: moel@345: /** moel@345: * Reads color table as 256 RGB integer values moel@345: * moel@345: * @param ncolors int number of colors to read moel@345: * @return int array containing 256 colors (packed ARGB with full alpha) moel@345: */ moel@345: private int[] ReadColorTable(int ncolors) moel@345: { moel@345: int nbytes = 3 * ncolors; moel@345: int[] tab = null; moel@345: byte[] c = new byte[nbytes]; moel@345: int n = 0; moel@345: try moel@345: { moel@345: n = inStream.Read(c, 0, c.Length ); moel@345: } moel@345: catch (IOException) moel@345: { moel@345: } moel@345: if (n < nbytes) moel@345: { moel@345: status = StatusFormatError; moel@345: } moel@345: else moel@345: { moel@345: tab = new int[256]; // max size to avoid bounds checks moel@345: int i = 0; moel@345: int j = 0; moel@345: while (i < ncolors) moel@345: { moel@345: int r = ((int) c[j++]) & 0xff; moel@345: int g = ((int) c[j++]) & 0xff; moel@345: int b = ((int) c[j++]) & 0xff; moel@345: tab[i++] = ( int ) ( 0xff000000 | (r << 16) | (g << 8) | b ); moel@345: } moel@345: } moel@345: return tab; moel@345: } moel@345: moel@345: /** moel@345: * Main file parser. Reads GIF content blocks. moel@345: */ moel@345: private void ReadContents() moel@345: { moel@345: // read GIF file content blocks moel@345: bool done = false; moel@345: while (!(done || Error())) moel@345: { moel@345: int code = Read(); moel@345: switch (code) moel@345: { moel@345: moel@345: case 0x2C : // image separator moel@345: ReadImage(); moel@345: break; moel@345: moel@345: case 0x21 : // extension moel@345: code = Read(); moel@345: switch (code) moel@345: { moel@345: case 0xf9 : // graphics control extension moel@345: ReadGraphicControlExt(); moel@345: break; moel@345: moel@345: case 0xff : // application extension moel@345: ReadBlock(); moel@345: String app = ""; moel@345: for (int i = 0; i < 11; i++) moel@345: { moel@345: app += (char) block[i]; moel@345: } moel@345: if (app.Equals("NETSCAPE2.0")) moel@345: { moel@345: ReadNetscapeExt(); moel@345: } moel@345: else moel@345: Skip(); // don't care moel@345: break; moel@345: moel@345: default : // uninteresting extension moel@345: Skip(); moel@345: break; moel@345: } moel@345: break; moel@345: moel@345: case 0x3b : // terminator moel@345: done = true; moel@345: break; moel@345: moel@345: case 0x00 : // bad byte, but keep going and see what happens moel@345: break; moel@345: moel@345: default : moel@345: status = StatusFormatError; moel@345: break; moel@345: } moel@345: } moel@345: } moel@345: moel@345: /** moel@345: * Reads Graphics Control Extension values moel@345: */ moel@345: private void ReadGraphicControlExt() moel@345: { moel@345: Read(); // block size moel@345: int packed = Read(); // packed fields moel@345: dispose = (packed & 0x1c) >> 2; // disposal method moel@345: if (dispose == 0) moel@345: { moel@345: dispose = 1; // elect to keep old image if discretionary moel@345: } moel@345: transparency = (packed & 1) != 0; moel@345: delay = ReadShort() * 10; // delay in milliseconds moel@345: transIndex = Read(); // transparent color index moel@345: Read(); // block terminator moel@345: } moel@345: moel@345: /** moel@345: * Reads GIF file header information. moel@345: */ moel@345: private void ReadHeader() moel@345: { moel@345: String id = ""; moel@345: for (int i = 0; i < 6; i++) moel@345: { moel@345: id += (char) Read(); moel@345: } moel@345: if (!id.StartsWith("GIF")) moel@345: { moel@345: status = StatusFormatError; moel@345: return; moel@345: } moel@345: moel@345: ReadLSD(); moel@345: if (gctFlag && !Error()) moel@345: { moel@345: gct = ReadColorTable(gctSize); moel@345: bgColor = gct[bgIndex]; moel@345: } moel@345: } moel@345: moel@345: /** moel@345: * Reads next frame image moel@345: */ moel@345: private void ReadImage() moel@345: { moel@345: ix = ReadShort(); // (sub)image position & size moel@345: iy = ReadShort(); moel@345: iw = ReadShort(); moel@345: ih = ReadShort(); moel@345: moel@345: int packed = Read(); moel@345: lctFlag = (packed & 0x80) != 0; // 1 - local color table flag moel@345: interlace = (packed & 0x40) != 0; // 2 - interlace flag moel@345: // 3 - sort flag moel@345: // 4-5 - reserved moel@345: lctSize = 2 << (packed & 7); // 6-8 - local color table size moel@345: moel@345: if (lctFlag) moel@345: { moel@345: lct = ReadColorTable(lctSize); // read table moel@345: act = lct; // make local table active moel@345: } moel@345: else moel@345: { moel@345: act = gct; // make global table active moel@345: if (bgIndex == transIndex) moel@345: bgColor = 0; moel@345: } moel@345: int save = 0; moel@345: if (transparency) moel@345: { moel@345: save = act[transIndex]; moel@345: act[transIndex] = 0; // set transparent color if specified moel@345: } moel@345: moel@345: if (act == null) moel@345: { moel@345: status = StatusFormatError; // no color table defined moel@345: } moel@345: moel@345: if (Error()) return; moel@345: moel@345: DecodeImageData(); // decode pixel data moel@345: Skip(); moel@345: moel@345: if (Error()) return; moel@345: moel@345: frameCount++; moel@345: moel@345: // create new image to receive frame data moel@345: // image = moel@345: // new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE); moel@345: moel@345: bitmap = new Bitmap( width, height ); moel@345: image = bitmap; moel@345: SetPixels(); // transfer pixel data to image moel@345: moel@345: frames.Add(new GifFrame(bitmap, delay)); // add image to frame list moel@345: moel@345: if (transparency) moel@345: { moel@345: act[transIndex] = save; moel@345: } moel@345: ResetFrame(); moel@345: moel@345: } moel@345: moel@345: /** moel@345: * Reads Logical Screen Descriptor moel@345: */ moel@345: private void ReadLSD() moel@345: { moel@345: moel@345: // logical screen size moel@345: width = ReadShort(); moel@345: height = ReadShort(); moel@345: moel@345: // packed fields moel@345: int packed = Read(); moel@345: gctFlag = (packed & 0x80) != 0; // 1 : global color table flag moel@345: // 2-4 : color resolution moel@345: // 5 : gct sort flag moel@345: gctSize = 2 << (packed & 7); // 6-8 : gct size moel@345: moel@345: bgIndex = Read(); // background color index moel@345: pixelAspect = Read(); // pixel aspect ratio moel@345: } moel@345: moel@345: /** moel@345: * Reads Netscape extenstion to obtain iteration count moel@345: */ moel@345: private void ReadNetscapeExt() moel@345: { moel@345: do moel@345: { moel@345: ReadBlock(); moel@345: if (block[0] == 1) moel@345: { moel@345: // loop count sub-block moel@345: int b1 = ((int) block[1]) & 0xff; moel@345: int b2 = ((int) block[2]) & 0xff; moel@345: loopCount = (b2 << 8) | b1; moel@345: } moel@345: } while ((blockSize > 0) && !Error()); moel@345: } moel@345: moel@345: /** moel@345: * Reads next 16-bit value, LSB first moel@345: */ moel@345: private int ReadShort() moel@345: { moel@345: // read 16-bit value, LSB first moel@345: return Read() | (Read() << 8); moel@345: } moel@345: moel@345: /** moel@345: * Resets frame state for reading next image. moel@345: */ moel@345: private void ResetFrame() moel@345: { moel@345: lastDispose = dispose; moel@345: lastRect = new Rectangle(ix, iy, iw, ih); moel@345: lastImage = image; moel@345: lastBgColor = bgColor; moel@345: // int dispose = 0; moel@345: lct = null; moel@345: } moel@345: moel@345: /** moel@345: * Skips variable length blocks up to and including moel@345: * next zero length block. moel@345: */ moel@345: private void Skip() moel@345: { moel@345: do moel@345: { moel@345: ReadBlock(); moel@345: } while ((blockSize > 0) && !Error()); moel@345: } moel@345: } moel@345: }