Information about FITS image's frame.
Inheritance: ImageInfo
Example #1
0
        /// <summary>
        /// Open specified stream.
        /// </summary>
        ///
        /// <param name="stream">Stream to open.</param>
        ///
        /// <returns>Returns number of images found in the specified stream.</returns>
        ///
        /// <exception cref="FormatException">Not a FITS image format.</exception>
        /// <exception cref="NotSupportedException">Format of the FITS image is not supported.</exception>
        /// <exception cref="ArgumentException">The stream contains invalid (broken) FITS image.</exception>
        ///
        public int Open(Stream stream)
        {
            // close previous decoding
            Close( );

            this.imageInfo    = ReadHeader(stream);
            this.stream       = stream;
            this.dataPosition = stream.Seek(0, SeekOrigin.Current);

            return(imageInfo.TotalFrames);
        }
Example #2
0
        /// <summary>
        /// Decode first frame of FITS image.
        /// </summary>
        ///
        /// <param name="stream">Source stream, which contains encoded image.</param>
        ///
        /// <returns>Returns decoded image frame.</returns>
        ///
        /// <exception cref="FormatException">Not a FITS image format.</exception>
        /// <exception cref="NotSupportedException">Format of the FITS image is not supported.</exception>
        /// <exception cref="ArgumentException">The stream contains invalid (broken) FITS image.</exception>
        ///
        public Bitmap DecodeSingleFrame(Stream stream)
        {
            FITSImageInfo imageInfo = ReadHeader(stream);

            // check if there any image frame
            if (imageInfo.TotalFrames == 0)
            {
                throw new ArgumentException("The FITS stream does not contain any image in main section.");
            }
            // read and return first frame
            return(ReadImageFrame(stream, imageInfo));
        }
Example #3
0
        public override object Clone()
        {
            FITSImageInfo fITSImageInfo = new FITSImageInfo(width, height, bitsPerPixel, frameIndex, totalFrames);

            fITSImageInfo.originalBitsPerPixl = originalBitsPerPixl;
            fITSImageInfo.minDataValue        = minDataValue;
            fITSImageInfo.maxDataValue        = maxDataValue;
            fITSImageInfo.telescope           = telescope;
            fITSImageInfo.acquiredObject      = acquiredObject;
            fITSImageInfo.observer            = observer;
            fITSImageInfo.instrument          = instrument;
            return(fITSImageInfo);
        }
Example #4
0
        /// <summary>
        /// Creates a new object that is a copy of the current instance.
        /// </summary>
        ///
        /// <returns>A new object that is a copy of this instance.</returns>
        ///
        public override object Clone()
        {
            var clone = new FITSImageInfo(width, height, bitsPerPixel, frameIndex, totalFrames)
            {
                originalBitsPerPixl = originalBitsPerPixl,
                minDataValue        = minDataValue,
                maxDataValue        = maxDataValue,
                telescope           = telescope,
                acquiredObject      = acquiredObject,
                observer            = observer,
                instrument          = instrument
            };

            return(clone);
        }
