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));
        }
Beispiel #2
0
        private static ProcessImageResult processImage(WicDecoder dec, WicProcessingContext ctx, Stream ostm)
        {
            var frm = new WicFrameReader(ctx);

            WicTransforms.AddMetadataReader(ctx);

            ctx.FinalizeSettings();

            WicTransforms.AddNativeScaler(ctx);
            WicTransforms.AddExifRotator(ctx);
            WicTransforms.AddConditionalCache(ctx);
            WicTransforms.AddCropper(ctx);
            WicTransforms.AddPixelFormatConverter(ctx);
            WicTransforms.AddScaler(ctx);
            WicTransforms.AddColorspaceConverter(ctx);
            MagicTransforms.AddMatte(ctx);
            MagicTransforms.AddPad(ctx);
            WicTransforms.AddIndexedColorConverter(ctx);

            var enc = new WicEncoder(ctx, ostm.AsIStream());

            enc.WriteSource(ctx);

            return(new ProcessImageResult {
                Settings = ctx.UsedSettings, Stats = ctx.Stats
            });
        }
Beispiel #3
0
        internal ProcessingPipeline(WicProcessingContext ctx)
        {
            Context = ctx;
            source  = new Lazy <IPixelSource>(() => {
                MagicTransforms.AddExternalFormatConverter(Context);
                WicTransforms.AddPixelFormatConverter(Context, false);

                return(Context.Source.AsIPixelSource());
            });
        }
#pragma warning restore 1573

        internal static ProcessImageResult WriteOutput(PipelineContext ctx, Stream ostm)
        {
            MagicTransforms.AddExternalFormatConverter(ctx);
            WicTransforms.AddIndexedColorConverter(ctx);

            var enc = new WicEncoder(ctx, ostm.AsIStream());

            enc.WriteSource(ctx);

            return(new ProcessImageResult(ctx.UsedSettings, ctx.Stats));
        }
Beispiel #5
0
        private static ProcessImageResult executePipeline(WicProcessingContext ctx, Stream ostm)
        {
            MagicTransforms.AddExternalFormatConverter(ctx);
            WicTransforms.AddIndexedColorConverter(ctx);

            var enc = new WicEncoder(ctx, ostm.AsIStream());

            enc.WriteSource(ctx);

            return(new ProcessImageResult {
                Settings = ctx.UsedSettings, Stats = ctx.Stats
            });
        }
Beispiel #6
0
        /// <summary>Adds a new transform filter to the pipeline.  Because a filter may alter dimensions or pixel format of an image, filters may not be added once the <see cref="PixelSource" /> has been retrieved.</summary>
        /// <param name="transform">The <see cref="IPixelTransform" /> that implements the filter.</param>
        public void AddTransform(IPixelTransform transform)
        {
            if (source.IsValueCreated)
            {
                throw new NotSupportedException("A Transform cannot be added once the Pipeline Source is materialized");
            }

            if (transform is IPixelTransformInternal tint)
            {
                tint.Init(Context);
                return;
            }

            MagicTransforms.AddExternalFormatConverter(Context);

            transform.Init(Context.Source.AsIPixelSource());
            Context.Source = transform.AsPixelSource();
        }
Beispiel #7
0
        private static void buildPipeline(WicProcessingContext ctx, bool outputPlanar = true)
        {
            var frm = new WicFrameReader(ctx, EnablePlanarPipeline);

            WicTransforms.AddMetadataReader(ctx);

            ctx.FinalizeSettings();
            ctx.Settings.UnsharpMask       = ctx.UsedSettings.UnsharpMask;
            ctx.Settings.JpegQuality       = ctx.UsedSettings.JpegQuality;
            ctx.Settings.JpegSubsampleMode = ctx.UsedSettings.JpegSubsampleMode;

            if (ctx.DecoderFrame.SupportsPlanarPipeline)
            {
                bool savePlanar = outputPlanar &&
                                  ctx.Settings.SaveFormat == FileFormat.Jpeg &&
                                  ctx.Settings.InnerRect == ctx.Settings.OuterRect &&
                                  ctx.SourceColorContext is null;

                WicTransforms.AddExifRotator(ctx);
                WicTransforms.AddPlanarCache(ctx);

                MagicTransforms.AddHighQualityScaler(ctx);
                MagicTransforms.AddUnsharpMask(ctx);
                MagicTransforms.AddExternalFormatConverter(ctx);

                ctx.SwitchPlanarSource(WicPlane.Chroma);

                if (savePlanar)
                {
                    var subsample = ctx.Settings.JpegSubsampleMode;
                    if (subsample == ChromaSubsampleMode.Subsample420)
                    {
                        ctx.Settings.InnerRect.Height = (int)Math.Ceiling(ctx.Settings.InnerRect.Height / 2d);
                    }

                    if (subsample == ChromaSubsampleMode.Subsample420 || subsample == ChromaSubsampleMode.Subsample422)
                    {
                        ctx.Settings.InnerRect.Width = (int)Math.Ceiling(ctx.Settings.InnerRect.Width / 2d);
                    }
                }

                MagicTransforms.AddHighQualityScaler(ctx);
                MagicTransforms.AddExternalFormatConverter(ctx);

                ctx.SwitchPlanarSource(WicPlane.Luma);

                if (!savePlanar)
                {
                    WicTransforms.AddPlanarConverter(ctx);
                    MagicTransforms.AddColorspaceConverter(ctx);
                    MagicTransforms.AddPad(ctx);
                }
            }
            else
            {
                WicTransforms.AddNativeScaler(ctx);
                WicTransforms.AddExifRotator(ctx);
                WicTransforms.AddConditionalCache(ctx);
                WicTransforms.AddCropper(ctx);
                MagicTransforms.AddHighQualityScaler(ctx, true);
                WicTransforms.AddPixelFormatConverter(ctx);
                WicTransforms.AddScaler(ctx, true);
                MagicTransforms.AddHighQualityScaler(ctx);
                MagicTransforms.AddColorspaceConverter(ctx);
                MagicTransforms.AddMatte(ctx);
                MagicTransforms.AddUnsharpMask(ctx);
                MagicTransforms.AddPad(ctx);
            }
        }
