Skip to content

Latest commit

 

History

116 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fefits-export
A fast pure Rust fits library 🔭 🦀

FeFits

The goal of FeFits is to provide a fast, conformant and friendly API for working with The Flexible Image Transport System format common in Astronomy.

The FITS standard is broad and this library does not implement all of it. Rather, FeFits attempts to cover the most general use cases first with a strong architectural foundation on which additional parts of the spec and extensions can be added.

Currently FeFits supports:

  1. Header read/write support
  2. Read only SIMPLE image data
  3. Read only bintable tiled image data
  4. Bit-for-bit parity with funpack for rice-compressed images, including quantized images.

API

FeFits does not attempt to match the api of cfitsio or astropy.fits exactly, though attempts have been made to keep the api as familiar as possible.

Here is how one might dump the contents of a file's headers:

let mut fits = Fits::open("test.fits").unwrap();
for i in 0..fits.len() {  // HDUs
    let header = fits.read_header(i).unwrap_or_default();
    for card in header.cards() {
        println!("{card}");
    }
}

Or to access image data:

let mut fits = Fits::open("test.fits")?;
let hdu = fits.find_image()?.ok_or("no 2D image HDU found")?;
let image = fits.read_image(hdu)?;
let pixels = image.into_f64();
println!(
    "First 10 pixel values: {:?}",
    &pixels[..10.min(pixels.len())]
);

See the examples directory for more usage examples. The integration tests also contain many examples of working with the API at a high level.

Benchmarks

As it turns out, decompressing tile-compressed FITS files is "embarrassingly parallel". With the rayon feature (enabled by default) FeFits will utilize multiple cores to decompress images. This results in a 5x speedup over cfitsio and a 6x speedup over astropy.fits on a machine with multiple cores.

Benchmarks are included in this repo (they don't cover Python) that test reading image data from coj0m421-sq37-20260512-0189-e91.fits.fz, a 150mb rice-compressed floating point image and tfn0m419-sq32-20250218-0237-e00.fits.fz a 5mb rice-compressed integer image:

image fefits cfitsio astropy.fits
150mb fp 52ms 281ms 327ms
5mb int 6ms 26ms 50ms
Screenshot from 2026-05-21 23-02-36

Single thread performance

Even without parallelism FeFits performs comparably to cfitsio and faster than astropy.io.fits:

image fefits cfitsio astropy.fits
150mb fp 285ms 281ms 327ms
5mb int 32ms 28ms 50ms
Screenshot from 2026-05-21 17-28-30

The very unscientific benchmarks for astropy.io.fits. were done with this script:

import time
from astropy.io import fits

start = time.time()
hdul = fits.open("../fefits/tests/fixtures/coj0m421-sq37-20260512-0189-e91.fits.fz")
data  = hdul['SCI'].data
elapsed = time.time() - start
print(elapsed)

Since astropy also uses cfitsio under the hood, unsurprisingly astropy was slightly slower probably due to marshalling Python objects.

Benchmarks can be run with cargo bench.

Integration tests

A suite of integration tests are present that rely on a ~300mb fixtures archive. The test-integration Just recipe will automatically download this archive, extract it and run the tests. Or, you can download the fixtures manually to run the tests.

Motivation

There are quite a few use cases for pure Rust based fits tooling on the horizon including fast thumbnail generation services, silly command line applications and in-browser image manipulation tools: imagine a webassembly based JS9! All of these without the need for complicated C compiler toolchains, FORTRAN or the performance penalties of Python.

About

A pure Rust fits file library

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages