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
- Example 2. Read and write the HDU data
- Example 3. Read and write the IMAGE values
- Example 4. Create a new IMAGE frame
- Example 5. Render an IMAGE frame
- Example 6. Create a new TABLE
- Example 7. Read and write the TABLE records
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;