예제 #1
0
        public static void Write <T>(this IPropertyBag2 bag, string name, T val) where T : unmanaged
        {
            var prop = new PROPBAG2 {
                pstrName = name
            };
            var pvar = new UnmanagedPropVariant();

            if (typeof(T) == typeof(bool))
            {
                pvar.vt         = VarEnum.VT_BOOL;
                pvar.int16Value = (bool)(object)val ? (short)-1 : (short)0;
            }
            else if (typeof(T) == typeof(byte))
            {
                pvar.vt        = VarEnum.VT_UI1;
                pvar.byteValue = (byte)(object)val;
            }
            else if (typeof(T) == typeof(float))
            {
                pvar.vt         = VarEnum.VT_R4;
                pvar.floatValue = (float)(object)val;
            }
            else
            {
                throw new ArgumentException("Marshaling not implemented for type: " + typeof(T).Name, nameof(T));
            }

            ProxyFunctions.PropertyBagWrite(bag, 1, prop, pvar);
        }
예제 #2
0
        public static void Write(this IPropertyBag2 bag, IEnumerable <KeyValuePair <string, object> > properties)
        {
            if (bag == null)
            {
                throw new ArgumentNullException(nameof(bag));
            }

            if (properties == null)
            {
                return;
            }

            foreach (var kv in properties)
            {
                var i = GetIndex(bag, kv.Key);
                if (i < 0) // ?
                {
                    continue;
                }

                // read info
                var values = new object[1];
                var props  = new PROPBAG2[1];
                props[0].pstrName = kv.Key;
                bag.GetPropertyInfo(i, 1, props, out int _).ThrowOnError();
                var value = props[0].ChangeType(kv.Value);
                values[0] = value;
                bag.Write(1, props, values).ThrowOnError();
            }
        }
