private static ProcessImageResult processImage(PipelineContext ctx, Stream ostm) { var frame = (WicImageFrame)ctx.ImageContainer.GetFrame(ctx.Settings.FrameIndex); ctx.AddFrameDisposer(); ctx.ImageFrame = frame; ctx.Source = frame.Source; MagicTransforms.AddGifFrameBuffer(ctx); ctx.FinalizeSettings(); WicTransforms.AddColorProfileReader(ctx); WicTransforms.AddNativeScaler(ctx); WicTransforms.AddExifFlipRotator(ctx); WicTransforms.AddCropper(ctx); WicTransforms.AddPixelFormatConverter(ctx); WicTransforms.AddHybridScaler(ctx); WicTransforms.AddScaler(ctx); WicTransforms.AddColorspaceConverter(ctx); MagicTransforms.AddMatte(ctx); MagicTransforms.AddPad(ctx); WicTransforms.AddIndexedColorConverter(ctx); using var enc = new WicImageEncoder(ctx.Settings.SaveFormat, ostm); using var frm = new WicImageEncoderFrame(ctx, enc); frm.WriteSource(ctx); enc.Commit(); return(new ProcessImageResult(ctx.UsedSettings, ctx.Stats)); }
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); } } }