Пример #1
0
        /// <summary>
        /// Attempts to find the TIFF "PhotometricInterpretation" metadata
        /// </summary>
        /// <param name="_Meta"></param>
        /// <param name="_MetaPath"></param>
        /// <returns>True if gamma was specified</returns>
        protected bool FindPhotometricInterpretation( BitmapMetadata _Meta, string _MetaPath )
        {
            bool	bGammaWasSpecified = false;
            EnumerateMetaData( _Meta,
                new MetaDataProcessor( _MetaPath, ( object v ) =>
                {
                    int	PhotometricInterpretation = -1;
                    if ( v is string )
                    {
                        if ( !int.TryParse( v as string, out PhotometricInterpretation ) )
                            throw new Exception( "Invalid string for TIFF Photometric Interpretation !" );
                    }
                    else if ( v is ushort )
                        PhotometricInterpretation = (ushort) v;

                    switch ( PhotometricInterpretation )
                    {
                        case 0:	// Grayscale
                        case 1:
                            m_GammaCurve = GAMMA_CURVE.STANDARD;
                            m_Gamma = 1.0f;
                            bGammaWasSpecified = true;
                            break;

                        case 2:	// NTSC RGB
                            m_GammaCurve = GAMMA_CURVE.STANDARD;
                            m_Gamma = 2.2f;
                            bGammaWasSpecified = true;
                            break;

                        default:
                            // According to the spec (page 117), a value of 6 is a YCrCb image while a value of 8 is a L*a*b* image
                            // SHould we handle this in case of ???
                            throw new Exception( "TODO: Handle TIFF special photometric interpretation !" );
                    }
                } ) );

            return bGammaWasSpecified;
        }
Пример #2
0
        /// <summary>
        /// Build from a standard profile
        /// </summary>
        /// <param name="_Profile"></param>
        public ColorProfile( STANDARD_PROFILE _Profile )
        {
            switch ( _Profile )
            {
                case STANDARD_PROFILE.LINEAR:
                    m_Chromaticities = Chromaticities.sRGB;
                    m_GammaCurve = GAMMA_CURVE.STANDARD;
                    m_Gamma = 1.0f;
                    break;
                case STANDARD_PROFILE.sRGB:
                    m_Chromaticities = Chromaticities.sRGB;
                    m_GammaCurve = GAMMA_CURVE.sRGB;
                    m_Gamma = GAMMA_EXPONENT_sRGB;
                    break;
                case STANDARD_PROFILE.ADOBE_RGB_D50:
                    m_Chromaticities = Chromaticities.AdobeRGB_D50;
                    m_GammaCurve = GAMMA_CURVE.STANDARD;
                    m_Gamma = GAMMA_EXPONENT_ADOBE;
                    break;
                case STANDARD_PROFILE.ADOBE_RGB_D65:
                    m_Chromaticities = Chromaticities.AdobeRGB_D65;
                    m_GammaCurve = GAMMA_CURVE.STANDARD;
                    m_Gamma = GAMMA_EXPONENT_ADOBE;
                    break;
                case STANDARD_PROFILE.PRO_PHOTO:
                    m_Chromaticities = Chromaticities.ProPhoto;
                    m_GammaCurve = GAMMA_CURVE.PRO_PHOTO;
                    m_Gamma = GAMMA_EXPONENT_PRO_PHOTO;
                    break;
                case STANDARD_PROFILE.RADIANCE:
                    m_Chromaticities = Chromaticities.Radiance;
                    m_GammaCurve = GAMMA_CURVE.STANDARD;
                    m_Gamma = 1.0f;
                    break;
                default:
                    throw new Exception( "Unsupported standard profile!" );
            }

            BuildTransformFromChroma( true );
        }
