Link Search Menu Expand Document

Get Started

Read about the FITS file organization. FITS is an HDU container. Each HDU consists of a header and a data section. The header is a set of keyword records in the form of ASCII “keyword=value/note” cards. The data section is a stream of bytes encoded according to the HDU extension.

Add the library’s “source” directory to your project’s search path.

Review the examples of working with FITS:

Example 1. Read and write the HDU header

To work with keyword records in the HDU header, create specialized card objects. Each descendant of the TFitsCard class implements methods for reading and writing the keyword name, as well as its associated value and note. See also the “itemhead” demo.

uses
  ..., DeLaFitsCommon, DeLaFitsClasses, DeLaFitsCard;

Create the FITS container: open and parse the FITS file

LStream := TFileStream.Create('demo-item.fits', fmOpenReadWrite);
LContainer := TFitsContainer.Create(LStream);

The FITS container contains a list of HDUs. Get the header of the selected HDU

for LIndex := 0 to LContainer.Count - 1 do
  LItem := LContainer.Items[LIndex];
LHead := LItem.Head;

Loop through the header cards

if LHead.FirstCard then
repeat
  LKeyword := LHead.CardKeyword;
  ...
until not LHead.NextCard;

Get the Right ascension of the observed object defined by the keyword “RA”

LCard := TFitsRightAscensionCard.Create;
if LHead.LocateCard('RA') then
begin
  LCard.Card := LHead.Card;
  LValue := LCard.ValueAsDouble;
end;
LCard.Free;

Set the observation date defined by the keyword “DATE-OBS”

LCard := TFitsDateTimeCard.Create;
if LHead.LocateCard('DATE-OBS') then
begin
  LCard.Card := LHead.Card;
  LCard.ValueAsDateTime := Now;
  LHead.Card := LCard.Card;
end else
begin
  LCard.Keyword := 'DATE-OBS';
  LCard.ValueAsDateTime := Now;
  LCard.Note := 'Date of the observation';
  LHead.AddCard(LCard.Card);
end;
LCard.Free;

Free objects

LContainer.Free;
LStream.Free;

Example 2. Read and write the HDU data

To work with the raw byte stream of the HDU data, use the properties and methods of the TFitsItemData instance. Important! Content access methods do not convert the byte stream into physical values. See also the “itemdata” demo.

uses
  ..., DeLaFitsCommon, DeLaFitsClasses;

Create the FITS container: open and parse the FITS file

LStream := TFileStream.Create('demo-item.fits', fmOpenReadWrite);
LContainer := TFitsContainer.Create(LStream);

The FITS container contains a list of HDUs. Get the data object of the selected HDU

for LIndex := 0 to LContainer.Count - 1 do
  LItem := LContainer.Items[LIndex];
LData := LItem.Data;

Read the data contents

var LChunk: array of Byte;
SetLength(LChunk, LData.InternalSize);    
LData.ReadChunk({AInternalOffset:} 0, Length(LChunk), {var} LChunk[0]);

Write the data contents

var LChunk: array of Byte;
SetLength(LChunk, LData.InternalSize);
FillChar(LChunk[0], Length(LChunk), $FF);
LData.WriteChunk({AInternalOffset:} 0, Length(LChunk), LChunk[0]);

Free objects

LContainer.Free;
LStream.Free;

Example 3. Read and write the IMAGE values

To work with physical values of the IMAGE extension, set the HDU class as TFitsImage and use the properties and methods of its data object. See also the “imagevalues” demo.

uses
  ..., DeLaFitsCommon, DeLaFitsClasses, DeLaFitsImage;

Create the FITS container: open and parse the FITS file

LStream := TFileStream.Create('demo-image.fits', fmOpenReadWrite);
LContainer := TFitsContainer.Create(LStream);

Set the HDU class to TFitsImage and get its data object

LIndex := 0;
if LContainer.ItemExtensionTypeIs(LIndex, TFitsImage) then
begin
  LContainer.ItemClasses[LIndex] := TFitsImage;
  LImage := LContainer.Items[LIndex] as TFitsImage;
  LData := LImage.Data;
end;

Get the optimal buffer type and read the physical values of the IMAGE data

case LData.ValueType of
  // floating-point physical values
  num80f, num64f, num32f:
    begin
      var LBuffer: array of Extended;
      SetLength(LBuffer, LData.ValueCount);
      LData.ReadValues({AIndex:} 0, Length(LBuffer), {var} TA80f(LBuffer));
    end;
  // integer physical values
  num08c, num08u, num16c, num16u, num32c, num32u, num64c:
    begin
      var LBuffer: array of Int64;
      SetLength(LBuffer, LData.ValueCount);
      LData.ReadValues({AIndex:} 0, Length(LBuffer), {var} TA64c(LBuffer));
    end;
end;

Write the physical values of the IMAGE data

