public static void AddMetadataReader(WicProcessingContext ctx, bool basicOnly = false) { if (ctx.DecoderFrame.Frame == null) { return; } if (ctx.DecoderFrame.Frame.TryGetMetadataQueryReader(out var metareader)) { ctx.AddRef(metareader); // Exif orientation if (metareader.TryGetMetadataByName("System.Photo.Orientation", out var pv)) { #pragma warning disable 0618 // VarEnum is obsolete if (pv.UnmanagedType == VarEnum.VT_UI2) { ctx.DecoderFrame.ExifOrientation = (Orientation)Math.Min(Math.Max((ushort)Orientation.Normal, (ushort)pv.Value), (ushort)Orientation.Rotate270); } #pragma warning restore 0618 var opt = ctx.DecoderFrame.ExifOrientation.ToWicTransformOptions(); if (ctx.DecoderFrame.SupportsPlanarPipeline && opt != WICBitmapTransformOptions.WICBitmapTransformRotate0 && ctx.DecoderFrame.Frame is IWICPlanarBitmapSourceTransform ptrans) { uint pw = 1, ph = 1; var pdesc = new WICBitmapPlaneDescription[2]; var pfmts = new[] { Consts.GUID_WICPixelFormat8bppY, Consts.GUID_WICPixelFormat16bppCbCr }; ctx.DecoderFrame.SupportsPlanarPipeline = ptrans.DoesSupportTransform(ref pw, ref ph, opt, WICPlanarOptions.WICPlanarOptionsDefault, pfmts, pdesc, 2); } } if (basicOnly) { return; } // other requested properties var propdic = new Dictionary <string, PropVariant>(); foreach (string prop in ctx.Settings.MetadataNames ?? Enumerable.Empty <string>()) { if (metareader.TryGetMetadataByName(prop, out var pvar) && pvar.Value != null) { propdic[prop] = pvar; } } ctx.DecoderFrame.Metadata = propdic; } if (basicOnly) { return; } // ICC profiles //http://ninedegreesbelow.com/photography/embedded-color-space-information.html uint ccc = ctx.DecoderFrame.Frame.GetColorContextCount(); var profiles = new IWICColorContext[ccc]; var profile = default(IWICColorContext); if (ccc > 0) { for (int i = 0; i < ccc; i++) { profiles[i] = ctx.AddRef(Wic.Factory.CreateColorContext()); } ctx.DecoderFrame.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 && ctx.Source.Format.ColorRepresentation == PixelColorRepresentation.Cmyk) /* || (Context.IsGreyscale && cp.DataColorSpace == "GRAY") */)) { profile = cc; break; } } else if (cct == WICColorContextType.WICColorContextExifColorSpace && cc.GetExifColorSpace() == ExifColorSpace.AdobeRGB) { profile = cc; break; } } ctx.SourceColorContext = profile ?? (ctx.Source.Format.ColorRepresentation == PixelColorRepresentation.Cmyk ? cmykProfile.Value : null); ctx.DestColorContext = srgbProfile.Value; }
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; }