Пример #3
0
        protected void EnumerateMetaDataPNG( BitmapMetadata _MetaData, out bool _bProfileFound, out bool _bGammaWasSpecified )
        {
            bool	bGammaWasSpecified = false;
            bool	bProfileFound = false;

            EnumerateMetaData( _MetaData,
                // Read chromaticities
                new MetaDataProcessor( "/cHRM", ( object v ) =>
                {
                    BitmapMetadata	ChromaData = v as BitmapMetadata;

                    Chromaticities	TempChroma = Chromaticities.Empty;
                    EnumerateMetaData( ChromaData,
                        new MetaDataProcessor( "/RedX",			( object v2 ) => { TempChroma.R.x = 0.00001f * (uint) v2; } ),
                        new MetaDataProcessor( "/RedY",			( object v2 ) => { TempChroma.R.y = 0.00001f * (uint) v2; } ),
                        new MetaDataProcessor( "/GreenX",		( object v2 ) => { TempChroma.G.x = 0.00001f * (uint) v2; } ),
                        new MetaDataProcessor( "/GreenY",		( object v2 ) => { TempChroma.G.y = 0.00001f * (uint) v2; } ),
                        new MetaDataProcessor( "/BlueX",		( object v2 ) => { TempChroma.B.x = 0.00001f * (uint) v2; } ),
                        new MetaDataProcessor( "/BlueY",		( object v2 ) => { TempChroma.B.y = 0.00001f * (uint) v2; } ),
                        new MetaDataProcessor( "/WhitePointX",	( object v2 ) => { TempChroma.W.x = 0.00001f * (uint) v2; } ),
                        new MetaDataProcessor( "/WhitePointY",	( object v2 ) => { TempChroma.W.y = 0.00001f * (uint) v2; } )
                        );

                    if ( TempChroma.RecognizedChromaticity != STANDARD_PROFILE.INVALID )
                    {	// Assign new chroma values
                        m_Chromaticities = TempChroma;
                        bProfileFound = true;
                    }
                } ),

                // Read gamma
                new MetaDataProcessor( "/gAMA/ImageGamma", ( object v ) => {
                    m_GammaCurve = GAMMA_CURVE.STANDARD; m_Gamma = 1.0f / (0.00001f * (uint) v); bGammaWasSpecified = true;
                } ),

                // Read explicit sRGB
                new MetaDataProcessor( "/sRGB/RenderingIntent", ( object v ) => {
                    m_Chromaticities = Chromaticities.sRGB; bProfileFound = true; bGammaWasSpecified = false;
                } ),

                // Read string profile from iTXT
                new MetaDataProcessor( "/iTXt/TextEntry", ( object v ) =>
                {
                    if ( bProfileFound )
                        return;	// No need...

                    // Hack content !
                    string	XMLContent = v as string;

                    string	ICCProfile = FindAttribute( XMLContent, "photoshop:ICCProfile" );
                    if ( ICCProfile != null && (bProfileFound = HandleICCProfileString( ICCProfile )) )
                        return;

                    string	ColorSpace = FindAttribute( XMLContent, "exif:ColorSpace" );
                    if ( ColorSpace != null )
                        bProfileFound = HandleEXIFColorSpace( ColorSpace );
                } )
                );

            _bGammaWasSpecified = bGammaWasSpecified;
            _bProfileFound = bProfileFound;
        }
Пример #4
0
 /// <summary>
 /// Ensures the current gamma curve type and value are the ones we want
 /// </summary>
 /// <param name="_Curve"></param>
 /// <param name="_Gamma"></param>
 /// <returns></returns>
 protected bool EnsureGamma( GAMMA_CURVE _Curve, float _Gamma )
 {
     return m_GammaCurve == _Curve && Math.Abs( _Gamma - m_Gamma ) < 1e-3f;
 }
