Skip to content

Instantly share code, notes, and snippets.

@richorama
Created November 1, 2018 00:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save richorama/ef0c373620d852a517f575a96aac5d0c to your computer and use it in GitHub Desktop.
Save richorama/ef0c373620d852a517f575a96aac5d0c to your computer and use it in GitHub Desktop.
KeplerNet
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Drawing;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.PixelFormats;
public class FitsFile : IDisposable
{
const string END_FLAG = " END ";
const int CHUNK_SIZE = 80;
const int BLOCK_SIZE = 2880;
Stream stream = null;
public FitsFile(string path)
{
this.stream = new FileStream(path, FileMode.Open);
}
public void Reset()
{
this.stream.Position = 0;
}
public IEnumerable<KeyValuePair<string,string>> ReadHeader()
{
var headerString = "";
var block = new byte[BLOCK_SIZE];
while (true)
{
var amountRead = this.stream.Read(block,0 , BLOCK_SIZE);
if (amountRead == 0) yield break;
headerString += Encoding.UTF8.GetString(block);
if (headerString.Contains(END_FLAG)){
break;
}
}
var position = 0;
while (position < headerString.Length)
{
var line = string.Concat(headerString.Skip(position).Take(CHUNK_SIZE));
position += CHUNK_SIZE;
if (string.IsNullOrWhiteSpace(line)) continue;
var kv = line.Split('=');
if (kv.Length != 2)
{
yield return KeyValuePair.Create<string,string>("TEXT", line);
if (line.Trim() == "END")
{
yield break;
}
continue;
}
yield return KeyValuePair.Create<string,string>(kv[0].Trim(), kv[1].Trim());
}
}
const int WIDTH = 1132;
const int HEIGHT = 1070;
public Image<Rgba32> ReadImage()
{
var position = this.stream.Position;
// hard code the min/max 32 bit pixel values we can expect from the image.
var max = (double)(Int32.MaxValue * 0.5625);
var min = (double)(Int32.MaxValue * 0.52734375);
this.stream.Position = position;
var image = new Image<Rgba32>(WIDTH, HEIGHT);
var buffer = new byte[4];
for (var y = 0; y < HEIGHT; y++)
{
for (var x = 0; x < WIDTH; x++)
{
stream.Read(buffer, 0, buffer.Length);
var value = (double)BitConverter.ToInt32(buffer.Reverse().ToArray());
byte output = (byte)Math.Min(255,( (256.0 * Math.Max(0,value - min)) / (max - min) ));
var colour = new Rgba32(output, output, output, 255);
image[x,y] = colour;
}
}
// round off to the next block
stream.Position += (WIDTH * HEIGHT * 4) % BLOCK_SIZE;
return image;
}
public void Dispose()
{
this.stream.Close();
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0005" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta0005" />
</ItemGroup>
</Project>
using System;
using System.IO;
using System.Linq;
using SixLabors.ImageSharp.Formats.Bmp;
namespace KeplerNet
{
class Program
{
static void Main(string[] args)
{
var path = @"C:\Users\richard.astbury\code\kep\ktwo2014070234206-c00_ffi-cal.fits";
using (var ffi = new FitsFile(path))
{
//Console.WriteLine("HEADER");
foreach (var header in ffi.ReadHeader())
{
// Console.WriteLine($"{header.Key} = {header.Value}");
}
// only extract the first image
for (var i = 0; i < 1; i++)
{
//Console.WriteLine($"FILE {i}");
foreach (var header in ffi.ReadHeader())
{
//Console.WriteLine($"{header.Key} = {header.Value}");
}
using (var image = ffi.ReadImage())
using (var fs = new FileStream($"output{i}.bmp", FileMode.CreateNew))
{
image.Save(fs, new BmpEncoder());
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment