Exemple #1
0
        public static Bitmap FromWic(IWICBitmapSource source)
        {
            Guid format; //Get the WIC pixel format

            source.GetPixelFormat(out format);
            //Get the matching GDI format
            PixelFormat gdiFormat = ConversionUtils.GetPixelFormat(format);

            //If it's not GDI-supported format, convert it to one.
            IWICComponentFactory factory   = null;
            IWICFormatConverter  converter = null;

            try {
                if (gdiFormat == PixelFormat.Undefined)
                {
                    factory   = (IWICComponentFactory) new WICImagingFactory();
                    converter = factory.CreateFormatConverter();
                    converter.Initialize(source, Consts.GUID_WICPixelFormat32bppBGRA, WICBitmapDitherType.WICBitmapDitherTypeNone, null, 0.9f, WICBitmapPaletteType.WICBitmapPaletteTypeCustom);
                    gdiFormat = PixelFormat.Format32bppArgb;
                }
                IWICBitmapSource data = converter != null ? converter : source;

                //Get the dimensions of the WIC bitmap
                uint w, h;
                data.GetSize(out w, out h);

                Bitmap     b  = new Bitmap((int)w, (int)h, gdiFormat);
                BitmapData bd = b.LockBits(new Rectangle(0, 0, (int)w, (int)h), ImageLockMode.WriteOnly, b.PixelFormat);
                try {
                    long result = CopyPixels(data, IntPtr.Zero, (uint)bd.Stride, (uint)(bd.Stride * bd.Height), bd.Scan0);
                    if (result == 0x80070057)
                    {
                        throw new ArgumentException();
                    }
                    if (result < 0)
                    {
                        throw new Exception("HRESULT " + result);
                    }
                    return(b);
                } finally {
                    b.UnlockBits(bd);
                }
            } finally {
                if (converter != null)
                {
                    Marshal.ReleaseComObject(converter);
                }
                if (factory != null)
                {
                    Marshal.ReleaseComObject(factory);
                }
            }
        }
Exemple #2
0
        public void EncodeToStream(IWICComponentFactory factory, IWICBitmapSource data, Size imageSize, IStream outputStream)
        {
            //A list of COM objects to destroy
            List<object> com = new List<object>();
            try {

                //Find the GUID of the destination format
                Guid guidEncoder = GetOutputFormatWicGuid();

                //Find out the data's pixel format
                Guid pFormat = Guid.Empty;
                data.GetPixelFormat(out pFormat);

                //Create the encoder
                var encoder = factory.CreateEncoder(guidEncoder, null);
                com.Add(encoder);
                //And initialize it
                encoder.Initialize(outputStream, WICBitmapEncoderCacheOption.WICBitmapEncoderNoCache);

                // Create the output frame and property bag
                IWICBitmapFrameEncode outputFrame;
                var propertyBagArray = new IPropertyBag2[1];
                encoder.CreateNewFrame(out outputFrame, propertyBagArray); //An array is used instead of an out parameter... I have no idea why
                com.Add(outputFrame);
                //The property bag is a COM object...
                var propBag = propertyBagArray[0];
                com.Add(propBag);

                //Adjust encoder settings if it's a jpegs
                if (guidEncoder.Equals(Consts.GUID_ContainerFormatJpeg)) {
                    //Jpeg
                    //ImageQuality 0..1
                    //"JpegYCrCbSubsampling"  WICJpegYCrCbSubsamplingOption.

                    //Configure encoder settings (see http://msdn.microsoft.com/en-us/library/windows/desktop/ee719871(v=vs.85).aspx#encoderoptions)
                    var qualityOption = new PROPBAG2[1];
                    qualityOption[0].pstrName = "ImageQuality";

                    propBag.Write(1, qualityOption, new object[] { ((float)Math.Max(0,Math.Min(100,Quality))) / 100 });

                    WICJpegYCrCbSubsamplingOption subsampling = WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsamplingDefault;
                    //411 NOT SUPPPORTED BY WIC - only by freeimage
                    if ("420".Equals(Subsampling)) subsampling = WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling420;
                    if ("422".Equals(Subsampling)) subsampling = WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling422;
                    if ("444".Equals(Subsampling)) subsampling = WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling444;

                    if (subsampling != WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsamplingDefault) {
                        var samplingOption = new PROPBAG2[1];
                        samplingOption[0].pstrName = "JpegYCrCbSubsampling";
                        samplingOption[0].vt = VarEnum.VT_UI1;
                        propBag.Write(1, samplingOption, new object[] { (byte)subsampling });
                    }
                }
                //PNG interlace
                if (guidEncoder.Equals(Consts.GUID_ContainerFormatPng)) {
                    var interlaceOption = new PROPBAG2[1];
                    interlaceOption[0].pstrName = "InterlaceOption";

                    propBag.Write(1, interlaceOption, new object[] { Interlace ?? false });

                }

                //Apply the property bag
                outputFrame.Initialize(propBag);

                //Convert the bitmap to the correct pixel format for encoding.

                //Jpeg: encodes as GUID_WICPixelFormat24bppBGR or GUID_WICPixelFormat8bppGray.
                //If the original pixel format has an alpha chanel, we need to specify a matte color.
                //UPDATE - IWICFormatConverter doesn't let you specify a matte color. Disabling code
                if (false && guidEncoder.Equals(Consts.GUID_ContainerFormatJpeg)) {
                    ConversionUtils.HasAlphaAbility(pFormat);
                    var conv = factory.CreateFormatConverter();
                    com.Add(conv);
                    if (conv.CanConvert(pFormat, Consts.GUID_WICPixelFormat24bppBGR)) {
                        /*dither, pIPalette, alphaThresholdPercent, and paletteTranslate are used to mitigate color loss when
                         * converting to a reduced bit-depth format. For conversions that do not need these settings, the
                         * following parameters values should be used: dither set to WICBitmapDitherTypeNone, pIPalette set to NULL,
                         * alphaThresholdPercent set to 0.0f, and paletteTranslate set to WICBitmapPaletteTypeCustom.*/
                        conv.Initialize(data, Consts.GUID_WICPixelFormat24bppBGR, WICBitmapDitherType.WICBitmapDitherTypeNone, null, 0.0f, WICBitmapPaletteType.WICBitmapPaletteTypeCustom);
                        data = conv;
                        //Oops, we didn't do anything - there's no way to specify a matte color!
                    }
                }

                //GIF encodes as GUID_WICPixelFormat8bppIndexed
                //If the current format is > 8bpp, quantization may be required, and we may need to manually build the palette with Median Cut.

                //PNG encodeds as EVERYTHING! Way too many formats supported.
                // If the user is specifying a colors setting, we need to
                // convert to GUID_WICPixelFormat8bppIndexed, GUID_WICPixelFormat4bppIndexed, GUID_WICPixelFormat2bppIndexed, or GUID_WICPixelFormat1bppIndexed

                if ((guidEncoder.Equals(Consts.GUID_ContainerFormatPng) && this.Colors != -1) || (guidEncoder.Equals(Consts.GUID_ContainerFormatGif))) {

                    Guid target = Consts.GUID_WICPixelFormat8bppIndexed;

                    int colors = this.Colors;

                    if (colors > 0 && guidEncoder.Equals(Consts.GUID_ContainerFormatPng)) {
                        if (colors <= 2) target = Consts.GUID_WICPixelFormat1bppIndexed;
                        if (colors <= 4) target = Consts.GUID_WICPixelFormat2bppIndexed;
                        if (colors <= 32) target = Consts.GUID_WICPixelFormat4bppIndexed;
                    }
                    if (colors < 0) colors = 256;
                    if (colors < 2) colors = 2;
                    if (colors > 256) colors = 256;

                    var conv = factory.CreateFormatConverter();
                    com.Add(conv);
                    if (conv.CanConvert(pFormat, target)) {

                        var palette = factory.CreatePalette();
                        com.Add(palette);
                        palette.InitializeFromBitmap(data, (uint)colors, true);

                        /*dither, pIPalette, alphaThresholdPercent, and paletteTranslate are used to mitigate color loss when
                         * converting to a reduced bit-depth format. For conversions that do not need these settings, the
                         * following parameters values should be used: dither set to WICBitmapDitherTypeNone, pIPalette set to NULL,
                         * alphaThresholdPercent set to 0.0f, and paletteTranslate set to WICBitmapPaletteTypeCustom.*/
                        conv.Initialize(data, target, this.Dither ? WICBitmapDitherType.WICBitmapDitherTypeErrorDiffusion :  WICBitmapDitherType.WICBitmapDitherTypeNone,
                                        palette, 50.0f, WICBitmapPaletteType.WICBitmapPaletteTypeCustom);
                        data = conv;

                    }
                }

                //Get size
                uint fw, fh;
                data.GetSize(out fw, out fh);

                //Set destination frame size
                outputFrame.SetSize(fw,fh);

                // Write the data to the output frame
                outputFrame.WriteSource(data, null);
                outputFrame.Commit();
                encoder.Commit();

            } finally {
                //Manually cleanup all the com reference counts, aggressively
                while (com.Count > 0) {
                    Marshal.ReleaseComObject(com[com.Count - 1]); //In reverse order, so no item is ever deleted out from under another.
                    com.RemoveAt(com.Count - 1);
                }
            }
        }
