Exemplo n.º 1
0
        public static ProcessImageResult ProcessImage(Stream imgStream, Stream outStream, ProcessImageSettings settings)
        {
            using var ctx      = new PipelineContext(settings);
            ctx.ImageContainer = WicImageContainer.Create(imgStream, ctx.WicContext);

            return(processImage(ctx, outStream));
        }
Exemplo n.º 2
0
        public static ProcessImageResult ProcessImage(ReadOnlySpan <byte> imgBuffer, Stream outStream, ProcessImageSettings settings)
        {
            using var ctx      = new PipelineContext(settings);
            ctx.ImageContainer = WicImageContainer.Create(imgBuffer, ctx.WicContext);

            return(processImage(ctx, outStream));
        }
Exemplo n.º 3
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)
        {
            checkInStream(imgStream);

            var ctx = new PipelineContext(settings);

            ctx.ImageContainer = WicImageContainer.Create(imgStream, ctx.WicContext);

            buildPipeline(ctx, false);
            return(new ProcessingPipeline(ctx));
        }
Exemplo n.º 4
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)
        {
            checkInStream(imgStream);
            checkOutStream(outStream);

            using var ctx      = new PipelineContext(settings);
            ctx.ImageContainer = WicImageContainer.Create(imgStream, ctx.WicContext);

            buildPipeline(ctx);
            return(WriteOutput(ctx, outStream));
        }
Exemplo n.º 5
0
        public static WicImageContainer Load(Stream inStream)
        {
            var gch = GCHandle.Alloc(inStream);
            var sti = new IStreamImpl(gch);

            using var ccw = new SafeHandleReleaser(new SafeComCallable <IStreamImpl>(sti));

            var dec = createDecoder((IStream *)ccw.Handle !.DangerousGetHandle());

            return(WicImageContainer.Create(dec, ccw.Detach()));
        }
Exemplo n.º 6
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 ImageFileInfo Load(ReadOnlySpan <byte> imgBuffer, DateTime lastModified)
        {
            if (imgBuffer == default)
            {
                throw new ArgumentNullException(nameof(imgBuffer));
            }

            using var ctx      = new PipelineContext(new ProcessImageSettings());
            ctx.ImageContainer = WicImageContainer.Create(imgBuffer, ctx.WicContext);

            return(fromWicImage(ctx, imgBuffer.Length, lastModified));
        }
Exemplo n.º 7
0
        public static WicImageContainer Load(string fileName)
        {
            using var stm = default(ComPtr <IWICStream>);
            HRESULT.Check(Wic.Factory->CreateStream(stm.GetAddressOf()));

            fixed(char *pname = fileName)
            HRESULT.Check(stm.Get()->InitializeFromFilename((ushort *)pname, GENERIC_READ));

            var dec = createDecoder((IStream *)stm.Get());

            return(WicImageContainer.Create(dec));
        }
Exemplo n.º 8
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 ctx      = new PipelineContext(new ProcessImageSettings());
            ctx.ImageContainer = WicImageContainer.Create(imgPath, ctx.WicContext);

            return(fromWicImage(ctx, fi.Length, fi.LastWriteTimeUtc));
        }
Exemplo n.º 9
0
        /// <summary>All-in-one processing of an image according to the specified <paramref name="settings" />.</summary>
        /// <param name="imgPath">The path to a file containing the input image.</param>
        /// <param name="outStream">The stream to which the output image will be written. The stream must allow Seek and Write.</param>
        /// <param name="settings">The settings for this processing operation.</param>
        /// <returns>A <see cref="ProcessImageResult" /> containing the settings used and basic instrumentation for the pipeline.</returns>
        public static ProcessImageResult ProcessImage(string imgPath, Stream outStream, ProcessImageSettings settings)
        {
            if (imgPath is null)
            {
                throw new ArgumentNullException(nameof(imgPath));
            }
            checkOutStream(outStream);

            using var ctx      = new PipelineContext(settings);
            ctx.ImageContainer = WicImageContainer.Create(imgPath, ctx.WicContext);

            buildPipeline(ctx);
            return(WriteOutput(ctx, outStream));
        }
Exemplo n.º 10
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 ProcessImageResult ProcessImage(ReadOnlySpan <byte> imgBuffer, Stream outStream, ProcessImageSettings settings)
        {
            if (imgBuffer == default)
            {
                throw new ArgumentNullException(nameof(imgBuffer));
            }
            checkOutStream(outStream);

            using var ctx      = new PipelineContext(settings);
            ctx.ImageContainer = WicImageContainer.Create(imgBuffer, ctx.WicContext);

            buildPipeline(ctx);
            return(WriteOutput(ctx, outStream));
        }
