Пример #1
0
        public static void UpdateGifAnimationContext(WicGifContainer cont, ComPtr <IWICBitmapSource> src, ComPtr <IWICMetadataQueryReader> meta)
        {
            Debug.Assert(cont.AnimationContext is not null);
            var anictx = cont.AnimationContext;

            const int bytesPerPixel = 4;

            var finfo = GetGifFrameInfo(cont, src, meta);
            var fbuff = anictx.FrameBufferSource ??= new FrameBufferSource(cont.ScreenWidth, cont.ScreenHeight, PixelFormat.Bgra32Bpp);
            var bspan = fbuff.Span;

            fbuff.ResumeTiming();

            // Most GIF viewers clear the background to transparent instead of the background color when the next frame has transparency
            bool ftrans = meta.GetValueOrDefault <bool>(Wic.Metadata.Gif.TransparencyFlag);

            if (!finfo.FullScreen && anictx.LastDisposal == GifDisposalMethod.RestoreBackground)
            {
                MemoryMarshal.Cast <byte, uint>(bspan).Fill(ftrans ? 0 : cont.BackgroundColor);
            }

            // Similarly, they overwrite a background color with transparent pixels but overlay instead when the previous frame is preserved
            var fspan = bspan.Slice(finfo.Top * fbuff.Stride + finfo.Left * bytesPerPixel);

            fixed(byte *buff = fspan)
            {
                if (!ftrans || anictx.LastDisposal == GifDisposalMethod.RestoreBackground)
                {
                    var rect = new WICRect {
                        Width = finfo.Width, Height = finfo.Height
                    };
                    HRESULT.Check(src.Get()->CopyPixels(&rect, (uint)fbuff.Stride, (uint)fspan.Length, buff));
                }
                else
                {
                    using var overlay = new OverlayTransform(fbuff, src.AsPixelSource(null, nameof(IWICBitmapFrameDecode), false), finfo.Left, finfo.Top, true, true);
                    overlay.CopyPixels(new PixelArea(finfo.Left, finfo.Top, finfo.Width, finfo.Height), fbuff.Stride, fspan.Length, (IntPtr)buff);
                }
            }

            fbuff.PauseTiming();
        }