Exemple #3
0
        public void EncodeToStream(IWICComponentFactory factory, IWICBitmapSource data, Size imageSize, IStream outputStream)
        {
            //A list of COM objects to destroy
            List <object> com = new List <object>();

            try {
                //Find the GUID of the destination format
                Guid guidEncoder = GetOutputFormatWicGuid();

                //Find out the data's pixel format
                Guid pFormat = Guid.Empty;
                data.GetPixelFormat(out pFormat);

                //Create the encoder
                var encoder = factory.CreateEncoder(guidEncoder, null);
                com.Add(encoder);
                //And initialize it
                encoder.Initialize(outputStream, WICBitmapEncoderCacheOption.WICBitmapEncoderNoCache);

                // Create the output frame and property bag
                IWICBitmapFrameEncode outputFrame;
                var propertyBagArray = new IPropertyBag2[1];
                encoder.CreateNewFrame(out outputFrame, propertyBagArray); //An array is used instead of an out parameter... I have no idea why
                com.Add(outputFrame);
                //The property bag is a COM object...
                var propBag = propertyBagArray[0];
                com.Add(propBag);

                //Adjust encoder settings if it's a jpegs
                if (guidEncoder.Equals(Consts.GUID_ContainerFormatJpeg))
                {
                    //Jpeg
                    //ImageQuality 0..1
                    //"JpegYCrCbSubsampling"  WICJpegYCrCbSubsamplingOption.

                    //Configure encoder settings (see http://msdn.microsoft.com/en-us/library/windows/desktop/ee719871(v=vs.85).aspx#encoderoptions)
                    var qualityOption = new PROPBAG2[1];
                    qualityOption[0].pstrName = "ImageQuality";

                    propBag.Write(1, qualityOption, new object[] { ((float)Math.Max(0, Math.Min(100, Quality))) / 100 });

                    WICJpegYCrCbSubsamplingOption subsampling = WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsamplingDefault;
                    //411 NOT SUPPPORTED BY WIC - only by freeimage
                    if ("420".Equals(Subsampling))
                    {
                        subsampling = WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling420;
                    }
                    if ("422".Equals(Subsampling))
                    {
                        subsampling = WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling422;
                    }
                    if ("444".Equals(Subsampling))
                    {
                        subsampling = WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsampling444;
                    }

                    if (subsampling != WICJpegYCrCbSubsamplingOption.WICJpegYCrCbSubsamplingDefault)
                    {
                        var samplingOption = new PROPBAG2[1];
                        samplingOption[0].pstrName = "JpegYCrCbSubsampling";
                        samplingOption[0].vt       = VarEnum.VT_UI1;
                        propBag.Write(1, samplingOption, new object[] { (byte)subsampling });
                    }
                }
                //PNG interlace
                if (guidEncoder.Equals(Consts.GUID_ContainerFormatPng))
                {
                    var interlaceOption = new PROPBAG2[1];
                    interlaceOption[0].pstrName = "InterlaceOption";

                    propBag.Write(1, interlaceOption, new object[] { Interlace ?? false });
                }

                //Apply the property bag
                outputFrame.Initialize(propBag);


                //Convert the bitmap to the correct pixel format for encoding.

                //Jpeg: encodes as GUID_WICPixelFormat24bppBGR or GUID_WICPixelFormat8bppGray.
                //If the original pixel format has an alpha chanel, we need to specify a matte color.
                //UPDATE - IWICFormatConverter doesn't let you specify a matte color. Disabling code
                if (false && guidEncoder.Equals(Consts.GUID_ContainerFormatJpeg))
                {
                    ConversionUtils.HasAlphaAbility(pFormat);
                    var conv = factory.CreateFormatConverter();
                    com.Add(conv);
                    if (conv.CanConvert(pFormat, Consts.GUID_WICPixelFormat24bppBGR))
                    {
                        /*dither, pIPalette, alphaThresholdPercent, and paletteTranslate are used to mitigate color loss when
                         * converting to a reduced bit-depth format. For conversions that do not need these settings, the
                         * following parameters values should be used: dither set to WICBitmapDitherTypeNone, pIPalette set to NULL,
                         * alphaThresholdPercent set to 0.0f, and paletteTranslate set to WICBitmapPaletteTypeCustom.*/
                        conv.Initialize(data, Consts.GUID_WICPixelFormat24bppBGR, WICBitmapDitherType.WICBitmapDitherTypeNone, null, 0.0f, WICBitmapPaletteType.WICBitmapPaletteTypeCustom);
                        data = conv;
                        //Oops, we didn't do anything - there's no way to specify a matte color!
                    }
                }

                //GIF encodes as GUID_WICPixelFormat8bppIndexed
                //If the current format is > 8bpp, quantization may be required, and we may need to manually build the palette with Median Cut.

                //PNG encodeds as EVERYTHING! Way too many formats supported.
                // If the user is specifying a colors setting, we need to
                // convert to GUID_WICPixelFormat8bppIndexed, GUID_WICPixelFormat4bppIndexed, GUID_WICPixelFormat2bppIndexed, or GUID_WICPixelFormat1bppIndexed

                if ((guidEncoder.Equals(Consts.GUID_ContainerFormatPng) && this.Colors != -1) || (guidEncoder.Equals(Consts.GUID_ContainerFormatGif)))
                {
                    Guid target = Consts.GUID_WICPixelFormat8bppIndexed;

                    int colors = this.Colors;

                    if (colors > 0 && guidEncoder.Equals(Consts.GUID_ContainerFormatPng))
                    {
                        if (colors <= 2)
                        {
                            target = Consts.GUID_WICPixelFormat1bppIndexed;
                        }
                        if (colors <= 4)
                        {
                            target = Consts.GUID_WICPixelFormat2bppIndexed;
                        }
                        if (colors <= 32)
                        {
                            target = Consts.GUID_WICPixelFormat4bppIndexed;
                        }
                    }
                    if (colors < 0)
                    {
                        colors = 256;
                    }
                    if (colors < 2)
                    {
                        colors = 2;
                    }
                    if (colors > 256)
                    {
                        colors = 256;
                    }

                    var conv = factory.CreateFormatConverter();
                    com.Add(conv);
                    if (conv.CanConvert(pFormat, target))
                    {
                        var palette = factory.CreatePalette();
                        com.Add(palette);
                        palette.InitializeFromBitmap(data, (uint)colors, true);

                        /*dither, pIPalette, alphaThresholdPercent, and paletteTranslate are used to mitigate color loss when
                         * converting to a reduced bit-depth format. For conversions that do not need these settings, the
                         * following parameters values should be used: dither set to WICBitmapDitherTypeNone, pIPalette set to NULL,
                         * alphaThresholdPercent set to 0.0f, and paletteTranslate set to WICBitmapPaletteTypeCustom.*/
                        conv.Initialize(data, target, this.Dither ? WICBitmapDitherType.WICBitmapDitherTypeErrorDiffusion :  WICBitmapDitherType.WICBitmapDitherTypeNone,
                                        palette, 50.0f, WICBitmapPaletteType.WICBitmapPaletteTypeCustom);
                        data = conv;
                    }
                }

                //Get size
                uint fw, fh;
                data.GetSize(out fw, out fh);

                //Set destination frame size
                outputFrame.SetSize(fw, fh);

                // Write the data to the output frame
                outputFrame.WriteSource(data, null);
                outputFrame.Commit();
                encoder.Commit();
            } finally {
                //Manually cleanup all the com reference counts, aggressively
                while (com.Count > 0)
                {
                    Marshal.ReleaseComObject(com[com.Count - 1]); //In reverse order, so no item is ever deleted out from under another.
                    com.RemoveAt(com.Count - 1);
                }
            }
        }