var LBuffer: array of Integer;
SetLength(LBuffer, LData.ValueCount);
for LIndex := Low(LBuffer) to High(LBuffer) do
  LBuffer[LIndex] := ...;
LData.WriteValues({AIndex:} 0, Length(LBuffer), TA32c(LBuffer));

Free objects

LContainer.Free;
LStream.Free;

Example 4. Create a new IMAGE frame

An IMAGE extension instance contains a multidimensional array of physical values in its data section. Such an array can be presented as a set of frames, which are two-dimensional arrays with dimensions [NAXIS1⨯NAXIS2]. To create a new frame, add an HDU of type TFitsPicture with the TFitsPictureSpec specification to the FITS container. Then, extract the TFitsFrame object and write the physical values into it. See also the “newframe” demo.

uses
  ..., DeLaFitsCommon, DeLaFitsClasses, DeLaFitsPicture;

Create a new empty file and use it to create the FITS container

LStream := TFileStream.Create('new.fits', fmCreate);
LContainer := TFitsContainer.Create(LStream);

Create a specification for a new frame: array [1000⨯1200] of 16-bit unsigned integer values

LSpec := TFitsPictureSpec.CreateNew(
  {AValueType:} num16u,
  {AFrameWidth:} 1000,
  {AFrameHeight:} 1200);

Add a new HDU of type TFitsPicture (IMAGE extension) to the FITS container

LPicture := LContainer.Add(TFitsPicture, LSpec) as TFitsPicture;

Get a handle to the first frame of the HDU

LFrameHandle := LPicture.Data.FrameHandles[0];

Create a new frame object

LFrame := TFitsFrame.Create(LFrameHandle);

Prepare a 16-bit unsigned integer buffer and write the frame values row by row

var LBuffer: array of Word;
SetLength(LBuffer, LFrame.Width);
for LY := 0 to LFrame.Height - 1 do
begin
  for LX := Low(LBuffer) to High(LBuffer)
    LBuffer[LX] := ...;
  LFrame.WriteValues({AX:} 0, {AY:} LY, Length(LBuffer), TA16u(LBuffer));
end;

Free objects

LFrame.Free;
LSpec.Free;
LContainer.Free;
LStream.Free;

Example 5. Render an IMAGE frame

The IMAGE extension instance contains a multidimensional array of physical values in its data section. Such an array can be presented as a set of frames, which are two-dimensional arrays with dimensions [NAXIS1⨯NAXIS2]. Set the HDU class to TFitsPicture, extract the frame as a TFitsFrame object, and use its properties and methods to create a bitmap of some region. See also the “renderframe” demo.

uses
  ..., DeLaFitsCommon, DeLaFitsClasses, DeLaFitsPicture;

Create the FITS container: open and parse the FITS file

LStream := TFileStream.Create('demo-image.fits', fmOpenRead);
LContainer := TFitsContainer.Create(LStream);

Set the HDU class to TFitsPicture

LIndex := 0;
if LContainer.ItemExtensionTypeIs(LIndex, TFitsPicture) then
begin
  LContainer.ItemClasses[LIndex] := TFitsPicture;
  LPicture := LContainer.Items[LIndex] as TFitsPicture;
end;

Get a handle to the first frame of the HDU

LFrameHandle := LPicture.Data.FrameHandles[0];

Create a frame object

LFrame := TFitsFrame.Create(LFrameHandle);

Optional. Set rendering parameters: increase contrast, invert color, and scale the frame scene

LFrame.Tone.Contrast := 1.5;
LFrame.Palette.Reverse := True;
LFrame.Geometry.Scale({ASX:} 2.0, {ASY:} 2.0, {APoint:} xy00);

Create a some rendering region

LRegion := LFrame.SceneRegion;
LRegion.Width := 400;
LRegion.Height := 400;

Create a bitmap object

LBitmap := TBitmap.Create;

Render the frame scene

LFrame.RenderScene(LRegion, LBitmap);

Free objects

LBitmap.Free;
LFrame.Free;
LContainer.Free;
LStream.Free;

Example 6. Create a new TABLE

The TABLE extension instance provides a means of storing catalogs and tables of astronomical data in FITS format. Each row of the table consists of a fixed-length sequence of ASCII characters divided into fields that correspond to the columns in the table. Add an HDU of type TFitsTable with the TFitsTableSpec specification to the FITS container. Then get a reference to the TFitsTableData object, and use its properties and methods to iterate through the table’s records and fields to write values. See also the “newtable” demo.

uses
  ..., DeLaFitsCommon, DeLaFitsClasses, DeLaFitsTable;

Create a new empty file and use it to create the FITS container

LStream := TFileStream.Create('new.fits', fmCreate);
LContainer := TFitsContainer.Create(LStream);

Create a new table specification with three fields: string, integer, and floating point

