Color.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Core / CSharp / System / Windows / Media / Color.cs / 1 / Color.cs

                            //------------------------------------------------------------------------------ 
//  Microsoft Windows Client Platform
//  Copyright (c) Microsoft Corporation, 2001, 2002, 2003
//
//  File: Color.cs 
//-----------------------------------------------------------------------------
using System; 
using System.ComponentModel; 
using System.IO;
using System.Runtime.InteropServices; 
using System.Text;
using System.Windows.Media.Imaging;
using MS.Internal;
using MS.Internal.PresentationCore; 

using SR=MS.Internal.PresentationCore.SR; 
using SRID=MS.Internal.PresentationCore.SRID; 

#pragma warning disable 1634, 1691  // suppressing PreSharp warnings 

namespace System.Windows.Media
{
    ///  
    /// Color
    /// The Color structure, composed of a private, synchronized ScRgb (IEC 61966-2-2) value 
    /// a color context, composed of an ICC profile and the native color values. 
    /// 
    [TypeConverter(typeof(ColorConverter))] 
    [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)]
    public struct Color : IFormattable, IEquatable
    {
        //----------------------------------------------------- 
        //
        //  Constructors 
        // 
        //-----------------------------------------------------
 
        #region Constructors


        /// 
        /// Color constructor based on ICC or Ashland profile context name. The returned value
        /// is opaque black. 
        /// 
        private static Color FromProfile(Uri profileUri)
        { 
            Color c1 = new Color();

            c1.context = new ColorContext(profileUri);
            c1.scRgbColor.a = 1.0f; 
            c1.scRgbColor.r = 0.0f;
            c1.scRgbColor.g = 0.0f; 
            c1.scRgbColor.b = 0.0f; 
            c1.sRgbColor.a = 255;
            c1.sRgbColor.r = 0; 
            c1.sRgbColor.g = 0;
            c1.sRgbColor.b = 0;
            if (c1.context != null)
            { 
                c1.nativeColorValue = new float[c1.context.NumChannels];
                for (int i = 0; i < c1.nativeColorValue.GetLength(0); i++) 
                { 
                    c1.nativeColorValue[i] = 0.0f;
                } 
            }

            c1.isFromScRgb = false;
 
            return c1;
        } 
 
        ///
        /// FromAValues - general constructor for multichannel color values with explicit alpha channel and color context, i.e. spectral colors 
        ///
        public static Color FromAValues(float a, float[] values, Uri profileUri)
        {
            Color c1 = Color.FromProfile(profileUri); 

            if (values == null) 
            { 
                throw new ArgumentException(SR.Get(SRID.Color_DimensionMismatch, null));
            } 

            if (values.GetLength(0) != c1.nativeColorValue.GetLength(0))
            {
                throw new ArgumentException(SR.Get(SRID.Color_DimensionMismatch, null)); 
            }
 
            for (int numChannels = 0; numChannels < values.GetLength(0); numChannels++) 
            {
                c1.nativeColorValue[numChannels] = values[numChannels]; 
            }
            c1.ComputeScRgbValues();
            c1.scRgbColor.a = a;
            if (a < 0.0f) 
            {
                a = 0.0f; 
            } 
            else if (a > 1.0f)
            { 
                a = 1.0f;
            }

            c1.sRgbColor.a = (byte)((a * 255.0f) + 0.5f); 
            c1.sRgbColor.r = ScRgbTosRgb(c1.scRgbColor.r);
            c1.sRgbColor.g = ScRgbTosRgb(c1.scRgbColor.g); 
            c1.sRgbColor.b = ScRgbTosRgb(c1.scRgbColor.b); 

            return c1; 
        }

        ///
        /// FromValues - general color constructor for multichannel color values with opaque alpha channel and explicit color context, i.e. spectral colors 
        ///
        public static Color FromValues(float[] values, Uri profileUri) 
        { 
            Color c1 = Color.FromAValues(1.0f, values, profileUri);
 
            return c1;
        }

        /// 
        /// Color - sRgb legacy interface, assumes Rgb values are sRgb
        /// 
        internal static Color FromUInt32(uint argb)// internal legacy sRGB interface 
        {
            Color c1 = new Color(); 

            c1.sRgbColor.a = (byte)((argb & 0xff000000) >> 24);
            c1.sRgbColor.r = (byte)((argb & 0x00ff0000) >> 16);
            c1.sRgbColor.g = (byte)((argb & 0x0000ff00) >> 8); 
            c1.sRgbColor.b = (byte)(argb & 0x000000ff);
            c1.scRgbColor.a = (float)c1.sRgbColor.a / 255.0f; 
            c1.scRgbColor.r = sRgbToScRgb(c1.sRgbColor.r);  // note that context is undefined and thus unloaded 
            c1.scRgbColor.g = sRgbToScRgb(c1.sRgbColor.g);
            c1.scRgbColor.b = sRgbToScRgb(c1.sRgbColor.b); 
            c1.context = null;

            c1.isFromScRgb = false;
 
            return c1;
        } 
 
        ///
        /// FromScRgb 
        ///
        public static Color FromScRgb(float a, float r, float g, float b)
        {
            Color c1 = new Color(); 

            c1.scRgbColor.r = r; 
            c1.scRgbColor.g = g; 
            c1.scRgbColor.b = b;
            c1.scRgbColor.a = a; 
            if (a < 0.0f)
            {
                a = 0.0f;
            } 
            else if (a > 1.0f)
            { 
                a = 1.0f; 
            }
 
            c1.sRgbColor.a = (byte)((a * 255.0f) + 0.5f);
            c1.sRgbColor.r = ScRgbTosRgb(c1.scRgbColor.r);
            c1.sRgbColor.g = ScRgbTosRgb(c1.scRgbColor.g);
            c1.sRgbColor.b = ScRgbTosRgb(c1.scRgbColor.b); 
            c1.context = null;
 
            c1.isFromScRgb = true; 

            return c1; 
        }

        ///
        /// Color - sRgb legacy interface, assumes Rgb values are sRgb, alpha channel is linear 1.0 gamma 
        ///
        public static Color FromArgb(byte a, byte r, byte g, byte b)// legacy sRGB interface, bytes are required to properly round trip 
        { 
            Color c1 = new Color();
 
            c1.scRgbColor.a = (float)a / 255.0f;
            c1.scRgbColor.r = sRgbToScRgb(r);  // note that context is undefined and thus unloaded
            c1.scRgbColor.g = sRgbToScRgb(g);
            c1.scRgbColor.b = sRgbToScRgb(b); 
            c1.context = null;
            c1.sRgbColor.a = a; 
            c1.sRgbColor.r = ScRgbTosRgb(c1.scRgbColor.r); 
            c1.sRgbColor.g = ScRgbTosRgb(c1.scRgbColor.g);
            c1.sRgbColor.b = ScRgbTosRgb(c1.scRgbColor.b); 

            c1.isFromScRgb = false;

            return c1; 
        }
 
        /// 
        /// Color - sRgb legacy interface, assumes Rgb values are sRgb
        /// 
        public static Color FromRgb(byte r, byte g, byte b)// legacy sRGB interface, bytes are required to properly round trip
        {
            Color c1 = Color.FromArgb(0xff, r, g, b);
            return c1; 
        }
        #endregion Constructors 
 
        //------------------------------------------------------
        // 
        //  Public Methods
        //
        //-----------------------------------------------------
 
        #region Public Methods
        /// 
        /// GetHashCode 
        ///
        public override int GetHashCode() 
        {
            return this.scRgbColor.GetHashCode(); //^this.context.GetHashCode();
        }
 
        /// 
        /// Creates a string representation of this object based on the current culture. 
        ///  
        /// 
        /// A string representation of this object. 
        /// 
        public override string ToString()
        {
            // Delegate to the internal method which implements all ToString calls. 

            string format = isFromScRgb ? c_scRgbFormat : null; 
 
            return ConvertToString(format, null);
        } 

        /// 
        /// Creates a string representation of this object based on the IFormatProvider
        /// passed in.  If the provider is null, the CurrentCulture is used. 
        /// 
        ///  
        /// A string representation of this object. 
        /// 
        public string ToString(IFormatProvider provider) 
        {
            // Delegate to the internal method which implements all ToString calls.

            string format = isFromScRgb ? c_scRgbFormat : null; 

            return ConvertToString(format, provider); 
        } 

        ///  
        /// Creates a string representation of this object based on the format string
        /// and IFormatProvider passed in.
        /// If the provider is null, the CurrentCulture is used.
        /// See the documentation for IFormattable for more information. 
        /// 
        ///  
        /// A string representation of this object. 
        /// 
        string IFormattable.ToString(string format, IFormatProvider provider) 
        {
            // Delegate to the internal method which implements all ToString calls.
            return ConvertToString(format, provider);
        } 

        ///  
        /// Creates a string representation of this object based on the format string 
        /// and IFormatProvider passed in.
        /// If the provider is null, the CurrentCulture is used. 
        /// See the documentation for IFormattable for more information.
        /// 
        /// 
        /// A string representation of this object. 
        /// 
        internal string ConvertToString(string format, IFormatProvider provider) 
        { 
            StringBuilder sb = new StringBuilder();
 
            if (context == null)
            {
                if (format == null)
                { 
                    sb.AppendFormat(provider, "#{0:X2}", this.sRgbColor.a);
                    sb.AppendFormat(provider, "{0:X2}", this.sRgbColor.r); 
                    sb.AppendFormat(provider, "{0:X2}", this.sRgbColor.g); 
                    sb.AppendFormat(provider, "{0:X2}", this.sRgbColor.b);
                } 
                else
                {
                    // Helper to get the numeric list separator for a given culture.
                    char separator = MS.Internal.TokenizerHelper.GetNumericListSeparator(provider); 

                    sb.AppendFormat(provider, 
                        "sc#{1:" + format + "}{0} {2:" + format + "}{0} {3:" + format + "}{0} {4:" + format + "}", 
                        separator, scRgbColor.a, scRgbColor.r,
                        scRgbColor.g, scRgbColor.b); 
                }
            }
            else
            { 
                char separator = MS.Internal.TokenizerHelper.GetNumericListSeparator(provider);
 
                format = c_scRgbFormat; 

                //First Stepmake sure that nothing that should not be escaped is escaped 
                Uri safeUnescapedUri = new Uri(context.ProfileUri.GetComponents(UriComponents.SerializationInfoString, UriFormat.SafeUnescaped),
                                                    context.ProfileUri.IsAbsoluteUri ? UriKind.Absolute : UriKind.Relative);
                //Second Step make sure that everything that should escaped is escaped
                String uriString = safeUnescapedUri.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped); 

                sb.AppendFormat(provider, "{0}{1} ", Parsers.s_ContextColor, uriString); 
                sb.AppendFormat(provider,"{1:" + format + "}{0}",separator,scRgbColor.a); 
                for (int i= 0; i< nativeColorValue.GetLength(0); ++i )
                { 
                    sb.AppendFormat(provider,"{0:" + format + "}",nativeColorValue[i]);
                    if (i< nativeColorValue.GetLength(0)-1 )
                    {
                        sb.AppendFormat(provider,"{0}",separator); 
                    }
                } 
            } 

            return sb.ToString(); 
        }

        /// 
        /// Compares two colors for fuzzy equality.  This function 
        /// helps compensate for the fact that float values can
        /// acquire error when operated upon 
        ///  
        /// The first color to compare
        /// The second color to compare 
        /// Whether or not the two colors are equal
        public static bool AreClose(Color color1, Color color2)
        {
            return color1.IsClose(color2); 
        }
 
        ///  
        /// Compares two colors for fuzzy equality.  This function
        /// helps compensate for the fact that float values can 
        /// acquire error when operated upon
        /// 
        /// The color to compare to this
        /// Whether or not the two colors are equal 
        private bool IsClose(Color color)
        { 
            // Alpha is the least likely channel to differ 
            bool result = true;
 
            if (context == null || color.nativeColorValue == null)
            {
                result = result && FloatUtil.AreClose(scRgbColor.r, color.scRgbColor.r);
                result = result && FloatUtil.AreClose(scRgbColor.g, color.scRgbColor.g); 
                result = result && FloatUtil.AreClose(scRgbColor.b, color.scRgbColor.b);
            } 
            else 
            {
                for (int i = 0; i < color.nativeColorValue.GetLength(0); i++) 
                    result = result && FloatUtil.AreClose(nativeColorValue[i], color.nativeColorValue[i]);
            }

            return result && FloatUtil.AreClose(scRgbColor.a, color.scRgbColor.a); 
        }
 
        /// 
        /// Clamp - the color channels to the gamut [0..1].  If a channel is out
        /// of gamut, it will be set to 1, which represents full saturation. 
        /// todo: [....] up context values if they exist
        ///
        public void Clamp()
        { 
            scRgbColor.r = (scRgbColor.r < 0) ? 0 : (scRgbColor.r > 1.0f) ? 1.0f : scRgbColor.r;
            scRgbColor.g = (scRgbColor.g < 0) ? 0 : (scRgbColor.g > 1.0f) ? 1.0f : scRgbColor.g; 
            scRgbColor.b = (scRgbColor.b < 0) ? 0 : (scRgbColor.b > 1.0f) ? 1.0f : scRgbColor.b; 
            scRgbColor.a = (scRgbColor.a < 0) ? 0 : (scRgbColor.a > 1.0f) ? 1.0f : scRgbColor.a;
            sRgbColor.a = (byte)(scRgbColor.a * 255f); 
            sRgbColor.r = ScRgbTosRgb(scRgbColor.r);
            sRgbColor.g = ScRgbTosRgb(scRgbColor.g);
            sRgbColor.b = ScRgbTosRgb(scRgbColor.b);
 
            //
        } 
 
        ///
        /// GetNativeColorValues - return color values from color context 
        ///
        public float[] GetNativeColorValues()
        {
            if (context != null) 
            {
                return (float[])nativeColorValue.Clone(); 
            } 
            else
            { 
                throw new InvalidOperationException(SR.Get(SRID.Color_NullColorContext, null));
            }
        }
        #endregion Public Methods 

        //------------------------------------------------------ 
        // 
        //  Public Operators
        // 
        //------------------------------------------------------

        #region Public Operators
        /// 
        /// Addition operator - Adds each channel of the second color to each channel of the
        /// first and returns the result 
        /// 
        public static Color operator +(Color color1, Color color2)
        { 
            if (color1.context == null && color2.context == null)
            {
            Color c1 = FromScRgb(
                  color1.scRgbColor.a + color2.scRgbColor.a, 
                  color1.scRgbColor.r + color2.scRgbColor.r,
                  color1.scRgbColor.g + color2.scRgbColor.g, 
                  color1.scRgbColor.b + color2.scRgbColor.b); 
                return c1;
            } 
            else if (color1.context == color2.context)
            {
                Color c1 = new Color();
                c1.context = color1.context; 

                #pragma warning suppress 6506 // c1.context is obviously not null - both color1.context AND color2.context are not null 
                c1.nativeColorValue = new float[c1.context.NumChannels]; 
                for (int i = 0; i < c1.nativeColorValue.GetLength(0); i++)
                { 
                    c1.nativeColorValue[i] = color1.nativeColorValue[i] + color2.nativeColorValue[i] ;
                }

                Color c2 = Color.FromRgb(0, 0, 0); 

                c2.context = new ColorContext(PixelFormats.Bgra32); 
 
                ColorTransform colorTransform = new ColorTransform(c1.context, c2.context);
                float[] sRGBValue = new float[3]; 

                colorTransform.Translate(c1.nativeColorValue, sRGBValue);

                if (sRGBValue[0] < 0.0f) 
                {
                    c1.sRgbColor.r = 0; 
                } 
                else if (sRGBValue[0] > 1.0f)
                { 
                    c1.sRgbColor.r = 255;
                }
                else
                { 
                    c1.sRgbColor.r = (byte)((sRGBValue[0] * 255.0f) + 0.5f);
                } 
 
                if (sRGBValue[1] < 0.0f)
                { 
                    c1.sRgbColor.g = 0;
                }
                else if (sRGBValue[1] > 1.0f)
                { 
                    c1.sRgbColor.g = 255;
                } 
                else 
                {
                    c1.sRgbColor.g = (byte)((sRGBValue[1] * 255.0f) + 0.5f); 
                }

                if (sRGBValue[2] < 0.0f)
                { 
                    c1.sRgbColor.b = 0;
                } 
                else if (sRGBValue[2] > 1.0f) 
                {
                    c1.sRgbColor.b = 255; 
                }
                else
                {
                    c1.sRgbColor.b = (byte)((sRGBValue[2] * 255.0f) + 0.5f); 
                }
 
                c1.scRgbColor.r = sRgbToScRgb(c1.sRgbColor.r); 
                c1.scRgbColor.g = sRgbToScRgb(c1.sRgbColor.g);
                c1.scRgbColor.b = sRgbToScRgb(c1.sRgbColor.b); 
                c1.scRgbColor.a = color1.scRgbColor.a + color2.scRgbColor.a;
                if (c1.scRgbColor.a < 0.0f)
                {
                    c1.scRgbColor.a = 0.0f; 
                    c1.sRgbColor.a = 0;
                } 
                else if (c1.scRgbColor.a > 1.0f) 
                {
                    c1.scRgbColor.a = 1.0f; 
                    c1.sRgbColor.a = 255;
                }
                else
                { 
                    c1.sRgbColor.a = (byte)((c1.scRgbColor.a * 255.0f) + 0.5f);
                } 
 
                return c1;
            } 
            else
            {
                throw new ArgumentException(SR.Get(SRID.Color_ColorContextTypeMismatch, null));
            } 
        }
 
        /// 
        /// Addition method - Adds each channel of the second color to each channel of the
        /// first and returns the result 
        ///
        public static Color Add(Color color1, Color color2)
        {
            return (color1 + color2); 
        }
 
        ///  
        /// Subtract operator - substracts each channel of the second color from each channel of the
        /// first and returns the result 
        /// 
        /// The minuend
        /// The subtrahend
        /// Returns the unclamped differnce 
        public static Color operator -(Color color1, Color color2)
        { 
            if (color1.context == null && color2.context == null) 
            {
                Color c1 = FromScRgb( 
                    color1.scRgbColor.a - color2.scRgbColor.a,
                    color1.scRgbColor.r - color2.scRgbColor.r,
                    color1.scRgbColor.g - color2.scRgbColor.g,
                    color1.scRgbColor.b - color2.scRgbColor.b 
                    );
                return c1; 
            } 
            else if (color1.context == null || color2.context == null)
            { 
                throw new ArgumentException(SR.Get(SRID.Color_ColorContextTypeMismatch, null));
            }
            else if (color1.context == color2.context)
            { 
                Color c1 = new Color();
                c1.context = color1.context; 
 
                #pragma warning suppress 6506 // c1.context is obviously not null - both color1.context AND color2.context are not null
                c1.nativeColorValue = new float[c1.context.NumChannels]; 
                for (int i = 0; i < c1.nativeColorValue.GetLength(0); i++)
                {
                    c1.nativeColorValue[i] = color1.nativeColorValue[i] - color2.nativeColorValue[i];
                } 

                Color c2 = Color.FromRgb(0, 0, 0); 
 
                c2.context = new ColorContext(PixelFormats.Bgra32);
 
                ColorTransform colorTransform = new ColorTransform(c1.context, c2.context);
                float[] sRGBValue = new float[3];

                colorTransform.Translate(c1.nativeColorValue, sRGBValue); 

                if (sRGBValue[0] < 0.0f) 
                { 
                    c1.sRgbColor.r = 0;
                } 
                else if (sRGBValue[0] > 1.0f)
                {
                    c1.sRgbColor.r = 255;
                } 
                else
                { 
                    c1.sRgbColor.r = (byte)((sRGBValue[0] * 255.0f) + 0.5f); 
                }
 
                if (sRGBValue[1] < 0.0f)
                {
                    c1.sRgbColor.g = 0;
                } 
                else if (sRGBValue[1] > 1.0f)
                { 
                    c1.sRgbColor.g = 255; 
                }
                else 
                {
                    c1.sRgbColor.g = (byte)((sRGBValue[1] * 255.0f) + 0.5f);
                }
 
                if (sRGBValue[2] < 0.0f)
                { 
                    c1.sRgbColor.b = 0; 
                }
                else if (sRGBValue[2] > 1.0f) 
                {
                    c1.sRgbColor.b = 255;
                }
                else 
                {
                    c1.sRgbColor.b = (byte)((sRGBValue[2] * 255.0f) + 0.5f); 
                } 

                c1.scRgbColor.r = sRgbToScRgb(c1.sRgbColor.r); 
                c1.scRgbColor.g = sRgbToScRgb(c1.sRgbColor.g);
                c1.scRgbColor.b = sRgbToScRgb(c1.sRgbColor.b);
                c1.scRgbColor.a = color1.scRgbColor.a - color2.scRgbColor.a;
                if (c1.scRgbColor.a < 0.0f) 
                {
                    c1.scRgbColor.a = 0.0f; 
                    c1.sRgbColor.a = 0; 
                }
                else if (c1.scRgbColor.a > 1.0f) 
                {
                    c1.scRgbColor.a = 1.0f;
                    c1.sRgbColor.a = 255;
                } 
                else
                { 
                    c1.sRgbColor.a = (byte)((c1.scRgbColor.a * 255.0f) + 0.5f); 
                }
 
                return c1;
            }
            else
            { 
                throw new ArgumentException(SR.Get(SRID.Color_ColorContextTypeMismatch, null));
            } 
        } 

        /// 
        /// Subtract method - subtracts each channel of the second color from each channel of the
        /// first and returns the result
        ///
        public static Color Subtract(Color color1, Color color2) 
        {
            return (color1 - color2); 
        } 

        ///  
        /// Multiplication operator - Multiplies each channel of the color by a coefficient and returns the result
        /// 
        /// The color
        /// The coefficient 
        /// Returns the unclamped product
        public static Color operator *(Color color, float coefficient) 
        { 
            Color c1 = FromScRgb(color.scRgbColor.a * coefficient, color.scRgbColor.r * coefficient, color.scRgbColor.g * coefficient, color.scRgbColor.b * coefficient);
 
            if (color.context == null)
            {
                return c1;
            } 
            else
            { 
                c1.context = color.context; 

                #pragma warning suppress 6506 // c1.context is obviously not null 
                c1.ComputeNativeValues(c1.context.NumChannels);
            }

            return c1; 
        }
 
        /// 
        /// Multiplication method - Multiplies each channel of the color by a coefficient and returns the result
        /// 
        public static Color Multiply(Color color, float coefficient)
        {
            return (color * coefficient);
        } 

        /// 
        /// Equality method for two colors - return true of colors are equal, otherwise returns false 
        ///
        public static bool Equals(Color color1, Color color2) 
        {
            return (color1 == color2);
        }
 
        /// 
        /// Compares two colors for exact equality.  Note that float values can acquire error 
        /// when operated upon, such that an exact comparison between two values which are logically 
        /// equal may fail. see cref="AreClose" for a "fuzzy" version of this comparison.
        ///  
        /// The color to compare to "this"
        /// Whether or not the two colors are equal
        public bool Equals(Color color)
        { 
            return this == color;
        } 
 
        /// 
        /// Compares two colors for exact equality.  Note that float values can acquire error 
        /// when operated upon, such that an exact comparison between two vEquals(color);alues which are logically
        /// equal may fail. see cref="AreClose" for a "fuzzy" version of this comparison.
        /// 
        /// The object to compare to "this" 
        /// Whether or not the two colors are equal
        public override bool Equals(object o) 
        { 
            if (o is Color)
            { 
                Color color = (Color)o;

                return (this == color);
            } 
            else
            { 
                return false; 
            }
        } 

       ///
        /// IsEqual operator - Compares two colors for exact equality.  Note that float values can acquire error
        /// when operated upon, such that an exact comparison between two values which are logically 
        /// equal may fail. see cref="AreClose".
        /// 
        public static bool operator ==(Color color1, Color color2) 
        {
            if (color1.context == null && color2.context == null) 
            {
                if (color1.scRgbColor.r != color2.scRgbColor.r)
                {
                    return false; 
                }
 
                if (color1.scRgbColor.g != color2.scRgbColor.g) 
                {
                    return false; 
                }

                if (color1.scRgbColor.b != color2.scRgbColor.b)
                { 
                    return false;
                } 
 
                if (color1.scRgbColor.a != color2.scRgbColor.a)
                { 
                    return false;
                }

                return true; 
            }
            else if (color1.context == null || color2.context == null) 
            { 
                return false;
            } 
            else if (color1.context.ColorSpaceFamily == color2.context.ColorSpaceFamily)
            {
                if (color1.nativeColorValue == null && color2.nativeColorValue == null)
                { 
                    return true;
                } 
 
                if (color1.nativeColorValue == null || color2.nativeColorValue == null)
                { 
                    return false;
                }

                if (color1.nativeColorValue.GetLength(0) != color2.nativeColorValue.GetLength(0)) 
                {
                    return false; 
                } 

                for (int i = 0; i < color1.nativeColorValue.GetLength(0); i++) 
                {
                    if (color1.nativeColorValue[i] != color2.nativeColorValue[i])
                    {
                        return false; 
                    }
                } 
 
                if (color1.scRgbColor.a != color2.scRgbColor.a)
                { 
                    return false;
                }

                return true; 
            }
 
            return false; 
        }
 
        ///
        /// !=
        ///
        public static bool operator !=(Color color1, Color color2) 
        {
            return (!(color1 == color2)); 
        } 
        #endregion Public Operators
 
        //-----------------------------------------------------
        //
        //  Public Properties
        // 
        //------------------------------------------------------
 
        #region Public Properties 

        /// 
        /// ColorContext
        ///
        public ColorContext ColorContext
        { 
            get
            { 
                return context; 
            }
        } 

        ///
        /// A
        /// 
        public byte A
        { 
            get 
            {
                return sRgbColor.a; 
            }
            set
            {
                scRgbColor.a = (float)value / 255.0f; 
                sRgbColor.a = value;
            } 
        } 

        /// The Red channel as a byte whose range is [0..255]. 
        /// the value is not allowed to be out of range
        /// 
        /// R
        ///  
        public byte R
        { 
            get 
            {
                return sRgbColor.r; 
            }
            set
            {
                if (context == null || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.Srgb) || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.ScRgb)) 
                {
                    scRgbColor.r = sRgbToScRgb(value); 
                    sRgbColor.r = value; 
                }
                else 
                {
                    throw new InvalidOperationException(SR.Get(SRID.Color_ColorContextNotsRGB_or_scRGB, null));
                }
            } 
        }
 
        ///The Green channel as a byte whose range is [0..255]. 
        /// the value is not allowed to be out of range
        /// G 
        ///
        public byte G
        {
            get 
            {
                return sRgbColor.g; 
            } 
            set
            { 
                if (context == null || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.Srgb) || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.ScRgb))
                {
                    scRgbColor.g = sRgbToScRgb(value);
                    sRgbColor.g = value; 
                }
                else 
                { 
                    throw new InvalidOperationException(SR.Get(SRID.Color_ColorContextNotsRGB_or_scRGB, null));
                } 
            }
        }

        ///The Blue channel as a byte whose range is [0..255]. 
        /// the value is not allowed to be out of range
        /// B 
        /// 
        public byte B
        { 
            get
            {
                return sRgbColor.b;
            } 
            set
            { 
                if (context == null || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.Srgb) || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.ScRgb)) 
                {
                    scRgbColor.b = sRgbToScRgb(value); 
                    sRgbColor.b = value;
                }
                else
                { 
                    throw new InvalidOperationException(SR.Get(SRID.Color_ColorContextNotsRGB_or_scRGB, null));
                } 
            } 
        }
 
        ///The Alpha channel as a float whose range is [0..1].
        /// the value is allowed to be out of range
        /// ScA
        /// 
        public float ScA
        { 
            get 
            {
                return scRgbColor.a; 
            }
            set
            {
                scRgbColor.a = value; 
                if (value < 0.0f)
                { 
                    sRgbColor.a = 0; 
                }
                else if (value > 1.0f) 
                {
                    sRgbColor.a = (byte)255;
                }
                else 
                {
                    sRgbColor.a = (byte)(value * 255f); 
                } 
            }
        } 

        ///The Red channel as a float whose range is [0..1].
        /// the value is allowed to be out of range
        /// 
        /// ScR
        /// 
        public float ScR 
        {
            get 
            {
                return scRgbColor.r;
                // throw new ArgumentException(SR.Get(SRID.Color_ColorContextNotsRgb_or_ScRgb, null));
            } 
            set
            { 
                if (context == null || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.Srgb) || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.ScRgb)) 
                {
                    scRgbColor.r = value; 
                    sRgbColor.r = ScRgbTosRgb(value);
                }
                else
                { 
                    throw new InvalidOperationException(SR.Get(SRID.Color_ColorContextNotsRGB_or_scRGB, null));
                } 
            } 
        }
 
        ///The Green channel as a float whose range is [0..1].
        /// the value is allowed to be out of range
        /// ScG
        /// 
        public float ScG
        { 
            get 
            {
                return scRgbColor.g; 
                // throw new ArgumentException(SR.Get(SRID.Color_ColorContextNotsRgb_or_ScRgb, null));
            }
            set
            { 
                if (context == null || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.Srgb) || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.ScRgb))
                { 
                    scRgbColor.g = value; 
                    sRgbColor.g = ScRgbTosRgb(value);
                } 
                else
                {
                    throw new InvalidOperationException(SR.Get(SRID.Color_ColorContextNotsRGB_or_scRGB, null));
                } 
            }
        } 
 
        ///The Blue channel as a float whose range is [0..1].
        /// the value is allowed to be out of range 
        /// ScB
        ///
        public float ScB
        { 
            get
            { 
                return scRgbColor.b; 
                // throw new ArgumentException(SR.Get(SRID.Color_ColorContextNotsRgb_or_ScRgb, null));
            } 
            set
            {
                if (context == null || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.Srgb) || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.ScRgb))
                { 
                    scRgbColor.b = value;
                    sRgbColor.b = ScRgbTosRgb(value); 
                } 
                else
                { 
                    throw new InvalidOperationException(SR.Get(SRID.Color_ColorContextNotsRGB_or_scRGB, null));
                }
            }
        } 

        #endregion Public Properties 
 
        //-----------------------------------------------------
        // 
        //  Public Events
        //
        //-----------------------------------------------------
        //----------------------------------------------------- 
        //
        //  Public Events 
        // 
        //------------------------------------------------------
        //----------------------------------------------------- 
        //
        //  Protected Methods
        //
        //------------------------------------------------------ 
        //------------------------------------------------------
        // 
        //  Internal Properties 
        //
        //----------------------------------------------------- 
        //------------------------------------------------------
        //
        //  Internal Events
        // 
        //-----------------------------------------------------
        //----------------------------------------------------- 
        // 
        //  Internal Methods
        // 
        //-----------------------------------------------------
        //------------------------------------------------------
        //
        //  Private Methods 
        //
        //----------------------------------------------------- 
        #region Private Methods 

        /// 
        /// private helper function to set context values from a color value with a set context and ScRgb values
        ///
        private static float sRgbToScRgb(byte bval)
        { 
            float val = ((float)bval / 255.0f);
 
            if (!(val > 0.0))       // Handles NaN case too. (Though, NaN isn't actually 
                                    // possible in this case.)
            { 
                return (0.0f);
            }
            else if (val <= 0.04045)
            { 
                return (val / 12.92f);
            } 
            else if (val < 1.0f) 
            {
                return (float)Math.Pow(((double)val + 0.055) / 1.055, 2.4); 
            }
            else
            {
                return (1.0f); 
            }
        } 
 
        ///
        /// private helper function to set context values from a color value with a set context and ScRgb values 
        ///
        ///
        private static byte ScRgbTosRgb(float val)
        { 
            if (!(val > 0.0))       // Handles NaN case too
            { 
                return (0); 
            }
            else if (val <= 0.0031308) 
            {
                return ((byte)((255.0f * val * 12.92f) + 0.5f));
            }
            else if (val < 1.0) 
            {
                return ((byte)((255.0f * ((1.055f * (float)Math.Pow((double)val, (1.0 / 2.4))) - 0.055f)) + 0.5f)); 
            } 
            else
            { 
                return (255);
            }
        }
 
        ///
        /// private helper function to set context values from a color value with a set context and ScRgb values 
        /// 
        ///
        private void ComputeScRgbValues() 
        {
            if (this.context != null)
            {
                Color c2 = Color.FromRgb(0, 0, 0); 

                c2.context = new ColorContext(PixelFormats.Bgra32); 
 
                ColorTransform colorTransform = new ColorTransform(this.context, c2.context);
                float[] scRGBValue = new float[3]; 

                colorTransform.Translate(this.nativeColorValue, scRGBValue);

                this.scRgbColor.r = sRgbToScRgb((byte)((255.0f * scRGBValue[0]) + 0.5f)); 
                this.scRgbColor.g = sRgbToScRgb((byte)((255.0f * scRGBValue[1]) + 0.5f));
                this.scRgbColor.b = sRgbToScRgb((byte)((255.0f * scRGBValue[2]) + 0.5f)); 
            } 
        }
 
        private void ComputeNativeValues(int numChannels)
        {
            this.nativeColorValue = new float[numChannels];
            if (this.nativeColorValue.GetLength(0) > 0) 
            {
                float[] sRGBValue = new float[3]; 
 
                sRGBValue[0] = this.sRgbColor.r / 255.0f;
                sRGBValue[1] = this.sRgbColor.g / 255.0f; 
                sRGBValue[2] = this.sRgbColor.b / 255.0f;

                ColorTransform colorTransform = new ColorTransform(this.context, new ColorContext(PixelFormats.Bgra32));
 
                colorTransform.Translate(sRGBValue, this.nativeColorValue);
            } 
        } 

        #endregion Private Methods 

        //------------------------------------------------------
        //
        //  Private Properties 
        //
        //------------------------------------------------------ 
        //----------------------------------------------------- 
        //
        //  Private Events 
        //
        //------------------------------------------------------
        //-----------------------------------------------------
        // 
        //  Private Fields
        // 
        //----------------------------------------------------- 

        #region Private Fields 

        [MarshalAs(UnmanagedType.Interface)]
        ColorContext context;
 
        private struct MILColorF // this structure is the "milrendertypes.h" structure and should be identical for performance
        { 
            public float a, r, g, b; 
        };
 
        private MILColorF scRgbColor;

        private struct MILColor
        { 
            public byte a, r, g, b;
        } 
 
        private MILColor sRgbColor;
 
        private float[] nativeColorValue;

        private bool isFromScRgb;
 
        private const string c_scRgbFormat = "R";
 
        #endregion Private Fields 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------ 
