12 releases

0.2.11 Jul 19, 2024
0.2.10 Jul 18, 2024
0.2.9 May 22, 2023
0.2.7 Apr 25, 2023
0.1.1 Jan 4, 2023

#54 in Science

Download history 58/week @ 2024-07-22 25/week @ 2024-07-29 9/week @ 2024-08-05 22/week @ 2024-08-12 23/week @ 2024-08-19 17/week @ 2024-08-26 7/week @ 2024-09-02 19/week @ 2024-09-09 43/week @ 2024-09-16 63/week @ 2024-09-23 68/week @ 2024-09-30 32/week @ 2024-10-07 21/week @ 2024-10-14 3/week @ 2024-10-21 46/week @ 2024-10-28 27/week @ 2024-11-04

102 downloads per month
Used in wcs

Apache-2.0 OR MIT

150KB
3K SLoC

Fits reader written in pure Rust using nom

API Documentation on docs.rs testing CI

This crate is under development, it was initiated for reading fits HiPS tile, i.e. generated from hipsgen.

This fits parser only supports image data (not tables), and does not know anything about WCS parsing. For WCS parsing, see wcsrs. This parser is able to parse extension HDUs. Ascii tables and binary tables are still not properly parsed, only the list bytes of their data block can be retrieved but no interpretation/parsing is done on it.

To Do list

  • Support single typed data block (i.e. image type data)
  • Single HDU parsing, header and data units
  • Support big fits file parsing that may not fit in memory (iterator usage)
  • Async reading (experimental and not tested)
  • Keep CARD comment
  • Support data table (each column can have a specific types)
  • Support of multiple HDU, fits extensions (in progress, only the header is parsed)
  • WCS parsing, see wcsrs

Example

For files that can fit in memory

use fitsrs::{
    fits::Fits,
    hdu::{
        data::InMemData,
        extension::XtensionHDU
    }
};

use std::fs::File;
use std::io::Cursor;

let mut f = File::open("samples/fits.gsfc.nasa.gov/EUVE.fits").unwrap();

let mut buf = Vec::new();
f.read_to_end(&mut buf).unwrap();
let mut reader = Cursor::new(&buf[..]);

let Fits { hdu } = Fits::from_reader(&mut reader).unwrap();

// Access the HDU extensions
let mut hdu_ext = hdu.next();

while let Ok(Some(hdu)) = hdu_ext {
    match &hdu {
        XtensionHDU::Image(xhdu) => {
            let xtension = xhdu.get_header().get_xtension();

            let naxis1 = *xtension.get_naxisn(1).unwrap() as usize;
            let naxis2 = *xtension.get_naxisn(2).unwrap() as usize;

            let num_pixels = naxis2 * naxis1;

            match xhdu.get_data() {
                InMemData::U8(mem) => assert_eq!(num_pixels, mem.len()),
                InMemData::I16(mem) => assert_eq!(num_pixels, mem.len()),
                InMemData::I32(mem) => assert_eq!(num_pixels, mem.len()),
                InMemData::I64(mem) => assert_eq!(num_pixels, mem.len()),
                InMemData::F32(mem) => assert_eq!(num_pixels, mem.len()),
                InMemData::F64(mem) => assert_eq!(num_pixels, mem.len()),
            }
        },
        XtensionHDU::BinTable(xhdu) => {
            let num_bytes = xhdu.get_header()
                .get_xtension()
                .get_num_bytes_data_block();

            match xhdu.get_data() {
                InMemData::U8(mem) => assert_eq!(num_bytes as usize, mem.len()),
                _ => unreachable!()
            }
        },
        XtensionHDU::AsciiTable(xhdu) => {
            let num_bytes = xhdu.get_header()
                .get_xtension()
                .get_num_bytes_data_block();

            match xhdu.get_data() {
                InMemData::U8(mem) => assert_eq!(num_bytes as usize, mem.len()),
                _ => unreachable!()
            }
        },
    }

    hdu_ext = hdu.next();
}

For files that may not be contained into the memory

use fitsrs::{
    fits::Fits,
    hdu::{
        data::iter,
        extension::XtensionHDU
    }
};

use std::fs::File;
use std::io::{BufReader, Read};

let f = File::open("samples/fits.gsfc.nasa.gov/EUVE.fits").unwrap();
let mut reader = BufReader::new(f);

let Fits { hdu } = Fits::from_reader(&mut reader).unwrap();

let mut hdu_ext = hdu.next();