예제 #3
0
        public static byte[] WicResize(IWICComponentFactory factory, IWICBitmapFrameDecode frame, int width,
                                       int height, int quality)
        {
            // Prepare output stream to cache file
            var outputStream = new MemoryIStream();
            // Prepare PNG encoder
            var encoder = factory.CreateEncoder(Consts.GUID_ContainerFormatJpeg, null);

            encoder.Initialize(outputStream, WICBitmapEncoderCacheOption.WICBitmapEncoderNoCache);
            // Prepare output frame
            IWICBitmapFrameEncode outputFrame;
            var arg = new IPropertyBag2[1];

            encoder.CreateNewFrame(out outputFrame, arg);
            var propBag           = arg[0];
            var propertyBagOption = new PROPBAG2[1];

            propertyBagOption[0].pstrName = "ImageQuality";
            propBag.Write(1, propertyBagOption, new object[] { ((float)quality) / 100 });
            outputFrame.Initialize(propBag);
            double dpiX, dpiY;

            frame.GetResolution(out dpiX, out dpiY);
            outputFrame.SetResolution(dpiX, dpiY);

            uint ow, oh, w, h;

            frame.GetSize(out ow, out oh);
            if (ow > oh)
            {
                w = (uint)width;
                h = (uint)((double)height * (double)oh / (double)ow);
            }
            else
            {
                w = (uint)((double)height * (double)ow / (double)oh);
                h = (uint)height;
            }


            outputFrame.SetSize(w, h);
            // Prepare scaler
            var scaler = factory.CreateBitmapScaler();

            scaler.Initialize(frame, w, h, WICBitmapInterpolationMode.WICBitmapInterpolationModeFant);
            // Write the scaled source to the output frame
            outputFrame.WriteSource(scaler, new WICRect {
                X = 0, Y = 0, Width = (int)width, Height = (int)height
            });
            outputFrame.Commit();
            encoder.Commit();
            var outputArray = outputStream.ToArray();

            outputStream.Close();
            Marshal.ReleaseComObject(outputFrame);
            Marshal.ReleaseComObject(scaler);
            Marshal.ReleaseComObject(propBag);
            Marshal.ReleaseComObject(encoder);
            return(outputArray);
        }
        public void Resize(byte[] sourceBytes, Stream targetStream, uint targetMaxSize)
        {
            var factory = (IWICComponentFactory)new WICImagingFactory();
            var inputStream = factory.CreateStream();
            inputStream.InitializeFromMemory(sourceBytes, (uint)sourceBytes.Length);
            var decoder = factory.CreateDecoderFromStream(inputStream, null, WICDecodeOptions.WICDecodeMetadataCacheOnLoad);
            var frame = decoder.GetFrame(0);

            // Compute target size
            uint width, height, targetWidth, targetHeight;
            frame.GetSize(out width, out height);
            if (width <= targetMaxSize && height <= targetMaxSize)
            {
                targetHeight = height;
                targetWidth = width;
            }
            else if (width > height)
            {
                targetWidth = targetMaxSize;
                targetHeight = height * targetMaxSize / width;
            }
            else
            {
                targetWidth = width * targetMaxSize / height;
                targetHeight = targetMaxSize;
            }

            // Prepare output stream to cache file
            var outputStreamAdapter = new StreamAdapter(targetStream);
            
            // Prepare JPG encoder
            var encoder = factory.CreateEncoder(Consts.GUID_ContainerFormatJpeg, null);
            encoder.Initialize(outputStreamAdapter, WICBitmapEncoderCacheOption.WICBitmapEncoderNoCache);

            // Prepare output frame
            IWICBitmapFrameEncode outputFrame;
            var argument = new IPropertyBag2[1];
            encoder.CreateNewFrame(out outputFrame, argument);
            var propBag = argument[0];
            var propertyBagOption = new PROPBAG2[1];
            propertyBagOption[0].pstrName = ImageQualityParamName;
            propBag.Write(1, propertyBagOption, this.jpegQuality);
            outputFrame.Initialize(propBag);
            outputFrame.SetResolution(this.thumbDpi, this.thumbDpi);
            outputFrame.SetSize(targetWidth, targetHeight);

            // Prepare scaler
            var scaler = factory.CreateBitmapScaler();
            scaler.Initialize(frame, targetWidth, targetHeight, WICBitmapInterpolationMode.WICBitmapInterpolationModeLinear);

            // Write the scaled source to the output frame
            outputFrame.WriteSource(scaler, new WICRect { X = 0, Y = 0, Width = (int)targetWidth, Height = (int)targetHeight });
            outputFrame.Commit();
            encoder.Commit();
        }
예제 #5
0
        public static void Initialize(this IWICBitmapFrameEncode frame, IPropertyBag2 bag = null)
        {
            if (frame == null)
            {
                throw new ArgumentNullException(nameof(frame));
            }

            if (bag != null)
            {
                frame.Initialize(bag).ThrowOnError();
            }
        }
예제 #6
0
 /// <summary>Method called when the NativePointer is updated.</summary>
 /// <param name="oldNativePointer">The old native pointer.</param>
 protected override void NativePointerUpdated(IntPtr oldNativePointer)
 {
     base.NativePointerUpdated(oldNativePointer);
     if (NativePointer != IntPtr.Zero)
     {
         nativePropertyBag = (IPropertyBag2)Marshal.GetObjectForIUnknown(NativePointer);
     }
     else
     {
         nativePropertyBag = null;
     }
 }
예제 #7
0
        public static void Write(this IPropertyBag2 propertyBag2, string propertyName, object?value)
        {
            PROPBAG2 propBag = new PROPBAG2();

            propBag.pstrName = Marshal.StringToCoTaskMemUni(propertyName);
            try
            {
                propertyBag2.Write(1, new[] { propBag }, new[] { value });
            }
            finally
            {
                Marshal.FreeCoTaskMem(propBag.pstrName);
            }
        }