Пример #5
0
        /// <summary>
        /// Builds the RGB<->XYZ transforms from chromaticities
        /// (refer to http://wiki.nuaj.net/index.php/Color_Transforms#XYZ_Matrices for explanations)
        /// </summary>
        protected void BuildTransformFromChroma( bool _bCheckGammaCurveOverride )
        {
            float3	xyz_R = new float3( m_Chromaticities.R.x, m_Chromaticities.R.y, 1.0f - m_Chromaticities.R.x - m_Chromaticities.R.y );
            float3	xyz_G = new float3( m_Chromaticities.G.x, m_Chromaticities.G.y, 1.0f - m_Chromaticities.G.x - m_Chromaticities.G.y );
            float3	xyz_B = new float3( m_Chromaticities.B.x, m_Chromaticities.B.y, 1.0f - m_Chromaticities.B.x - m_Chromaticities.B.y );
            float3	XYZ_W = xyY2XYZ( new float3( m_Chromaticities.W.x, m_Chromaticities.W.y, 1.0f ) );

            float4x4	M_xyz = new float4x4() {
                row0 = new float4( xyz_R, 0.0f ),
                row1 = new float4( xyz_G, 0.0f ),
                row2 = new float4( xyz_B, 0.0f ),
                row3 = new float4( 0.0f, 0.0f, 0.0f, 1.0f )
            };

            M_xyz.Invert();

            float4	Sum_RGB = new float4( XYZ_W, 1.0f ) * M_xyz;

            // Finally, we can retrieve the RGB->XYZ transform
            m_RGB2XYZ.row0 = new float4( Sum_RGB.x * xyz_R, 0.0f );
            m_RGB2XYZ.row1 = new float4( Sum_RGB.y * xyz_G, 0.0f );
            m_RGB2XYZ.row2 = new float4( Sum_RGB.z * xyz_B, 0.0f );

            // And the XYZ->RGB transform
            m_XYZ2RGB = m_RGB2XYZ;
            m_XYZ2RGB.Invert();

            // ============= Attempt to recognize a standard profile =============
            STANDARD_PROFILE	RecognizedChromaticity = m_Chromaticities.RecognizedChromaticity;

            if ( _bCheckGammaCurveOverride )
            {	// Also ensure the gamma ramp is correct before assigning a standard profile
                bool	bIsGammaCorrect = true;
                switch ( RecognizedChromaticity )
                {
                    case STANDARD_PROFILE.sRGB:				bIsGammaCorrect = EnsureGamma( GAMMA_CURVE.sRGB, GAMMA_EXPONENT_sRGB ); break;
                    case STANDARD_PROFILE.ADOBE_RGB_D50:	bIsGammaCorrect = EnsureGamma( GAMMA_CURVE.STANDARD, GAMMA_EXPONENT_ADOBE ); break;
                    case STANDARD_PROFILE.ADOBE_RGB_D65:	bIsGammaCorrect = EnsureGamma( GAMMA_CURVE.STANDARD, GAMMA_EXPONENT_ADOBE ); break;
                    case STANDARD_PROFILE.PRO_PHOTO:		bIsGammaCorrect = EnsureGamma( GAMMA_CURVE.PRO_PHOTO, GAMMA_EXPONENT_PRO_PHOTO ); break;
                    case STANDARD_PROFILE.RADIANCE:			bIsGammaCorrect = EnsureGamma( GAMMA_CURVE.STANDARD, 1.0f ); break;
                }

                if ( !bIsGammaCorrect )
                    RecognizedChromaticity = STANDARD_PROFILE.CUSTOM;	// A non-standard gamma curves fails our pre-defined design...
            }

            // ============= Assign the internal converter depending on the profile =============
            switch ( RecognizedChromaticity )
            {
                case STANDARD_PROFILE.sRGB:
                    m_GammaCurve = GAMMA_CURVE.sRGB;
                    m_Gamma = GAMMA_EXPONENT_sRGB;
                    m_InternalConverter = new InternalColorConverter_sRGB();
                    break;

                case STANDARD_PROFILE.ADOBE_RGB_D50:
                    m_GammaCurve = GAMMA_CURVE.STANDARD;
                    m_Gamma = GAMMA_EXPONENT_ADOBE;
                    m_InternalConverter = new InternalColorConverter_AdobeRGB_D50();
                    break;

                case STANDARD_PROFILE.ADOBE_RGB_D65:
                    m_GammaCurve = GAMMA_CURVE.STANDARD;
                    m_Gamma = GAMMA_EXPONENT_ADOBE;
                    m_InternalConverter = new InternalColorConverter_AdobeRGB_D65();
                    break;

                case STANDARD_PROFILE.PRO_PHOTO:
                    m_GammaCurve = GAMMA_CURVE.PRO_PHOTO;
                    m_Gamma = GAMMA_EXPONENT_PRO_PHOTO;
                    m_InternalConverter = new InternalColorConverter_ProPhoto();
                    break;

                case STANDARD_PROFILE.RADIANCE:
                    m_GammaCurve = GAMMA_CURVE.STANDARD;
                    m_Gamma = 1.0f;
                    m_InternalConverter = new InternalColorConverter_Radiance();
                    break;

                default:	// Switch to one of our generic converters
                    switch ( m_GammaCurve )
                    {
                        case GAMMA_CURVE.sRGB:
                            m_InternalConverter = new InternalColorConverter_Generic_sRGBGamma( m_RGB2XYZ, m_XYZ2RGB );
                            break;
                        case GAMMA_CURVE.PRO_PHOTO:
                            m_InternalConverter = new InternalColorConverter_Generic_ProPhoto( m_RGB2XYZ, m_XYZ2RGB );
                            break;
                        case GAMMA_CURVE.STANDARD:
                            if ( Math.Abs( m_Gamma - 1.0f ) < 1e-3f )
                                m_InternalConverter = new InternalColorConverter_Generic_NoGamma( m_RGB2XYZ, m_XYZ2RGB );
                            else
                                m_InternalConverter = new InternalColorConverter_Generic_StandardGamma( m_RGB2XYZ, m_XYZ2RGB, m_Gamma );
                            break;
                    }
                    break;
            }
        }