while let Ok(Some(mut xhdu)) = hdu_ext {
    match &mut xhdu {
        XtensionHDU::Image(xhdu) => {
            let xtension = xhdu.get_header().get_xtension();

            let naxis1 = *xtension.get_naxisn(1).unwrap();
            let naxis2 = *xtension.get_naxisn(2).unwrap();

            let num_pixels = (naxis2 * naxis1) as usize;

            match xhdu.get_data_mut() {
                iter::Data::U8(it) => {
                    let data = it.collect::<Vec<_>>();
                    assert_eq!(num_pixels, data.len())
                },
                iter::Data::I16(it) => {
                    let data = it.collect::<Vec<_>>();
                    assert_eq!(num_pixels, data.len())
                },
                iter::Data::I32(it) => {
                    let data = it.collect::<Vec<_>>();
                    assert_eq!(num_pixels, data.len())
                },
                iter::Data::I64(it) => {
                    let data = it.collect::<Vec<_>>();
                    assert_eq!(num_pixels, data.len())
                },
                iter::Data::F32(it) => {
                    let data = it.collect::<Vec<_>>();
                    assert_eq!(num_pixels, data.len())
                },
                iter::Data::F64(it) => {
                    let data = it.collect::<Vec<_>>();
                    assert_eq!(num_pixels, data.len())
                },
            }
        },
        XtensionHDU::BinTable(xhdu) => {
            let num_bytes = xhdu.get_header()
                .get_xtension()
                .get_num_bytes_data_block();

            let it_bytes = xhdu.get_data_mut();
            let data = it_bytes.collect::<Vec<_>>();
            assert_eq!(num_bytes as usize, data.len());
        },
        XtensionHDU::AsciiTable(xhdu) => {
            let num_bytes = xhdu.get_header()
                .get_xtension()
                .get_num_bytes_data_block();

            let it_bytes = xhdu.get_data_mut();
            let data = it_bytes.collect::<Vec<_>>();
            assert_eq!(num_bytes as usize, data.len());
        },
    }

    hdu_ext = xhdu.next();
}

For async input readers:

use fitsrs::{
    fits::AsyncFits,
    hdu::{
        data::stream,
        extension::AsyncXtensionHDU
    }
};

// reader needs to implement futures::io::AsyncRead
let AsyncFits { hdu } = AsyncFits::from_reader(&mut reader).await.unwrap();

let mut hdu_ext = hdu.next().await;

while let Ok(Some(mut xhdu)) = hdu_ext {
    match &mut xhdu {
        AsyncXtensionHDU::Image(xhdu) => {
            let xtension = xhdu.get_header().get_xtension();

            let naxis1 = *xtension.get_naxisn(1).unwrap() as usize;
            let naxis2 = *xtension.get_naxisn(2).unwrap() as usize;

            let num_pixels = naxis2 * naxis1;

            match xhdu.get_data_mut() {
                stream::Data::U8(st) => {
                    let data = st.collect::<Vec<_>>().await;
                    assert_eq!(num_pixels, data.len())
                },
                stream::Data::I16(st) => {
                    let data = st.collect::<Vec<_>>().await;
                    assert_eq!(num_pixels, data.len())
                },
                stream::Data::I32(st) => {
                    let data = st.collect::<Vec<_>>().await;
                    assert_eq!(num_pixels, data.len())
                },
                stream::Data::I64(st) => {
                    let data = st.collect::<Vec<_>>().await;
                    assert_eq!(num_pixels, data.len())
                },
                stream::Data::F32(st) => {
                    let data = st.collect::<Vec<_>>().await;
                    assert_eq!(num_pixels, data.len())
                },
                stream::Data::F64(st) => {
                    let data = st.collect::<Vec<_>>().await;
                    assert_eq!(num_pixels, data.len())
                },
            }
        },
        AsyncXtensionHDU::BinTable(xhdu) => {
            let num_bytes = xhdu.get_header()
                .get_xtension()
                .get_num_bytes_data_block();

            let it_bytes = xhdu.get_data_mut();
            let data = it_bytes.collect::<Vec<_>>().await;
            assert_eq!(num_bytes as usize, data.len());
        },
        AsyncXtensionHDU::AsciiTable(xhdu) => {
            let num_bytes = xhdu.get_header()
                .get_xtension()
                .get_num_bytes_data_block();

            let it_bytes = xhdu.get_data_mut();
            let data = it_bytes.collect::<Vec<_>>().await;
            assert_eq!(num_bytes as usize, data.len());
        },
    }

    hdu_ext = xhdu.next().await;
}

Dependencies

~2.1–3.5MB
~67K SLoC