public static void AddExifFlipRotator(PipelineContext ctx) { if (ctx.Orientation == Orientation.Normal) { return; } using var rotator = default(ComPtr <IWICBitmapFlipRotator>); HRESULT.Check(Wic.Factory->CreateBitmapFlipRotator(rotator.GetAddressOf())); HRESULT.Check(rotator.Get()->Initialize(ctx.Source.AsIWICBitmapSource(ctx), ctx.Orientation.ToWicTransformOptions())); ctx.Source = ctx.AddDispose(new ComPtr <IWICBitmapSource>((IWICBitmapSource *)rotator.Get()).AsPixelSource(ctx, nameof(IWICBitmapFlipRotator))); if (ctx.Orientation.RequiresCache()) { var crop = ctx.Settings.Crop; using var bmp = default(ComPtr <IWICBitmap>); HRESULT.Check(Wic.Factory->CreateBitmapFromSourceRect(ctx.Source.AsIWICBitmapSource(ctx), (uint)crop.X, (uint)crop.Y, (uint)crop.Width, (uint)crop.Height, bmp.GetAddressOf())); ctx.Source = ctx.AddDispose(new ComPtr <IWICBitmapSource>((IWICBitmapSource *)bmp.Get()).AsPixelSource(ctx, nameof(IWICBitmap))); ctx.Settings.Crop = ctx.Source.Area.ToGdiRect(); } ctx.Orientation = Orientation.Normal; }
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 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 AddScaler(PipelineContext ctx) { bool swap = ctx.Orientation.SwapsDimensions(); var tsize = ctx.Settings.InnerSize; int width = swap ? tsize.Height : tsize.Width, height = swap ? tsize.Width : tsize.Height; if (ctx.Source.Width == width && ctx.Source.Height == height) { return; } var mode = ctx.Settings.Interpolation.WeightingFunction.Support <0.1 ? WICBitmapInterpolationMode.WICBitmapInterpolationModeNearestNeighbor : ctx.Settings.Interpolation.WeightingFunction.Support <1.0 ? ctx.Settings.ScaleRatio> 1.0 ? WICBitmapInterpolationMode.WICBitmapInterpolationModeFant : WICBitmapInterpolationMode.WICBitmapInterpolationModeNearestNeighbor : ctx.Settings.Interpolation.WeightingFunction.Support> 1.0 ? ctx.Settings.ScaleRatio > 1.0 ? WICBitmapInterpolationMode.WICBitmapInterpolationModeHighQualityCubic :WICBitmapInterpolationMode.WICBitmapInterpolationModeCubic : ctx.Settings.ScaleRatio > 1.0 ? WICBitmapInterpolationMode.WICBitmapInterpolationModeFant : WICBitmapInterpolationMode.WICBitmapInterpolationModeLinear; using var scaler = default(ComPtr <IWICBitmapScaler>); HRESULT.Check(Wic.Factory->CreateBitmapScaler(scaler.GetAddressOf())); HRESULT.Check(scaler.Get()->Initialize(ctx.Source.AsIWICBitmapSource(ctx), (uint)width, (uint)height, mode)); ctx.Source = ctx.AddDispose(new ComPtr <IWICBitmapSource>((IWICBitmapSource *)scaler.Get()).AsPixelSource(ctx, nameof(IWICBitmapScaler))); }
public static ProcessImageResult ProcessImage(Stream imgStream, Stream outStream, ProcessImageSettings settings) { using var ctx = new PipelineContext(settings); ctx.ImageContainer = ctx.AddDispose(WicImageDecoder.Load(imgStream)); return(processImage(ctx, outStream)); }
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 void WriteSource(PipelineContext ctx, PixelArea area = default) { var wicFrame = WicEncoderFrame; var wicRect = area.ToWicRect(); if (ctx.PlanarContext is not null) { var oformat = GUID_WICPixelFormat24bppBGR; HRESULT.Check(wicFrame->SetPixelFormat(&oformat)); using var gchY = new WeakGCHandle(ctx.PlanarContext.SourceY); using var gchCb = new WeakGCHandle(ctx.PlanarContext.SourceCb); using var gchCr = new WeakGCHandle(ctx.PlanarContext.SourceCr); var srcY = new IWICBitmapSourceImpl(gchY.Handle); var srcCb = new IWICBitmapSourceImpl(gchCb.Handle); var srcCr = new IWICBitmapSourceImpl(gchCr.Handle); var planes = stackalloc[] {&srcY, &srcCb, &srcCr }; using var pframe = default(ComPtr <IWICPlanarBitmapFrameEncode>); HRESULT.Check(wicFrame->QueryInterface(__uuidof <IWICPlanarBitmapFrameEncode>(), (void **)pframe.GetAddressOf())); HRESULT.Check(pframe.Get()->WriteSource((IWICBitmapSource **)planes, 3, area.IsEmpty ? null : &wicRect)); } else { var oformat = ctx.Source.Format.FormatGuid; HRESULT.Check(wicFrame->SetPixelFormat(&oformat)); if (oformat != ctx.Source.Format.FormatGuid) { var ptt = WICBitmapPaletteType.WICBitmapPaletteTypeCustom; using var pal = default(ComPtr <IWICPalette>); if (PixelFormat.FromGuid(oformat).NumericRepresentation == PixelNumericRepresentation.Indexed) { HRESULT.Check(Wic.Factory->CreatePalette(pal.GetAddressOf())); HRESULT.Check(pal.Get()->InitializePredefined(WICBitmapPaletteType.WICBitmapPaletteTypeFixedGray256, 0)); ptt = WICBitmapPaletteType.WICBitmapPaletteTypeFixedGray256; HRESULT.Check(wicFrame->SetPalette(pal)); } using var conv = default(ComPtr <IWICFormatConverter>); HRESULT.Check(Wic.Factory->CreateFormatConverter(conv.GetAddressOf())); HRESULT.Check(conv.Get()->Initialize(ctx.Source.AsIWICBitmapSource(ctx), &oformat, WICBitmapDitherType.WICBitmapDitherTypeNone, pal, 0.0, ptt)); ctx.Source = ctx.AddDispose(new ComPtr <IWICBitmapSource>((IWICBitmapSource *)conv.Get()).AsPixelSource(null, $"{nameof(IWICFormatConverter)}: {ctx.Source.Format.Name}->{PixelFormat.FromGuid(oformat).Name}", false)); } else if (oformat == PixelFormat.Indexed8Bpp.FormatGuid) { Debug.Assert(ctx.WicContext.DestPalette is not null); HRESULT.Check(wicFrame->SetPalette(ctx.WicContext.DestPalette)); } using var gch = new WeakGCHandle(ctx.Source); var src = new IWICBitmapSourceImpl(gch.Handle); HRESULT.Check(wicFrame->WriteSource((IWICBitmapSource *)&src, area.IsEmpty ? null : &wicRect)); } HRESULT.Check(wicFrame->Commit()); }
public static unsafe ProcessImageResult ProcessImage(ReadOnlySpan <byte> imgBuffer, Stream outStream, ProcessImageSettings settings) { fixed(byte *pbBuffer = imgBuffer) { using var ctx = new PipelineContext(settings); ctx.ImageContainer = ctx.AddDispose(WicImageDecoder.Load(pbBuffer, imgBuffer.Length)); return(processImage(ctx, outStream)); } }
public static WicImageContainer Create(IWICBitmapDecoder dec, PipelineContext ctx) { var fmt = WicImageDecoder.FormatMap.GetValueOrDefault(dec.GetContainerFormat(), FileFormat.Unknown); if (fmt == FileFormat.Gif) { return(ctx.AddDispose(new WicGifContainer(dec, ctx.WicContext))); } return(new WicImageContainer(dec, ctx.WicContext, fmt)); }
/// <summary>Constructs a new processing pipeline from which pixels can be retrieved.</summary> /// <param name="imgPath">The path to a file containing the input image.</param> /// <param name="settings">The settings for this processing operation.</param> /// <returns>A <see cref="ProcessingPipeline" /> containing the <see cref="IPixelSource" />, settings used, and basic instrumentation for the pipeline.</returns> public static ProcessingPipeline BuildPipeline(string imgPath, ProcessImageSettings settings) { if (imgPath is null) { throw new ArgumentNullException(nameof(imgPath)); } if (settings is null) { throw new ArgumentNullException(nameof(settings)); } var ctx = new PipelineContext(settings); var fs = ctx.AddDispose(File.OpenRead(imgPath)); ctx.AddDispose(new StreamBufferInjector(fs)); ctx.ImageContainer = ctx.AddDispose(WicImageDecoder.Load(fs)); buildPipeline(ctx, false); return(new ProcessingPipeline(ctx)); }
/// <summary>Constructs a new <see cref="ImageFileInfo" /> instance by reading the metadata from an image file contained in a <see cref="ReadOnlySpan{T}" />.</summary> /// <param name="imgBuffer">The buffer containing the image data.</param> /// <param name="lastModified">The last modified date of the image container.</param> public static unsafe ImageFileInfo Load(ReadOnlySpan <byte> imgBuffer, DateTime lastModified) { if (imgBuffer == default) { throw new ArgumentNullException(nameof(imgBuffer)); fixed(byte *pbBuffer = imgBuffer) { using var ctx = new PipelineContext(new ProcessImageSettings()); ctx.ImageContainer = ctx.AddDispose(WicImageDecoder.Load(pbBuffer, imgBuffer.Length)); return(fromWicImage(ctx, imgBuffer.Length, lastModified)); } }
public static void AddHybridScaler(PipelineContext ctx, int ratio = default) { ratio = ratio == default ? ctx.Settings.HybridScaleRatio : ratio; if (ratio == 1 || ctx.Settings.Interpolation.WeightingFunction.Support < 0.1) { return; } uint width = (uint)MathUtil.DivCeiling(ctx.Source.Width, ratio); uint height = (uint)MathUtil.DivCeiling(ctx.Source.Height, ratio); using var transform = default(ComPtr <IWICBitmapSourceTransform>); if (ctx.Source is WicPixelSource wsrc && SUCCEEDED(wsrc.WicSource->QueryInterface(__uuidof <IWICBitmapSourceTransform>(), (void **)transform.GetAddressOf()))) { ctx.Source = ctx.AddDispose(new ComPtr <IWICBitmapSource>(wsrc.WicSource).AsPixelSource(ctx, nameof(IWICBitmapFrameDecode))); } using var scaler = default(ComPtr <IWICBitmapScaler>); HRESULT.Check(Wic.Factory->CreateBitmapScaler(scaler.GetAddressOf())); HRESULT.Check(scaler.Get()->Initialize(ctx.Source.AsIWICBitmapSource(ctx), width, height, WICBitmapInterpolationMode.WICBitmapInterpolationModeFant)); ctx.Source = ctx.AddDispose(new ComPtr <IWICBitmapSource>((IWICBitmapSource *)scaler.Get()).AsPixelSource(ctx, nameof(IWICBitmapScaler) + " (hybrid)")); ctx.Settings.HybridMode = HybridScaleMode.Off; }
public static void AddIndexedColorConverter(PipelineContext ctx) { var curFormat = ctx.Source.Format; var newFormat = PixelFormat.Indexed8Bpp; if (!ctx.Settings.IndexedColor || curFormat.NumericRepresentation == PixelNumericRepresentation.Indexed || curFormat.ColorRepresentation == PixelColorRepresentation.Grey) { return; } using var conv = default(ComPtr <IWICFormatConverter>); HRESULT.Check(Wic.Factory->CreateFormatConverter(conv.GetAddressOf())); int bval; var cfmt = curFormat.FormatGuid; var nfmt = newFormat.FormatGuid; if (FAILED(conv.Get()->CanConvert(&cfmt, &nfmt, &bval)) || bval == 0) { throw new NotSupportedException("Can't convert to destination pixel format"); } using var bmp = default(ComPtr <IWICBitmap>); HRESULT.Check(Wic.Factory->CreateBitmapFromSource(ctx.Source.AsIWICBitmapSource(ctx), WICBitmapCreateCacheOption.WICBitmapCacheOnDemand, bmp.GetAddressOf())); ctx.Source = ctx.AddDispose(new ComPtr <IWICBitmapSource>((IWICBitmapSource *)bmp.Get()).AsPixelSource(ctx, nameof(IWICBitmap))); int tcolor = curFormat.AlphaRepresentation == PixelAlphaRepresentation.None ? 0 : -1; using var pal = default(ComPtr <IWICPalette>); HRESULT.Check(Wic.Factory->CreatePalette(pal.GetAddressOf())); HRESULT.Check(pal.Get()->InitializeFromBitmap(ctx.Source.AsIWICBitmapSource(ctx), 256u, tcolor)); ctx.WicContext.DestPalette = pal.Detach(); HRESULT.Check(conv.Get()->Initialize(ctx.Source.AsIWICBitmapSource(ctx), &nfmt, WICBitmapDitherType.WICBitmapDitherTypeErrorDiffusion, ctx.WicContext.DestPalette, 33.33, WICBitmapPaletteType.WICBitmapPaletteTypeCustom)); ctx.Source = ctx.AddDispose(new ComPtr <IWICBitmapSource>((IWICBitmapSource *)conv.Get()).AsPixelSource(ctx, $"{nameof(IWICFormatConverter)}: {curFormat.Name}->{newFormat.Name}")); }
/// <inheritdoc cref="BuildPipeline(string, ProcessImageSettings)" /> /// <param name="imgStream">A stream containing a supported input image container. The stream must allow Seek and Read.</param> public static ProcessingPipeline BuildPipeline(Stream imgStream, ProcessImageSettings settings) { if (settings is null) { throw new ArgumentNullException(nameof(settings)); } checkInStream(imgStream); var ctx = new PipelineContext(settings); ctx.ImageContainer = ctx.AddDispose(WicImageDecoder.Load(imgStream)); buildPipeline(ctx, false); return(new ProcessingPipeline(ctx)); }
/// <inheritdoc cref="ProcessImage(string, Stream, ProcessImageSettings)" /> /// <param name="imgStream">A stream containing a supported input image container. The stream must allow Seek and Read.</param> public static ProcessImageResult ProcessImage(Stream imgStream, Stream outStream, ProcessImageSettings settings) { if (settings is null) { throw new ArgumentNullException(nameof(settings)); } checkInStream(imgStream); checkOutStream(outStream); using var stb = new StreamBufferInjector(imgStream); using var ctx = new PipelineContext(settings); ctx.ImageContainer = ctx.AddDispose(WicImageDecoder.Load(imgStream)); buildPipeline(ctx); return(WriteOutput(ctx, outStream)); }
public static void AddColorspaceConverter(PipelineContext ctx) { if (ctx.WicContext.SourceColorContext is null || ctx.WicContext.DestColorContext is null || ctx.WicContext.SourceColorContext == ctx.WicContext.DestColorContext) { return; } var guid = ctx.Source.Format.FormatGuid; using var trans = default(ComPtr <IWICColorTransform>); HRESULT.Check(Wic.Factory->CreateColorTransformer(trans.GetAddressOf())); if (SUCCEEDED(trans.Get()->Initialize(ctx.Source.AsIWICBitmapSource(ctx), ctx.WicContext.SourceColorContext, ctx.WicContext.DestColorContext, &guid))) { ctx.Source = ctx.AddDispose(new ComPtr <IWICBitmapSource>((IWICBitmapSource *)trans.Get()).AsPixelSource(ctx, nameof(IWICColorTransform))); } }
/// <summary>Constructs a new <see cref="ImageFileInfo" /> instance by reading the metadata from an image file header.</summary> /// <param name="imgPath">The path to the image file.</param> public static ImageFileInfo Load(string imgPath) { var fi = new FileInfo(imgPath); if (!fi.Exists) { throw new FileNotFoundException("File not found", imgPath); } using var fs = File.OpenRead(imgPath); using var stb = new StreamBufferInjector(fs); using var ctx = new PipelineContext(new ProcessImageSettings()); ctx.ImageContainer = ctx.AddDispose(WicImageDecoder.Load(fs)); return(fromWicImage(ctx, fi.Length, fi.LastWriteTimeUtc)); }
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(); }
public static unsafe ProcessingPipeline BuildPipeline(ReadOnlySpan <byte> imgBuffer, ProcessImageSettings settings) { if (imgBuffer == default) { throw new ArgumentNullException(nameof(imgBuffer)); } if (settings is null) { throw new ArgumentNullException(nameof(settings)); fixed(byte *pbBuffer = imgBuffer) { var ctx = new PipelineContext(settings); ctx.ImageContainer = ctx.AddDispose(WicImageDecoder.Load(pbBuffer, imgBuffer.Length, true)); buildPipeline(ctx, false); return(new ProcessingPipeline(ctx)); } }
#pragma warning disable 1573 // not all params have docs /// <inheritdoc cref="ProcessImage(string, Stream, ProcessImageSettings)" /> /// <param name="imgBuffer">A buffer containing a supported input image container.</param> public static unsafe ProcessImageResult ProcessImage(ReadOnlySpan <byte> imgBuffer, Stream outStream, ProcessImageSettings settings) { if (imgBuffer == default) { throw new ArgumentNullException(nameof(imgBuffer)); } if (settings is null) { throw new ArgumentNullException(nameof(settings)); } checkOutStream(outStream); fixed(byte *pbBuffer = imgBuffer) { using var ctx = new PipelineContext(settings); ctx.ImageContainer = ctx.AddDispose(WicImageDecoder.Load(pbBuffer, imgBuffer.Length)); buildPipeline(ctx); return(WriteOutput(ctx, outStream)); } }
public static void AddPlanarConverter(PipelineContext ctx) { Debug.Assert(ctx.PlanarContext is not null); var guid = GUID_WICPixelFormat24bppBGR; var planes = stackalloc[] { ctx.PlanarContext.SourceY.AsIWICBitmapSource(ctx), ctx.PlanarContext.SourceCb.AsIWICBitmapSource(ctx), ctx.PlanarContext.SourceCr.AsIWICBitmapSource(ctx) }; using var conv = default(ComPtr <IWICFormatConverter>); using var pconv = default(ComPtr <IWICPlanarFormatConverter>); HRESULT.Check(Wic.Factory->CreateFormatConverter(conv.GetAddressOf())); HRESULT.Check(conv.As(&pconv)); HRESULT.Check(pconv.Get()->Initialize(planes, (uint)PlanarPixelFormats.Length, &guid, WICBitmapDitherType.WICBitmapDitherTypeNone, null, 0.0, WICBitmapPaletteType.WICBitmapPaletteTypeCustom)); ctx.Source = ctx.AddDispose(new ComPtr <IWICBitmapSource>((IWICBitmapSource *)pconv.Get()).AsPixelSource(ctx, nameof(IWICPlanarFormatConverter))); ctx.PlanarContext = null; } }
public static void AddPixelFormatConverter(PipelineContext ctx, bool allowPbgra = true) { var curFormat = ctx.Source.Format; if (curFormat.ColorRepresentation == PixelColorRepresentation.Cmyk) { var rgbColorContext = ctx.Settings.ColorProfileMode == ColorProfileMode.ConvertToSrgb ? WicColorProfile.Srgb.Value : WicColorProfile.AdobeRgb.Value; if (ctx.WicContext.SourceColorContext is null) { ctx.WicContext.SourceColorContext = WicColorProfile.Cmyk.Value.WicColorContext; } // TODO WIC doesn't support proper CMYKA conversion with color profile if (curFormat.AlphaRepresentation == PixelAlphaRepresentation.None) { // WIC doesn't support 16bpc CMYK conversion with color profile if (curFormat.BitsPerPixel == 64) { ctx.Source = ctx.AddDispose(new ConversionTransform(ctx.Source, null, null, PixelFormat.Cmyk32Bpp)); } var guid = GUID_WICPixelFormat24bppBGR; using var trans = default(ComPtr <IWICColorTransform>); HRESULT.Check(Wic.Factory->CreateColorTransformer(trans.GetAddressOf())); if (SUCCEEDED(trans.Get()->Initialize(ctx.Source.AsIWICBitmapSource(ctx), ctx.WicContext.SourceColorContext, rgbColorContext.WicColorContext, &guid))) { ctx.Source = ctx.AddDispose(new ComPtr <IWICBitmapSource>((IWICBitmapSource *)trans.Get()).AsPixelSource(ctx, nameof(IWICColorTransform))); curFormat = ctx.Source.Format; } } ctx.WicContext.DestColorContext = ctx.WicContext.SourceColorContext = rgbColorContext.WicColorContext; ctx.DestColorProfile = ctx.SourceColorProfile = rgbColorContext.ParsedProfile; } if (curFormat == PixelFormat.Y8Bpp || curFormat == PixelFormat.Cb8Bpp || curFormat == PixelFormat.Cr8Bpp) { return; } var newFormat = PixelFormat.Bgr24Bpp; if (allowPbgra && curFormat.AlphaRepresentation == PixelAlphaRepresentation.Associated && ctx.Settings.BlendingMode != GammaMode.Linear && ctx.Settings.MatteColor.IsEmpty) { newFormat = PixelFormat.Pbgra32Bpp; } else if (curFormat.AlphaRepresentation != PixelAlphaRepresentation.None) { newFormat = PixelFormat.Bgra32Bpp; } else if (curFormat.ColorRepresentation == PixelColorRepresentation.Grey) { newFormat = PixelFormat.Grey8Bpp; } if (curFormat == newFormat) { return; } using var conv = default(ComPtr <IWICFormatConverter>); HRESULT.Check(Wic.Factory->CreateFormatConverter(conv.GetAddressOf())); int bval; var cfmt = curFormat.FormatGuid; var nfmt = newFormat.FormatGuid; if (FAILED(conv.Get()->CanConvert(&cfmt, &nfmt, &bval)) || bval == 0) { throw new NotSupportedException("Can't convert to destination pixel format"); } HRESULT.Check(conv.Get()->Initialize(ctx.Source.AsIWICBitmapSource(ctx), &nfmt, WICBitmapDitherType.WICBitmapDitherTypeNone, null, 0.0, WICBitmapPaletteType.WICBitmapPaletteTypeCustom)); ctx.Source = ctx.AddDispose(new ComPtr <IWICBitmapSource>((IWICBitmapSource *)conv.Get()).AsPixelSource(ctx, $"{nameof(IWICFormatConverter)}: {curFormat.Name}->{newFormat.Name}")); }
public static void AddPixelFormatConverter(PipelineContext ctx, bool allowPbgra = true) { var curFormat = ctx.Source.Format; if (curFormat.ColorRepresentation == PixelColorRepresentation.Cmyk) { var sRgbContext = WicColorProfile.Srgb.Value; Debug.Assert(ctx.WicContext.SourceColorContext != null); // TODO WIC doesn't support proper CMYKA conversion with color profile if (curFormat.AlphaRepresentation == PixelAlphaRepresentation.None) { // WIC doesn't support 16bpc CMYK conversion with color profile if (curFormat.BitsPerPixel == 64) { ctx.Source = ctx.AddDispose(new ConversionTransform(ctx.Source, null, null, Consts.GUID_WICPixelFormat32bppCMYK)); } var trans = ctx.WicContext.AddRef(Wic.Factory.CreateColorTransformer()); if (trans.TryInitialize(ctx.Source.WicSource, ctx.WicContext.SourceColorContext, sRgbContext.WicColorContext, Consts.GUID_WICPixelFormat24bppBGR)) { ctx.Source = trans.AsPixelSource(nameof(IWICColorTransform)); curFormat = ctx.Source.Format; } } ctx.WicContext.DestColorContext = ctx.WicContext.SourceColorContext = sRgbContext.WicColorContext; ctx.DestColorProfile = ctx.SourceColorProfile = sRgbContext.ParsedProfile; } if (curFormat.FormatGuid == Consts.GUID_WICPixelFormat8bppY || curFormat.FormatGuid == Consts.GUID_WICPixelFormat8bppCb || curFormat.FormatGuid == Consts.GUID_WICPixelFormat8bppCr) { return; } var newFormat = PixelFormat.FromGuid(Consts.GUID_WICPixelFormat24bppBGR); if (curFormat.AlphaRepresentation == PixelAlphaRepresentation.Associated && allowPbgra && ctx.Settings.BlendingMode != GammaMode.Linear && ctx.Settings.MatteColor.IsEmpty) { newFormat = PixelFormat.FromGuid(Consts.GUID_WICPixelFormat32bppPBGRA); } else if (curFormat.AlphaRepresentation != PixelAlphaRepresentation.None) { newFormat = PixelFormat.FromGuid(Consts.GUID_WICPixelFormat32bppBGRA); } else if (curFormat.ColorRepresentation == PixelColorRepresentation.Grey) { newFormat = PixelFormat.FromGuid(Consts.GUID_WICPixelFormat8bppGray); } if (curFormat.FormatGuid == newFormat.FormatGuid) { return; } var conv = ctx.WicContext.AddRef(Wic.Factory.CreateFormatConverter()); if (!conv.CanConvert(curFormat.FormatGuid, newFormat.FormatGuid)) { throw new NotSupportedException("Can't convert to destination pixel format"); } conv.Initialize(ctx.Source.WicSource, newFormat.FormatGuid, WICBitmapDitherType.WICBitmapDitherTypeNone, null, 0.0, WICBitmapPaletteType.WICBitmapPaletteTypeCustom); ctx.Source = conv.AsPixelSource($"{nameof(IWICFormatConverter)}: {curFormat.Name}->{newFormat.Name}"); }