Пример #6
0
        /// <summary>
        /// Creates a color profile from chromaticities
        /// </summary>
        /// <param name="_Chromaticities">The chromaticities for this profile</param>
        /// <param name="_GammaCurve">The type of gamma curve to use</param>
        /// <param name="_Gamma">The gamma power</param>
        public ColorProfile( Chromaticities _Chromaticities, GAMMA_CURVE _GammaCurve, float _Gamma )
        {
            m_Chromaticities = _Chromaticities;
            m_GammaCurve = _GammaCurve;
            m_Gamma = _Gamma;

            BuildTransformFromChroma( true );
        }
Пример #7
0
        /// <summary>
        /// Creates the color profile from metadata embedded in the image file
        /// </summary>
        /// <param name="_MetaData"></param>
        /// <param name="_FileType"></param>
        public ColorProfile( BitmapMetadata _MetaData, Bitmap.FILE_TYPE _FileType )
        {
            string	MetaDump = _MetaData != null ? DumpMetaData( _MetaData ) : null;

            bool	bGammaFoundInFile = false;
            switch ( _FileType ) {
                case Bitmap.FILE_TYPE.JPEG:
                    m_GammaCurve = GAMMA_CURVE.STANDARD;
                    m_Gamma = 2.2f;							// JPG uses a 2.2 gamma by default
                    m_Chromaticities = Chromaticities.sRGB;	// Default for JPEGs is sRGB
                    EnumerateMetaDataJPG( _MetaData, out m_bProfileFoundInFile, out bGammaFoundInFile );

                    if ( !m_bProfileFoundInFile && !bGammaFoundInFile )
                        bGammaFoundInFile = true;			// Unless specified otherwise, we override the gamma no matter what since JPEGs use a 2.2 gamma by default anyway
                    break;

                case Bitmap.FILE_TYPE.PNG:
                    m_GammaCurve = GAMMA_CURVE.sRGB;
                    m_Gamma = GAMMA_EXPONENT_sRGB;
                    m_Chromaticities = Chromaticities.sRGB;	// Default for PNGs is standard sRGB
                    EnumerateMetaDataPNG( _MetaData, out m_bProfileFoundInFile, out bGammaFoundInFile );
                    break;

                case Bitmap.FILE_TYPE.TIFF:
                    m_GammaCurve = GAMMA_CURVE.STANDARD;
                    m_Gamma = 1.0f;							// Linear gamma by default
                    m_Chromaticities = Chromaticities.sRGB;	// Default for TIFFs is sRGB
                    EnumerateMetaDataTIFF( _MetaData, out m_bProfileFoundInFile, out bGammaFoundInFile );
                    break;

                case Bitmap.FILE_TYPE.GIF:
                    m_GammaCurve = GAMMA_CURVE.STANDARD;
                    m_Gamma = 1.0f;
                    m_Chromaticities = Chromaticities.sRGB;	// Default for GIFs is standard sRGB with no gamma
                    break;

                case Bitmap.FILE_TYPE.BMP:	// BMP Don't have metadata!
                    m_GammaCurve = GAMMA_CURVE.STANDARD;
                    m_Gamma = 1.0f;
                    m_Chromaticities = Chromaticities.sRGB;	// Default for BMPs is standard sRGB with no gamma
                    break;

                case Bitmap.FILE_TYPE.CRW:	// Raw files have no correction
                case Bitmap.FILE_TYPE.CR2:
                case Bitmap.FILE_TYPE.DNG:
                    m_GammaCurve = GAMMA_CURVE.STANDARD;
                    m_Gamma = 1.0f;
                    m_Chromaticities = Chromaticities.sRGB;	// Default for BMPs is standard sRGB with no gamma
                    break;
            }

            BuildTransformFromChroma( bGammaFoundInFile );
        }