public WicPaletizer(WicTransform prev, uint colors = 256u) : base(prev) { var newFormat = Consts.GUID_WICPixelFormat8bppIndexed; if (!Context.Settings.IndexedColor || Context.PixelFormat.FormatGuid == newFormat || Context.IsGreyscale) { return; } var conv = AddRef(Wic.CreateFormatConverter()); if (!conv.CanConvert(Context.PixelFormat.FormatGuid, newFormat)) { throw new NotSupportedException("Can't convert to destination pixel format"); } var bmp = AddRef(Wic.CreateBitmapFromSource(Source, WICBitmapCreateCacheOption.WICBitmapCacheOnDemand)); var pal = AddRef(Wic.CreatePalette()); pal.InitializeFromBitmap(bmp, colors, false); Context.DestPalette = pal; conv.Initialize(bmp, newFormat, WICBitmapDitherType.WICBitmapDitherTypeErrorDiffusion, pal, 10.0, WICBitmapPaletteType.WICBitmapPaletteTypeCustom); Source = conv; Context.PixelFormat = PixelFormat.Cache[Source.GetPixelFormat()]; }
public void WriteSource(WicTransform prev) { var src = prev.Source; var iformat = src.GetPixelFormat(); var oformat = iformat; Frame.SetPixelFormat(ref oformat); if (oformat != iformat) { var pal = default(IWICPalette); var ptt = WICBitmapPaletteType.WICBitmapPaletteTypeCustom; if (PixelFormat.Cache[oformat].NumericRepresentation == PixelNumericRepresentation.Indexed) { pal = AddRef(Wic.CreatePalette()); pal.InitializePredefined(WICBitmapPaletteType.WICBitmapPaletteTypeFixedGray256, false); ptt = WICBitmapPaletteType.WICBitmapPaletteTypeFixedGray256; } var conv = AddRef(Wic.CreateFormatConverter()); conv.Initialize(src, oformat, WICBitmapDitherType.WICBitmapDitherTypeNone, pal, 0.0, ptt); src = conv; } Frame.WriteSource(src, null); Frame.Commit(); Encoder.Commit(); }
public WicMetadataReader(WicTransform prev, bool basicOnly = false) : base(prev) { if (Context.PixelFormat.NumericRepresentation == PixelNumericRepresentation.Indexed) { var pal = AddRef(Wic.CreatePalette()); Frame.CopyPalette(pal); Context.HasAlpha = pal.HasAlpha(); Context.IsGreyscale = pal.IsGrayscale(); } else { Context.HasAlpha = Context.PixelFormat.AlphaRepresentation != PixelAlphaRepresentation.None; Context.IsGreyscale = Context.PixelFormat.ColorRepresentation == PixelColorRepresentation.Grey; } #if NET46 if (Frame.TryGetMetadataQueryReader(out var metareader)) { AddRef(metareader); // Exif orientation if (metareader.TryGetMetadataByName("System.Photo.Orientation", out var ovar)) { ushort orientation = 1; if (ovar.UnmanagedType == VarEnum.VT_UI2) { orientation = (ushort)ovar.Value; } var opt = WICBitmapTransformOptions.WICBitmapTransformRotate0; if (orientation == 3 || orientation == 4) { opt = WICBitmapTransformOptions.WICBitmapTransformRotate180; } else if (orientation == 6 || orientation == 7) { opt = WICBitmapTransformOptions.WICBitmapTransformRotate90; } else if (orientation == 5 || orientation == 8) { opt = WICBitmapTransformOptions.WICBitmapTransformRotate270; } if (orientation == 2 || orientation == 4 || orientation == 5 || orientation == 7) { opt |= WICBitmapTransformOptions.WICBitmapTransformFlipHorizontal; } Context.TransformOptions = opt; } if (basicOnly) { return; } // other requested properties var propdic = new Dictionary <string, PropVariant>(); foreach (string prop in Context.Settings.MetadataNames ?? Enumerable.Empty <string>()) { if (metareader.TryGetMetadataByName(prop, out var pvar) && pvar.Value != null) { propdic[prop] = pvar; } } Context.Metadata = propdic; } #endif // ICC profiles //http://ninedegreesbelow.com/photography/embedded-color-space-information.html uint ccc = Frame.GetColorContextCount(); var profiles = new IWICColorContext[ccc]; var profile = default(IWICColorContext); if (ccc > 0) { for (int i = 0; i < ccc; i++) { profiles[i] = AddRef(Wic.CreateColorContext()); } Frame.GetColorContexts(ccc, profiles); } foreach (var cc in profiles) { var cct = cc.GetType(); if (cct == WICColorContextType.WICColorContextProfile) { uint ccs = cc.GetProfileBytes(0, null); var ccb = ArrayPool <byte> .Shared.Rent((int)ccs); cc.GetProfileBytes(ccs, ccb); var cp = new ColorProfileInfo(new ArraySegment <byte>(ccb, 0, (int)ccs)); ArrayPool <byte> .Shared.Return(ccb); // match only color profiles that match our intended use. if we have a standard sRGB profile, don't save it; we don't need to convert if (cp.IsValid && ((cp.IsDisplayRgb && !cp.IsStandardSrgb) || (cp.IsCmyk && Context.PixelFormat.ColorRepresentation == PixelColorRepresentation.Cmyk) /* || (Context.IsGreyscale && cp.DataColorSpace == "GRAY") */)) { profile = cc; break; } } else if (cct == WICColorContextType.WICColorContextExifColorSpace && cc.GetExifColorSpace() == ExifColorSpace.AdobeRGB) { profile = cc; break; } } Context.SourceColorContext = profile ?? (Context.PixelFormat.ColorRepresentation == PixelColorRepresentation.Cmyk ? cmykProfile.Value : null); Context.DestColorContext = srgbProfile.Value; }
public WicMetadataReader(WicTransform prev, bool basicOnly = false) : base(prev) { var pfi = AddRef(Wic.CreateComponentInfo(Context.PixelFormat)) as IWICPixelFormatInfo2; if (pfi.GetNumericRepresentation() == WICPixelFormatNumericRepresentation.WICPixelFormatNumericRepresentationIndexed) { var pal = AddRef(Wic.CreatePalette()); Frame.CopyPalette(pal); Context.HasAlpha = pal.HasAlpha(); Context.IsGreyscale = pal.IsGrayscale(); } else { uint chans = pfi.GetChannelCount(); bool trans = pfi.SupportsTransparency(); Context.HasAlpha = trans; Context.IsGreyscale = chans == 1u; Context.IsCmyk = (chans == 4u && !trans) || (chans == 5u && trans); } var metareader = Frame.GetMetadataQueryReaderNoThrow(); if (metareader != null) { AddRef(metareader); // Exif orientation if (metareader.HasMetadataName("System.Photo.Orientation")) { ushort orientation = 1; var ovar = new PropVariant(); metareader.GetMetadataByName("System.Photo.Orientation", ovar); if (ovar.UnmanagedType == VarEnum.VT_UI2) { orientation = (ushort)ovar.Value; } var opt = WICBitmapTransformOptions.WICBitmapTransformRotate0; if (orientation == 3 || orientation == 4) { opt = WICBitmapTransformOptions.WICBitmapTransformRotate180; } else if (orientation == 6 || orientation == 7) { opt = WICBitmapTransformOptions.WICBitmapTransformRotate90; } else if (orientation == 5 || orientation == 8) { opt = WICBitmapTransformOptions.WICBitmapTransformRotate270; } if (orientation == 2 || orientation == 4 || orientation == 5 || orientation == 7) { opt |= WICBitmapTransformOptions.WICBitmapTransformFlipHorizontal; } Context.TransformOptions = opt; } if (basicOnly) { return; } // other requested properties var propdic = new Dictionary <string, PropVariant>(); foreach (string prop in Context.Settings.MetadataNames ?? Enumerable.Empty <string>()) { if (metareader.HasMetadataName(prop)) { var pvar = new PropVariant(); metareader.GetMetadataByName(prop, pvar); if (pvar.Value != null) { propdic[prop] = pvar; } } } Context.Metadata = propdic; } // ICC profiles //http://ninedegreesbelow.com/photography/embedded-color-space-information.html uint ccc = Frame.GetColorContextCount(); var profiles = new IWICColorContext[ccc]; var profile = (IWICColorContext)null; if (ccc > 0) { for (int i = 0; i < ccc; i++) { profiles[i] = AddRef(Wic.CreateColorContext()); } Frame.GetColorContexts(ccc, profiles); } foreach (var cc in profiles) { var cct = cc.GetType(); if (cct == WICColorContextType.WICColorContextProfile) { uint ccs = cc.GetProfileBytes(0, null); var ccb = new byte[ccs]; cc.GetProfileBytes(ccs, ccb); // match only color profiles that match our intended use. if we have a standard sRGB profile, don't save it; we don't need to convert var cp = new ColorProfileInfo(ccb); if (cp.IsValid && ((cp.IsDisplayRgb && !cp.IsStandardSrgb) || (Context.IsCmyk && cp.IsCmyk) /* || (Context.IsGreyscale && cp.DataColorSpace == "GRAY") */)) { profile = cc; break; } } else if (cct == WICColorContextType.WICColorContextExifColorSpace && cc.GetExifColorSpace() == ExifColorSpace.AdobeRGB) { profile = cc; break; } } Context.SourceColorContext = profile ?? (Context.IsCmyk ? cmykProfile.Value : null); Context.DestColorContext = srgbProfile.Value; }