Exemplo n.º 11
0
        /// <inheritdoc cref="BuildPipeline(string, ProcessImageSettings)" />
        /// <param name="imgBuffer">A buffer containing a supported input image container.</param>
        public static ProcessingPipeline BuildPipeline(ReadOnlySpan <byte> imgBuffer, ProcessImageSettings settings)
        {
            if (imgBuffer == default)
            {
                throw new ArgumentNullException(nameof(imgBuffer));
            }

            var ctx = new PipelineContext(settings);

            ctx.ImageContainer = WicImageContainer.Create(imgBuffer, ctx.WicContext);

            buildPipeline(ctx, false);
            return(new ProcessingPipeline(ctx));
        }
Exemplo n.º 12
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));
            }

            var ctx = new PipelineContext(settings);

            ctx.ImageContainer = WicImageContainer.Create(imgPath, ctx.WicContext);

            buildPipeline(ctx, false);
            return(new ProcessingPipeline(ctx));
        }
Exemplo n.º 13
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 = WicImageContainer.Create(imgStream, ctx.WicContext);

            buildPipeline(ctx, false);
            return(new ProcessingPipeline(ctx));
        }
Exemplo n.º 14
0
        unsafe public static WicImageContainer Load(byte *pbBuffer, int cbBuffer, PipelineContext ctx, bool ownCopy = false)
        {
            var istm = ctx.WicContext.AddRef(Wic.Factory.CreateStream());
            var ptr  = (IntPtr)pbBuffer;

            if (ownCopy)
            {
                ptr = ctx.WicContext.AddUnmanagedMemory(cbBuffer).DangerousGetHandle();
                Buffer.MemoryCopy(pbBuffer, ptr.ToPointer(), cbBuffer, cbBuffer);
            }

            istm.InitializeFromMemory(ptr, (uint)cbBuffer);

            var dec = createDecoder(stm => Wic.Factory.CreateDecoderFromStream(stm, null, WICDecodeOptions.WICDecodeMetadataCacheOnDemand), istm);

            return(WicImageContainer.Create(dec, ctx));
        }
Exemplo n.º 15
0
        public static WicImageContainer Load(byte *pbBuffer, int cbBuffer, bool ownCopy = false)
        {
            using var stream = default(ComPtr <IWICStream>);
            HRESULT.Check(Wic.Factory->CreateStream(stream.GetAddressOf()));
            var ptr = (IntPtr)pbBuffer;

            using var mem = default(SafeHandleReleaser);
            if (ownCopy)
            {
                ptr = mem.Attach(new SafeHGlobalHandle(cbBuffer)).DangerousGetHandle();
                Buffer.MemoryCopy(pbBuffer, ptr.ToPointer(), cbBuffer, cbBuffer);
            }

            HRESULT.Check(stream.Get()->InitializeFromMemory((byte *)ptr, (uint)cbBuffer));

            var dec = createDecoder((IStream *)stream.Get());

            return(WicImageContainer.Create(dec, mem.Detach()));
        }
Exemplo n.º 16
0
        /// <summary>Constructs a new <see cref="ImageFileInfo" /> instance by reading the metadata from an image file exposed by a <see cref="Stream" />.</summary>
        /// <param name="imgStream">The stream containing the image data.</param>
        /// <param name="lastModified">The last modified date of the image container.</param>
        public static ImageFileInfo Load(Stream imgStream, DateTime lastModified)
        {
            if (imgStream is null)
            {
                throw new ArgumentNullException(nameof(imgStream));
            }
            if (!imgStream.CanSeek || !imgStream.CanRead)
            {
                throw new ArgumentException("Input Stream must allow Seek and Read", nameof(imgStream));
            }
            if (imgStream.Length <= 0 || imgStream.Position >= imgStream.Length)
            {
                throw new ArgumentException("Input Stream is empty or positioned at its end", nameof(imgStream));
            }

            using var ctx      = new PipelineContext(new ProcessImageSettings());
            ctx.ImageContainer = WicImageContainer.Create(imgStream, ctx.WicContext);

            return(fromWicImage(ctx, imgStream.Length, lastModified));
        }
Exemplo n.º 17
0
        public static WicImageContainer Load(Stream inStream, PipelineContext ctx)
        {
            var dec = createDecoder(stm => Wic.Factory.CreateDecoderFromStream(stm, null, WICDecodeOptions.WICDecodeMetadataCacheOnDemand), inStream.AsIStream());

            return(WicImageContainer.Create(dec, ctx));
        }
