The source color for the bitmap The color profile helps converting between the original color space and the internal CIEXYZ color space used in the Bitmap class For now, only standard profiles like Linear, sRGB, Adobe RGB, ProPhoto RGB or any custom chromaticities are supported. I believe it would be overkill to include a library for parsing embedded ICC profiles...
Наследование: IColorConverter
Пример #1
0
        void TestGraph( TEST_GRAPH_TYPE _type )
        {
            ColorProfile	sRGB = new ColorProfile( ColorProfile.STANDARD_PROFILE.sRGB );
            m_imageFile.Init( 1024, 768, ImageFile.PIXEL_FORMAT.RGBA8, sRGB );
            m_imageFile.Clear( new float4( 1, 1, 1, 1 ) );
            //			m_imageFile.Clear( new float4( 0, 0, 0, 1 ) );

            if ( _type == TEST_GRAPH_TYPE.SIMPLE_FUNCTION ) {
                // Unit test simple graph
                float2	rangeY = new float2( -1.0f, 1.0f );
            //				m_imageFile.PlotGraph( black, new float2( -30.0f, 30.0f ), rangeY, ( float x ) => { return (float) Math.Sin( x ) / x; } );
             				m_imageFile.PlotGraphAutoRangeY( black, new float2( -30.0f, 30.0f ), ref rangeY, ( float x ) => { return (float) Math.Sin( x ) / x; } );
             				m_imageFile.PlotAxes( black, new float2( -30.0f, 30.0f ), rangeY, (float) (0.5 * Math.PI), 0.1f );

            } else if ( _type == TEST_GRAPH_TYPE.SIMPLE_LOG_FUNCTIONS ) {
                m_imageFile.PlotLogGraph( red, new float2( 0.0f, 2.0f ), new float2( 0.0f, 100.0f ), ( float x ) => { return (float) Math.Pow( 10.0, x ); }, 1.0f, 1.0f );
            //				m_imageFile.PlotLogGraph( green, new float2( -2.0f, 2.0f ), new float2( 0.0f, 100.0f ), ( float x ) => { return (float) Math.Pow( 10.0, x ); }, 10.0f, 1.0f );
                m_imageFile.PlotLogGraph( green, new float2( 0.0f, 2.0f ), new float2( 0.0f, 2.0f ), ( float x ) => { return (float) Math.Pow( 10.0, x ); }, 1.0f, 10.0f );
                m_imageFile.PlotLogGraph( blue, new float2( -2.0f, 2.0f ), new float2( -2.0f, 2.0f ), ( float x ) => { return (float) Math.Pow( 10.0, x ); }, 10.0f, 10.0f );
            // 				m_imageFile.PlotLogAxes( black, new float2( -1000.0f, 1000.0f ), new float2( -100.0f, 100.0f ), -100.0f, -10.0f );
            // 				m_imageFile.PlotLogAxes( black, new float2( -100.0f, 1000.0f ), new float2( -2.0f, 2.0f ), -10.0f, 10.0f );
             				m_imageFile.PlotLogAxes( black, new float2( -2.0f, 2.0f ), new float2( -2.0f, 2.0f ), 10.0f, 2.0f );

            } else if ( _type == TEST_GRAPH_TYPE.MANY_LINES ) {
                // Unit test a LOT of clipped lines!
                int	W = (int) m_imageFile.Width;
                int	H = (int) m_imageFile.Height;
                Random	R = new Random( 1 );
                float2	P0 = new float2();
                float2	P1 = new float2();
                for ( int i=0; i < 10000; i++ ) {
                    P0.x = (float) (R.NextDouble() * 3*W) - W;
                    P0.y = (float) (R.NextDouble() * 3*H) - H;
                    P1.x = (float) (R.NextDouble() * 3*W) - W;
                    P1.y = (float) (R.NextDouble() * 3*H) - H;
                    m_imageFile.DrawLine( black, P0, P1 );
            //					m_imageFile.DrawLine( R.NextDouble() > 0.5 ? white : black, P0, P1 );
                }
            }

            panelDrawing.Bitmap = m_imageFile.AsBitmap;
        }
