async Task ParseAsync(GIFDecoderStreamReader stream, bool skipTypeIdentifier) { if (!skipTypeIdentifier) { TypeIdentifier = stream.ReadString(3); } else { TypeIdentifier = "GIF"; } if (IsGIFHeader) { Version = stream.ReadString(3); Width = stream.ReadShort(); Height = stream.ReadShort(); int flags = stream.Read(); BackgroundColorIndex = stream.Read(); PixelAspectRatio = stream.Read(); if (UseGlobalColorTable(flags)) { GlobalColorTable = await GIFColorTable.CreateColorTableAsync(stream, GlobalColorTableSize(flags)).ConfigureAwait(false); BackgroundColor = GlobalColorTable.Data[BackgroundColorIndex]; } } else { throw new GIFDecoderFormatException("Unknown GIF format type identifier: " + TypeIdentifier); } }
public async Task ParseAsync(Stream stream, bool skipTypeIdentifier = false, bool ignoreImageData = false) { if (stream != null) { GIFBitmap previousBitmap = null; GIFBitmap currentBitmap = null; GIFBitmapDecoder decoder = new GIFBitmapDecoder(); GIFDecoderStreamReader reader = new GIFDecoderStreamReader(stream); StartParsing(); GIFHeader header = await GIFHeader.CreateHeaderAsync(reader, skipTypeIdentifier).ConfigureAwait(false); currentBitmap = await GIFBitmap.CreateBitmapAsync(reader, header, decoder, previousBitmap, ignoreImageData).ConfigureAwait(false); while (currentBitmap != null) { AddBitmap(header, currentBitmap, ignoreImageData); previousBitmap = currentBitmap; currentBitmap = await GIFBitmap.CreateBitmapAsync(reader, header, decoder, previousBitmap, ignoreImageData).ConfigureAwait(false); } FinishedParsing(); } else { throw new ArgumentNullException(nameof(stream)); } }
async Task ParseImageDescriptorAsync(GIFDecoderStreamReader stream, GIFBitmapDecoder decoder, GIFBitmap previousBitmap, bool ignoreImageData) { await ParseGIFBitmapHeaderAsync(stream).ConfigureAwait(false); if (IsTransparent) { ColorTable.SetTransparency(TransparencyIndex); } DataPosition = stream.CurrentPosition; if (!ignoreImageData) { // Decode LZW data stream. await decoder.DecodeAsync(stream, _header.Width, _header.Height).ConfigureAwait(false); // Compose bitmap from decoded data stream. decoder.Compose(_header, this, previousBitmap); // Consume block terminator. await stream.SkipBlockAsync().ConfigureAwait(false); } else { // Read pass variable length LZW data stream. // First byte is LZW code size followed by data blocks repeated until block terminator. stream.Read(); await stream.SkipBlockAsync().ConfigureAwait(false); } if (IsTransparent) { ColorTable.ResetTransparency(); } }
public static async Task <GIFColorTable> CreateColorTableAsync(GIFDecoderStreamReader stream, short size) { var colorTable = new GIFColorTable(size); await colorTable.ParseAsync(stream).ConfigureAwait(false); return(colorTable); }
public static async Task <GIFHeader> CreateHeaderAsync(GIFDecoderStreamReader stream, bool skipTypeIdentifier = false) { GIFHeader header = new GIFHeader(); await header.ParseAsync(stream, skipTypeIdentifier).ConfigureAwait(false); if (!header.IsGIFHeader) { header = null; } return(header); }
public static async Task <GIFBitmap> CreateBitmapAsync(GIFDecoderStreamReader stream, GIFHeader header, GIFBitmapDecoder decoder, GIFBitmap previousBitmap, bool ignoreImageData = false) { GIFBitmap currentBitmap = null; bool haveImage = false; bool done = false; while (!done) { int blockCode = stream.Read(); if (blockCode == -1) { currentBitmap = null; break; } switch (blockCode) { case GIFBlockCodes.ImageSeparator: if (currentBitmap == null) { currentBitmap = new GIFBitmap(header); } await currentBitmap.ParseImageDescriptorAsync(stream, decoder, previousBitmap, ignoreImageData).ConfigureAwait(false); haveImage = true; done = true; break; case GIFBlockCodes.Extension: if (currentBitmap == null) { currentBitmap = new GIFBitmap(header); } await currentBitmap.ParseExtensionAsync(stream).ConfigureAwait(false); break; case GIFBlockCodes.Trailer: done = true; if (!haveImage) { currentBitmap = null; } break; default: break; } } return(currentBitmap); }
async Task ParseGIFBitmapHeaderAsync(GIFDecoderStreamReader stream) { Bounds = new GIFBitmap.Rect(stream.ReadShort(), stream.ReadShort(), stream.ReadShort(), stream.ReadShort()); ColorTable = _header.GlobalColorTable; int flags = stream.Read(); if (UseLocalColorTable(flags)) { ColorTable = await GIFColorTable.CreateColorTableAsync(stream, LocalColorTableSize(flags)).ConfigureAwait(false); } BackgroundColor = _header.BackgroundColor; IsInterlaced = UseInterlace(flags); }
void ParseGraphicControlExtension(GIFDecoderStreamReader stream) { int blockSize = stream.Read(); if (blockSize != 4) { throw new GIFDecoderFormatException("Invalid graphic control extension size."); } int flags = stream.Read(); SetDisposeMethod(flags); SetDelay(stream.ReadShort()); SetTransparency(flags, stream.Read()); // Consume block terminator. stream.Read(); }
async Task ParseApplicationExtensionAsync(GIFDecoderStreamReader stream) { var blockSize = await stream.ReadBlockAsync().ConfigureAwait(false); if (blockSize >= NetscapeApplicationExtensionID.Length) { var buffer = stream.CurrentBlockBuffer; string identifier = System.Text.Encoding.UTF8.GetString(buffer, 0, NetscapeApplicationExtensionID.Length); if (identifier.Equals(NetscapeApplicationExtensionID, StringComparison.OrdinalIgnoreCase)) { await ParseNetscapeApplicationExtensionAsync(stream).ConfigureAwait(false); return; } } await stream.SkipBlockAsync().ConfigureAwait(false); return; }
async Task ParseExtensionAsync(GIFDecoderStreamReader stream) { int blockCode = stream.Read(); switch (blockCode) { case GIFBlockCodes.GraphicsControlExtension: ParseGraphicControlExtension(stream); break; case GIFBlockCodes.ApplicationExtensionBlock: await ParseApplicationExtensionAsync(stream).ConfigureAwait(false); break; default: await stream.SkipBlockAsync().ConfigureAwait(false); break; } }
async Task ParseNetscapeApplicationExtensionAsync(GIFDecoderStreamReader stream) { int blockSize = await stream.ReadBlockAsync().ConfigureAwait(false); while (blockSize > 0) { if (stream.CurrentBlockBuffer[0] == 1 && blockSize == 3) { int count = (stream.CurrentBlockBuffer[2] << 8) | stream.CurrentBlockBuffer[1]; if (count == 0) { LoopCount = int.MaxValue; } else if (count != 0) { LoopCount = count; } } blockSize = await stream.ReadBlockAsync().ConfigureAwait(false); } }
async Task ParseAsync(GIFDecoderStreamReader stream) { int toRead = _colorData.Length; int bytesRead = await stream.ReadAsync(_colorData, toRead).ConfigureAwait(false); if (bytesRead < toRead) { throw new GIFDecoderFormatException("Invalid color table size."); } int currentColor = 0; int currentColorData = 0; while (currentColor < _size) { int r = _colorData[currentColorData++]; int g = _colorData[currentColorData++]; int b = _colorData[currentColorData++]; var rgb = (r << 16) | (g << 8) | b; _colorTable[currentColor++] = (int)(0xFF000000 | rgb); } }
public async Task DecodeAsync(GIFDecoderStreamReader stream, int width, int height) { int pixelCount = width * height; InitializeBuffers(pixelCount); int nullCode = -1; int inCode = nullCode; int oldCode = nullCode; int currentCode = nullCode; int dataSize = stream.Read(); int codeSize = dataSize + 1; int codeMask = (1 << codeSize) - 1; int clearCode = 1 << dataSize; int endOfInformationCode = clearCode + 1; int availableCode = clearCode + 2; for (currentCode = 0; currentCode < clearCode; currentCode++) { _prefix[currentCode] = 0; _suffix[currentCode] = (byte)currentCode; } int datum = 0; int bits = 0; int count = 0; int firstCode = 0; int currentStackIndex = 0; int currentPixelIndex = 0; int currentBitIndex = 0; int i = 0; for (i = 0; i < pixelCount;) { if (currentStackIndex == 0) { if (bits < codeSize) { if (count == 0) { count = await stream.ReadBlockAsync().ConfigureAwait(false); if (count <= 0) { break; } currentBitIndex = 0; } datum += (stream.CurrentBlockBuffer[currentBitIndex] << bits); bits += 8; currentBitIndex++; count--; continue; } currentCode = datum & codeMask; datum >>= codeSize; bits -= codeSize; if ((currentCode > availableCode) || (currentCode == endOfInformationCode)) { break; } if (currentCode == clearCode) { codeSize = dataSize + 1; codeMask = (1 << codeSize) - 1; availableCode = clearCode + 2; oldCode = nullCode; continue; } if (oldCode == nullCode) { _pixelStack[currentStackIndex++] = _suffix[currentCode]; oldCode = currentCode; firstCode = currentCode; continue; } inCode = currentCode; if (currentCode == availableCode) { _pixelStack[currentStackIndex++] = (byte)firstCode; currentCode = oldCode; } while (currentCode > clearCode) { _pixelStack[currentStackIndex++] = _suffix[currentCode]; currentCode = _prefix[currentCode]; } firstCode = _suffix[currentCode]; if (availableCode >= DecoderStackSize) { break; } _pixelStack[currentStackIndex++] = (byte)firstCode; _prefix[availableCode] = (short)oldCode; _suffix[availableCode] = (byte)firstCode; availableCode++; if (((availableCode & codeMask) == 0) && (availableCode < DecoderStackSize)) { codeSize++; codeMask += availableCode; } oldCode = inCode; } currentStackIndex--; _pixels[currentPixelIndex++] = _pixelStack[currentStackIndex]; i++; } for (i = currentPixelIndex; i < pixelCount; i++) { _pixels[i] = 0; } }