예제 #8
0
        private static int GetIndex(IPropertyBag2 bag, string name)
        {
            if (bag == null || name == null)
            {
                return(-1);
            }

            bag.CountProperties(out int count);
            for (var i = 0; i < count; i++)
            {
                var props = new PROPBAG2[1];
                bag.GetPropertyInfo(i, 1, props, out _).ThrowOnError();
                if (props[0].pstrName.EqualsIgnoreCase(name))
                {
                    return(i);
                }
            }
            return(-1);
        }
예제 #9
0
        public static object?Read(this IPropertyBag2 propertyBag2, string propertyName)
        {
            PROPBAG2 propBag = new PROPBAG2();

            propBag.pstrName = Marshal.StringToCoTaskMemUni(propertyName);
            try
            {
                object?[] values = new object?[1];
                int[]     errors = new int[1];
                propertyBag2.Read(1, new[] { propBag }, null, values, errors);
                if (errors[0] != 0)
                {
                    throw new COMException("Could not read property.", errors[0]);
                }
                return(values[0]);
            }
            finally
            {
                Marshal.FreeCoTaskMem(propBag.pstrName);
            }
        }
예제 #10
0
        protected override bool ProcessEncoder(MainForm form, IWICBitmapEncoder encoder, object tag)
        {
            Tag t = (Tag)tag;
            IWICImagingFactory factory = (IWICImagingFactory) new WICImagingFactory();
            IWICPalette        palette = factory.CreatePalette();

            palette.InitializePredefined(WICBitmapPaletteType.WICBitmapPaletteTypeFixedBW, false);
            IWICBitmapFrameEncode frame  = null;
            IWICBitmapFrameEncode frame2 = null;

            IPropertyBag2[] bag = new IPropertyBag2[1];
            try
            {
                MethodInfo mi = typeof(IWICBitmapEncoder).GetMethod("CreateNewFrame");
                try
                {
                    encoder.CreateNewFrame(out frame, bag);
                }
                catch (Exception e)
                {
                    form.Add(this, mi.ToString(Resources._0_Failed), new DataEntry(Resources.FrameIndex, 0), new DataEntry(e));
                }

                if (frame == null)
                {
                    form.Add(this, mi.ToString(Resources._0_NULL), new DataEntry(Resources.Parameter, mi.GetParameters()[0].Name));
                }
                else
                {
                    if (bag[0] == null)
                    {
                        form.Add(this, mi.ToString(Resources._0_NULL), new DataEntry(Resources.Parameter, mi.GetParameters()[1].Name));
                    }
                    try
                    {
                        frame.Initialize(bag[0]);
                        frame.SetSize(1, 1);
                        frame.SetPalette(palette);
                        Guid pixelFormat = Guid.Empty;

                        List <Guid> allPixelFormats = new List <Guid>(PixelFormatInfoRule.AllPixelFormats);
                        allPixelFormats.Add(Consts.GUID_WICPixelFormatDontCare);

                        foreach (Guid g in allPixelFormats)
                        {
                            pixelFormat = g;
                            frame.SetPixelFormat(ref pixelFormat);
                            if (g == pixelFormat)
                            {
                                if (Array.IndexOf(t.PixelFormats, g) < 0)
                                {
                                    form.Add(this, string.Format(CultureInfo.CurrentUICulture, Resources.DidNotChangeUnsupportedPixelFormat, "IWICBitmapFrameEncode::SetPixelFormat(...)"), new DataEntry(Resources.PixelFormat, g), new DataEntry(Resources.SupportedPixelFormats, t.PixelFormats));
                                }
                            }
                            else
                            {
                                if (Array.IndexOf(t.PixelFormats, g) >= 0)
                                {
                                    form.Add(this, string.Format(CultureInfo.CurrentUICulture, Resources.ChangedSupportedPixelFormat, "IWICBitmapFrameEncode::SetPixelFormat(...)"), new DataEntry(Resources.Expected, g), new DataEntry(Resources.Actual, pixelFormat));
                                }
                            }
                        }
                        pixelFormat = Consts.GUID_WICPixelFormat32bppBGRA;
                        frame.SetPixelFormat(ref pixelFormat);
                        byte[] buffer = new byte[(PixelFormatInfoRule.GetBitPerPixel(pixelFormat) + 7) / 8];
                        frame.WritePixels(1, (uint)buffer.Length, (uint)buffer.Length, buffer);
                        frame.Commit();

                        try
                        {
                            encoder.CreateNewFrame(out frame2, null);
                            if (!t.SupportsMultiframe)
                            {
                                form.Add(this, mi.ToString(Resources._0_ShouldFail), new DataEntry(WinCodecError.WINCODEC_ERR_UNSUPPORTEDOPERATION));
                            }
                        }
                        catch (Exception e)
                        {
                            if (t.SupportsMultiframe)
                            {
                                form.Add(this, e.TargetSite.ToString(Resources._0_Failed), new DataEntry(Resources.FrameIndex, 1), new DataEntry(e));
                            }
                            else
                            {
                                form.CheckHRESULT(this, WinCodecError.WINCODEC_ERR_UNSUPPORTEDOPERATION, e, new DataEntry(Resources.FrameIndex, 1));
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        form.Add(this, e.TargetSite.ToString(Resources._0_Failed), new DataEntry(e));
                    }
                }
            }
            finally
            {
                frame2.ReleaseComObject();
                encoder.ReleaseComObject();
                bag.ReleaseComObject();
                factory.ReleaseComObject();
                palette.ReleaseComObject();
            }

            return(base.ProcessEncoder(form, encoder, tag));
        }
예제 #11
0
        public void EncodeToStream(IWICComponentFactory factory, IWICBitmapSource data, 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 = Consts.GUID_ContainerFormatJpeg;

                //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))
                {
                    //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";
                    qualityOption[0].vt       = VarEnum.VT_R4;
                    object qualityValue = ((float)90) / 100;

                    propBag.Write(1, qualityOption, new object[] { qualityValue });
                }

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


                //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);
                }
            }
        }
 public static IPropertyBag2 CreateRef(this IPropertyBag2 objectRef) =>
 ((IPropertyBag2)objectRef.CreateRef(typeof(IPropertyBag2)));