Пример #2
0
        void TestBlackBodyRadiation( TEST_COLOR_PROFILES _type )
        {
            ColorProfile	sRGB = new ColorProfile( ColorProfile.STANDARD_PROFILE.sRGB );

            switch ( _type ) {
                // Load the color gamut and try and plot the locii of various white points
                //
                case TEST_COLOR_PROFILES.DRAW_WHITE_POINT_LOCI: {
                    m_imageFile.Load( new System.IO.FileInfo( @"..\..\Images\In\xyGamut.png" ) );

                    float2	cornerZero = new float2( 114, 1336 );			// xy=(0.0, 0.0)
                    float2	cornerPoint8Point9 = new float2( 1257, 49 );	// xy=(0.8, 0.9)

            // Check XYZ<->RGB and XYZ<->xyY converter code
            // 			float3	xyY = new float3();
            // 			float3	XYZ = new float3();
            //
            // float4	testRGB = new float4();
            // float4	testXYZ = new float4();
            // for ( int i=1; i <= 10; i++ ) {
            // 	float	f = i / 10.0f;
            // 	testRGB.Set( 1*f, 1*f, 1*f, 1.0f );
            // 	sRGB.RGB2XYZ( testRGB, ref testXYZ );
            //
            // XYZ.Set( testXYZ.x, testXYZ.y, testXYZ.z );
            // ColorProfile.XYZ2xyY( XYZ, ref xyY );
            // ColorProfile.xyY2XYZ( xyY, ref XYZ );
            // testXYZ.Set( XYZ, 1.0f );
            //
            // 	sRGB.XYZ2RGB( testXYZ, ref testRGB );
            // }

                    float2	xy = new float2();
                    float4	color = new float4( 1, 0, 0, 1 );
                    float4	color2 = new float4( 0, 0.5f, 1, 1 );
                    for ( int locusIndex=0; locusIndex < 20; locusIndex++ ) {
            //						float	T = 1500.0f + (8000.0f - 1500.0f) * locusIndex / 20.0f;
                        float	T = 1500.0f + 500.0f * locusIndex;

                        ColorProfile.ComputeWhitePointChromaticities( T, ref xy );

            // Plot with the color of the white point
            // ColorProfile.xyY2XYZ( new float3( xy, 1.0f ), ref XYZ );
            // sRGB.XYZ2RGB( new float4( XYZ, 1.0f ), ref color );

                        float2	fPos = cornerZero + (cornerPoint8Point9 - cornerZero) * new float2( xy.x / 0.8f, xy.y / 0.9f );
                        DrawPoint( (int) fPos.x, (int) fPos.y, 6, ref color );

                        ColorProfile.ComputeWhitePointChromaticitiesAnalytical( T, ref xy );
                        fPos = cornerZero + (cornerPoint8Point9 - cornerZero) * new float2( xy.x / 0.8f, xy.y / 0.9f );
                        DrawPoint( (int) fPos.x, (int) fPos.y, 3, ref color2 );
                    }
                }
                break;

                case TEST_COLOR_PROFILES.BUILD_WHITE_POINTS_GRADIENT_NO_BALANCE:
                case TEST_COLOR_PROFILES.BUILD_WHITE_POINTS_GRADIENT_BALANCE_D50_TO_D65:
                case TEST_COLOR_PROFILES.BUILD_WHITE_POINTS_GRADIENT_BALANCE_D65_TO_D50: {

                    float3x3	whiteBalancingXYZ = float3x3.Identity;
                    float		whitePointCCT = 6500.0f;
                    if ( _type == TEST_COLOR_PROFILES.BUILD_WHITE_POINTS_GRADIENT_BALANCE_D50_TO_D65 ) {
                        // Compute white balancing from a D50 to a D65 illuminant
                        whiteBalancingXYZ = ColorProfile.ComputeWhiteBalanceXYZMatrix( ColorProfile.Chromaticities.AdobeRGB_D50, ColorProfile.ILLUMINANT_D65 );
                        whitePointCCT = 5000.0f;
                    } else if ( _type == TEST_COLOR_PROFILES.BUILD_WHITE_POINTS_GRADIENT_BALANCE_D65_TO_D50 ) {
                        // Compute white balancing from a D65 to a D50 illuminant
                        whiteBalancingXYZ = ColorProfile.ComputeWhiteBalanceXYZMatrix( ColorProfile.Chromaticities.sRGB, ColorProfile.ILLUMINANT_D50 );
                        whitePointCCT = 10000.0f;	// ?? Actually we're already in D65 so assuming we're starting from a D50 illuminant instead actually pushes the white point far away...
                    }

                    // Build a gradient of white points from 1500K to 8000K
                    m_imageFile.Init( 650, 32, ImageFile.PIXEL_FORMAT.RGBA8, sRGB );

                    float4	RGB = new float4( 0, 0, 0, 0 );
                    float3	XYZ = new float3( 0, 0, 0 );
                    float2	xy = new float2();
                    for ( uint X=0; X < 650; X++ ) {
                        float	T = 1500 + 10 * X;	// From 1500K to 8000K
                        ColorProfile.ComputeWhitePointChromaticities( T, ref xy );

                        ColorProfile.xyY2XYZ( new float3( xy, 1.0f ), ref XYZ );

                        // Apply white balancing
                        XYZ *= whiteBalancingXYZ;

                        sRGB.XYZ2RGB( new float4( XYZ, 1 ), ref RGB );

            // "Normalize"
            //RGB /= Math.Max( Math.Max( RGB.x, RGB.y ), RGB.z );

            // Isolate D65
            if ( Math.Abs( T - whitePointCCT ) < 10.0f )
            RGB.Set( 1, 0, 1, 1 );

                        for ( uint Y=0; Y < 32; Y++ ) {
                            m_imageFile[X,Y] = RGB;
                        }
                    }

            // Check white balancing yields correct results
            // float3	XYZ_R_in = new float3();
            // float3	XYZ_G_in = new float3();
            // float3	XYZ_B_in = new float3();
            // float3	XYZ_W_in = new float3();
            // sRGB.RGB2XYZ( new float3( 1, 0, 0 ), ref XYZ_R_in );
            // sRGB.RGB2XYZ( new float3( 0, 1, 0 ), ref XYZ_G_in );
            // sRGB.RGB2XYZ( new float3( 0, 0, 1 ), ref XYZ_B_in );
            // sRGB.RGB2XYZ( new float3( 1, 1, 1 ), ref XYZ_W_in );
            //
            // float3	XYZ_R_out = XYZ_R_in * XYZ_D65_D50;
            // float3	XYZ_G_out = XYZ_G_in * XYZ_D65_D50;
            // float3	XYZ_B_out = XYZ_B_in * XYZ_D65_D50;
            // float3	XYZ_W_out = XYZ_W_in * XYZ_D65_D50;
            //

            // float3	xyY_R_out = new float3();
            // float3	xyY_G_out = new float3();
            // float3	xyY_B_out = new float3();
            // float3	xyY_W_out = new float3();
            // ColorProfile.XYZ2xyY( XYZ_R_out, ref xyY_R_out );
            // ColorProfile.XYZ2xyY( XYZ_G_out, ref xyY_G_out );
            // ColorProfile.XYZ2xyY( XYZ_B_out, ref xyY_B_out );
            // ColorProfile.XYZ2xyY( XYZ_W_out, ref xyY_W_out );
                }
                break;
            }

            panelColorProfile.Bitmap = m_imageFile.AsBitmap;
        }
