internal new static async Task<GifFrame> ReadAsync(Stream stream, IEnumerable<GifExtension> controlExtensions) { var frame = new GifFrame(); await frame.ReadInternalAsync(stream, controlExtensions).ConfigureAwait(false); return frame; }
private static TimeSpan GetFrameDelay(GifFrame frame) { var gce = frame.GraphicControl; if (gce != null) { if (gce.Delay != 0) return TimeSpan.FromMilliseconds(gce.Delay); } return TimeSpan.FromMilliseconds(100); }
private async Task<Stream> GetIndexStreamAsync(GifFrame frame, CancellationToken cancellationToken) { var data = frame.ImageData; cancellationToken.ThrowIfCancellationRequested(); _sourceStream.Seek(data.CompressedDataStartOffset, SeekOrigin.Begin); using (var ms = new MemoryStream(_indexStreamBuffer)) { await GifHelpers.CopyDataBlocksToStreamAsync(_sourceStream, ms, cancellationToken).ConfigureAwait(false); } var lzwStream = new LzwDecompressStream(_indexStreamBuffer, data.LzwMinimumCodeSize); return lzwStream; }
private void DisposePreviousFrame(GifFrame currentFrame) { var pgce = _previousFrame?.GraphicControl; if (pgce != null) { switch (pgce.DisposalMethod) { case GifFrameDisposalMethod.None: case GifFrameDisposalMethod.DoNotDispose: { // Leave previous frame in place break; } case GifFrameDisposalMethod.RestoreBackground: { ClearArea(_previousFrame.Descriptor); break; } case GifFrameDisposalMethod.RestorePrevious: { CopyToBitmap(_previousBackBuffer, _bitmap, 0, _previousBackBuffer.Length); #if WPF var desc = _metadata.Header.LogicalScreenDescriptor; var rect = new Int32Rect(0, 0, desc.Width, desc.Height); _bitmap.AddDirtyRect(rect); #endif break; } default: { throw new ArgumentOutOfRangeException(); } } } var gce = currentFrame.GraphicControl; if (gce != null && gce.DisposalMethod == GifFrameDisposalMethod.RestorePrevious) { CopyFromBitmap(_previousBackBuffer, _bitmap, 0, _previousBackBuffer.Length); } }
private async Task RenderFrameAsync(int frameIndex, CancellationToken cancellationToken) { if (frameIndex < 0) return; var frame = _metadata.Frames[frameIndex]; var desc = frame.Descriptor; using (var indexStream = await GetIndexStreamAsync(frame, cancellationToken)) { #if WPF _bitmap.Lock(); try { #endif if (frameIndex < _previousFrameIndex) ClearArea(_metadata.Header.LogicalScreenDescriptor); else DisposePreviousFrame(frame); int bufferLength = 4 * desc.Width; byte[] indexBuffer = new byte[desc.Width]; byte[] lineBuffer = new byte[bufferLength]; var palette = _palettes[frameIndex]; int transparencyIndex = palette.TransparencyIndex ?? -1; var rows = frame.Descriptor.Interlace ? InterlacedRows(frame.Descriptor.Height) : NormalRows(frame.Descriptor.Height); foreach (int y in rows) { int read = indexStream.Read(indexBuffer, 0, desc.Width); if (read != desc.Width) throw new EndOfStreamException(); int offset = (desc.Top + y) * _stride + desc.Left * 4; if (transparencyIndex >= 0) { CopyFromBitmap(lineBuffer, _bitmap, offset, bufferLength); } for (int x = 0; x < desc.Width; x++) { byte index = indexBuffer[x]; int i = 4 * x; if (index != transparencyIndex) { WriteColor(lineBuffer, palette[index], i); } } CopyToBitmap(lineBuffer, _bitmap, offset, bufferLength); } #if WPF var rect = new Int32Rect(desc.Left, desc.Top, desc.Width, desc.Height); _bitmap.AddDirtyRect(rect); } finally { _bitmap.Unlock(); } #elif WINRT _bitmap.Invalidate(); #endif _previousFrame = frame; _previousFrameIndex = frameIndex; } }