Пример #1
0
        private void loadFrame(BufferFrame frame)
        {
            using var srcmeta = new ComPtr <IWICMetadataQueryReader>(((WicImageFrame)ctx.ImageFrame).WicMetadataReader);

            frame.Disposal = (GifDisposalMethod)srcmeta.GetValueOrDefault <byte>(Wic.Metadata.Gif.FrameDisposal) == GifDisposalMethod.RestoreBackground ? GifDisposalMethod.RestoreBackground : GifDisposalMethod.Preserve;
            frame.Delay    = srcmeta.GetValueOrDefault <ushort>(Wic.Metadata.Gif.FrameDelay);
            frame.Trans    = srcmeta.GetValueOrDefault <bool>(Wic.Metadata.Gif.TransparencyFlag);
            frame.Area     = ctx.Source.Area;

            var buff = frame.Source;

            fixed(byte *pbuff = buff.Span)
            ctx.Source.CopyPixels(frame.Area, buff.Stride, buff.Span.Length, (IntPtr)pbuff);
        }
Пример #2
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);
        }
Пример #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();
        }