Пример #3
0
		public void	Load( System.IO.Stream _ImageStream, FILE_TYPE _FileType, ColorProfile _ProfileOverride )
		{
			// Read the file's content
			byte[]	ImageContent = new byte[_ImageStream.Length];
			_ImageStream.Read( ImageContent, 0, (int) _ImageStream.Length );

			Load( ImageContent, _FileType, _ProfileOverride );
		}
Пример #4
0
		public void	Load( byte[] _ImageFileContent, FILE_TYPE _FileType, ColorProfile _ProfileOverride )
		{
			m_Type = _FileType;
			try
			{
				switch ( _FileType )
				{
					case FILE_TYPE.JPEG:
					case FILE_TYPE.PNG:
					case FILE_TYPE.TIFF:
					case FILE_TYPE.GIF:
					case FILE_TYPE.BMP:
						using ( System.IO.MemoryStream Stream = new System.IO.MemoryStream( _ImageFileContent ) )
						{
							// ===== 1] Load the bitmap source =====
							BitmapDecoder	Decoder = BitmapDecoder.Create( Stream, BitmapCreateOptions.IgnoreColorProfile | BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnDemand );
							if ( Decoder.Frames.Count == 0 )
								throw new Exception( "BitmapDecoder failed to read at least one bitmap frame!" );

							BitmapFrame	Frame = Decoder.Frames[0];
							if ( Frame == null )
								throw new Exception( "Invalid decoded bitmap!" );

// DEBUG
// int		StrideX = (Frame.Format.BitsPerPixel>>3)*Frame.PixelWidth;
// byte[]	DebugImageSource = new byte[StrideX*Frame.PixelHeight];
// Frame.CopyPixels( DebugImageSource, StrideX, 0 );
// DEBUG

// pas de gamma sur les JPEG si non spécifié !
// Il y a bien une magouille faite lors de la conversion par le FormatConvertedBitmap!


							// ===== 2] Build the color profile =====
							m_ColorProfile = _ProfileOverride != null ? _ProfileOverride : new ColorProfile( Frame.Metadata as BitmapMetadata, _FileType );

							// ===== 3] Convert the frame to generic RGBA32F =====
							ConvertFrame( Frame );

							// ===== 4] Convert to CIE XYZ (our device-independent profile connection space) =====
							if ( ms_ReadContent && ms_ConvertContent2XYZ )
								m_ColorProfile.RGB2XYZ( m_Bitmap, m_Bitmap );
						}
						break;

					case FILE_TYPE.TGA:
						{
							// Load as a System.Drawing.Bitmap and convert to float4
							using ( System.IO.MemoryStream Stream = new System.IO.MemoryStream( _ImageFileContent ) )
								using ( TargaImage TGA = new TargaImage( Stream, !ms_ReadContent ) ) {
									// Create a default sRGB linear color profile
									m_ColorProfile = _ProfileOverride != null ? _ProfileOverride
										: new ColorProfile(
											ColorProfile.Chromaticities.sRGB,	// Use default sRGB color profile
											ColorProfile.GAMMA_CURVE.STANDARD,	// But with a standard gamma curve...
											TGA.ExtensionArea.GammaRatio		// ...whose gamma is retrieved from extension data
										);

									if ( ms_ReadContent ) {
										// Convert
										byte[]	ImageContent = LoadBitmap( TGA.Image, out m_Width, out m_Height );
										m_Bitmap = new float4[m_Width,m_Height];
										byte	A;
										int		i = 0;
										for ( int Y=0; Y < m_Height; Y++ )
											for ( int X=0; X < m_Width; X++ )
											{
												m_Bitmap[X,Y].x = BYTE_TO_FLOAT * ImageContent[i++];
												m_Bitmap[X,Y].y = BYTE_TO_FLOAT * ImageContent[i++];
												m_Bitmap[X,Y].z = BYTE_TO_FLOAT * ImageContent[i++];

												A = ImageContent[i++];
												m_bHasAlpha |= A != 0xFF;

												m_Bitmap[X,Y].w = BYTE_TO_FLOAT * A;
											}

										if ( ms_ConvertContent2XYZ ) {
											// Convert to CIEXYZ
											m_ColorProfile.RGB2XYZ( m_Bitmap, m_Bitmap );
										}
									} else {
										// Only read dimensions
										m_Width = TGA.Header.Width;
										m_Height = TGA.Header.Height;
									}
								}
							return;
						}

					case FILE_TYPE.HDR:
						{
							// Load as XYZ
							m_Bitmap = LoadAndDecodeHDRFormat( _ImageFileContent, true, _ProfileOverride, out m_ColorProfile );
							m_Width = m_Bitmap.GetLength( 0 );
							m_Height = m_Bitmap.GetLength( 1 );
							return;
						}

				#if USE_LIB_RAW
					case FILE_TYPE.CRW:
					case FILE_TYPE.CR2:
					case FILE_TYPE.DNG:
						{
							using ( System.IO.MemoryStream Stream = new System.IO.MemoryStream( _ImageFileContent ) )
								using ( LibRawManaged.RawFile Raw = new LibRawManaged.RawFile() ) {
									Raw.UnpackRAW( Stream );

									ColorProfile.Chromaticities	Chroma = Raw.ColorProfile == LibRawManaged.RawFile.COLOR_PROFILE.ADOBE_RGB
																		? ColorProfile.Chromaticities.AdobeRGB_D65	// Use Adobe RGB
																		: ColorProfile.Chromaticities.sRGB;			// Use default sRGB color profile

									// Create a default sRGB linear color profile
									m_ColorProfile = _ProfileOverride != null ? _ProfileOverride
										: new ColorProfile(
											Chroma,
											ColorProfile.GAMMA_CURVE.STANDARD,	// But with a standard gamma curve...
											1.0f								// Linear
										);

									// Also get back valid camera shot info
									m_bHasValidShotInfo = true;
									m_ISOSpeed = Raw.ISOSpeed;
									m_ShutterSpeed = Raw.ShutterSpeed;
									m_Aperture = Raw.Aperture;
									m_FocalLength = Raw.FocalLength;

 									// Convert
									m_Width = Raw.Width;
									m_Height = Raw.Height;
//									float	ColorNormalizer = 1.0f / Raw.Maximum;
									float	ColorNormalizer = 1.0f / 65535.0f;

									if ( ms_ReadContent ) {
										m_Bitmap = new float4[m_Width,m_Height];
										UInt16[,][]	ImageContent = Raw.Image;
										for ( int Y=0; Y < m_Height; Y++ )
											for ( int X=0; X < m_Width; X++ )
											{
 												m_Bitmap[X,Y].x = ImageContent[X,Y][0] * ColorNormalizer;
 												m_Bitmap[X,Y].y = ImageContent[X,Y][1] * ColorNormalizer;
 												m_Bitmap[X,Y].z = ImageContent[X,Y][2] * ColorNormalizer;
 												m_Bitmap[X,Y].w = ImageContent[X,Y][3] * ColorNormalizer;
 											}

										if ( ms_ConvertContent2XYZ ) {
											// Convert to CIEXYZ
											m_ColorProfile.RGB2XYZ( m_Bitmap, m_Bitmap );
										}
									}
								}

#region My poor attempt at reading CRW files
// 							using ( System.IO.MemoryStream Stream = new System.IO.MemoryStream( _ImageFileContent ) )
// 								using ( CanonRawLoader CRWLoader = new CanonRawLoader( Stream ) )
// 								{
// 									ColorProfile.Chromaticities	Chroma = CRWLoader.m_ColorProfile == CanonRawLoader.DataColorProfile.COLOR_PROFILE.ADOBE_RGB
// 																		? ColorProfile.Chromaticities.AdobeRGB_D65	// Use Adobe RGB
// 																		: ColorProfile.Chromaticities.sRGB;			// Use default sRGB color profile
// 
// 									// Create a default sRGB linear color profile
// 									m_ColorProfile = new ColorProfile(
// 											Chroma,
// 											ColorProfile.GAMMA_CURVE.STANDARD,	// But with a standard gamma curve...
// 											1.0f								// Linear
// 										);
// 
//  									// Convert
// 									m_Width = CRWLoader.m_RAWImage.m_Width;
// 									m_Height = CRWLoader.m_RAWImage.m_Height;
// 
// 									m_Bitmap = new float4[m_Width,m_Height];
// 									UInt16[]	ImageContent = CRWLoader.m_RAWImage.m_DecodedImage;
// 									int			i = 0;
// // 									for ( int Y=0; Y < m_Height; Y++ )
// // 										for ( int X=0; X < m_Width; X++ )
// // 										{
// //  											m_Bitmap[X,Y].x = ImageContent[i++] / 4096.0f;
// //  											m_Bitmap[X,Y].y = ImageContent[i++] / 4096.0f;
// //  											m_Bitmap[X,Y].z = ImageContent[i++] / 4096.0f;
// // 											i++;
// //  										}
// 
// 									i=0;
// 									for ( int Y=0; Y < m_Height; Y++ )
// 										for ( int X=0; X < m_Width; X++ )
//  											m_Bitmap[X,Y].x = ImageContent[i++] / 4096.0f;
// 									i=0;
// 									for ( int Y=0; Y < m_Height; Y++ )
// 										for ( int X=0; X < m_Width; X++ )
//  											m_Bitmap[X,Y].y = ImageContent[i++] / 4096.0f;
// 									i=0;
// 									for ( int Y=0; Y < m_Height; Y++ )
// 										for ( int X=0; X < m_Width; X++ )
//  											m_Bitmap[X,Y].z = ImageContent[i++] / 4096.0f;
// 
// 									// Convert to CIEXYZ
// 									m_ColorProfile.RGB2XYZ( m_Bitmap );
// 								}
#endregion
							return;
 						}
					#endif

					default:
						throw new NotSupportedException( "The image file type \"" + _FileType + "\" is not supported by the Bitmap class!" );
				}
			}
			catch ( Exception )
			{
				throw;	// Go on !
			}
		}
