コード例 #1
0
        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;
        }
コード例 #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 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;
        }
コード例 #4
0
        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)));
        }
コード例 #5
0
        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));
        }
コード例 #6
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;
        }
コード例 #7
0
        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());
        }
コード例 #8
0
        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));
            }
        }
コード例 #9
0
ファイル: WicImageContainer.cs プロジェクト: wk-j/PhotoSauce
        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));
        }
コード例 #10
0
        /// <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));
        }
コード例 #11
0
        /// <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));
                }
        }
コード例 #12
0
        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;
        }
コード例 #13
0
        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}"));
        }
コード例 #14
0
        /// <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));
        }
コード例 #15
0
        /// <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));
        }
コード例 #16
0
        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)));
            }
        }
コード例 #17
0
        /// <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));
        }
コード例 #18
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();
        }
コード例 #19
0
        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));
                }
        }
コード例 #20
0
#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));
            }
        }
コード例 #21
0
        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;
        }
    }
コード例 #22
0
        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}"));
        }
コード例 #23
0
        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}");
        }