예제 #13
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);
                }
            }
        }
        public void Resize(byte[] sourceBytes, Stream targetStream, uint targetMaxSize)
        {
            var factory     = (IWICComponentFactory) new WICImagingFactory();
            var inputStream = factory.CreateStream();

            inputStream.InitializeFromMemory(sourceBytes, (uint)sourceBytes.Length);
            var decoder = factory.CreateDecoderFromStream(inputStream, null, WICDecodeOptions.WICDecodeMetadataCacheOnLoad);
            var frame   = decoder.GetFrame(0);

            // Compute target size
            uint width, height, targetWidth, targetHeight;

            frame.GetSize(out width, out height);
            if (width <= targetMaxSize && height <= targetMaxSize)
            {
                targetHeight = height;
                targetWidth  = width;
            }
            else if (width > height)
            {
                targetWidth  = targetMaxSize;
                targetHeight = height * targetMaxSize / width;
            }
            else
            {
                targetWidth  = width * targetMaxSize / height;
                targetHeight = targetMaxSize;
            }

            // Prepare output stream to cache file
            var outputStreamAdapter = new StreamAdapter(targetStream);

            // Prepare JPG encoder
            var encoder = factory.CreateEncoder(Consts.GUID_ContainerFormatJpeg, null);

            encoder.Initialize(outputStreamAdapter, WICBitmapEncoderCacheOption.WICBitmapEncoderNoCache);

            // Prepare output frame
            IWICBitmapFrameEncode outputFrame;
            var argument = new IPropertyBag2[1];

            encoder.CreateNewFrame(out outputFrame, argument);
            var propBag           = argument[0];
            var propertyBagOption = new PROPBAG2[1];

            propertyBagOption[0].pstrName = ImageQualityParamName;
            propBag.Write(1, propertyBagOption, this.jpegQuality);
            outputFrame.Initialize(propBag);
            outputFrame.SetResolution(this.thumbDpi, this.thumbDpi);
            outputFrame.SetSize(targetWidth, targetHeight);

            // Prepare scaler
            var scaler = factory.CreateBitmapScaler();

            scaler.Initialize(frame, targetWidth, targetHeight, WICBitmapInterpolationMode.WICBitmapInterpolationModeLinear);

            // Write the scaled source to the output frame
            outputFrame.WriteSource(scaler, new WICRect {
                X = 0, Y = 0, Width = (int)targetWidth, Height = (int)targetHeight
            });
            outputFrame.Commit();
            encoder.Commit();
        }