Пример #5
0
		/// <summary>
		/// Creates a bitmap from a System.Drawing.Bitmap and a color profile
		/// </summary>
		/// <param name="_Device"></param>
		/// <param name="_Name"></param>
		/// <param name="_Bitmap">The System.Drawing.Bitmap</param>
		/// <param name="_ColorProfile">The color profile to use to transform the bitmap</param>
		public	Bitmap( System.Drawing.Bitmap _Bitmap, ColorProfile _ColorProfile )
		{
			if ( _ColorProfile == null )
				throw new Exception( "Invalid profile: can't convert to CIE XYZ!" );
			m_ColorProfile = _ColorProfile;

			// Load the bitmap's content and copy it to a double entry array
			byte[]	BitmapContent = LoadBitmap( _Bitmap, out m_Width, out m_Height );
			if ( BitmapContent == null )
				return;

			m_Bitmap = new float4[m_Width,m_Height];

			int	i=0;
			for ( int Y=0; Y < m_Height; Y++ )
				for ( int X=0; X < m_Width; X++ )
				{
					m_Bitmap[X,Y] = new float4(
							BYTE_TO_FLOAT * BitmapContent[i++],	// R
							BYTE_TO_FLOAT * BitmapContent[i++],	// G
							BYTE_TO_FLOAT * BitmapContent[i++],	// B
							BYTE_TO_FLOAT * BitmapContent[i++]	// A
						);
				}

			if ( ms_ConvertContent2XYZ ) {
				// Convert to CIE XYZ
				m_ColorProfile.RGB2XYZ( m_Bitmap, m_Bitmap );
			}
		}
