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); }
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(); } }
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(); }
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(); } }
/// <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; } }
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); } }
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); }
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); } }
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)); }
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)));
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(); }
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 static IWICBitmapFrameEncode CreateNewFrame(this IWICBitmapEncoder bitmapEncoder, out IPropertyBag2 encoderOptions) { IPropertyBag2?encoderOptionsNullable = null; bitmapEncoder.CreateNewFrame(out IWICBitmapFrameEncode frameEncode, ref encoderOptionsNullable); encoderOptions = encoderOptionsNullable !; return(frameEncode); }
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); }
public static IWICBitmapFrameEncode CreateNewFrame(this IWICBitmapEncoder bitmapEncoder, IPropertyBag2 ppIEncoderOptions = null) { IWICBitmapFrameEncode ppIFrameEncode; bitmapEncoder.CreateNewFrame(out ppIFrameEncode, ppIEncoderOptions); return(ppIFrameEncode); }
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); }