Example #5
0
        /// <summary>
        /// Decode specified frame.
        /// </summary>
        ///
        /// <param name="frameIndex">Image frame to decode.</param>
        /// <param name="imageInfo">Receives information about decoded frame.</param>
        ///
        /// <returns>Returns decoded frame.</returns>
        ///
        /// <exception cref="NullReferenceException">No image stream was opened previously.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Stream does not contain frame with specified index.</exception>
        /// <exception cref="ArgumentException">The stream contains invalid (broken) FITS image.</exception>
        ///
        public Bitmap DecodeFrame(int frameIndex, out ImageInfo imageInfo)
        {
            // check requested frame index
            if (frameIndex >= this.imageInfo.TotalFrames)
            {
                throw new ArgumentOutOfRangeException("Currently opened stream does not contain frame with specified index.");
            }

            // seek to the required frame
            stream.Seek(dataPosition + frameIndex * this.imageInfo.Width * this.imageInfo.Height *
                        Math.Abs(this.imageInfo.OriginalBitsPerPixl) / 8, SeekOrigin.Begin);

            // read required frame
            Bitmap image = ReadImageFrame(stream, this.imageInfo);

            // provide also frame information
            imageInfo            = (FITSImageInfo)this.imageInfo.Clone( );
            imageInfo.FrameIndex = frameIndex;

            return(image);
        }
        // Read image frame from the specified stream (current stream's position is used)
        private unsafe Bitmap ReadImageFrame( Stream stream, FITSImageInfo imageInfo )
        {
            int width  = imageInfo.Width;
            int height = imageInfo.Height;

            // create new bitmap
            Bitmap image = ( imageInfo.BitsPerPixel == 8 ) ?
                Tools.CreateGrayscaleImage( width, height ) :
                new Bitmap( width, height, PixelFormat.Format16bppGrayScale );

            // lock it
            BitmapData imageData = image.LockBits( new Rectangle( 0, 0, width, height ),
                ImageLockMode.ReadWrite, image.PixelFormat );

            int originalBitsPerPixel = imageInfo.OriginalBitsPerPixl;
            int stride = imageData.Stride;
            byte* ptr = (byte*) imageData.Scan0.ToPointer( );

            double min = imageInfo.MinDataValue;
            double max = imageInfo.MaxDataValue;

            // check number of bits per pixel and load image appropriately
            if ( imageInfo.BitsPerPixel == 16 )
            {
                // 16 bpp grayscale image
                double coef = 65535.0 / ( max - min );

                // prepare a buffer for one line
                int lineSize = width * Math.Abs( originalBitsPerPixel ) / 8;
                byte[] line = new byte[lineSize];
                byte[] temp = new byte[8];

                // load all rows
                for ( int y = height - 1; y >= 0; y-- )
                {
                    // load next line
                    if ( Tools.ReadStream( stream, line, 0, lineSize ) < lineSize )
                        throw new ArgumentException( "The stream does not contain valid FITS image." );

                    // fill next image row
                    ushort* row = (ushort*) ( ptr + stride * y );

                    for ( int x = 0, i = 0; x < width; x++, row++ )
                    {
                        double value = 0;

                        switch ( originalBitsPerPixel )
                        {
                            case 16:    // 16 bit signed integer
                            {
                                short tempValue = 0;
                                unchecked
                                {
                                    tempValue = (short) ( ( line[i++] << 8 ) + line[i++] );
                                }
                                value = tempValue;
                                break;
                            }
                            case 32:    // 32 bit signed integer
                            {
                                temp[3] = line[i++];
                                temp[2] = line[i++];
                                temp[1] = line[i++];
                                temp[0] = line[i++];

                                value = BitConverter.ToInt32( temp, 0 );

                                break;
                            }
                            case -32:    // 32 bit float
                            {
                                temp[3] = line[i++];
                                temp[2] = line[i++];
                                temp[1] = line[i++];
                                temp[0] = line[i++];

                                value = BitConverter.ToSingle( temp, 0 );
                                break;
                            }
                            case -64:    // 64 bit double
                            {
                                temp[7] = line[i++];
                                temp[6] = line[i++];
                                temp[5] = line[i++];
                                temp[4] = line[i++];
                                temp[3] = line[i++];
                                temp[2] = line[i++];
                                temp[1] = line[i++];
                                temp[0] = line[i++];

                                value = BitConverter.ToDouble( temp, 0 );
                                break;
                            }
                        }

                        *row = (ushort) ( ( value - min ) * coef );
                    }
                }
            }
            else
            {
                // 8 bpp grayscale image
                double coef = 255.0 / ( max - min );

                // prepare a buffer for one line
                byte[] line = new byte[width];

                // load all rows
                for ( int y = height - 1; y >= 0; y-- )
                {
                    // load next line
                    if ( Tools.ReadStream( stream, line, 0, width ) < width )
                        throw new ArgumentException( "The stream does not contain valid FITS image." );

                    // fill next image row
                    byte* row = ptr + stride * y;

                    for ( int x = 0; x < width; x++, row++ )
                    {
                        *row = (byte) ( ( (double) line[x] - min ) * coef );
                    }
                }
            }

            // unlock image and return it
            image.UnlockBits( imageData );
            return image;
        }
        // Read and process FITS header. After the header is read stream pointer will
        // point to data or extension.
        private FITSImageInfo ReadHeader( Stream stream )
        {
            byte[]  headerRecord = new byte[80];
            int     recordsRead = 1;
            bool    endKeyWasFound = false;

            FITSImageInfo imageInfo = new FITSImageInfo( );

            // read first record and check for correct image
            if (
                ( Tools.ReadStream( stream, headerRecord, 0, 80 ) < 80 ) ||
                ( Encoding.ASCII.GetString( headerRecord, 0, 8 ) != "SIMPLE  " ) )
            {
                throw new FormatException( "The stream does not contatin FITS image." );
            }
            else
            {
                // check if the image has standard FITS format
                if ( Encoding.ASCII.GetString( headerRecord, 10, 70 ).Split( '/' )[0].Trim( ) != "T" )
                {
                    throw new NotSupportedException( "The stream contains not standard FITS data file." );
                }
            }

            // read header and locate data block
            while ( true )
            {
                // read next record
                if ( Tools.ReadStream( stream, headerRecord, 0, 80 ) < 80 )
                {
                    throw new ArgumentException( "The stream does not contain valid FITS image." );
                }
                recordsRead++;

                // get keyword
                string keyword = Encoding.ASCII.GetString( headerRecord, 0, 8 );

                // skip commenct and history
                if ( ( keyword == "COMMENT " ) || ( keyword == "HISTORY " ) )
                    continue;

                // check if it is end of header keyword
                if ( keyword == "END     " )
                    endKeyWasFound = true;

                if ( endKeyWasFound )
                {
                    if ( recordsRead % 36 == 0 )
                    {
                        // found data or extension header

                        // make a small check of some header values
                        if ( ( imageInfo.BitsPerPixel == 0 ) || ( imageInfo.Width == 0 ) || ( imageInfo.Height == 0 ) )
                        {
                            imageInfo.TotalFrames = 0;
                        }

                        // let's return here and let other routines process data
                        break;
                    }
                }
                else
                {
                    // get string representation of value/comments
                    string strValue = Encoding.ASCII.GetString( headerRecord, 10, 70 );

                    // check important keywords
                    if ( keyword == "BITPIX  " )
                    {
                        int value = ExtractIntegerValue( strValue );

                        if ( ( value != 8 ) && ( value != 16 ) && ( value != 32 ) && ( value != -32 ) && ( value != -64 ) )
                        {
                            throw new NotSupportedException( "Data format (" + value + ") is not supported." );
                        }

                        // bits per pixel
                        imageInfo.BitsPerPixel = ( value == 8 ) ? 8 : 16;
                        imageInfo.OriginalBitsPerPixl = value;
                    }
                    else if ( Encoding.ASCII.GetString( headerRecord, 0, 5 ) == "NAXIS" )
                    {
                        // information about data axis
                        int value = ExtractIntegerValue( strValue );

                        // check axis
                        switch ( headerRecord[5] )
                        {
                            // number of axis
                            case (byte) ' ':
                                switch ( value )
                                {
                                    case 1:
                                    default:
                                        throw new NotSupportedException( "FITS files with data dimension of " + value + " are not supported." );
                                    case 0:
                                        // the stream does not have an image, do nothing
                                        break;
                                    case 2:
                                        // the stream has 1 2D image
                                        imageInfo.TotalFrames = 1;
                                        break;
                                    case 3:
                                        // the stream has 3D image - series of 2D images
                                        break;
                                }
                                break;
                            // length of 1st axis
                            case (byte) '1':
                                imageInfo.Width = value;
                                break;
                            // length of 2nd axis
                            case (byte) '2':
                                imageInfo.Height = value;
                                break;
                            // length of 3rd axis
                            case (byte) '3':
                                imageInfo.TotalFrames = value;
                                break;
                        }
                    }
                    else if ( keyword == "TELESCOP" )
                    {
                        imageInfo.Telescope = ExtractStringValue( strValue );
                    }
                    else if ( keyword == "OBJECT  " )
                    {
                        imageInfo.Object = ExtractStringValue( strValue );
                    }
                    else if ( keyword == "OBSERVER" )
                    {
                        imageInfo.Observer = ExtractStringValue( strValue );
                    }
                    else if ( keyword == "INSTRUME" )
                    {
                        imageInfo.Instrument = ExtractStringValue( strValue );
                    }

                    // --- for debugging ---
                    /* if ( keyword[0] != ' ' )
                    {
                        System.Diagnostics.Debug.Write( keyword );
                        if ( headerRecord[8] == '=' )
                        {
                            System.Diagnostics.Debug.WriteLine( " = " + strValue );
                        }
                        else
                        {
                            System.Diagnostics.Debug.WriteLine( "" );
                        }
                    } */
                    // --- ---
                }
            }

            // scan all available data to find minimum and maximum values,
            // which will be used for scaling. the scan is done here (not while
            // reading actual frame) because FITS file may have set of images
            // packed into data cube, so entire scan of all the data is required.

            // if is stream is seekable
            if ( !stream.CanSeek )
            {
                throw new ArgumentException( "The stream must be seekable." );
            }
            
            // remember current position
            long dataPos = stream.Seek( 0, SeekOrigin.Current );

            // data size
            int lineLength = imageInfo.Width * ( Math.Abs( imageInfo.OriginalBitsPerPixl ) / 8 );
            int totalLines = imageInfo.Height * imageInfo.TotalFrames;
            int originalBitsPerPixel = imageInfo.OriginalBitsPerPixl;

            byte[] buffer = new byte[lineLength];
            byte[] temp = new byte[8];

            // min and max values
            double min = double.MaxValue;
            double max = double.MinValue;

            for ( int i = 0; i < totalLines; i++ )
            {
                // read next line
                if ( Tools.ReadStream( stream, buffer, 0, lineLength ) < lineLength )
                    throw new ArgumentException( "The stream does not contain valid FITS image." );

                // scan the line
                for ( int j = 0; j < lineLength; )
                {
                    double value = 0;

                    // read values accordint to their format
                    switch ( originalBitsPerPixel )
                    {
                        case 8:    // 8 bit unsigned integer
                            value = buffer[j++];
                            break;
                        case 16:    // 16 bit signed integer
                        {
                            short tempValue = 0;
                            unchecked
                            {
                                tempValue = (short) ( ( buffer[j++] << 8 ) | buffer[j++] );
                            }
                            value = tempValue;
                            break;
                        }
                        case 32:    // 32 bit signed integer
                        {
                            temp[3] = buffer[j++];
                            temp[2] = buffer[j++];
                            temp[1] = buffer[j++];
                            temp[0] = buffer[j++];

                            value = BitConverter.ToInt32( temp, 0 );

                            break;
                        }
                        case -32:   // 32 bit float
                        {
                            temp[3] = buffer[j++];
                            temp[2] = buffer[j++];
                            temp[1] = buffer[j++];
                            temp[0] = buffer[j++];

                            value = BitConverter.ToSingle( temp, 0 );
                            break;
                        }
                        case -64:   // 64 bit double
                        {
                            temp[7] = buffer[j++];
                            temp[6] = buffer[j++];
                            temp[5] = buffer[j++];
                            temp[4] = buffer[j++];
                            temp[3] = buffer[j++];
                            temp[2] = buffer[j++];
                            temp[1] = buffer[j++];
                            temp[0] = buffer[j++];

                            value = BitConverter.ToDouble( temp, 0 );
                            break;
                        }
                    }

                    if ( value > max )
                        max = value;
                    if ( value < min )
                        min = value;
                }
            }

            imageInfo.MaxDataValue = max;
            imageInfo.MinDataValue = min;

            // restore stream position to the begining of data
            stream.Seek( dataPos, SeekOrigin.Begin );

            return imageInfo;
        }
 /// <summary>
 /// Close decoding of previously opened stream.
 /// </summary>
 /// 
 /// <remarks><para>The method does not close stream itself, but just closes
 /// decoding cleaning all associated data with it.</para></remarks>
 /// 
 public void Close( )
 {
     stream    = null;
     imageInfo = null;
 }
        /// <summary>
        /// Decode specified frame.
        /// </summary>
        /// 
        /// <param name="frameIndex">Image frame to decode.</param>
        /// <param name="imageInfo">Receives information about decoded frame.</param>
        /// 
        /// <returns>Returns decoded frame.</returns>
        /// 
        /// <exception cref="NullReferenceException">No image stream was opened previously.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Stream does not contain frame with specified index.</exception>
        /// <exception cref="ArgumentException">The stream contains invalid (broken) FITS image.</exception>
        /// 
        public Bitmap DecodeFrame( int frameIndex, out ImageInfo imageInfo )
        {
            // check requested frame index
            if ( frameIndex >= this.imageInfo.TotalFrames )
            {
                throw new ArgumentOutOfRangeException( "Currently opened stream does not contain frame with specified index." );
            }

            // seek to the required frame
            stream.Seek( dataPosition + frameIndex * this.imageInfo.Width * this.imageInfo.Height *
                Math.Abs( this.imageInfo.OriginalBitsPerPixl ) / 8, SeekOrigin.Begin );

            // read required frame
            Bitmap image = ReadImageFrame( stream, this.imageInfo );

            // provide also frame information
            imageInfo = (FITSImageInfo) this.imageInfo.Clone( );
            imageInfo.FrameIndex = frameIndex;

            return image;
        }
        /// <summary>
        /// Open specified stream.
        /// </summary>
        /// 
        /// <param name="stream">Stream to open.</param>
        /// 
        /// <returns>Returns number of images found in the specified stream.</returns>
        /// 
        /// <exception cref="FormatException">Not a FITS image format.</exception>
        /// <exception cref="NotSupportedException">Format of the FITS image is not supported.</exception>
        /// <exception cref="ArgumentException">The stream contains invalid (broken) FITS image.</exception>
        /// 
        public int Open( Stream stream )
        {
            // close previous decoding
            Close( );

            this.imageInfo    = ReadHeader( stream );
            this.stream       = stream;
            this.dataPosition = stream.Seek( 0, SeekOrigin.Current );

            return imageInfo.TotalFrames;
        }
        /// <summary>
        /// Creates a new object that is a copy of the current instance. 
        /// </summary>
        /// 
        /// <returns>A new object that is a copy of this instance.</returns>
        /// 
        public override object Clone( )
        {
            FITSImageInfo clone = new FITSImageInfo( width, height, bitsPerPixel, frameIndex, totalFrames );

            clone.originalBitsPerPixl = originalBitsPerPixl;
            clone.minDataValue = minDataValue;
            clone.maxDataValue = maxDataValue;
            clone.telescope = telescope;
            clone.acquiredObject = acquiredObject;
            clone.observer = observer;
            clone.instrument = instrument;

            return clone;
        }