예제 #15
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);
                }
            }
        }
예제 #16
0
        public static IWICBitmapFrameEncode CreateNewFrame(this IWICBitmapEncoder bitmapEncoder, out IPropertyBag2 encoderOptions)
        {
            IPropertyBag2?encoderOptionsNullable = null;

            bitmapEncoder.CreateNewFrame(out IWICBitmapFrameEncode frameEncode, ref encoderOptionsNullable);
            encoderOptions = encoderOptionsNullable !;
            return(frameEncode);
        }
예제 #17
0
파일: Utils.cs 프로젝트: eakova/resizer
        public static byte[] WicResize(IWICComponentFactory factory, IWICBitmapFrameDecode frame, int width,
            int height, int quality)
        {
            // Prepare output stream to cache file
            var outputStream = new MemoryIStream();
            // Prepare PNG encoder
            var encoder = factory.CreateEncoder(Consts.GUID_ContainerFormatJpeg, null);
            encoder.Initialize(outputStream, WICBitmapEncoderCacheOption.WICBitmapEncoderNoCache);
            // Prepare output frame
            IWICBitmapFrameEncode outputFrame;
            var arg = new IPropertyBag2[1];
            encoder.CreateNewFrame(out outputFrame, arg);
            var propBag = arg[0];
            var propertyBagOption = new PROPBAG2[1];
            propertyBagOption[0].pstrName = "ImageQuality";
            propBag.Write(1, propertyBagOption, new object[] {((float) quality)/100});
            outputFrame.Initialize(propBag);
            double dpiX, dpiY;
            frame.GetResolution(out dpiX, out dpiY);
            outputFrame.SetResolution(dpiX, dpiY);

            uint ow, oh, w, h;
            frame.GetSize(out ow, out oh);
            if (ow > oh ) {
                w = (uint)width;
                h = (uint)((double)height * (double)oh / (double)ow);
            } else {
                w = (uint)((double)height * (double)ow / (double)oh);
                h = (uint)height;
            }

            outputFrame.SetSize(w, h);
            // Prepare scaler
            var scaler = factory.CreateBitmapScaler();
            scaler.Initialize(frame, w, h, WICBitmapInterpolationMode.WICBitmapInterpolationModeFant);
            // Write the scaled source to the output frame
            outputFrame.WriteSource(scaler, new WICRect {X = 0, Y = 0, Width = (int) width, Height = (int) height});
            outputFrame.Commit();
            encoder.Commit();
            var outputArray = outputStream.ToArray();
            outputStream.Close();
            Marshal.ReleaseComObject(outputFrame);
            Marshal.ReleaseComObject(scaler);
            Marshal.ReleaseComObject(propBag);
            Marshal.ReleaseComObject(encoder);
            return outputArray;
        }
 public static void Initialize(this IWICBitmapFrameEncode bitmapFrameEncode, IPropertyBag2 pIEncoderOptions = null)
 {
     bitmapFrameEncode.Initialize(pIEncoderOptions);
 }