Exemplo n.º 18
0
        public static WicImageContainer Load(string fileName, PipelineContext ctx)
        {
            var dec = createDecoder(fn => Wic.Factory.CreateDecoderFromFilename(fn, null, GenericAccessRights.GENERIC_READ, WICDecodeOptions.WICDecodeMetadataCacheOnDemand), fileName);

            return(WicImageContainer.Create(dec, ctx));
        }
Exemplo n.º 19
0
        public WicImageFrame(WicImageContainer decoder, uint index)
        {
            Container = decoder;

            using var frame = default(ComPtr <IWICBitmapFrameDecode>);
            HRESULT.Check(decoder.WicDecoder->GetFrame(index, frame.GetAddressOf()));

            using var source = new ComPtr <IWICBitmapSource>((IWICBitmapSource *)frame.Get());

            double dpix, dpiy;

            HRESULT.Check(frame.Get()->GetResolution(&dpix, &dpiy));
            (DpiX, DpiY) = (dpix, dpiy);

            uint frameWidth, frameHeight;

            HRESULT.Check(frame.Get()->GetSize(&frameWidth, &frameHeight));

            using var metareader = default(ComPtr <IWICMetadataQueryReader>);
            if (SUCCEEDED(frame.Get()->GetMetadataQueryReader(metareader.GetAddressOf())))
            {
                string orientationPath =
                    MagicImageProcessor.EnableXmpOrientation ? Wic.Metadata.OrientationWindowsPolicy :
                    Container.ContainerFormat == FileFormat.Jpeg ? Wic.Metadata.OrientationJpeg :
                    Wic.Metadata.OrientationExif;

                ExifOrientation   = ((Orientation)metareader.GetValueOrDefault <ushort>(orientationPath)).Clamp();
                WicMetadataReader = metareader.Detach();
            }

            using var preview = default(ComPtr <IWICBitmapSource>);
            if (decoder.IsRawContainer && index == 0 && SUCCEEDED(decoder.WicDecoder->GetPreview(preview.GetAddressOf())))
            {
                uint pw, ph;
                HRESULT.Check(preview.Get()->GetSize(&pw, &ph));

                if (pw == frameWidth && ph == frameHeight)
                {
                    source.Attach(preview.Detach());
                }
            }

            using var transform = default(ComPtr <IWICBitmapSourceTransform>);
            if (SUCCEEDED(source.Get()->QueryInterface(__uuidof <IWICBitmapSourceTransform>(), (void **)transform.GetAddressOf())))
            {
                uint tw = 1, th = 1;
                HRESULT.Check(transform.Get()->GetClosestSize(&tw, &th));

                SupportsNativeScale = tw < frameWidth || th < frameHeight;
            }

            using var ptransform = default(ComPtr <IWICPlanarBitmapSourceTransform>);
            if (SUCCEEDED(source.Get()->QueryInterface(__uuidof <IWICPlanarBitmapSourceTransform>(), (void **)ptransform.GetAddressOf())))
            {
                var fmts = WicTransforms.PlanarPixelFormats;
                var desc = stackalloc WICBitmapPlaneDescription[fmts.Length];
                fixed(Guid *pfmt = fmts)
                {
                    uint tw = frameWidth, th = frameHeight, st = 0;

                    HRESULT.Check(ptransform.Get()->DoesSupportTransform(
                                      &tw, &th,
                                      WICBitmapTransformOptions.WICBitmapTransformRotate0, WICPlanarOptions.WICPlanarOptionsDefault,
                                      pfmt, desc, (uint)fmts.Length, (int *)&st
                                      ));

                    SupportsPlanarProcessing = st != 0;
                }

                ChromaSubsampling =
                    desc[1].Width < desc[0].Width && desc[1].Height < desc[0].Height ? WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling420 :
                    desc[1].Width < desc[0].Width ? WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling422 :
                    desc[1].Height < desc[0].Height ? WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling440 :
                    WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling444;
            }

            var guid = default(Guid);

            HRESULT.Check(source.Get()->GetPixelFormat(&guid));
            if (PixelFormat.FromGuid(guid).NumericRepresentation == PixelNumericRepresentation.Indexed)
            {
                var newFormat = PixelFormat.Bgr24Bpp;
                if (Container.ContainerFormat == FileFormat.Gif && Container.FrameCount > 1)
                {
                    newFormat = PixelFormat.Bgra32Bpp;
                }
                else
                {
                    using var pal = default(ComPtr <IWICPalette>);
                    HRESULT.Check(Wic.Factory->CreatePalette(pal.GetAddressOf()));
                    HRESULT.Check(source.Get()->CopyPalette(pal));

                    int bval;
                    if (SUCCEEDED(pal.Get()->HasAlpha(&bval)) && bval != 0)
                    {
                        newFormat = PixelFormat.Bgra32Bpp;
                    }
                    else if ((SUCCEEDED(pal.Get()->IsGrayscale(&bval)) && bval != 0) || (SUCCEEDED(pal.Get()->IsBlackWhite(&bval)) && bval != 0))
                    {
                        newFormat = PixelFormat.Grey8Bpp;
                    }
                }

                var nfmt = newFormat.FormatGuid;
                using var conv = default(ComPtr <IWICFormatConverter>);
                HRESULT.Check(Wic.Factory->CreateFormatConverter(conv.GetAddressOf()));
                HRESULT.Check(conv.Get()->Initialize(source, &nfmt, WICBitmapDitherType.WICBitmapDitherTypeNone, null, 0.0, WICBitmapPaletteType.WICBitmapPaletteTypeCustom));

                source.Attach((IWICBitmapSource *)conv.Detach());
            }

            WicFrame  = frame.Detach();
            WicSource = source.Detach();
        }