Example #12
0
        // Read image frame from the specified stream (current stream's position is used)
        private unsafe Bitmap ReadImageFrame(Stream stream, FITSImageInfo imageInfo)
        {
            int width  = imageInfo.Width;
            int height = imageInfo.Height;

            // create new bitmap
            Bitmap image = (imageInfo.BitsPerPixel == 8) ?
                           Tools.CreateGrayscaleImage(width, height) :
                           new Bitmap(width, height, PixelFormat.Format16bppGrayScale);

            // lock it
            BitmapData imageData = image.LockBits(new Rectangle(0, 0, width, height),
                                                  ImageLockMode.ReadWrite, image.PixelFormat);

            int   originalBitsPerPixel = imageInfo.OriginalBitsPerPixl;
            int   stride = imageData.Stride;
            byte *ptr    = (byte *)imageData.Scan0.ToPointer( );

            double min = imageInfo.MinDataValue;
            double max = imageInfo.MaxDataValue;

            // check number of bits per pixel and load image appropriately
            if (imageInfo.BitsPerPixel == 16)
            {
                // 16 bpp grayscale image
                double coef = 65535.0 / (max - min);

                // prepare a buffer for one line
                int    lineSize = width * Math.Abs(originalBitsPerPixel) / 8;
                byte[] line     = new byte[lineSize];
                byte[] temp     = new byte[8];

                // load all rows
                for (int y = height - 1; y >= 0; y--)
                {
                    // load next line
                    if (Tools.ReadStream(stream, line, 0, lineSize) < lineSize)
                    {
                        throw new ArgumentException("The stream does not contain valid FITS image.");
                    }

                    // fill next image row
                    ushort *row = (ushort *)(ptr + stride * y);

                    for (int x = 0, i = 0; x < width; x++, row++)
                    {
                        double value = 0;

                        switch (originalBitsPerPixel)
                        {
                        case 16:        // 16 bit signed integer
                        {
                            short tempValue = 0;
                            unchecked
                            {
                                tempValue = (short)((line[i++] << 8) + line[i++]);
                            }
                            value = tempValue;
                            break;
                        }

                        case 32:        // 32 bit signed integer
                        {
                            temp[3] = line[i++];
                            temp[2] = line[i++];
                            temp[1] = line[i++];
                            temp[0] = line[i++];

                            value = BitConverter.ToInt32(temp, 0);

                            break;
                        }

                        case -32:        // 32 bit float
                        {
                            temp[3] = line[i++];
                            temp[2] = line[i++];
                            temp[1] = line[i++];
                            temp[0] = line[i++];

                            value = BitConverter.ToSingle(temp, 0);
                            break;
                        }

                        case -64:        // 64 bit double
                        {
                            temp[7] = line[i++];
                            temp[6] = line[i++];
                            temp[5] = line[i++];
                            temp[4] = line[i++];
                            temp[3] = line[i++];
                            temp[2] = line[i++];
                            temp[1] = line[i++];
                            temp[0] = line[i++];

                            value = BitConverter.ToDouble(temp, 0);
                            break;
                        }
                        }

                        *row = (ushort)((value - min) * coef);
                    }
                }
            }
            else
            {
                // 8 bpp grayscale image
                double coef = 255.0 / (max - min);

                // prepare a buffer for one line
                byte[] line = new byte[width];

                // load all rows
                for (int y = height - 1; y >= 0; y--)
                {
                    // load next line
                    if (Tools.ReadStream(stream, line, 0, width) < width)
                    {
                        throw new ArgumentException("The stream does not contain valid FITS image.");
                    }

                    // fill next image row
                    byte *row = ptr + stride * y;

                    for (int x = 0; x < width; x++, row++)
                    {
                        *row = (byte)(((double)line[x] - min) * coef);
                    }
                }
            }

            // unlock image and return it
            image.UnlockBits(imageData);
            return(image);
        }
