}; // class GifCodeHelper // Decompress the bytes corresponding to a GIF image. private static void Decompress (Stream stream, byte[] buffer, Frame frame, bool interlaced) { int minCodeSize, code; int clearCode, endCode; int nextCode, oldCode; GifCodeHelper helper; ushort[] prefix = new ushort [4096]; byte[] suffix = new byte [4096]; ushort[] length = new ushort [4096]; int offset, x, y, width, height; int stride, lineChange, temp; byte[] data; byte[] stringbuf = new byte [4096]; int stringLen, tempCode, pass; byte lastSuffix; // Read the minimum code size and validate it. if (stream.Read(buffer, 0, 1) != 1) { throw new FormatException(); } minCodeSize = buffer[0]; if (minCodeSize < 2) { minCodeSize = 2; } else if (minCodeSize > 11) { minCodeSize = 11; } // Create a code helper. helper = new GifCodeHelper(stream, buffer, minCodeSize + 1); // Set the clear and end codes. clearCode = (1 << minCodeSize); endCode = clearCode + 1; nextCode = endCode; // Initialize the table. for (code = 0; code < clearCode; ++code) { prefix[code] = (ushort)49428; suffix[code] = (byte)code; length[code] = (ushort)1; } // Initialize the image output parameters. x = 0; y = 0; width = frame.Width; height = frame.Height; data = frame.Data; pass = 0; lineChange = (interlaced ? 8 : 1); stride = frame.Stride; // Process the codes in the input stream. code = clearCode; for (;;) { oldCode = code; if ((code = helper.GetCode()) == -1) { // We've run out of data blocks. break; } else if (code == clearCode) { // Clear the code table and restart. helper.ResetCodeSize(); nextCode = endCode; continue; } else if (code == endCode) { // End of the GIF input stream: skip remaining blocks. SkipSubBlocks(stream, buffer); break; } else { // Sanity check for out of range codes. if (code > nextCode && nextCode != 0) { code = 0; } // Update the next code in the table. prefix[nextCode] = (ushort)oldCode; length[nextCode] = (ushort)(length[oldCode] + 1); // Form the full string for this code. stringLen = length[code]; tempCode = code; do { lastSuffix = suffix[tempCode]; --stringLen; stringbuf[stringLen] = lastSuffix; tempCode = prefix[tempCode]; }while(stringLen > 0); suffix[nextCode] = lastSuffix; stringLen = length[code]; if (code == nextCode) { stringbuf[stringLen - 1] = lastSuffix; } // Copy the string into the actual image. offset = 0; while (stringLen > 0) { temp = width - x; if (temp > stringLen) { temp = stringLen; } Array.Copy(stringbuf, offset, data, y * stride + x, temp); x += temp; offset += temp; stringLen -= temp; if (x >= width) { x = 0; y += lineChange; while (y >= height && interlaced) { // Move on to the next interlace pass. ++pass; if (pass == 1) { y = 4; lineChange = 8; } else if (pass == 2) { y = 2; lineChange = 4; } else if (pass == 3) { y = 1; lineChange = 2; } else { break; } } if (y >= height) { // Shouldn't happen - just in case. y = 0; } } } // Set the suffix for the next code. suffix[nextCode] = (byte)lastSuffix; // Move on to the next code. if (nextCode != clearCode) { ++nextCode; if (nextCode == helper.codeMax) { helper.IncreaseCodeSize(); if (helper.codeSize > 12) { helper.ResetCodeSize(); nextCode = clearCode; } } } } } }
}; // class GifCodeHelper // Decompress the bytes corresponding to a GIF image. private static void Decompress (Stream stream, byte[] buffer, Frame frame, bool interlaced) { int minCodeSize, code; int clearCode, endCode; int nextCode, oldCode; GifCodeHelper helper; ushort[] prefix = new ushort [4096]; byte[] suffix = new byte [4096]; ushort[] length = new ushort [4096]; int offset, x, y, width, height; int stride, lineChange, temp; byte[] data; byte[] stringbuf = new byte [4096]; int stringLen, tempCode, pass; byte lastSuffix; // Read the minimum code size and validate it. if(stream.Read(buffer, 0, 1) != 1) { throw new FormatException(); } minCodeSize = buffer[0]; if(minCodeSize < 2) { minCodeSize = 2; } else if(minCodeSize > 11) { minCodeSize = 11; } // Create a code helper. helper = new GifCodeHelper(stream, buffer, minCodeSize + 1); // Set the clear and end codes. clearCode = (1 << minCodeSize); endCode = clearCode + 1; nextCode = endCode; // Initialize the table. for(code = 0; code < clearCode; ++code) { prefix[code] = (ushort)49428; suffix[code] = (byte)code; length[code] = (ushort)1; } // Initialize the image output parameters. x = 0; y = 0; width = frame.Width; height = frame.Height; data = frame.Data; pass = 0; lineChange = (interlaced ? 8 : 1); stride = frame.Stride; // Process the codes in the input stream. code = clearCode; for(;;) { oldCode = code; if((code = helper.GetCode()) == -1) { // We've run out of data blocks. break; } else if(code == clearCode) { // Clear the code table and restart. helper.ResetCodeSize(); nextCode = endCode; continue; } else if(code == endCode) { // End of the GIF input stream: skip remaining blocks. SkipSubBlocks(stream, buffer); break; } else { // Sanity check for out of range codes. if(code > nextCode && nextCode != 0) { code = 0; } // Update the next code in the table. prefix[nextCode] = (ushort)oldCode; length[nextCode] = (ushort)(length[oldCode] + 1); // Form the full string for this code. stringLen = length[code]; tempCode = code; do { lastSuffix = suffix[tempCode]; --stringLen; stringbuf[stringLen] = lastSuffix; tempCode = prefix[tempCode]; } while(stringLen > 0); suffix[nextCode] = lastSuffix; stringLen = length[code]; if(code == nextCode) { stringbuf[stringLen - 1] = lastSuffix; } // Copy the string into the actual image. offset = 0; while(stringLen > 0) { temp = width - x; if(temp > stringLen) { temp = stringLen; } Array.Copy(stringbuf, offset, data, y * stride + x, temp); x += temp; offset += temp; stringLen -= temp; if(x >= width) { x = 0; y += lineChange; while(y >= height && interlaced) { // Move on to the next interlace pass. ++pass; if(pass == 1) { y = 4; lineChange = 8; } else if(pass == 2) { y = 2; lineChange = 4; } else if(pass == 3) { y = 1; lineChange = 2; } else { break; } } if(y >= height) { // Shouldn't happen - just in case. y = 0; } } } // Set the suffix for the next code. suffix[nextCode] = (byte)lastSuffix; // Move on to the next code. if(nextCode != clearCode) { ++nextCode; if(nextCode == helper.codeMax) { helper.IncreaseCodeSize(); if(helper.codeSize > 12) { helper.ResetCodeSize(); nextCode = clearCode; } } } } } }