Exemplo n.º 20
0
        public WicImageFrame(WicImageContainer decoder, uint index)
        {
            if (index >= (uint)decoder.FrameCount)
            {
                throw new IndexOutOfRangeException("Frame index does not exist");
            }

            WicFrame  = comHandles.AddRef(decoder.WicDecoder.GetFrame(index));
            WicSource = WicFrame;
            WicFrame.GetSize(out uint frameWidth, out uint frameHeight);
            container = decoder;

            if (decoder.IsRawContainer && index == 0 && decoder.WicDecoder.TryGetPreview(out var preview))
            {
                using var pvwSource = new ComHandle <IWICBitmapSource>(preview);
                preview.GetSize(out uint pw, out uint ph);

                if (pw == frameWidth && ph == frameHeight)
                {
                    WicSource = comHandles.AddOwnRef(preview);
                }
            }

            WicFrame.GetResolution(out double dpix, out double dpiy);
            DpiX = dpix;
            DpiY = dpiy;

            if (PixelFormat.FromGuid(WicSource.GetPixelFormat()).NumericRepresentation == PixelNumericRepresentation.Indexed)
            {
                var pal = comHandles.AddRef(Wic.Factory.CreatePalette());
                WicSource.CopyPalette(pal);

                var newFormat = Consts.GUID_WICPixelFormat24bppBGR;
                if (pal.HasAlpha())
                {
                    newFormat = Consts.GUID_WICPixelFormat32bppBGRA;
                }
                else if (pal.IsGrayscale() || pal.IsBlackWhite())
                {
                    newFormat = Consts.GUID_WICPixelFormat8bppGray;
                }

                var conv = comHandles.AddRef(Wic.Factory.CreateFormatConverter());
                conv.Initialize(WicSource, newFormat, WICBitmapDitherType.WICBitmapDitherTypeNone, null, 0.0, WICBitmapPaletteType.WICBitmapPaletteTypeCustom);
                WicSource = conv;
            }

            if (WicSource is IWICBitmapSourceTransform trans)
            {
                uint pw = 1, ph = 1;
                trans.GetClosestSize(ref pw, ref ph);

                SupportsNativeScale     = pw < frameWidth || ph < frameHeight;
                SupportsNativeTransform = trans.DoesSupportTransform(WICBitmapTransformOptions.WICBitmapTransformRotate270);
            }

            if (WicSource is IWICPlanarBitmapSourceTransform ptrans)
            {
                var desc = ArrayPool <WICBitmapPlaneDescription> .Shared.Rent(WicTransforms.PlanarPixelFormats.Length);

                SupportsPlanarProcessing = ptrans.DoesSupportTransform(ref frameWidth, ref frameHeight, WICBitmapTransformOptions.WICBitmapTransformRotate0, WICPlanarOptions.WICPlanarOptionsDefault, WicTransforms.PlanarPixelFormats, desc, (uint)WicTransforms.PlanarPixelFormats.Length);
                ChromaSubsampling        =
                    desc[1].Width < desc[0].Width && desc[1].Height < desc[0].Height ? WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling420 :
                    desc[1].Width < desc[0].Width ? WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling422 :
                    desc[1].Height < desc[0].Height ? WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling440 :
                    WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling444;

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

            if (WicFrame.TryGetMetadataQueryReader(out var metareader))
            {
                WicMetadataReader = comHandles.AddRef(metareader);

                string orientationPath =
                    MagicImageProcessor.EnableXmpOrientation ? Wic.Metadata.OrientationWindowsPolicy :
                    decoder.ContainerFormat == FileFormat.Jpeg ? Wic.Metadata.OrientationJpegPath :
                    Wic.Metadata.OrientationExifPath;

                if (metareader.TryGetMetadataByName(orientationPath, out var pvorient) && pvorient.UnmanagedType == VarEnum.VT_UI2)
                {
                    ExifOrientation = (Orientation)Math.Min(Math.Max((ushort)Orientation.Normal, (ushort)pvorient.Value !), (ushort)Orientation.Rotate270);
                }
            }
        }
Exemplo n.º 21
0
        public WicImageFrame(WicImageContainer decoder, uint index)
        {
            WicFrame  = comHandles.AddRef(decoder.WicDecoder.GetFrame(index));
            WicSource = WicFrame;
            Container = decoder;

            WicFrame.GetResolution(out double dpix, out double dpiy);
            DpiX = dpix;
            DpiY = dpiy;

            WicFrame.GetSize(out uint frameWidth, out uint frameHeight);

            if (WicFrame.TryGetMetadataQueryReader(out var metareader))
            {
                WicMetadataReader = comHandles.AddRef(metareader);

                string orientationPath =
                    MagicImageProcessor.EnableXmpOrientation ? Wic.Metadata.OrientationWindowsPolicy :
                    Container.ContainerFormat == FileFormat.Jpeg ? Wic.Metadata.OrientationJpeg :
                    Wic.Metadata.OrientationExif;

                ExifOrientation = ((Orientation)metareader.GetValueOrDefault <ushort>(orientationPath)).Clamp();
            }

            if (decoder.IsRawContainer && index == 0 && decoder.WicDecoder.TryGetPreview(out var preview))
            {
                using var pvwSource = ComHandle.Wrap(preview);
                preview.GetSize(out uint pw, out uint ph);

                if (pw == frameWidth && ph == frameHeight)
                {
                    WicSource = comHandles.AddOwnRef(preview);
                }
            }

            if (WicSource is IWICBitmapSourceTransform trans)
            {
                uint pw = 1, ph = 1;
                trans.GetClosestSize(ref pw, ref ph);

                SupportsNativeScale = pw < frameWidth || ph < frameHeight;
            }

            if (WicSource is IWICPlanarBitmapSourceTransform ptrans)
            {
                var desc = ArrayPool <WICBitmapPlaneDescription> .Shared.Rent(WicTransforms.PlanarPixelFormats.Length);

                uint twidth = frameWidth, theight = frameHeight;
                SupportsPlanarProcessing = ptrans.DoesSupportTransform(
                    ref twidth, ref theight,
                    WICBitmapTransformOptions.WICBitmapTransformRotate0, WICPlanarOptions.WICPlanarOptionsDefault,
                    WicTransforms.PlanarPixelFormats, desc, (uint)WicTransforms.PlanarPixelFormats.Length
                    );

                ChromaSubsampling =
                    desc[1].Width < desc[0].Width && desc[1].Height < desc[0].Height ? WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling420 :
                    desc[1].Width < desc[0].Width ? WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling422 :
                    desc[1].Height < desc[0].Height ? WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling440 :
                    WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling444;

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

            if (PixelFormat.FromGuid(WicSource.GetPixelFormat()).NumericRepresentation == PixelNumericRepresentation.Indexed)
            {
                var newFormat = PixelFormat.Bgr24Bpp;
                if (Container.ContainerFormat == FileFormat.Gif && Container.FrameCount > 1)
                {
                    newFormat = PixelFormat.Bgra32Bpp;
                }
                else
                {
                    using var wicpal = ComHandle.Wrap(Wic.Factory.CreatePalette());
                    var pal = wicpal.ComObject;
                    WicSource.CopyPalette(pal);

                    if (pal.HasAlpha())
                    {
                        newFormat = PixelFormat.Bgra32Bpp;
                    }
                    else if (pal.IsGrayscale() || pal.IsBlackWhite())
                    {
                        newFormat = PixelFormat.Grey8Bpp;
                    }
                }

                var conv = comHandles.AddRef(Wic.Factory.CreateFormatConverter());
                conv.Initialize(WicSource, newFormat.FormatGuid, WICBitmapDitherType.WICBitmapDitherTypeNone, null, 0.0, WICBitmapPaletteType.WICBitmapPaletteTypeCustom);
                WicSource = conv;
            }
        }