Пример #1
0
        public static void AddNativeScaler(PipelineContext ctx)
        {
            int ratio = ctx.Settings.HybridScaleRatio;

            if (ratio == 1 || ctx.ImageFrame is not WicImageFrame wicFrame || !wicFrame.SupportsNativeScale || ctx.Source is not WicPixelSource wsrc)
            {
                return;
            }

            using var transform = default(ComPtr <IWICBitmapSourceTransform>);
            if (FAILED(wsrc.WicSource->QueryInterface(__uuidof <IWICBitmapSourceTransform>(), (void **)transform.GetAddressOf())))
            {
                return;
            }

            uint ow = (uint)ctx.Source.Width, oh = (uint)ctx.Source.Height;
            uint cw = (uint)MathUtil.DivCeiling((int)ow, ratio), ch = (uint)MathUtil.DivCeiling((int)oh, ratio);

            HRESULT.Check(transform.Get()->GetClosestSize(&cw, &ch));

            if (cw == ow && ch == oh)
            {
                return;
            }

            var orient = ctx.Orientation;

            using var scaler = default(ComPtr <IWICBitmapScaler>);
            HRESULT.Check(Wic.Factory->CreateBitmapScaler(scaler.GetAddressOf()));
            HRESULT.Check(scaler.Get()->Initialize(ctx.Source.AsIWICBitmapSource(ctx), cw, ch, WICBitmapInterpolationMode.WICBitmapInterpolationModeFant));

            ctx.Source              = ctx.AddDispose(new ComPtr <IWICBitmapSource>((IWICBitmapSource *)scaler.Get()).AsPixelSource(ctx, nameof(IWICBitmapSourceTransform)));
            ctx.Settings.Crop       = PixelArea.FromGdiRect(ctx.Settings.Crop).DeOrient(orient, (int)ow, (int)oh).ProportionalScale((int)ow, (int)oh, (int)cw, (int)ch).ReOrient(orient, (int)cw, (int)ch).ToGdiRect();
            ctx.Settings.HybridMode = HybridScaleMode.Off;
        }
Пример #2
0
        public static void AddPlanarCache(PipelineContext ctx)
        {
            using var transform = default(ComPtr <IWICPlanarBitmapSourceTransform>);
            if (ctx.Source is not WicPixelSource wsrc || FAILED(wsrc.WicSource->QueryInterface(__uuidof <IWICPlanarBitmapSourceTransform>(), (void **)transform.GetAddressOf())))
            {
                throw new NotSupportedException("Transform chain doesn't support planar mode.  Only JPEG Decoder, Rotator, Scaler, and PixelFormatConverter are allowed");
            }

            int  ratio = ctx.Settings.HybridScaleRatio.Clamp(1, 8);
            uint ow = (uint)ctx.Source.Width, oh = (uint)ctx.Source.Height;
            uint cw = (uint)MathUtil.DivCeiling((int)ow, ratio), ch = (uint)MathUtil.DivCeiling((int)oh, ratio);

            var desc = stackalloc WICBitmapPlaneDescription[PlanarPixelFormats.Length];

            fixed(Guid *pfmt = PlanarPixelFormats)
            {
                int bval;

                HRESULT.Check(transform.Get()->DoesSupportTransform(&cw, &ch, WICBitmapTransformOptions.WICBitmapTransformRotate0, WICPlanarOptions.WICPlanarOptionsDefault, pfmt, desc, (uint)PlanarPixelFormats.Length, &bval));
                if (bval == 0)
                {
                    throw new NotSupportedException("Requested planar transform not supported");
                }
            }

            var crop  = PixelArea.FromGdiRect(ctx.Settings.Crop).DeOrient(ctx.Orientation, (int)ow, (int)oh).ProportionalScale((int)ow, (int)oh, (int)cw, (int)ch);
            var cache = ctx.AddDispose(new WicPlanarCache(transform.Detach(), new Span <WICBitmapPlaneDescription>(desc, PlanarPixelFormats.Length), WICBitmapTransformOptions.WICBitmapTransformRotate0, cw, ch, crop));

            ctx.PlanarContext       = new PipelineContext.PlanarPipelineContext(cache.SourceY, cache.SourceCb, cache.SourceCr);
            ctx.Source              = ctx.PlanarContext.SourceY;
            ctx.Settings.Crop       = ctx.Source.Area.ReOrient(ctx.Orientation, ctx.Source.Width, ctx.Source.Height).ToGdiRect();
            ctx.Settings.HybridMode = HybridScaleMode.Off;
        }
