Example #1
0
        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;
        }
Example #3
0
        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;
        }