% Write key-value pairs in a struct as a FITS header
% comment is an optional cell array of comment strings
function fitsWriteHeader(keys,fd,comment)
% records are always 80*36 characters in length, exactly,
% padded with spaces. each 80 character line is called a 'card'
% For images, The SIMPLE card must always be first,
% followed by BITPIX second, NAXIS third, and END last.
%
% the keyword identifier always occupies columns one through seven.
% The keyword value indicator, if present, occupies columns eight and nine.
% A boolean value always occupies column 30.
% a complex-integer value always occupies columns 31 through 50.
% Columns that do not contain data are filled with spaces.
% Character strings are contained within single quotes.
% If a string contains a single quote, then it is represented by two consecutive single quotes (`O'Reilly' becomes `O''Reilly').
% All strings contain only 7-bit ASCII values and must be at least eight characters in length, padded with spaces.
% Strings may contain a maximum of 68 characters. Strings may begin with leading spaces, but trailing spaces are considered padding.
% All boolean, integer, and floating-point values are represented by their ASCII string equivalents.
% Boolean variables are represented by the value T or F and are always found in column 30 of the card image.
% Integer and floating-point values are located in columns 11 through 30 and are right-justified with spaces, if necessary.
% Complex integers and complex floating-point values are located in columns 31 through 50 and are also right-justified when necessary.
% All letters used in exponential forms are uppercase.
%
% unrecognized keywords are treated as comments by FITS readers
%
% There are five keywords that are required in every FITS file: SIMPLE, BITPIX, NAXIS, NAXISn, and END.
% (EXTEND is also a required keyword if extensions are present in the file.)
%
% Fill (ASCII 00h) is added to the data to pad the data out to end on a 2880-byte boundary.
hdr=char(zeros(36,80) + ' ');
fn=fieldnames(keys);
n=length(fn);
hdr(1,1:30)='SIMPLE = T';
k=2;
for j=1:n
key=fn{j};
val = getfield(keys,key);
typ=class(val);
if (strcmp(val,'char'))
line = sprintf('%7s =%-21s',key,val);
elseif (strcmp(val,'double'))
line = sprintf('%7s = %20.16g',key,val);
else
line = sprintf('%-7s = %20g',key,val);
end
hdr(k,1:length(line))=line;
k=k+1;
end
line = sprintf('EXTEND = %20s','T');
hdr(k,1:length(line))=line;
k=k+1;
if (nargin > 2)
nc=length(comment);
for j=1:nc
line=['COMMENT ',comment{j}];
hdr(k,1:length(line))=line;
k=k+1;
end
end
hdr(k,1:3)='END';
disp(hdr(1:k,:));
fwrite(fd,hdr');
end