Пример #6
0
		public void	Load( System.IO.FileInfo _ImageFileName, FILE_TYPE _FileType, ColorProfile _ProfileOverride )
		{
			using ( System.IO.FileStream ImageStream = _ImageFileName.Open( System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read ) )
				Load( ImageStream, _FileType, _ProfileOverride );
		}
Пример #7
0
		/// <summary>
		/// Creates a bitmap from memory
		/// </summary>
		/// <param name="_Device"></param>
		/// <param name="_Name"></param>
		/// <param name="_ImageFileContent">The memory buffer to load the bitmap from</param>
		/// <param name="_ImageFileNameName">The name of the image file the stream is coming from originally (used to identify image file type)</param>
		public	Bitmap( byte[] _ImageFileContent, System.IO.FileInfo _ImageFileNameName, ColorProfile _ProfileOverride )
		{
			Load( _ImageFileContent, GetFileType( _ImageFileNameName ), _ProfileOverride );
		}
Пример #8
0
		/// <summary>
		/// Creates a bitmap from memory
		/// </summary>
		/// <param name="_Device"></param>
		/// <param name="_Name"></param>
		/// <param name="_ImageFileContent">The memory buffer to load the bitmap from</param>
		/// <param name="_FileType">The image type</param>
		public	Bitmap( byte[] _ImageFileContent, FILE_TYPE _FileType, ColorProfile _ProfileOverride )
		{
			Load( _ImageFileContent, _FileType, _ProfileOverride );
		}
Пример #9
0
		/// <summary>
		/// Creates a bitmap from a stream
		/// </summary>
		/// <param name="_Device"></param>
		/// <param name="_Name"></param>
		/// <param name="_ImageStream">The image stream to load the bitmap from</param>
		/// <param name="_ImageFileNameName">The name of the image file the stream is coming from originally (used to identify image file type)</param>
		public	Bitmap( System.IO.Stream _ImageStream, System.IO.FileInfo _ImageFileNameName, ColorProfile _ProfileOverride )
		{
			Load( _ImageStream, GetFileType( _ImageFileNameName ), _ProfileOverride );
		}