Example #13
0
        // Read and process FITS header. After the header is read stream pointer will
        // point to data or extension.
        private FITSImageInfo ReadHeader(Stream stream)
        {
            byte[] headerRecord   = new byte[80];
            int    recordsRead    = 1;
            bool   endKeyWasFound = false;

            FITSImageInfo imageInfo = new FITSImageInfo( );

            // read first record and check for correct image
            if (
                (Tools.ReadStream(stream, headerRecord, 0, 80) < 80) ||
                (Encoding.UTF8.GetString(headerRecord, 0, 8) != "SIMPLE  "))
            {
                throw new FormatException("The stream does not contatin FITS image.");
            }
            else
            {
                // check if the image has standard FITS format
                if (Encoding.UTF8.GetString(headerRecord, 10, 70).Split('/')[0].Trim( ) != "T")
                {
                    throw new NotSupportedException("The stream contains not standard FITS data file.");
                }
            }

            // read header and locate data block
            while (true)
            {
                // read next record
                if (Tools.ReadStream(stream, headerRecord, 0, 80) < 80)
                {
                    throw new ArgumentException("The stream does not contain valid FITS image.");
                }
                recordsRead++;

                // get keyword
                string keyword = Encoding.UTF8.GetString(headerRecord, 0, 8);

                // skip commenct and history
                if ((keyword == "COMMENT ") || (keyword == "HISTORY "))
                {
                    continue;
                }

                // check if it is end of header keyword
                if (keyword == "END     ")
                {
                    endKeyWasFound = true;
                }

                if (endKeyWasFound)
                {
                    if (recordsRead % 36 == 0)
                    {
                        // found data or extension header

                        // make a small check of some header values
                        if ((imageInfo.BitsPerPixel == 0) || (imageInfo.Width == 0) || (imageInfo.Height == 0))
                        {
                            imageInfo.TotalFrames = 0;
                        }

                        // let's return here and let other routines process data
                        break;
                    }
                }
                else
                {
                    // get string representation of value/comments
                    string strValue = Encoding.UTF8.GetString(headerRecord, 10, 70);

                    // check important keywords
                    if (keyword == "BITPIX  ")
                    {
                        int value = ExtractIntegerValue(strValue);

                        if ((value != 8) && (value != 16) && (value != 32) && (value != -32) && (value != -64))
                        {
                            throw new NotSupportedException("Data format (" + value + ") is not supported.");
                        }

                        // bits per pixel
                        imageInfo.BitsPerPixel        = (value == 8) ? 8 : 16;
                        imageInfo.OriginalBitsPerPixl = value;
                    }
                    else if (Encoding.UTF8.GetString(headerRecord, 0, 5) == "NAXIS")
                    {
                        // information about data axis
                        int value = ExtractIntegerValue(strValue);

                        // check axis
                        switch (headerRecord[5])
                        {
                        // number of axis
                        case (byte)' ':
                            switch (value)
                            {
                            case 1:
                            default:
                                throw new NotSupportedException("FITS files with data dimension of " + value + " are not supported.");

                            case 0:
                                // the stream does not have an image, do nothing
                                break;

                            case 2:
                                // the stream has 1 2D image
                                imageInfo.TotalFrames = 1;
                                break;

                            case 3:
                                // the stream has 3D image - series of 2D images
                                break;
                            }
                            break;

                        // length of 1st axis
                        case (byte)'1':
                            imageInfo.Width = value;
                            break;

                        // length of 2nd axis
                        case (byte)'2':
                            imageInfo.Height = value;
                            break;

                        // length of 3rd axis
                        case (byte)'3':
                            imageInfo.TotalFrames = value;
                            break;
                        }
                    }
                    else if (keyword == "TELESCOP")
                    {
                        imageInfo.Telescope = ExtractStringValue(strValue);
                    }
                    else if (keyword == "OBJECT  ")
                    {
                        imageInfo.Object = ExtractStringValue(strValue);
                    }
                    else if (keyword == "OBSERVER")
                    {
                        imageInfo.Observer = ExtractStringValue(strValue);
                    }
                    else if (keyword == "INSTRUME")
                    {
                        imageInfo.Instrument = ExtractStringValue(strValue);
                    }

                    // --- for debugging ---

                    /* if ( keyword[0] != ' ' )
                     * {
                     *  System.Diagnostics.Debug.Write( keyword );
                     *  if ( headerRecord[8] == '=' )
                     *  {
                     *      System.Diagnostics.Debug.WriteLine( " = " + strValue );
                     *  }
                     *  else
                     *  {
                     *      System.Diagnostics.Debug.WriteLine( "" );
                     *  }
                     * } */
                    // --- ---
                }
            }

            // scan all available data to find minimum and maximum values,
            // which will be used for scaling. the scan is done here (not while
            // reading actual frame) because FITS file may have set of images
            // packed into data cube, so entire scan of all the data is required.

            // if is stream is seekable
            if (!stream.CanSeek)
            {
                throw new ArgumentException("The stream must be seekable.");
            }

            // remember current position
            long dataPos = stream.Seek(0, SeekOrigin.Current);

            // data size
            int lineLength           = imageInfo.Width * (Math.Abs(imageInfo.OriginalBitsPerPixl) / 8);
            int totalLines           = imageInfo.Height * imageInfo.TotalFrames;
            int originalBitsPerPixel = imageInfo.OriginalBitsPerPixl;

            byte[] buffer = new byte[lineLength];
            byte[] temp   = new byte[8];

            // min and max values
            double min = double.MaxValue;
            double max = double.MinValue;

            for (int i = 0; i < totalLines; i++)
            {
                // read next line
                if (Tools.ReadStream(stream, buffer, 0, lineLength) < lineLength)
                {
                    throw new ArgumentException("The stream does not contain valid FITS image.");
                }

                // scan the line
                for (int j = 0; j < lineLength;)
                {
                    double value = 0;

                    // read values accordint to their format
                    switch (originalBitsPerPixel)
                    {
                    case 8:        // 8 bit unsigned integer
                        value = buffer[j++];
                        break;

                    case 16:        // 16 bit signed integer
                    {
                        short tempValue = 0;
                        unchecked
                        {
                            tempValue = (short)((buffer[j++] << 8) | buffer[j++]);
                        }
                        value = tempValue;
                        break;
                    }

                    case 32:        // 32 bit signed integer
                    {
                        temp[3] = buffer[j++];
                        temp[2] = buffer[j++];
                        temp[1] = buffer[j++];
                        temp[0] = buffer[j++];

                        value = BitConverter.ToInt32(temp, 0);

                        break;
                    }

                    case -32:       // 32 bit float
                    {
                        temp[3] = buffer[j++];
                        temp[2] = buffer[j++];
                        temp[1] = buffer[j++];
                        temp[0] = buffer[j++];

                        value = BitConverter.ToSingle(temp, 0);
                        break;
                    }

                    case -64:       // 64 bit double
                    {
                        temp[7] = buffer[j++];
                        temp[6] = buffer[j++];
                        temp[5] = buffer[j++];
                        temp[4] = buffer[j++];
                        temp[3] = buffer[j++];
                        temp[2] = buffer[j++];
                        temp[1] = buffer[j++];
                        temp[0] = buffer[j++];

                        value = BitConverter.ToDouble(temp, 0);
                        break;
                    }
                    }

                    if (value > max)
                    {
                        max = value;
                    }
                    if (value < min)
                    {
                        min = value;
                    }
                }
            }

            imageInfo.MaxDataValue = max;
            imageInfo.MinDataValue = min;

            // restore stream position to the begining of data
            stream.Seek(dataPos, SeekOrigin.Begin);

            return(imageInfo);
        }
Example #14
0
 /// <summary>
 /// Close decoding of previously opened stream.
 /// </summary>
 ///
 /// <remarks><para>The method does not close stream itself, but just closes
 /// decoding cleaning all associated data with it.</para></remarks>
 ///
 public void Close( )
 {
     stream    = null;
     imageInfo = null;
 }