Пример #3
0
        public static void AddPlanarCache(PipelineContext ctx)
        {
            if (!(ctx.Source.WicSource is IWICPlanarBitmapSourceTransform trans))
            {
                throw new NotSupportedException("Transform chain doesn't support planar mode.  Only JPEG Decoder, Rotator, Scaler, and PixelFormatConverter are allowed");
            }

            int  ratio = ctx.Settings.HybridScaleRatio.Clamp(1, 8);
            uint ow = (uint)ctx.Source.Width, oh = (uint)ctx.Source.Height;
            uint cw = (uint)MathUtil.DivCeiling((int)ow, ratio), ch = (uint)MathUtil.DivCeiling((int)oh, ratio);

            var desc = ArrayPool <WICBitmapPlaneDescription> .Shared.Rent(PlanarPixelFormats.Length);

            if (!trans.DoesSupportTransform(ref cw, ref ch, WICBitmapTransformOptions.WICBitmapTransformRotate0, WICPlanarOptions.WICPlanarOptionsDefault, PlanarPixelFormats, desc, (uint)PlanarPixelFormats.Length))
            {
                throw new NotSupportedException("Requested planar transform not supported");
            }

            var crop  = PixelArea.FromGdiRect(ctx.Settings.Crop).DeOrient(ctx.Orientation, (int)ow, (int)oh).ProportionalScale((int)ow, (int)oh, (int)cw, (int)ch);
            var cache = ctx.AddDispose(new WicPlanarCache(trans, desc, WICBitmapTransformOptions.WICBitmapTransformRotate0, cw, ch, crop));

            ArrayPool <WICBitmapPlaneDescription> .Shared.Return(desc);

            ctx.PlanarContext       = new PipelineContext.PlanarPipelineContext(cache.SourceY, cache.SourceCb, cache.SourceCr);
            ctx.Source              = ctx.PlanarContext.SourceY;
            ctx.Settings.Crop       = ctx.Source.Area.ReOrient(ctx.Orientation, ctx.Source.Width, ctx.Source.Height).ToGdiRect();
            ctx.Settings.HybridMode = HybridScaleMode.Off;
        }
Пример #4
0
        public static void AddNativeScaler(PipelineContext ctx)
        {
            int ratio = ctx.Settings.HybridScaleRatio;

            if (ratio == 1 || !(ctx.ImageFrame is WicImageFrame wicFrame) || !wicFrame.SupportsNativeScale || !(ctx.Source.WicSource is IWICBitmapSourceTransform trans))
            {
                return;
            }

            uint ow = (uint)ctx.Source.Width, oh = (uint)ctx.Source.Height;
            uint cw = (uint)MathUtil.DivCeiling((int)ow, ratio), ch = (uint)MathUtil.DivCeiling((int)oh, ratio);

            trans.GetClosestSize(ref cw, ref ch);

            if (cw == ow && ch == oh)
            {
                return;
            }

            var orient = ctx.Orientation;
            var scaler = ctx.WicContext.AddRef(Wic.Factory.CreateBitmapScaler());

            scaler.Initialize(ctx.Source.WicSource, cw, ch, WICBitmapInterpolationMode.WICBitmapInterpolationModeFant);

            ctx.Source              = scaler.AsPixelSource(nameof(IWICBitmapSourceTransform));
            ctx.Settings.Crop       = PixelArea.FromGdiRect(ctx.Settings.Crop).DeOrient(orient, (int)ow, (int)oh).ProportionalScale((int)ow, (int)oh, (int)cw, (int)ch).ReOrient(orient, (int)cw, (int)ch).ToGdiRect();
            ctx.Settings.HybridMode = HybridScaleMode.Off;
        }
Пример #5
0
        public static void AddCropper(PipelineContext ctx)
        {
            var crop = PixelArea.FromGdiRect(ctx.Settings.Crop);

            if (crop == ctx.Source.Area)
            {
                return;
            }

            var cropper = ctx.WicContext.AddRef(Wic.Factory.CreateBitmapClipper());

            cropper.Initialize(ctx.Source.WicSource, crop.ToWicRect());

            ctx.Source        = cropper.AsPixelSource(nameof(IWICBitmapClipper));
            ctx.Settings.Crop = ctx.Source.Area.ToGdiRect();
        }
Пример #6
0
        public static void AddCropper(PipelineContext ctx)
        {
            var crop = PixelArea.FromGdiRect(ctx.Settings.Crop);

            if (crop == ctx.Source.Area)
            {
                return;
            }

            var rect = crop.ToWicRect();

            using var cropper = default(ComPtr <IWICBitmapClipper>);
            HRESULT.Check(Wic.Factory->CreateBitmapClipper(cropper.GetAddressOf()));
            HRESULT.Check(cropper.Get()->Initialize(ctx.Source.AsIWICBitmapSource(ctx), &rect));

            ctx.Source        = ctx.AddDispose(new ComPtr <IWICBitmapSource>((IWICBitmapSource *)cropper.Get()).AsPixelSource(ctx, nameof(IWICBitmapClipper)));
            ctx.Settings.Crop = ctx.Source.Area.ToGdiRect();
        }
Пример #7
0
        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);
            }
        }