Пример #10
0
		/// <summary>
		/// Creates a bitmap from a stream
		/// </summary>
		/// <param name="_Device"></param>
		/// <param name="_Name"></param>
		/// <param name="_ImageStream">The image stream to load the bitmap from</param>
		/// <param name="_FileType">The image type</param>
		public	Bitmap( System.IO.Stream _ImageStream, FILE_TYPE _FileType, ColorProfile _ProfileOverride )
		{
			Load( _ImageStream, _FileType, _ProfileOverride );
		}
Пример #11
0
		/// <summary>
		/// Manual creation
		/// </summary>
		/// <param name="_Width"></param>
		/// <param name="_Height"></param>
		/// <param name="_Profile">An optional color profile, you will need a valid profile if you wish to save the bitmap!</param>
		public Bitmap( int _Width, int _Height, ColorProfile _Profile )
		{
			m_Width = _Width;
			m_Height = _Height;
			m_Bitmap = new float4[m_Width,m_Height];
			for ( int Y=0; Y < m_Height; Y++ )
				for ( int X=0; X < m_Width; X++ )
					m_Bitmap[X,Y] = new float4( 0, 0, 0, 0 );
			m_ColorProfile = _Profile;
		}
Пример #12
0
		/// <summary>
		/// Decodes a RGBE formatted image into a plain floating-point image
		/// </summary>
		/// <param name="_Source">The source RGBE formatted image</param>
		/// <param name="_bSourceIsXYZ">Tells if the source image is encoded as XYZE rather than RGBE</param>
		/// <param name="_Target">The target float4 image</param>
		/// <param name="_bTargetNeedsXYZ">Tells if the target needs to be in CIE XYZ space (true) or RGB (false)</param>
		/// <param name="_ColorProfile">The color profile for the image</param>
		public static void			DecodeRGBEImage( PF_RGBE[,] _Source, bool _bSourceIsXYZ, float4[,] _Target, bool _bTargetNeedsXYZ, ColorProfile _ColorProfile )
		{
			if ( _bSourceIsXYZ ^ _bTargetNeedsXYZ )
			{	// Requires conversion...
				if ( _bSourceIsXYZ )
				{	// Convert from XYZ to RGB
					for ( int Y=0; Y < _Source.GetLength( 1 ); Y++ )
						for ( int X=0; X < _Source.GetLength( 0 ); X++ )
							_Target[X,Y] = _ColorProfile.XYZ2RGB( new float4( _Source[X,Y].DecodedColor.x, _Source[X,Y].DecodedColor.y, _Source[X,Y].DecodedColor.z, 1.0f ) );
				}
				else
				{	// Convert from RGB to XYZ
					for ( int Y=0; Y < _Source.GetLength( 1 ); Y++ )
						for ( int X=0; X < _Source.GetLength( 0 ); X++ )
							_Target[X,Y] = _ColorProfile.RGB2XYZ( new float4( _Source[X,Y].DecodedColor.x, _Source[X,Y].DecodedColor.y, _Source[X,Y].DecodedColor.z, 1.0f ) );
				}
				return;
			}

			// Simply decode vector and leave as-is
			for ( int Y=0; Y < _Source.GetLength( 1 ); Y++ )
				for ( int X=0; X < _Source.GetLength( 0 ); X++ )
					_Target[X,Y] = new float4( _Source[X,Y].DecodedColor.x, _Source[X,Y].DecodedColor.y, _Source[X,Y].DecodedColor.z, 1.0f );
		}
Пример #13
0
		/// <summary>
		/// Decodes a RGBE formatted image into a plain floating-point image
		/// </summary>
		/// <param name="_Source">The source RGBE formatted image</param>
		/// <param name="_bSourceIsXYZ">Tells if the source image is encoded as XYZE rather than RGBE</param>
		/// <param name="_bTargetNeedsXYZ">Tells if the target needs to be in CIE XYZ space (true) or RGB (false)</param>
		/// <param name="_ColorProfile">The color profile for the image</param>
		/// <returns>A HDR image as floats</returns>
		public static float4[,]	DecodeRGBEImage( PF_RGBE[,] _Source, bool _bSourceIsXYZ, bool _bTargetNeedsXYZ, ColorProfile _ColorProfile )
		{
			if ( _Source == null )
				return	null;

			float4[,]	Result = new float4[_Source.GetLength( 0 ), _Source.GetLength( 1 )];
			DecodeRGBEImage( _Source, _bSourceIsXYZ, Result, _bTargetNeedsXYZ, _ColorProfile );

			return Result;
		}