//  Microsoft Windows Client Platform
//  Copyright (c) Microsoft Corporation, 2001, 2002, 2003
//
//  File: Color.cs 
//-----------------------------------------------------------------------------
using System; 
using System.ComponentModel; 
using System.IO;
using System.Runtime.InteropServices; 
using System.Text;
using System.Windows.Media.Imaging;
using MS.Internal;
using MS.Internal.PresentationCore; 

using SR=MS.Internal.PresentationCore.SR; 
using SRID=MS.Internal.PresentationCore.SRID; 

#pragma warning disable 1634, 1691  // suppressing PreSharp warnings 

namespace System.Windows.Media
{
    ///  
    /// Color
    /// The Color structure, composed of a private, synchronized ScRgb (IEC 61966-2-2) value 
    /// a color context, composed of an ICC profile and the native color values. 
    /// 
    [TypeConverter(typeof(ColorConverter))] 
    [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)]
    public struct Color : IFormattable, IEquatable
    {
        //----------------------------------------------------- 
        //
        //  Constructors 
        // 
        //-----------------------------------------------------
 
        #region Constructors


        /// 
        /// Color constructor based on ICC or Ashland profile context name. The returned value
        /// is opaque black. 
        /// 
        private static Color FromProfile(Uri profileUri)
        { 
            Color c1 = new Color();

            c1.context = new ColorContext(profileUri);
            c1.scRgbColor.a = 1.0f; 
            c1.scRgbColor.r = 0.0f;
            c1.scRgbColor.g = 0.0f; 
            c1.scRgbColor.b = 0.0f; 
            c1.sRgbColor.a = 255;
            c1.sRgbColor.r = 0; 
            c1.sRgbColor.g = 0;
            c1.sRgbColor.b = 0;
            if (c1.context != null)
            { 
                c1.nativeColorValue = new float[c1.context.NumChannels];
                for (int i = 0; i < c1.nativeColorValue.GetLength(0); i++) 
                { 
                    c1.nativeColorValue[i] = 0.0f;
                } 
            }

            c1.isFromScRgb = false;
 
            return c1;
        } 
 
        ///
        /// FromAValues - general constructor for multichannel color values with explicit alpha channel and color context, i.e. spectral colors 
        ///
        public static Color FromAValues(float a, float[] values, Uri profileUri)
        {
            Color c1 = Color.FromProfile(profileUri); 

            if (values == null) 
            { 
                throw new ArgumentException(SR.Get(SRID.Color_DimensionMismatch, null));
            } 

            if (values.GetLength(0) != c1.nativeColorValue.GetLength(0))
            {
                throw new ArgumentException(SR.Get(SRID.Color_DimensionMismatch, null)); 
            }
 
            for (int numChannels = 0; numChannels < values.GetLength(0); numChannels++) 
            {
                c1.nativeColorValue[numChannels] = values[numChannels]; 
            }
            c1.ComputeScRgbValues();
            c1.scRgbColor.a = a;
            if (a < 0.0f) 
            {
                a = 0.0f; 
            } 
            else if (a > 1.0f)
            { 
                a = 1.0f;
            }

            c1.sRgbColor.a = (byte)((a * 255.0f) + 0.5f); 
            c1.sRgbColor.r = ScRgbTosRgb(c1.scRgbColor.r);
            c1.sRgbColor.g = ScRgbTosRgb(c1.scRgbColor.g); 
            c1.sRgbColor.b = ScRgbTosRgb(c1.scRgbColor.b); 

            return c1; 
        }

        ///
        /// FromValues - general color constructor for multichannel color values with opaque alpha channel and explicit color context, i.e. spectral colors 
        ///
        public static Color FromValues(float[] values, Uri profileUri) 
        { 
            Color c1 = Color.FromAValues(1.0f, values, profileUri);
 
            return c1;
        }

        /// 
        /// Color - sRgb legacy interface, assumes Rgb values are sRgb
        /// 
        internal static Color FromUInt32(uint argb)// internal legacy sRGB interface 
        {
            Color c1 = new Color(); 

            c1.sRgbColor.a = (byte)((argb & 0xff000000) >> 24);
            c1.sRgbColor.r = (byte)((argb & 0x00ff0000) >> 16);
            c1.sRgbColor.g = (byte)((argb & 0x0000ff00) >> 8); 
            c1.sRgbColor.b = (byte)(argb & 0x000000ff);
            c1.scRgbColor.a = (float)c1.sRgbColor.a / 255.0f; 
            c1.scRgbColor.r = sRgbToScRgb(c1.sRgbColor.r);  // note that context is undefined and thus unloaded 
            c1.scRgbColor.g = sRgbToScRgb(c1.sRgbColor.g);
            c1.scRgbColor.b = sRgbToScRgb(c1.sRgbColor.b); 
            c1.context = null;

            c1.isFromScRgb = false;
 
            return c1;
        } 
 
        ///
        /// FromScRgb 
        ///
        public static Color FromScRgb(float a, float r, float g, float b)
        {
            Color c1 = new Color(); 

            c1.scRgbColor.r = r; 
            c1.scRgbColor.g = g; 
            c1.scRgbColor.b = b;
            c1.scRgbColor.a = a; 
            if (a < 0.0f)
            {
                a = 0.0f;
            } 
            else if (a > 1.0f)
            { 
                a = 1.0f; 
            }
 
            c1.sRgbColor.a = (byte)((a * 255.0f) + 0.5f);
            c1.sRgbColor.r = ScRgbTosRgb(c1.scRgbColor.r);
            c1.sRgbColor.g = ScRgbTosRgb(c1.scRgbColor.g);
            c1.sRgbColor.b = ScRgbTosRgb(c1.scRgbColor.b); 
            c1.context = null;
 
            c1.isFromScRgb = true; 

            return c1; 
        }

        ///
        /// Color - sRgb legacy interface, assumes Rgb values are sRgb, alpha channel is linear 1.0 gamma 
        ///
        public static Color FromArgb(byte a, byte r, byte g, byte b)// legacy sRGB interface, bytes are required to properly round trip 
        { 
            Color c1 = new Color();
 
            c1.scRgbColor.a = (float)a / 255.0f;
            c1.scRgbColor.r = sRgbToScRgb(r);  // note that context is undefined and thus unloaded
            c1.scRgbColor.g = sRgbToScRgb(g);
            c1.scRgbColor.b = sRgbToScRgb(b); 
            c1.context = null;
            c1.sRgbColor.a = a; 
            c1.sRgbColor.r = ScRgbTosRgb(c1.scRgbColor.r); 
            c1.sRgbColor.g = ScRgbTosRgb(c1.scRgbColor.g);
            c1.sRgbColor.b = ScRgbTosRgb(c1.scRgbColor.b); 

            c1.isFromScRgb = false;

            return c1; 
        }
 
        /// 
        /// Color - sRgb legacy interface, assumes Rgb values are sRgb
        /// 
        public static Color FromRgb(byte r, byte g, byte b)// legacy sRGB interface, bytes are required to properly round trip
        {
            Color c1 = Color.FromArgb(0xff, r, g, b);
            return c1; 
        }
        #endregion Constructors 
 
        //------------------------------------------------------
        // 
        //  Public Methods
        //
        //-----------------------------------------------------
 
        #region Public Methods
        /// 
        /// GetHashCode 
        ///
        public override int GetHashCode() 
        {
            return this.scRgbColor.GetHashCode(); //^this.context.GetHashCode();
        }
 
        /// 
        /// Creates a string representation of this object based on the current culture. 
        ///  
        /// 
        /// A string representation of this object. 
        /// 
        public override string ToString()
        {
            // Delegate to the internal method which implements all ToString calls. 

            string format = isFromScRgb ? c_scRgbFormat : null; 
 
            return ConvertToString(format, null);
        } 

        /// 
        /// Creates a string representation of this object based on the IFormatProvider
        /// passed in.  If the provider is null, the CurrentCulture is used. 
        /// 
        ///  
        /// A string representation of this object. 
        /// 
        public string ToString(IFormatProvider provider) 
        {
            // Delegate to the internal method which implements all ToString calls.

            string format = isFromScRgb ? c_scRgbFormat : null; 

            return ConvertToString(format, provider); 
        } 

        ///  
        /// Creates a string representation of this object based on the format string
        /// and IFormatProvider passed in.
        /// If the provider is null, the CurrentCulture is used.
        /// See the documentation for IFormattable for more information. 
        /// 
        ///  
        /// A string representation of this object. 
        /// 
        string IFormattable.ToString(string format, IFormatProvider provider) 
        {
            // Delegate to the internal method which implements all ToString calls.
            return ConvertToString(format, provider);
        } 

        ///  
        /// Creates a string representation of this object based on the format string 
        /// and IFormatProvider passed in.
        /// If the provider is null, the CurrentCulture is used. 
        /// See the documentation for IFormattable for more information.
        /// 
        /// 
        /// A string representation of this object. 
        /// 
        internal string ConvertToString(string format, IFormatProvider provider) 
        { 
            StringBuilder sb = new StringBuilder();
 
            if (context == null)
            {
                if (format == null)
                { 
                    sb.AppendFormat(provider, "#{0:X2}", this.sRgbColor.a);
                    sb.AppendFormat(provider, "{0:X2}", this.sRgbColor.r); 
                    sb.AppendFormat(provider, "{0:X2}", this.sRgbColor.g); 
                    sb.AppendFormat(provider, "{0:X2}", this.sRgbColor.b);
                } 
                else
                {
                    // Helper to get the numeric list separator for a given culture.
                    char separator = MS.Internal.TokenizerHelper.GetNumericListSeparator(provider); 

                    sb.AppendFormat(provider, 
                        "sc#{1:" + format + "}{0} {2:" + format + "}{0} {3:" + format + "}{0} {4:" + format + "}", 
                        separator, scRgbColor.a, scRgbColor.r,
                        scRgbColor.g, scRgbColor.b); 
                }
            }
            else
            { 
                char separator = MS.Internal.TokenizerHelper.GetNumericListSeparator(provider);
 
                format = c_scRgbFormat; 

                //First Stepmake sure that nothing that should not be escaped is escaped 
                Uri safeUnescapedUri = new Uri(context.ProfileUri.GetComponents(UriComponents.SerializationInfoString, UriFormat.SafeUnescaped),
                                                    context.ProfileUri.IsAbsoluteUri ? UriKind.Absolute : UriKind.Relative);
                //Second Step make sure that everything that should escaped is escaped
                String uriString = safeUnescapedUri.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped); 

                sb.AppendFormat(provider, "{0}{1} ", Parsers.s_ContextColor, uriString); 
                sb.AppendFormat(provider,"{1:" + format + "}{0}",separator,scRgbColor.a); 
                for (int i= 0; i< nativeColorValue.GetLength(0); ++i )
                { 
                    sb.AppendFormat(provider,"{0:" + format + "}",nativeColorValue[i]);
                    if (i< nativeColorValue.GetLength(0)-1 )
                    {
                        sb.AppendFormat(provider,"{0}",separator); 
                    }
                } 
            } 

            return sb.ToString(); 
        }

        /// 
        /// Compares two colors for fuzzy equality.  This function 
        /// helps compensate for the fact that float values can
        /// acquire error when operated upon 
        ///  
        /// The first color to compare
        /// The second color to compare 
        /// Whether or not the two colors are equal
        public static bool AreClose(Color color1, Color color2)
        {
            return color1.IsClose(color2); 
        }
 
        ///  
        /// Compares two colors for fuzzy equality.  This function
        /// helps compensate for the fact that float values can 
        /// acquire error when operated upon
        /// 
        /// The color to compare to this
        /// Whether or not the two colors are equal 
        private bool IsClose(Color color)
        { 
            // Alpha is the least likely channel to differ 
            bool result = true;
 
            if (context == null || color.nativeColorValue == null)
            {
                result = result && FloatUtil.AreClose(scRgbColor.r, color.scRgbColor.r);
                result = result && FloatUtil.AreClose(scRgbColor.g, color.scRgbColor.g); 
                result = result && FloatUtil.AreClose(scRgbColor.b, color.scRgbColor.b);
            } 
            else 
            {
                for (int i = 0; i < color.nativeColorValue.GetLength(0); i++) 
                    result = result && FloatUtil.AreClose(nativeColorValue[i], color.nativeColorValue[i]);
            }

            return result && FloatUtil.AreClose(scRgbColor.a, color.scRgbColor.a); 
        }
 
        /// 
        /// Clamp - the color channels to the gamut [0..1].  If a channel is out
        /// of gamut, it will be set to 1, which represents full saturation. 
        /// todo: [....] up context values if they exist
        ///
        public void Clamp()
        { 
            scRgbColor.r = (scRgbColor.r < 0) ? 0 : (scRgbColor.r > 1.0f) ? 1.0f : scRgbColor.r;
            scRgbColor.g = (scRgbColor.g < 0) ? 0 : (scRgbColor.g > 1.0f) ? 1.0f : scRgbColor.g; 
            scRgbColor.b = (scRgbColor.b < 0) ? 0 : (scRgbColor.b > 1.0f) ? 1.0f : scRgbColor.b; 
            scRgbColor.a = (scRgbColor.a < 0) ? 0 : (scRgbColor.a > 1.0f) ? 1.0f : scRgbColor.a;
            sRgbColor.a = (byte)(scRgbColor.a * 255f); 
            sRgbColor.r = ScRgbTosRgb(scRgbColor.r);
            sRgbColor.g = ScRgbTosRgb(scRgbColor.g);
            sRgbColor.b = ScRgbTosRgb(scRgbColor.b);
 
            //
        } 
 
        ///
        /// GetNativeColorValues - return color values from color context 
        ///
        public float[] GetNativeColorValues()
        {
            if (context != null) 
            {
                return (float[])nativeColorValue.Clone(); 
            } 
            else
            { 
                throw new InvalidOperationException(SR.Get(SRID.Color_NullColorContext, null));
            }
        }
        #endregion Public Methods 

        //------------------------------------------------------ 
        // 
        //  Public Operators
        // 
        //------------------------------------------------------

        #region Public Operators
        /// 
        /// Addition operator - Adds each channel of the second color to each channel of the
        /// first and returns the result 
        /// 
        public static Color operator +(Color color1, Color color2)
        { 
            if (color1.context == null && color2.context == null)
            {
            Color c1 = FromScRgb(
                  color1.scRgbColor.a + color2.scRgbColor.a, 
                  color1.scRgbColor.r + color2.scRgbColor.r,
                  color1.scRgbColor.g + color2.scRgbColor.g, 
                  color1.scRgbColor.b + color2.scRgbColor.b); 
                return c1;
            } 
            else if (color1.context == color2.context)
            {
                Color c1 = new Color();
                c1.context = color1.context; 

                #pragma warning suppress 6506 // c1.context is obviously not null - both color1.context AND color2.context are not null 
                c1.nativeColorValue = new float[c1.context.NumChannels]; 
                for (int i = 0; i < c1.nativeColorValue.GetLength(0); i++)
                { 
                    c1.nativeColorValue[i] = color1.nativeColorValue[i] + color2.nativeColorValue[i] ;
                }

                Color c2 = Color.FromRgb(0, 0, 0); 

                c2.context = new ColorContext(PixelFormats.Bgra32); 
 
                ColorTransform colorTransform = new ColorTransform(c1.context, c2.context);
                float[] sRGBValue = new float[3]; 

                colorTransform.Translate(c1.nativeColorValue, sRGBValue);

                if (sRGBValue[0] < 0.0f) 
                {
                    c1.sRgbColor.r = 0; 
                } 
                else if (sRGBValue[0] > 1.0f)
                { 
                    c1.sRgbColor.r = 255;
                }
                else
                { 
                    c1.sRgbColor.r = (byte)((sRGBValue[0] * 255.0f) + 0.5f);
                } 
 
                if (sRGBValue[1] < 0.0f)
                { 
                    c1.sRgbColor.g = 0;
                }
                else if (sRGBValue[1] > 1.0f)
                { 
                    c1.sRgbColor.g = 255;
                } 
                else 
                {
                    c1.sRgbColor.g = (byte)((sRGBValue[1] * 255.0f) + 0.5f); 
                }

                if (sRGBValue[2] < 0.0f)
                { 
                    c1.sRgbColor.b = 0;
                } 
                else if (sRGBValue[2] > 1.0f) 
                {
                    c1.sRgbColor.b = 255; 
                }
                else
                {
                    c1.sRgbColor.b = (byte)((sRGBValue[2] * 255.0f) + 0.5f); 
                }
 
                c1.scRgbColor.r = sRgbToScRgb(c1.sRgbColor.r); 
                c1.scRgbColor.g = sRgbToScRgb(c1.sRgbColor.g);
                c1.scRgbColor.b = sRgbToScRgb(c1.sRgbColor.b); 
                c1.scRgbColor.a = color1.scRgbColor.a + color2.scRgbColor.a;
                if (c1.scRgbColor.a < 0.0f)
                {
                    c1.scRgbColor.a = 0.0f; 
                    c1.sRgbColor.a = 0;
                } 
                else if (c1.scRgbColor.a > 1.0f) 
                {
                    c1.scRgbColor.a = 1.0f; 
                    c1.sRgbColor.a = 255;
                }
                else
                { 
                    c1.sRgbColor.a = (byte)((c1.scRgbColor.a * 255.0f) + 0.5f);
                } 
 
                return c1;
            } 
            else
            {
                throw new ArgumentException(SR.Get(SRID.Color_ColorContextTypeMismatch, null));
            } 
        }
 
        /// 
        /// Addition method - Adds each channel of the second color to each channel of the
        /// first and returns the result 
        ///
        public static Color Add(Color color1, Color color2)
        {
            return (color1 + color2); 
        }
 
        ///  
        /// Subtract operator - substracts each channel of the second color from each channel of the
        /// first and returns the result 
        /// 
        /// The minuend
        /// The subtrahend
        /// Returns the unclamped differnce 
        public static Color operator -(Color color1, Color color2)
        { 
            if (color1.context == null && color2.context == null) 
            {
                Color c1 = FromScRgb( 
                    color1.scRgbColor.a - color2.scRgbColor.a,
                    color1.scRgbColor.r - color2.scRgbColor.r,
                    color1.scRgbColor.g - color2.scRgbColor.g,
                    color1.scRgbColor.b - color2.scRgbColor.b 
                    );
                return c1; 
            } 
            else if (color1.context == null || color2.context == null)
            { 
                throw new ArgumentException(SR.Get(SRID.Color_ColorContextTypeMismatch, null));
            }
            else if (color1.context == color2.context)
            { 
                Color c1 = new Color();
                c1.context = color1.context; 
 
                #pragma warning suppress 6506 // c1.context is obviously not null - both color1.context AND color2.context are not null
                c1.nativeColorValue = new float[c1.context.NumChannels]; 
                for (int i = 0; i < c1.nativeColorValue.GetLength(0); i++)
                {
                    c1.nativeColorValue[i] = color1.nativeColorValue[i] - color2.nativeColorValue[i];
                } 

                Color c2 = Color.FromRgb(0, 0, 0); 
 
                c2.context = new ColorContext(PixelFormats.Bgra32);
 
                ColorTransform colorTransform = new ColorTransform(c1.context, c2.context);
                float[] sRGBValue = new float[3];

                colorTransform.Translate(c1.nativeColorValue, sRGBValue); 

                if (sRGBValue[0] < 0.0f) 
                { 
                    c1.sRgbColor.r = 0;
                } 
                else if (sRGBValue[0] > 1.0f)
                {
                    c1.sRgbColor.r = 255;
                } 
                else
                { 
                    c1.sRgbColor.r = (byte)((sRGBValue[0] * 255.0f) + 0.5f); 
                }
 
                if (sRGBValue[1] < 0.0f)
                {
                    c1.sRgbColor.g = 0;
                } 
                else if (sRGBValue[1] > 1.0f)
                { 
                    c1.sRgbColor.g = 255; 
                }
                else 
                {
                    c1.sRgbColor.g = (byte)((sRGBValue[1] * 255.0f) + 0.5f);
                }
 
                if (sRGBValue[2] < 0.0f)
                { 
                    c1.sRgbColor.b = 0; 
                }
                else if (sRGBValue[2] > 1.0f) 
                {
                    c1.sRgbColor.b = 255;
                }
                else 
                {
                    c1.sRgbColor.b = (byte)((sRGBValue[2] * 255.0f) + 0.5f); 
                } 

                c1.scRgbColor.r = sRgbToScRgb(c1.sRgbColor.r); 
                c1.scRgbColor.g = sRgbToScRgb(c1.sRgbColor.g);
                c1.scRgbColor.b = sRgbToScRgb(c1.sRgbColor.b);
                c1.scRgbColor.a = color1.scRgbColor.a - color2.scRgbColor.a;
                if (c1.scRgbColor.a < 0.0f) 
                {
                    c1.scRgbColor.a = 0.0f; 
                    c1.sRgbColor.a = 0; 
                }
                else if (c1.scRgbColor.a > 1.0f) 
                {
                    c1.scRgbColor.a = 1.0f;
                    c1.sRgbColor.a = 255;
                } 
                else
                { 
                    c1.sRgbColor.a = (byte)((c1.scRgbColor.a * 255.0f) + 0.5f); 
                }
 
                return c1;
            }
            else
            { 
                throw new ArgumentException(SR.Get(SRID.Color_ColorContextTypeMismatch, null));
            } 
        } 

        /// 
        /// Subtract method - subtracts each channel of the second color from each channel of the
        /// first and returns the result
        ///
        public static Color Subtract(Color color1, Color color2) 
        {
            return (color1 - color2); 
        } 

        ///  
        /// Multiplication operator - Multiplies each channel of the color by a coefficient and returns the result
        /// 
        /// The color
        /// The coefficient 
        /// Returns the unclamped product
        public static Color operator *(Color color, float coefficient) 
        { 
            Color c1 = FromScRgb(color.scRgbColor.a * coefficient, color.scRgbColor.r * coefficient, color.scRgbColor.g * coefficient, color.scRgbColor.b * coefficient);
 
            if (color.context == null)
            {
                return c1;
            } 
            else
            { 
                c1.context = color.context; 

                #pragma warning suppress 6506 // c1.context is obviously not null 
                c1.ComputeNativeValues(c1.context.NumChannels);
            }

            return c1; 
        }
 
        /// 
        /// Multiplication method - Multiplies each channel of the color by a coefficient and returns the result
        /// 
        public static Color Multiply(Color color, float coefficient)
        {
            return (color * coefficient);
        } 

        /// 
        /// Equality method for two colors - return true of colors are equal, otherwise returns false 
        ///
        public static bool Equals(Color color1, Color color2) 
        {
            return (color1 == color2);
        }
 
        /// 
        /// Compares two colors for exact equality.  Note that float values can acquire error 
        /// when operated upon, such that an exact comparison between two values which are logically 
        /// equal may fail. see cref="AreClose" for a "fuzzy" version of this comparison.
        ///  
        /// The color to compare to "this"
        /// Whether or not the two colors are equal
        public bool Equals(Color color)
        { 
            return this == color;
        } 
 
        /// 
        /// Compares two colors for exact equality.  Note that float values can acquire error 
        /// when operated upon, such that an exact comparison between two vEquals(color);alues which are logically
        /// equal may fail. see cref="AreClose" for a "fuzzy" version of this comparison.
        /// 
        /// The object to compare to "this" 
        /// Whether or not the two colors are equal
        public override bool Equals(object o) 
        { 
            if (o is Color)
            { 
                Color color = (Color)o;

                return (this == color);
            } 
            else
            { 
                return false; 
            }
        } 

       ///
        /// IsEqual operator - Compares two colors for exact equality.  Note that float values can acquire error
        /// when operated upon, such that an exact comparison between two values which are logically 
        /// equal may fail. see cref="AreClose".
        /// 
        public static bool operator ==(Color color1, Color color2) 
        {
            if (color1.context == null && color2.context == null) 
            {
                if (color1.scRgbColor.r != color2.scRgbColor.r)
                {
                    return false; 
                }
 
                if (color1.scRgbColor.g != color2.scRgbColor.g) 
                {
                    return false; 
                }

                if (color1.scRgbColor.b != color2.scRgbColor.b)
                { 
                    return false;
                } 
 
                if (color1.scRgbColor.a != color2.scRgbColor.a)
                { 
                    return false;
                }

                return true; 
            }
            else if (color1.context == null || color2.context == null) 
            { 
                return false;
            } 
            else if (color1.context.ColorSpaceFamily == color2.context.ColorSpaceFamily)
            {
                if (color1.nativeColorValue == null && color2.nativeColorValue == null)
                { 
                    return true;
                } 
 
                if (color1.nativeColorValue == null || color2.nativeColorValue == null)
                { 
                    return false;
                }

                if (color1.nativeColorValue.GetLength(0) != color2.nativeColorValue.GetLength(0)) 
                {
                    return false; 
                } 

                for (int i = 0; i < color1.nativeColorValue.GetLength(0); i++) 
                {
                    if (color1.nativeColorValue[i] != color2.nativeColorValue[i])
                    {
                        return false; 
                    }
                } 
 
                if (color1.scRgbColor.a != color2.scRgbColor.a)
                { 
                    return false;
                }

                return true; 
            }
 
            return false; 
        }
 
        ///
        /// !=
        ///
        public static bool operator !=(Color color1, Color color2) 
        {
            return (!(color1 == color2)); 
        } 
        #endregion Public Operators
 
        //-----------------------------------------------------
        //
        //  Public Properties
        // 
        //------------------------------------------------------
 
        #region Public Properties 

        /// 
        /// ColorContext
        ///
        public ColorContext ColorContext
        { 
            get
            { 
                return context; 
            }
        } 

        ///
        /// A
        /// 
        public byte A
        { 
            get 
            {
                return sRgbColor.a; 
            }
            set
            {
                scRgbColor.a = (float)value / 255.0f; 
                sRgbColor.a = value;
            } 
        } 

        /// The Red channel as a byte whose range is [0..255]. 
        /// the value is not allowed to be out of range
        /// 
        /// R
        ///  
        public byte R
        { 
            get 
            {
                return sRgbColor.r; 
            }
            set
            {
                if (context == null || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.Srgb) || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.ScRgb)) 
                {
                    scRgbColor.r = sRgbToScRgb(value); 
                    sRgbColor.r = value; 
                }
                else 
                {
                    throw new InvalidOperationException(SR.Get(SRID.Color_ColorContextNotsRGB_or_scRGB, null));
                }
            } 
        }
 
        ///The Green channel as a byte whose range is [0..255]. 
        /// the value is not allowed to be out of range
        /// G 
        ///
        public byte G
        {
            get 
            {
                return sRgbColor.g; 
            } 
            set
            { 
                if (context == null || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.Srgb) || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.ScRgb))
                {
                    scRgbColor.g = sRgbToScRgb(value);
                    sRgbColor.g = value; 
                }
                else 
                { 
                    throw new InvalidOperationException(SR.Get(SRID.Color_ColorContextNotsRGB_or_scRGB, null));
                } 
            }
        }

        ///The Blue channel as a byte whose range is [0..255]. 
        /// the value is not allowed to be out of range
        /// B 
        /// 
        public byte B
        { 
            get
            {
                return sRgbColor.b;
            } 
            set
            { 
                if (context == null || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.Srgb) || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.ScRgb)) 
                {
                    scRgbColor.b = sRgbToScRgb(value); 
                    sRgbColor.b = value;
                }
                else
                { 
                    throw new InvalidOperationException(SR.Get(SRID.Color_ColorContextNotsRGB_or_scRGB, null));
                } 
            } 
        }
 
        ///The Alpha channel as a float whose range is [0..1].
        /// the value is allowed to be out of range
        /// ScA
        /// 
        public float ScA
        { 
            get 
            {
                return scRgbColor.a; 
            }
            set
            {
                scRgbColor.a = value; 
                if (value < 0.0f)
                { 
                    sRgbColor.a = 0; 
                }
                else if (value > 1.0f) 
                {
                    sRgbColor.a = (byte)255;
                }
                else 
                {
                    sRgbColor.a = (byte)(value * 255f); 
                } 
            }
        } 

        ///The Red channel as a float whose range is [0..1].
        /// the value is allowed to be out of range
        /// 
        /// ScR
        /// 
        public float ScR 
        {
            get 
            {
                return scRgbColor.r;
                // throw new ArgumentException(SR.Get(SRID.Color_ColorContextNotsRgb_or_ScRgb, null));
            } 
            set
            { 
                if (context == null || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.Srgb) || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.ScRgb)) 
                {
                    scRgbColor.r = value; 
                    sRgbColor.r = ScRgbTosRgb(value);
                }
                else
                { 
                    throw new InvalidOperationException(SR.Get(SRID.Color_ColorContextNotsRGB_or_scRGB, null));
                } 
            } 
        }
 
        ///The Green channel as a float whose range is [0..1].
        /// the value is allowed to be out of range
        /// ScG
        /// 
        public float ScG
        { 
            get 
            {
                return scRgbColor.g; 
                // throw new ArgumentException(SR.Get(SRID.Color_ColorContextNotsRgb_or_ScRgb, null));
            }
            set
            { 
                if (context == null || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.Srgb) || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.ScRgb))
                { 
                    scRgbColor.g = value; 
                    sRgbColor.g = ScRgbTosRgb(value);
                } 
                else
                {
                    throw new InvalidOperationException(SR.Get(SRID.Color_ColorContextNotsRGB_or_scRGB, null));
                } 
            }
        } 
 
        ///The Blue channel as a float whose range is [0..1].
        /// the value is allowed to be out of range 
        /// ScB
        ///
        public float ScB
        { 
            get
            { 
                return scRgbColor.b; 
                // throw new ArgumentException(SR.Get(SRID.Color_ColorContextNotsRgb_or_ScRgb, null));
            } 
            set
            {
                if (context == null || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.Srgb) || (context.ColorSpaceFamily == ColorContext.StandardColorSpace.ScRgb))
                { 
                    scRgbColor.b = value;
                    sRgbColor.b = ScRgbTosRgb(value); 
                } 
                else
                { 
                    throw new InvalidOperationException(SR.Get(SRID.Color_ColorContextNotsRGB_or_scRGB, null));
                }
            }
        } 

        #endregion Public Properties 
 
        //-----------------------------------------------------
        // 
        //  Public Events
        //
        //-----------------------------------------------------
        //----------------------------------------------------- 
        //
        //  Public Events 
        // 
        //------------------------------------------------------
        //----------------------------------------------------- 
        //
        //  Protected Methods
        //
        //------------------------------------------------------ 
        //------------------------------------------------------
        // 
        //  Internal Properties 
        //
        //----------------------------------------------------- 
        //------------------------------------------------------
        //
        //  Internal Events
        // 
        //-----------------------------------------------------
        //----------------------------------------------------- 
        // 
        //  Internal Methods
        // 
        //-----------------------------------------------------
        //------------------------------------------------------
        //
        //  Private Methods 
        //
        //----------------------------------------------------- 
        #region Private Methods 

        /// 
        /// private helper function to set context values from a color value with a set context and ScRgb values
        ///
        private static float sRgbToScRgb(byte bval)
        { 
            float val = ((float)bval / 255.0f);
 
            if (!(val > 0.0))       // Handles NaN case too. (Though, NaN isn't actually 
                                    // possible in this case.)
            { 
                return (0.0f);
            }
            else if (val <= 0.04045)
            { 
                return (val / 12.92f);
            } 
            else if (val < 1.0f) 
            {
                return (float)Math.Pow(((double)val + 0.055) / 1.055, 2.4); 
            }
            else
            {
                return (1.0f); 
            }
        } 
 
        ///
        /// private helper function to set context values from a color value with a set context and ScRgb values 
        ///
        ///
        private static byte ScRgbTosRgb(float val)
        { 
            if (!(val > 0.0))       // Handles NaN case too
            { 
                return (0); 
            }
            else if (val <= 0.0031308) 
            {
                return ((byte)((255.0f * val * 12.92f) + 0.5f));
            }
            else if (val < 1.0) 
            {
                return ((byte)((255.0f * ((1.055f * (float)Math.Pow((double)val, (1.0 / 2.4))) - 0.055f)) + 0.5f)); 
            } 
            else
            { 
                return (255);
            }
        }
 
        ///
        /// private helper function to set context values from a color value with a set context and ScRgb values 
        /// 
        ///
        private void ComputeScRgbValues() 
        {
            if (this.context != null)
            {
                Color c2 = Color.FromRgb(0, 0, 0); 

                c2.context = new ColorContext(PixelFormats.Bgra32); 
 
                ColorTransform colorTransform = new ColorTransform(this.context, c2.context);
                float[] scRGBValue = new float[3]; 

                colorTransform.Translate(this.nativeColorValue, scRGBValue);

                this.scRgbColor.r = sRgbToScRgb((byte)((255.0f * scRGBValue[0]) + 0.5f)); 
                this.scRgbColor.g = sRgbToScRgb((byte)((255.0f * scRGBValue[1]) + 0.5f));
                this.scRgbColor.b = sRgbToScRgb((byte)((255.0f * scRGBValue[2]) + 0.5f)); 
            } 
        }
 
        private void ComputeNativeValues(int numChannels)
        {
            this.nativeColorValue = new float[numChannels];
            if (this.nativeColorValue.GetLength(0) > 0) 
            {
                float[] sRGBValue = new float[3]; 
 
                sRGBValue[0] = this.sRgbColor.r / 255.0f;
                sRGBValue[1] = this.sRgbColor.g / 255.0f; 
                sRGBValue[2] = this.sRgbColor.b / 255.0f;

                ColorTransform colorTransform = new ColorTransform(this.context, new ColorContext(PixelFormats.Bgra32));
 
                colorTransform.Translate(sRGBValue, this.nativeColorValue);
            } 
        } 

        #endregion Private Methods 

        //------------------------------------------------------
        //
        //  Private Properties 
        //
        //------------------------------------------------------ 
        //----------------------------------------------------- 
        //
        //  Private Events 
        //
        //------------------------------------------------------
        //-----------------------------------------------------
        // 
        //  Private Fields
        // 
        //----------------------------------------------------- 

        #region Private Fields 

        [MarshalAs(UnmanagedType.Interface)]
        ColorContext context;
 
        private struct MILColorF // this structure is the "milrendertypes.h" structure and should be identical for performance
        { 
            public float a, r, g, b; 
        };
 
        private MILColorF scRgbColor;

        private struct MILColor
        { 
            public byte a, r, g, b;
        } 
 
        private MILColor sRgbColor;
 
        private float[] nativeColorValue;

        private bool isFromScRgb;
 
        private const string c_scRgbFormat = "R";
 
        #endregion Private Fields 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK