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; }
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; }
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; }
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; }
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(); }
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(); }
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); } }