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)); } }
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); }
void RestoreToBackground(GIFHeader header, GIFBitmap currentBitmap, GIFBitmap previousBitmap, int[] bitmapData) { int color = 0; if (!currentBitmap.IsTransparent) { color = previousBitmap.BackgroundColor; } var previousBitmapBounds = previousBitmap.Bounds; for (int currentRow = 0; currentRow < previousBitmapBounds.Height; currentRow++) { int startBitmapIndex = (previousBitmapBounds.Y + currentRow) * header.Width + previousBitmapBounds.X; int endBitmapIndex = startBitmapIndex + previousBitmapBounds.Width; for (int currentBitmapIndex = startBitmapIndex; currentBitmapIndex < endBitmapIndex; currentBitmapIndex++) { bitmapData[currentBitmapIndex] = color; } } }
protected abstract void AddBitmap(GIFHeader header, GIFBitmap bitmap, bool ignoreImageData);
public void Compose(GIFHeader header, GIFBitmap currentBitmap, GIFBitmap previousBitmap) { int[] bitmapData = null; var width = header.Width; var height = header.Height; if (previousBitmap != null && previousBitmap.Dispose != GIFBitmap.DisposeMethod.NoAction) { if (previousBitmap.Data != null) { bitmapData = previousBitmap.Data; if (previousBitmap.Dispose == GIFBitmap.DisposeMethod.RestoreToBackground) { RestoreToBackground(header, currentBitmap, previousBitmap, bitmapData); } } } // Reuse previous bitmap buffer or allocate new. if (bitmapData == null) { bitmapData = new int[width * height]; } int interlacePass = 1; int interlaceRowInc = 8; int interlaceStartRow = 0; var bounds = currentBitmap.Bounds; var isInterlaced = currentBitmap.IsInterlaced; var colorTable = currentBitmap.ColorTable.Data; for (int sourceRow = 0; sourceRow < bounds.Height; sourceRow++) { int targetRow = sourceRow; if (isInterlaced) { if (interlaceStartRow >= bounds.Height) { interlacePass++; switch (interlacePass) { case 2: interlaceStartRow = 4; break; case 3: interlaceStartRow = 2; interlaceRowInc = 4; break; case 4: interlaceStartRow = 1; interlaceRowInc = 2; break; default: break; } } targetRow = interlaceStartRow; interlaceStartRow += interlaceRowInc; } targetRow += bounds.Y; if (targetRow < height) { int startBitmapIndex = targetRow * width; int currentBitmapIndex = startBitmapIndex + bounds.X; int endBitmapIndex = currentBitmapIndex + bounds.Width; if ((startBitmapIndex + width) < endBitmapIndex) { endBitmapIndex = startBitmapIndex + width; } int currentPixelIndex = sourceRow * bounds.Width; while (currentBitmapIndex < endBitmapIndex) { int colorIndex = _pixels[currentPixelIndex++]; int color = colorTable[colorIndex]; if (color != 0) { bitmapData[currentBitmapIndex] = color; } currentBitmapIndex++; } } } currentBitmap.Data = bitmapData; }
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); }
GIFBitmap(GIFHeader header) { _header = header; LoopCount = 0; Delay = 10; }