예제 #19
0
        public static IWICBitmapFrameEncode CreateNewFrame(this IWICBitmapEncoder bitmapEncoder, IPropertyBag2 ppIEncoderOptions = null)
        {
            IWICBitmapFrameEncode ppIFrameEncode;

            bitmapEncoder.CreateNewFrame(out ppIFrameEncode, ppIEncoderOptions);
            return(ppIFrameEncode);
        }
예제 #20
0
        protected override bool ProcessFrameDecode(MainForm form, IWICBitmapFrameDecode frame, DataEntry[] de, object tag)
        {
            Guid pixelFormatOriginal;

            frame.GetPixelFormat(out pixelFormatOriginal);

            IWICDevelopRaw raw = null;

            try
            {
                raw = (IWICDevelopRaw)frame;
                if (raw == null)
                {
                    form.Add(this, string.Format(CultureInfo.CurrentUICulture, Resources._0_NULL, "IWICBitmapFrameDecode::QueryInterface(IID_IWICDevelopRaw, ...)"), de);
                }
                else
                {
                    CheckPixelFormat(form, raw, de, pixelFormatOriginal);

                    WICRawCapabilitiesInfo capabilities = new WICRawCapabilitiesInfo();
                    capabilities.cbSize = (uint)Marshal.SizeOf(capabilities);
                    try
                    {
                        raw.QueryRawCapabilitiesInfo(ref capabilities);
                    }
                    catch (Exception e)
                    {
                        form.Add(this, e.TargetSite.ToString(Resources._0_Failed), de, new DataEntry(e));

                        return(true);
                    }
                    bool supports = false;
                    foreach (FieldInfo fi in typeof(WICRawCapabilitiesInfo).GetFields())
                    {
                        if (fi.FieldType == typeof(WICRawCapabilities) || fi.FieldType == typeof(WICRawRotationCapabilities))
                        {
                            if (!Enum.IsDefined(fi.FieldType, fi.GetValue(capabilities)))
                            {
                                form.Add(this, string.Format(CultureInfo.CurrentUICulture, Resources._0_UnexpectedFieldValue, fi.Name), de, new DataEntry(Resources.Expected, Enum.GetValues(fi.FieldType)), new DataEntry(Resources.Actual, fi.GetValue(capabilities)));
                            }
                            supports |= 0 != (uint)Convert.ChangeType(fi.GetValue(capabilities), typeof(uint));
                        }
                    }
                    if (!supports)
                    {
                        form.Add(this, Resources.DevelopRaw_NoSupportedFeatures, de);
                    }

                    CheckGetSupported <double>(form, GetSupported(capabilities.ContrastSupport), raw.GetContrast, de, 0);
                    CheckGetSupported(form, GetSupported(capabilities.DestinationColorProfileSupport), raw.GetColorContexts, de).ReleaseComObject();
                    CheckGetSupported <double>(form, GetSupported(capabilities.ExposureCompensationSupport), raw.GetExposureCompensation, de, 0);
                    CheckGetSupported <double>(form, GetSupported(capabilities.GammaSupport), raw.GetGamma, de, 1);
                    uint?kelvinWhitePoint = CheckGetSupported <uint>(form, GetSupported(capabilities.KelvinWhitePointSupport), raw.GetWhitePointKelvin, de, null);
                    WICNamedWhitePoint?namedWhitePoint = CheckGetSupported <WICNamedWhitePoint>(form, GetSupported(capabilities.NamedWhitePointSupport), raw.GetNamedWhitePoint, de, null);
                    CheckGetSupported <double>(form, GetSupported(capabilities.NoiseReductionSupport), raw.GetNoiseReduction, de, 0);
                    uint[]           rgbWhitePoint = CheckGetSupported(form, GetSupported(capabilities.RGBWhitePointSupport), raw.GetWhitePointRGB, de, null);
                    WICRawRenderMode?renderingMode = CheckGetSupported <WICRawRenderMode>(form, GetSupported(capabilities.RenderModeSupport), raw.GetRenderMode, de, WICRawRenderMode.WICRawRenderModeNormal);
                    CheckGetSupported <double>(form, GetSupported(capabilities.RotationSupport), raw.GetRotation, de, 0);
                    CheckGetSupported <double>(form, GetSupported(capabilities.SaturationSupport), raw.GetSaturation, de, 0);
                    CheckGetSupported <double>(form, GetSupported(capabilities.SharpnessSupport), raw.GetSharpness, de, 0);
                    CheckGetSupported <double>(form, GetSupported(capabilities.TintSupport), raw.GetTint, de, 0);
                    WICRawToneCurvePoint[] toneCurve = CheckGetSupported(form, GetSupported(capabilities.ToneCurveSupport), raw.GetToneCurve, de);

                    CheckSetSupported <double>(form, SetSupported(capabilities.ContrastSupport), raw.GetContrast, raw.SetContrast, raw, WICRawChangeNotification.WICRawChangeNotification_Contrast, de, pixelFormatOriginal, -1, 0, 1);
                    CheckSetSupported <double>(form, SetSupported(capabilities.ExposureCompensationSupport), raw.GetExposureCompensation, raw.SetExposureCompensation, raw, WICRawChangeNotification.WICRawChangeNotification_ExposureCompensation, de, pixelFormatOriginal, 0, -5, 5);
                    CheckSetSupported <double>(form, SetSupported(capabilities.GammaSupport), raw.GetGamma, raw.SetGamma, raw, WICRawChangeNotification.WICRawChangeNotification_Gamma, de, pixelFormatOriginal, 1, 0.2, 5);
                    CheckSetSupported <double>(form, SetSupported(capabilities.NoiseReductionSupport), raw.GetNoiseReduction, raw.SetNoiseReduction, raw, WICRawChangeNotification.WICRawChangeNotification_NoiseReduction, de, pixelFormatOriginal, 0, 1);
                    CheckSetSupported <double>(form, SetSupported(capabilities.SaturationSupport), raw.GetSaturation, raw.SetSaturation, raw, WICRawChangeNotification.WICRawChangeNotification_Saturation, de, pixelFormatOriginal, 0, -1, 1);
                    CheckSetSupported <double>(form, SetSupported(capabilities.SharpnessSupport), raw.GetSharpness, raw.SetSharpness, raw, WICRawChangeNotification.WICRawChangeNotification_Sharpness, de, pixelFormatOriginal, 0, 1);
                    CheckSetSupported <double>(form, SetSupported(capabilities.TintSupport), raw.GetTint, raw.SetTint, raw, WICRawChangeNotification.WICRawChangeNotification_Tint, de, pixelFormatOriginal, 0, -1, 1);
                    CheckSetSupported <WICRawRenderMode>(form, SetSupported(capabilities.RenderModeSupport), raw.GetRenderMode, raw.SetRenderMode, raw, WICRawChangeNotification.WICRawChangeNotification_RenderMode, de, pixelFormatOriginal, WICRawRenderMode.WICRawRenderModeDraft, WICRawRenderMode.WICRawRenderModeNormal, WICRawRenderMode.WICRawRenderModeBestQuality);

                    try
                    {
                        uint max, min, step;
                        raw.GetKelvinRangeInfo(out min, out max, out step);
                        MethodInfo mi = typeof(IWICDevelopRaw).GetMethod("GetKelvinRangeInfo");
                        if ((max < min) ||
                            (min == max && step != 0) ||
                            (min != max && (step == 0 || ((max - min) % step) != 0)))
                        {
                            ParameterInfo[] pi = mi.GetParameters();
                            form.Add(this, mi.ToString(Resources._0_NotExpectedValue), de, new DataEntry(pi[0].Name, max), new DataEntry(pi[1].Name, min), new DataEntry(pi[2].Name, step));
                        }
                        else
                        {
                            uint[] goodTemps = min == max ? new uint[] { min } : new uint[] { min, min + step, max, max - step };
                            uint[] badTemps  = step == 1 ? new uint[] { min - step, max + step } : new uint[] { min - step, max + step, min + step / 2, max - step / 2 };

                            CheckSetSupported <uint>(form, null, raw.GetWhitePointKelvin, raw.SetWhitePointKelvin, raw, WICRawChangeNotification.WICRawChangeNotification_KelvinWhitePoint, de, pixelFormatOriginal, goodTemps);
                            CheckSetSupported <uint>(form, WinCodecError.WINCODEC_ERR_VALUEOUTOFRANGE, raw.GetWhitePointKelvin, raw.SetWhitePointKelvin, raw, WICRawChangeNotification.WICRawChangeNotification_KelvinWhitePoint, de, pixelFormatOriginal, badTemps);
                        }
                    }
                    catch (Exception e)
                    {
                        form.Add(this, e.TargetSite.ToString(Resources._0_Failed), de, new DataEntry(e));
                    }

                    CheckSetDestinationColorContextSupported(form, SetSupported(capabilities.DestinationColorProfileSupport), raw, de, pixelFormatOriginal);

                    switch (capabilities.RotationSupport)
                    {
                    case WICRawRotationCapabilities.WICRawRotationCapabilityFullySupported:
                        CheckSetSupported <double>(form, null, raw.GetRotation, raw.SetRotation, raw, WICRawChangeNotification.WICRawChangeNotification_Rotation, de, pixelFormatOriginal, rotation);
                        break;

                    case WICRawRotationCapabilities.WICRawRotationCapabilityNinetyDegreesSupported:
                        CheckSetSupported <double>(form, null, raw.GetRotation, raw.SetRotation, raw, WICRawChangeNotification.WICRawChangeNotification_Rotation, de, pixelFormatOriginal, rotation90);
                        CheckSetSupported <double>(form, WinCodecError.WINCODEC_ERR_VALUEOUTOFRANGE, raw.GetRotation, raw.SetRotation, raw, WICRawChangeNotification.WICRawChangeNotification_Rotation, de, pixelFormatOriginal, rotation90);
                        break;

                    default:
                        CheckSetSupported <double>(form, WinCodecError.WINCODEC_ERR_UNSUPPORTEDOPERATION, raw.GetRotation, raw.SetRotation, raw, WICRawChangeNotification.WICRawChangeNotification_Rotation, de, pixelFormatOriginal, rotation);
                        break;
                    }

                    CheckSetNamedWhitePointSupported(form, SetSupported(capabilities.NamedWhitePointSupport), capabilities.NamedWhitePointSupportMask, raw, de, pixelFormatOriginal);
                    CheckSetRgbWhitePointSupported(form, SetSupported(capabilities.RGBWhitePointSupport), raw, de, pixelFormatOriginal);
                    CheckSetToneCurveSupported(form, SetSupported(capabilities.ToneCurveSupport), raw, de, pixelFormatOriginal);

                    foreach (WICRawParameterSet ps in Enum.GetValues(typeof(WICRawParameterSet)))
                    {
                        try
                        {
                            raw.LoadParameterSet(ps);

                            IPropertyBag2 pb = null;
                            try
                            {
                                pb = raw.GetCurrentParameterSet();
                            }
                            catch (Exception e)
                            {
                                form.Add(this, e.TargetSite.ToString(Resources._0_Failed), de, new DataEntry(e));
                            }
                            finally
                            {
                                pb.ReleaseComObject();
                            }
                        }
                        catch (Exception e)
                        {
                            form.Add(this, e.TargetSite.ToString(Resources._0_Failed), de, new DataEntry(e), new DataEntry(Resources.Value, ps));
                        }
                    }
                }
            }
            catch (InvalidCastException)
            {
                return(false);
            }

            return(true);
        }