Пример #14
0
		/// <summary>
		/// Loads a bitmap in .HDR format into a RGBE array
		/// </summary>
		/// <param name="_HDRFormatBinary"></param>
		/// <param name="_bIsXYZ">Tells if the image is encoded as XYZE rather than RGBE</param>
		/// <param name="_ColorProfile">The color profile for the image</param>
		/// <returns></returns>
		public static unsafe PF_RGBE[,]	LoadHDRFormat( byte[] _HDRFormatBinary, ColorProfile _ProfileOverride, out bool _bIsXYZ, out ColorProfile _ColorProfile )
		{
			try
			{
				// The header of a .HDR image file consists of lines terminated by '\n'
				// It ends when there are 2 successive '\n' characters, then follows a single line containing the resolution of the image and only then, real scanlines begin...
				//

				// 1] We must isolate the header and find where it ends.
				//		To do this, we seek and replace every '\n' characters by '\0' (easier to read) until we find a double '\n'
				List<string>	HeaderLines = new List<string>();
				int				CharacterIndex = 0;
				int				LineStartCharacterIndex = 0;

				while ( true )
				{
					if ( _HDRFormatBinary[CharacterIndex] == '\n' || _HDRFormatBinary[CharacterIndex] == '\0' )
					{	// Found a new line!
						_HDRFormatBinary[CharacterIndex] = 0;
						fixed ( byte* pLineStart = &_HDRFormatBinary[LineStartCharacterIndex] )
							HeaderLines.Add( new string( (sbyte*) pLineStart, 0, CharacterIndex-LineStartCharacterIndex, System.Text.Encoding.ASCII ) );

						LineStartCharacterIndex = CharacterIndex + 1;

						// Check for header end
						if ( _HDRFormatBinary[CharacterIndex + 2] == '\n' )
						{
							CharacterIndex += 3;
							break;
						}
						if ( _HDRFormatBinary[CharacterIndex + 1] == '\n' )
						{
							CharacterIndex += 2;
							break;
						}
					}

					// Next character
					CharacterIndex++;
				}

				// 2] Read the last line containing the resolution of the image
				byte*	pScanlines = null;
				string	Resolution = null;
				LineStartCharacterIndex = CharacterIndex;
				while ( true )
				{
					if ( _HDRFormatBinary[CharacterIndex] == '\n' || _HDRFormatBinary[CharacterIndex] == '\0' )
					{
						_HDRFormatBinary[CharacterIndex] = 0;
						fixed ( byte* pLineStart = &_HDRFormatBinary[LineStartCharacterIndex] )
							Resolution = new string( (sbyte*) pLineStart, 0, CharacterIndex-LineStartCharacterIndex, System.Text.Encoding.ASCII );

						fixed ( byte* pScanlinesStart = &_HDRFormatBinary[CharacterIndex + 1] )
							pScanlines = pScanlinesStart;

						break;
					}

					// Next character
					CharacterIndex++;
				}

				// 3] Check format and retrieve resolution
					// 3.1] Search lines for "#?RADIANCE" or "#?RGBE"
				if ( RadianceFileFindInHeader( HeaderLines, "#?RADIANCE" ) == null && RadianceFileFindInHeader( HeaderLines, "#?RGBE" ) == null )
					throw new NotSupportedException( "Unknown HDR format!" );		// Unknown HDR file format!

					// 3.2] Search lines for format
				string	FileFormat = RadianceFileFindInHeader( HeaderLines, "FORMAT=" );
				if ( FileFormat == null )
					throw new Exception( "No format description!" );			// Couldn't get FORMAT

				_bIsXYZ = false;
				if ( FileFormat.IndexOf( "32-bit_rle_rgbe" ) == -1 )
				{	// Check for XYZ encoding
					_bIsXYZ = true;
					if ( FileFormat.IndexOf( "32-bit_rle_xyze" ) == -1 )
						throw new Exception( "Can't read format \"" + FileFormat + "\". Only 32-bit-rle-rgbe or 32-bit_rle_xyze is currently supported!" );
				}

					// 3.3] Search lines for the exposure
				float	fExposure = 0.0f;
				string	ExposureText = RadianceFileFindInHeader( HeaderLines, "EXPOSURE=" );
				if ( ExposureText != null )
					float.TryParse( ExposureText, out fExposure );

					// 3.4] Read the color primaries
				ColorProfile.Chromaticities	Chromas = ColorProfile.Chromaticities.Radiance;	// Default chromaticities
				string	PrimariesText = RadianceFileFindInHeader( HeaderLines, "PRIMARIES=" );
				if ( PrimariesText != null )
				{
					string[]	Primaries = PrimariesText.Split( ' ' );
					if ( Primaries == null || Primaries.Length != 8 )
						throw new Exception( "Failed to parse color profile chromaticities !" );

					float.TryParse( Primaries[0], out Chromas.R.x );
					float.TryParse( Primaries[1], out Chromas.R.y );
					float.TryParse( Primaries[2], out Chromas.G.x );
					float.TryParse( Primaries[3], out Chromas.G.y );
					float.TryParse( Primaries[4], out Chromas.B.x );
					float.TryParse( Primaries[5], out Chromas.B.y );
					float.TryParse( Primaries[6], out Chromas.W.x );
					float.TryParse( Primaries[7], out Chromas.W.y );
				}

					// 3.5] Create the color profile
				if ( _ProfileOverride == null )
				{
					_ColorProfile = new ColorProfile( Chromas, ColorProfile.GAMMA_CURVE.STANDARD, 1.0f );
					_ColorProfile.Exposure = fExposure;
				}
				else
					_ColorProfile = _ProfileOverride;

					// 3.6] Read the resolution out of the last line
				int		WayX = +1, WayY = +1;
				int		Width = 0, Height = 0;

				int	XIndex = Resolution.IndexOf( "+X" );
				if ( XIndex == -1 )
				{	// Wrong way!
					WayX = -1;
					XIndex = Resolution.IndexOf( "-X" );
				}
				if ( XIndex == -1 )
					throw new Exception( "Couldn't find image width in resolution string \"" + Resolution + "\"!" );
				int	WidthEndCharacterIndex = Resolution.IndexOf( ' ', XIndex + 3 );
				if ( WidthEndCharacterIndex == -1 )
					WidthEndCharacterIndex = Resolution.Length;
				Width = int.Parse( Resolution.Substring( XIndex + 2, WidthEndCharacterIndex - XIndex - 2 ) );

				int	YIndex = Resolution.IndexOf( "+Y" );
				if ( YIndex == -1 )
				{	// Flipped !
					WayY = -1;
					YIndex = Resolution.IndexOf( "-Y" );
				}
				if ( YIndex == -1 )
					throw new Exception( "Couldn't find image height in resolution string \"" + Resolution + "\"!" );
				int	HeightEndCharacterIndex = Resolution.IndexOf( ' ', YIndex + 3 );
				if ( HeightEndCharacterIndex == -1 )
					HeightEndCharacterIndex = Resolution.Length;
				Height = int.Parse( Resolution.Substring( YIndex + 2, HeightEndCharacterIndex - YIndex - 2 ) );

				// The encoding of the image data is quite simple:
				//
				//	_ Each floating-point component is first encoded in Greg Ward's packed-pixel format which encodes 3 floats into a single DWORD organized this way: RrrrrrrrGgggggggBbbbbbbbEeeeeeee (E being the common exponent)
				//	_ Each component of the packed-pixel is then encoded separately using a simple run-length encoding format
				//
				PF_RGBE[,]	Dest = null;
				if ( ms_ReadContent ) {
					// 1] Allocate memory for the image and the temporary p_HDRFormatBinaryScanline
					Dest = new PF_RGBE[Width, Height];

					// 2] Read the scanlines
					byte[,]		TempScanline = new byte[Width,4];
					int	ImageY = WayY == +1 ? 0 : Height - 1;
					for ( int y=0; y < Height; y++, ImageY += WayY )
					{
						if ( Width < 8 || Width > 0x7FFF || pScanlines[0] != 0x02 )
							throw new Exception( "Unsupported old encoding format!" );

						byte	Temp;
						byte	Green, Blue;

						// 2.1] Read an entire scanline
						pScanlines++;
						Green = *pScanlines++;
						Blue = *pScanlines++;
						Temp = *pScanlines++;

						if ( Green != 2 || (Blue & 0x80) != 0 )
							throw new Exception( "Unsupported old encoding format!" );

						if ( ((Blue << 8) | Temp) != Width )
							throw new Exception( "Line and image widths mismatch!" );

						for ( int ComponentIndex=0; ComponentIndex < 4; ComponentIndex++ )
						{
							for ( int x=0; x < Width; )
							{
								byte	Code = *pScanlines++;
								if ( Code > 128 )
								{	// Run-Length encoding
									Code &= 0x7F;
									byte	RLValue = *pScanlines++;
									while ( Code-- > 0 && x < Width )
										TempScanline[x++,ComponentIndex] = RLValue;
								}
								else
								{	// Normal encoding
									while ( Code-- > 0 && x < Width )
										TempScanline[x++, ComponentIndex] = *pScanlines++;
								}
							}	// For every pixels of the scanline
						}	// For every color components (including exponent)

						// 2.2] Post-process the scanline and re-order it correctly
						int	ImageX = WayX == +1 ? 0 : Width - 1;
						for ( int x=0; x < Width; x++, ImageX += WayX )
						{
							Dest[x,y].R = TempScanline[ImageX, 0];
							Dest[x,y].G = TempScanline[ImageX, 1];
							Dest[x,y].B = TempScanline[ImageX, 2];
							Dest[x,y].E = TempScanline[ImageX, 3];
						}
					}
				}

				return	Dest;
			}
			catch ( Exception _e )
			{	// Ouch!
				throw new Exception( "An exception occured while attempting to load an HDR file!", _e );
			}
		}
Пример #15
0
		/// <summary>
		/// Loads a bitmap in .HDR format into a float4 array directly useable by the image constructor
		/// </summary>
		/// <param name="_HDRFormatBinary"></param>
		/// <param name="_bTargetNeedsXYZ">Tells if the target needs to be in CIE XYZ space (true) or RGB (false)</param>
		/// <param name="_ColorProfile">The color profile for the image</param>
		/// <returns></returns>
		public static float4[,]	LoadAndDecodeHDRFormat( byte[] _HDRFormatBinary, bool _bTargetNeedsXYZ, ColorProfile _ProfileOverride, out ColorProfile _ColorProfile )
		{
			bool	bSourceIsXYZ;
			return DecodeRGBEImage( LoadHDRFormat( _HDRFormatBinary, _ProfileOverride, out bSourceIsXYZ, out _ColorProfile ), bSourceIsXYZ, _bTargetNeedsXYZ, _ColorProfile );
		}