Accord.Imaging.Formats.FITSCodec.ReadHeader C# (CSharp) Method

ReadHeader() private static method

private static ReadHeader ( Stream stream ) : FITSImageInfo
stream Stream
return FITSImageInfo
        private static 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;
        }