12次发布

0.2.11 2024年7月19日
0.2.10 2024年7月18日
0.2.9 2023年5月22日
0.2.7 2023年4月25日
0.1.1 2023年1月4日

#42 in 科学

Download history 1/week @ 2024-04-26 40/week @ 2024-05-10 6/week @ 2024-05-17 1/week @ 2024-05-24 11/week @ 2024-06-07 40/week @ 2024-06-14 5/week @ 2024-06-21 13/week @ 2024-06-28 7/week @ 2024-07-05 93/week @ 2024-07-12 227/week @ 2024-07-19 33/week @ 2024-07-26 14/week @ 2024-08-02 14/week @ 2024-08-09

369 每月下载量
wcs 中使用

Apache-2.0 OR MIT

150KB
3K SLoC

使用nom编写的纯Rust编写的FITS读取器

API Documentation on docs.rs testing CI

此crate正在开发中,它最初是为了读取fits HiPS瓦片而发起的,即由hipsgen生成的。

此FITS解析器仅支持图像数据(不支持表格),并且不了解WCS解析。对于WCS解析,请参阅wcsrs。此解析器能够解析扩展HDUs。ASCII表格和二进制表格尚未正确解析,只能检索其数据块的列表字节,但不对它进行解释/解析。

待办事项列表

  • 支持单类型数据块(即图像类型数据)
  • 单个HDU解析,头和数据单元
  • 支持大FITS文件解析,可能无法放入内存(迭代器使用)
  • 异步读取(实验性和未测试)
  • 保留CARD注释
  • 支持数据表(每列可以具有特定的类型)
  • 支持多个HDU,FITS扩展(进行中,仅解析头)
  • WCS解析,请参阅wcsrs

示例

对于可放入内存的文件

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();
}

对于可能无法放入内存的文件

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();
}

对于异步输入读取器

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;
}

依赖项

~2.2–3.5MB
~69K SLoC