Beispiel #8
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);
                }
            }
        }
        private static void buildPipeline(PipelineContext ctx, bool outputPlanar = true)
        {
            ctx.ImageFrame = ctx.ImageContainer.GetFrame(ctx.Settings.FrameIndex);

            bool processPlanar = false;
            var  wicFrame      = ctx.ImageFrame as WicImageFrame;

            if (wicFrame != null)
            {
                processPlanar = EnablePlanarPipeline && wicFrame.SupportsPlanarProcessing && ctx.Settings.Interpolation.WeightingFunction.Support >= 0.5;
                bool profilingPassThrough = processPlanar || (wicFrame.SupportsNativeScale && ctx.Settings.HybridScaleRatio > 1);
                ctx.Source = wicFrame.WicSource.AsPixelSource(nameof(IWICBitmapFrameDecode), !profilingPassThrough);
            }
            else if (ctx.ImageFrame is IYccImageFrame planarFrame)
            {
                processPlanar     = true;
                outputPlanar      = outputPlanar && planarFrame.IsFullRange && planarFrame.RgbYccMatrix.IsRouglyEqualTo(YccMatrix.Rec601);
                ctx.PlanarContext = new PipelineContext.PlanarPipelineContext(planarFrame.PixelSource.AsPixelSource(), planarFrame.PixelSourceCb.AsPixelSource(), planarFrame.PixelSourceCr.AsPixelSource());
                ctx.Source        = ctx.PlanarContext.SourceY;
            }

            MagicTransforms.AddColorProfileReader(ctx);

            ctx.FinalizeSettings();
            ctx.Settings.UnsharpMask       = ctx.UsedSettings.UnsharpMask;
            ctx.Settings.JpegQuality       = ctx.UsedSettings.JpegQuality;
            ctx.Settings.JpegSubsampleMode = ctx.UsedSettings.JpegSubsampleMode;

            var subsample = ctx.Settings.JpegSubsampleMode;

            if (processPlanar)
            {
                if (wicFrame != null && !ctx.Settings.AutoCrop && ctx.Settings.HybridScaleRatio == 1)
                {
                    var orCrop = PixelArea.FromGdiRect(ctx.Settings.Crop).DeOrient(ctx.Orientation, ctx.Source.Width, ctx.Source.Height);

                    if (wicFrame.ChromaSubsampling.IsSubsampledX() && ((orCrop.X & 1) != 0 || (orCrop.Width & 1) != 0))
                    {
                        processPlanar = false;
                    }
                    if (wicFrame.ChromaSubsampling.IsSubsampledY() && ((orCrop.Y & 1) != 0 || (orCrop.Height & 1) != 0))
                    {
                        processPlanar = false;
                    }
                }

                if (ctx.Settings.SaveFormat == FileFormat.Jpeg && ctx.Orientation.SwapsDimensions())
                {
                    if (subsample.IsSubsampledX() && (ctx.Settings.InnerSize.Width & 1) != 0)
                    {
                        outputPlanar = false;
                    }
                    if (subsample.IsSubsampledY() && (ctx.Settings.InnerSize.Height & 1) != 0)
                    {
                        outputPlanar = false;
                    }
                }
            }

            if (processPlanar)
            {
                bool savePlanar = outputPlanar &&
                                  ctx.Settings.SaveFormat == FileFormat.Jpeg &&
                                  ctx.Settings.OuterSize == ctx.Settings.InnerSize &&
                                  ctx.DestColorProfile == ctx.SourceColorProfile;

                if (wicFrame != null)
                {
                    WicTransforms.AddPlanarCache(ctx);
                }

                MagicTransforms.AddPlanarCropper(ctx);
                MagicTransforms.AddPlanarHybridScaler(ctx);
                MagicTransforms.AddPlanarHighQualityScaler(ctx, savePlanar ? subsample : ChromaSubsampleMode.Subsample444);
                MagicTransforms.AddUnsharpMask(ctx);

                if (savePlanar)
                {
                    MagicTransforms.AddPlanarExifFlipRotator(ctx);
                    MagicTransforms.AddPlanarExternalFormatConverter(ctx);
                }
                else
                {
                    MagicTransforms.AddPlanarConverter(ctx);
                    MagicTransforms.AddColorspaceConverter(ctx);
                    MagicTransforms.AddExifFlipRotator(ctx);
                    MagicTransforms.AddPad(ctx);
                }
            }
            else
            {
                WicTransforms.AddNativeScaler(ctx);
                MagicTransforms.AddCropper(ctx);
                MagicTransforms.AddHybridScaler(ctx);
                WicTransforms.AddPixelFormatConverter(ctx);
                MagicTransforms.AddHybridScaler(ctx);
                MagicTransforms.AddHighQualityScaler(ctx);
                MagicTransforms.AddColorspaceConverter(ctx);
                MagicTransforms.AddMatte(ctx);
                MagicTransforms.AddUnsharpMask(ctx);
                MagicTransforms.AddExifFlipRotator(ctx);
                MagicTransforms.AddPad(ctx);
            }
        }