LFieldInfo1 := CreateStringFieldInfo(
  {AFieldNumber:} 1,
  {AFieldWidth:} 10,
  {AFieldPosition:} 1,
  {AFieldName:} 'COLUMN1');
LFieldInfo2 := CreateIntegerFieldInfo(
  {AFieldNumber:} 2,
  {AFieldWidth:} 10,
  {AFieldPosition:} 12,
  {AFieldName:} 'COLUMN2');
LFieldInfo3 := CreateFixedFieldInfo(
  {AFieldNumber:} 3,
  {AFieldWidth:} 10,
  {AFieldPrecision:} 2,
  {AFieldPosition:} 23,
  {AFieldName:} 'COLUMN3');

LSpec := TFitsTableSpec.CreateNewFields(
  {ARecordSize:} 43,
  {ARecordCount:} 5,
  [LFieldInfo1, LFieldInfo2, LFieldInfo3]);

Add a new HDU of type TFitsTable (TABLE extension) to the FITS container. Get a reference to the data object of the selected table

LTable := LContainer.Add(TFitsTable, LSpec) as TFitsTable;
LData := LTable.Data;

Get a reference to the table fields

LField1 := LData.Fields[1] as TFitsStringField;
LField2 := LData.Fields[2] as TFitsIntegerField;
LField3 := LData.Fields[3] as TFitsFloatField;

Write the table records

for LRecordIndex := 0 to LData.RecordCount - 1 do
begin
  LData.OpenRecord(LRecordIndex);
  LField1.ValueAsString := ...;
  LField2.ValueAsInteger := ...;
  LField3.ValueAsDouble := ...;
  LData.PostRecord;
end;

Free objects

LSpec.Free;
LContainer.Free;
LStream.Free;

Example 7. Read and write the TABLE records

The TABLE extension instance provides a means of storing catalogs and tables of astronomical data in FITS format. Each row of the table consists of a fixed-length sequence of ASCII characters divided into fields that correspond to the columns in the table. To work with table data, set the HDU class to TFitsTable, get a reference to its data object, and iterate over the table’s records and fields to read and write their values. See also the “tablerecords” demo.

uses
  ..., DeLaFitsCommon, DeLaFitsClasses, DeLaFitsTable;

Create the FITS container: open and parse the FITS file

LStream := TFileStream.Create('demo-table.fits', fmOpenReadWrite);
LContainer := TFitsContainer.Create(LStream);

Set the HDU class to TFitsTable and get its data object

LIndex := 1;
if LContainer.ItemExtensionTypeIs(LIndex, TFitsTable) then
begin
  LContainer.ItemClasses[LIndex] := TFitsTable;
  LTable := LContainer.Items[LIndex] as TFitsTable;
  LData := LTable.Data;
end;

Get a reference to the table fields

LField1 := LData.FindField('COLUMN1') as TFitsStringField;
LField2 := LData.FindField('COLUMN2') as TFitsStringField;
LField3 := LData.FindField('COLUMN3') as TFitsIntegerField;
LField4 := LData.FindField('COLUMN4') as TFitsFloatField;
LField5 := LData.FindField('COLUMN5') as TFitsFloatField;
LField6 := LData.FindField('COLUMN6') as TFitsFloatField;

Read the table records

for LRecordIndex := 0 to LData.RecordCount - 1 do
begin
  LData.OpenRecord(LRecordIndex);
  LValue1 := LField1.ValueAsString;
  LValue2 := LField2.ValueAsString;
  LValue3 := LField3.ValueAsInteger;
  LValue4 := LField4.ValueAsDouble;
  LValue5 := LField5.ValueAsDouble;
  LValue6 := LField6.ValueAsDouble;
end;

Write the table records

for LRecordIndex := 0 to LData.RecordCount - 1 do
begin
  LData.OpenRecord(LRecordIndex);
  LField1.ValueAsString := ...;
  LField2.ValueAsString := ...;
  LField3.ValueAsInteger := ...;
  LField4.ValueAsDouble := ...;
  LField5.ValueAsDouble := ...;
  LField6.ValueAsDouble := ...;
  LData.PostRecord;
end;

Add a new table record

LData.AddRecord;
LField1.ValueAsString := ...;
LField2.ValueAsString:= ...;
LField3.ValueAsInteger := ...;
LField4.ValueAsDouble := ...;
LField5.ValueAsDouble := ...;
LField6.ValueAsDouble := ...;
LData.PostRecord;

Display table records

for LRecordIndex := 0 to LData.RecordCount - 1 do
begin
  LData.OpenRecord(LRecordIndex);
  LDisplayRecord := '';
  for LFieldNumber := 1 to LData.FieldCount do
    LDisplayRecord := LDisplayRecord + ' ' +
      LData.Fields[LFieldNumber].DisplayValue;
end;

Free objects

LContainer.Free;
LStream.Free;