Exemple #1
0
        public static void ReplayGifAnimationContext(WicGifContainer cont, int playTo)
        {
            var anictx = cont.AnimationContext ??= new GifAnimationContext();

            if (anictx.LastFrame > playTo)
            {
                anictx.LastFrame = -1;
            }

            for (; anictx.LastFrame < playTo; anictx.LastFrame++)
            {
                using var frame = default(ComPtr <IWICBitmapFrameDecode>);
                using var meta  = default(ComPtr <IWICMetadataQueryReader>);
                HRESULT.Check(cont.WicDecoder->GetFrame((uint)(anictx.LastFrame + 1), frame.GetAddressOf()));
                HRESULT.Check(frame.Get()->GetMetadataQueryReader(meta.GetAddressOf()));

                var disp = ((GifDisposalMethod)meta.GetValueOrDefault <byte>(Wic.Metadata.Gif.FrameDisposal)).Clamp();
                if (disp == GifDisposalMethod.Preserve)
                {
                    var nfmt = GUID_WICPixelFormat32bppBGRA;
                    using var conv = default(ComPtr <IWICFormatConverter>);
                    HRESULT.Check(Wic.Factory->CreateFormatConverter(conv.GetAddressOf()));
                    HRESULT.Check(conv.Get()->Initialize((IWICBitmapSource *)frame.Get(), &nfmt, WICBitmapDitherType.WICBitmapDitherTypeNone, null, 0.0, WICBitmapPaletteType.WICBitmapPaletteTypeCustom));

                    UpdateGifAnimationContext(cont, conv.Cast <IWICBitmapSource>(), meta);
                }

                anictx.LastDisposal = disp;
            }
        }
        public static void ReplayGifAnimationContext(WicGifContainer cont, int playTo)
        {
            var anictx = cont.AnimationContext ??= new GifAnimationContext();

            if (anictx.LastFrame > playTo)
            {
                anictx.LastFrame = -1;
            }

            for (; anictx.LastFrame < playTo; anictx.LastFrame++)
            {
                using var frame = ComHandle.Wrap(cont.WicDecoder.GetFrame((uint)(anictx.LastFrame + 1)));
                using var meta  = ComHandle.Wrap(frame.ComObject.GetMetadataQueryReader());

                var disp = ((GifDisposalMethod)meta.ComObject.GetValueOrDefault <byte>(Wic.Metadata.Gif.FrameDisposal)).Clamp();
                if (disp == GifDisposalMethod.Preserve)
                {
                    using var conv = ComHandle.Wrap(Wic.Factory.CreateFormatConverter());
                    conv.ComObject.Initialize(frame.ComObject, Consts.GUID_WICPixelFormat32bppBGRA, WICBitmapDitherType.WICBitmapDitherTypeNone, null, 0.0, WICBitmapPaletteType.WICBitmapPaletteTypeCustom);

                    UpdateGifAnimationContext(cont, conv.ComObject, meta.ComObject);
                }

                anictx.LastDisposal = disp;
            }
        }
Exemple #3
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();
        }
Exemple #4
0
        public static (int Left, int Top, int Width, int Height, bool Alpha, bool FullScreen, GifDisposalMethod Disposal) GetGifFrameInfo(WicGifContainer cont, ComPtr <IWICBitmapSource> frame, ComPtr <IWICMetadataQueryReader> meta)
        {
            uint width, height;

            HRESULT.Check(frame.Get()->GetSize(&width, &height));

            int  left = 0, top = 0;
            var  disp  = ((GifDisposalMethod)meta.GetValueOrDefault <byte>(Wic.Metadata.Gif.FrameDisposal)).Clamp();
            bool trans = meta.GetValueOrDefault <bool>(Wic.Metadata.Gif.TransparencyFlag);
            bool full  = width >= cont.ScreenWidth && height >= cont.ScreenHeight;

            if (!full)
            {
                left = meta.GetValueOrDefault <ushort>(Wic.Metadata.Gif.FrameLeft);
                top  = meta.GetValueOrDefault <ushort>(Wic.Metadata.Gif.FrameTop);
            }

            width  = Math.Min(width, cont.ScreenWidth - (uint)left);
            height = Math.Min(height, cont.ScreenHeight - (uint)top);

            return(left, top, (int)width, (int)height, trans, full, disp);
        }
        public static (int Left, int Top, int Width, int Height, bool Alpha, bool FullScreen, GifDisposalMethod Disposal) GetGifFrameInfo(WicGifContainer cont, IWICBitmapSource frame, IWICMetadataQueryReader meta)
        {
            frame.GetSize(out uint width, out uint height);

            int  left = 0, top = 0;
            var  disp  = ((GifDisposalMethod)meta.GetValueOrDefault <byte>(Wic.Metadata.Gif.FrameDisposal)).Clamp();
            bool trans = meta.GetValueOrDefault <bool>(Wic.Metadata.Gif.TransparencyFlag);
            bool full  = width == cont.ScreenWidth && height == cont.ScreenHeight;

            if (!full)
            {
                left = meta.GetValueOrDefault <ushort>(Wic.Metadata.Gif.FrameLeft);
                top  = meta.GetValueOrDefault <ushort>(Wic.Metadata.Gif.FrameTop);
            }

            return(left, top, (int)width, (int)height, trans, full, disp);
        }