Example #1
0
        private void writeFrame(BufferFrame src)
        {
            using var quant = new OctreeQuantizer();
            using var buffI = new FrameBufferSource(ctx.Source.Width, ctx.Source.Height, PixelFormat.Indexed8Bpp);
            var buffC = EncodeFrame.Source;

            quant.CreateHistorgram(buffC.Span, buffC.Width, buffC.Height, buffC.Stride);
            quant.Quantize(buffC.Span, buffI.Span, buffC.Width, buffC.Height, buffC.Stride, buffI.Stride);
            var palette = quant.Palette;

            using var pal = default(ComPtr <IWICPalette>);
            HRESULT.Check(Wic.Factory->CreatePalette(pal.GetAddressOf()));

            fixed(uint *ppal = palette)
            HRESULT.Check(pal.Get()->InitializeCustom(ppal, (uint)palette.Length));

            ctx.WicContext.DestPalette = pal;
            ctx.Source = buffI;

            using var frm     = new WicImageEncoderFrame(ctx, encoder, src.Area);
            using var frmmeta = default(ComPtr <IWICMetadataQueryWriter>);
            HRESULT.Check(frm.WicEncoderFrame->GetMetadataQueryWriter(frmmeta.GetAddressOf()));

            frmmeta.SetValue(Wic.Metadata.Gif.FrameDisposal, (byte)src.Disposal);
            frmmeta.SetValue(Wic.Metadata.Gif.FrameDelay, (ushort)src.Delay);

            if (src.Area.X != 0)
            {
                frmmeta.SetValue(Wic.Metadata.Gif.FrameLeft, (ushort)src.Area.X);
            }
            if (src.Area.Y != 0)
            {
                frmmeta.SetValue(Wic.Metadata.Gif.FrameTop, (ushort)src.Area.Y);
            }

            frmmeta.SetValue(Wic.Metadata.Gif.TransparencyFlag, true);
            frmmeta.SetValue(Wic.Metadata.Gif.TransparentColorIndex, (byte)(palette.Length - 1));

            frm.WriteSource(ctx, src.Area);

            ctx.WicContext.DestPalette = null;
        }
Example #2
0
        unsafe public void WriteAnimatedGif(PipelineContext ctx)
        {
            var cnt = ctx.ImageContainer as WicGifContainer ?? throw new NotSupportedException("Source must be a GIF");

            using (var decmeta = ComHandle.Wrap(cnt.WicDecoder.GetMetadataQueryReader()))
                using (var encmeta = ComHandle.Wrap(WicEncoder.GetMetadataQueryWriter()))
                {
                    if (decmeta.ComObject.TryGetMetadataByName(Wic.Metadata.Gif.AppExtension, out var appext))
                    {
                        encmeta.ComObject.SetMetadataByName(Wic.Metadata.Gif.AppExtension, appext);
                    }
                    if (decmeta.ComObject.TryGetMetadataByName(Wic.Metadata.Gif.AppExtensionData, out var appdata))
                    {
                        encmeta.ComObject.SetMetadataByName(Wic.Metadata.Gif.AppExtensionData, appdata);
                    }
                    if (decmeta.ComObject.TryGetMetadataByName(Wic.Metadata.Gif.PixelAspectRatio, out var aspect))
                    {
                        encmeta.ComObject.SetMetadataByName(Wic.Metadata.Gif.PixelAspectRatio, aspect);
                    }
                }

            using var buffer = new FrameBufferSource(ctx.Source.Width, ctx.Source.Height, ctx.Source.Format);
            var bspan      = buffer.Span;
            var lastSource = ctx.Source;
            var wicBuffer  = buffer.AsIWICBitmapSource();

            var anictx = cnt.AnimationContext ??= new GifAnimationContext();

            for (int i = 0; i < ctx.ImageContainer.FrameCount; i++)
            {
                if (i > 0)
                {
                    ctx.Settings.FrameIndex = i;

                    ctx.ImageFrame.Dispose();
                    ctx.ImageFrame = ctx.ImageContainer.GetFrame(ctx.Settings.FrameIndex);

                    if (ctx.ImageFrame is WicImageFrame wicFrame)
                    {
                        ctx.Source = wicFrame.WicSource.AsPixelSource(nameof(IWICBitmapFrameDecode), true);
                    }
                    else
                    {
                        ctx.Source = ctx.ImageFrame.PixelSource.AsPixelSource();
                    }

                    MagicTransforms.AddGifFrameBuffer(ctx, false);

                    if (lastSource is ChainedPixelSource chain)
                    {
                        chain.ReInit(ctx.Source);
                        ctx.Source = chain;
                    }
                }

                fixed(byte *pbuff = bspan)
                {
                    ctx.Source.CopyPixels(ctx.Source.Area, buffer.Stride, bspan.Length, (IntPtr)pbuff);

                    var  curFormat = ctx.Source.Format;
                    var  newFormat = PixelFormat.Indexed8Bpp;
                    bool alpha     = curFormat.AlphaRepresentation != PixelAlphaRepresentation.None;

                    using var pal = ComHandle.Wrap(Wic.Factory.CreatePalette());
                    pal.ComObject.InitializeFromBitmap(wicBuffer, 256u, alpha);
                    ctx.WicContext.DestPalette = pal.ComObject;

                    using var conv = ComHandle.Wrap(Wic.Factory.CreateFormatConverter());
                    conv.ComObject.Initialize(wicBuffer, newFormat.FormatGuid, WICBitmapDitherType.WICBitmapDitherTypeErrorDiffusion, pal.ComObject, 10.0, WICBitmapPaletteType.WICBitmapPaletteTypeCustom);
                    ctx.Source = conv.ComObject.AsPixelSource($"{nameof(IWICFormatConverter)}: {curFormat.Name}->{newFormat.Name}", false);

                    using var frm = new WicImageEncoderFrame(ctx, this);

                    var srcmeta = ((WicImageFrame)ctx.ImageFrame).WicMetadataReader !;

                    using (var frmmeta = ComHandle.Wrap(frm.WicEncoderFrame.GetMetadataQueryWriter()))
                    {
                        var disp = srcmeta.TryGetMetadataByName(Wic.Metadata.Gif.FrameDisposal, out var fdisp) && (byte)fdisp.Value ! == (byte)GifDisposalMethod.RestoreBackground ? GifDisposalMethod.RestoreBackground : GifDisposalMethod.Undefined;

                        frmmeta.ComObject.SetMetadataByName(Wic.Metadata.Gif.FrameDisposal, new PropVariant((byte)disp));
                        if (srcmeta.TryGetMetadataByName(Wic.Metadata.Gif.FrameDelay, out var delay))
                        {
                            frmmeta.ComObject.SetMetadataByName(Wic.Metadata.Gif.FrameDelay, delay);
                        }
                        if (alpha)
                        {
                            frmmeta.ComObject.SetMetadataByName(Wic.Metadata.Gif.TransparencyFlag, new PropVariant(true));
                            frmmeta.ComObject.SetMetadataByName(Wic.Metadata.Gif.TransparentColorIndex, new PropVariant((byte)(pal.ComObject.GetColorCount() - 1)));
                        }
                    }

                    frm.WriteSource(ctx);
                }
            }
        }