Example #1
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 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);
        }
Example #3
0
        /// <summary>
        /// Sets the value of the property with this name
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="value">The value.</param>
        public void Set(string name, object value)
        {
            CheckIfInitialized();
            // In order to set a property in the property bag
            // we need to convert the value to the destination type
            var previousValue = Get(name);

            value = Convert.ChangeType(value, previousValue == null?value.GetType() : previousValue.GetType());

            // Set the property
            var propbag2 = new PROPBAG2()
            {
                Name = name
            };
            var result = nativePropertyBag.Write(1, ref propbag2, value);

            result.CheckError();
            propbag2.Dispose();
        }
Example #4
0
        /// <summary>
        /// Gets the value of the property with this name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns>Value of the property</returns>
        public object Get(string name)
        {
            CheckIfInitialized();
            object value;
            var    propbag2 = new PROPBAG2()
            {
                Name = name
            };
            Result error;
            // Gets the property
            var result = nativePropertyBag.Read(1, ref propbag2, IntPtr.Zero, out value, out error);

            if (result.Failure || error.Failure)
            {
                throw new InvalidOperationException(string.Format(System.Globalization.CultureInfo.InvariantCulture, "Property with name [{0}] is not valid for this instance", name));
            }
            propbag2.Dispose();
            return(value);
        }
Example #5
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;
        }
Example #6
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);
                }
            }
        }
Example #7
0
        public WicEncoder(IStream stm, WicProcessingContext ctx)
        {
            var frame = (IWICBitmapFrameEncode)null;

            if (ctx.Settings.SaveFormat == FileFormat.Jpeg)
            {
                Encoder = AddRef(Wic.CreateEncoder(Consts.GUID_ContainerFormatJpeg, null));
                Encoder.Initialize(stm, WICBitmapEncoderCacheOption.WICBitmapEncoderNoCache);

                var bag = (IPropertyBag2)null;
                Encoder.CreateNewFrame(out frame, ref bag);
                AddRef(frame);
                AddRef(bag);

                if (ctx.Settings.JpegSubsampleMode != ChromaSubsampleMode.Default)
                {
                    var props = new PROPBAG2[] { new PROPBAG2 {
                                                     pstrName = "ImageQuality"
                                                 }, new PROPBAG2 {
                                                     pstrName = "JpegYCrCbSubsampling"
                                                 } };
                    bag.Write(2, props, new object[] { ctx.Settings.JpegQuality / 100f, (byte)ctx.Settings.JpegSubsampleMode });
                }
                else
                {
                    var props = new PROPBAG2[] { new PROPBAG2 {
                                                     pstrName = "ImageQuality"
                                                 } };
                    bag.Write(1, props, new object[] { ctx.Settings.JpegQuality / 100f });
                }

                frame.Initialize(bag);
            }
            else if (ctx.Settings.SaveFormat == FileFormat.Gif)
            {
                Encoder = AddRef(Wic.CreateEncoder(Consts.GUID_ContainerFormatGif, null));
                Encoder.Initialize(stm, WICBitmapEncoderCacheOption.WICBitmapEncoderNoCache);
                Encoder.SetPalette(ctx.DestPalette);

                Encoder.CreateNewFrame(out frame, null);
                AddRef(frame);

                frame.Initialize(null);
            }
            else if (ctx.Settings.SaveFormat == FileFormat.Bmp)
            {
                Encoder = AddRef(Wic.CreateEncoder(Consts.GUID_ContainerFormatBmp, null));
                Encoder.Initialize(stm, WICBitmapEncoderCacheOption.WICBitmapEncoderNoCache);

                var bag = (IPropertyBag2)null;
                Encoder.CreateNewFrame(out frame, ref bag);
                AddRef(frame);
                AddRef(bag);

                var props = new PROPBAG2[] { new PROPBAG2 {
                                                 pstrName = "EnableV5Header32bppBGRA"
                                             } };
                bag.Write(1, props, new object[] { ctx.PixelFormat == Consts.GUID_WICPixelFormat32bppBGRA });

                frame.Initialize(bag);
            }
            else if (ctx.Settings.SaveFormat == FileFormat.Tiff)
            {
                Encoder = AddRef(Wic.CreateEncoder(Consts.GUID_ContainerFormatTiff, null));
                Encoder.Initialize(stm, WICBitmapEncoderCacheOption.WICBitmapEncoderNoCache);

                var bag = (IPropertyBag2)null;
                Encoder.CreateNewFrame(out frame, ref bag);
                AddRef(frame);
                AddRef(bag);

                var props = new PROPBAG2[] { new PROPBAG2 {
                                                 pstrName = "TiffCompressionMethod"
                                             } };
                bag.Write(1, props, new object[] { (byte)WICTiffCompressionOption.WICTiffCompressionNone });

                frame.Initialize(bag);
            }
            else
            {
                Encoder = AddRef(Wic.CreateEncoder(Consts.GUID_ContainerFormatPng, null));
                Encoder.Initialize(stm, WICBitmapEncoderCacheOption.WICBitmapEncoderNoCache);

                Encoder.CreateNewFrame(out frame, null);
                AddRef(frame);

                frame.Initialize(null);
            }

            frame.SetResolution(96d, 96d);
            frame.SetSize(ctx.Width, ctx.Height);

            if (ctx.Settings.IndexedColor && ctx.PixelFormat == Consts.GUID_WICPixelFormat8bppIndexed)
            {
                frame.SetPalette(ctx.DestPalette);
            }

            if (ctx.Metadata?.Count > 0)
            {
                var metawriter = frame.GetMetadataQueryWriterNoThrow();
                if (metawriter != null)
                {
                    AddRef(metawriter);
                    foreach (var nv in ctx.Metadata)
                    {
                        metawriter.SetMetadataByNameNoThrow(nv.Key, nv.Value);
                    }
                }
            }

            // TODO setting
            //if (ctx.DestColorContext != null)
            //	frame.SetColorContexts(1, new IWICColorContext[] { ctx.DestColorContext });

            Frame = frame;
        }
        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();
        }
Example #9
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);
                }
            }
        }