FitsIo
A safe, ergonomic, and pure-Rust library for reading and writing FITS (Flexible Image Transport System) files, inspired by CFITSIO.
This crate offers optional async I/O with Tokio and structured access to FITS headers, images, and tables — without any C dependencies.
Designed for astronomy, astrophotography, and scientific pipelines where portability and safety matter.
Features
- 📦 Pure Rust implementation (no CFITSIO, no C bindings)
- ⚡ Async I/O with Tokio (enabled by default)
- 🧩 Support for Primary HDUs and extensions
- 🖼️ Image HDUs of any dimensionality, cubes and hypercubes included
- 📊 Binary and ASCII tables alike, with optional
serdesupport in both directions - 🗜️ Tile-compressed images, read and written as images like any other
- 🌍 World coordinate helpers: pixels to sky positions and back, with SIP and TPV distortions
- 🧠 Typed access to FITS header keywords, and any keyword at all by name
- 🚀 Streaming and memory-efficient reads
- 🛡️ Idiomatic error handling with Result
- 🔁 CFITSIO-inspired API, redesigned for Rust
Installation
Add the crate to your Cargo.toml:
[]
= "0.2"
Reading a file
#
#
#
Reading table rows into your own structs
With the serde feature, a table's rows deserialize straight into a struct,
matching columns to fields by their TTYPEn names. The same works for an ASCII
table through read_rows, from_ascii_table and to_ascii_table.
#
#
#
Writing
Setting data also brings the header into line with it, and saving fills in the mandatory cards, puts them in the order the standard requires, and writes CHECKSUM and DATASUM.
#
#
#
Editing the header
Every keyword this crate knows has an accessor of its own, and any keyword at
all can be set by name. A keyword too long for the eight columns a card gives it
becomes a HIERARCH card, and a value too long for one card is written across
CONTINUE cards.
#
Compressing an image
An image can be stored tile-compressed, the way fpack writes one: cut into
tiles, each tile compressed on its own, and the result written as a binary table
that a reader treats as the image it stands for. Everything that reads an image
goes on working.
#
#
#
Building a file from nothing
#
#
#
Working without a filesystem
FitsSlice reads a file that is already in memory — one arriving over a
network, say, or a build with the fs feature turned off. It reads, writes and
streams the same things FsFits does, and from_vec takes over your buffer
rather than copying it. A gzipped buffer is decompressed transparently.
use ;
use ImageHDU;
#
Feature flags
default-features = false gives you header, image and table parsing over
in-memory data through FitsSlice, with no filesystem, async or threading
support.
| Feature | Default | Effect |
|---|---|---|
fs |
✅ | Read and write FITS files on the filesystem via FsFits |
gzip |
✅ | Transparently decompress gzipped files and buffers |
tokio |
✅ | Async open and streaming reads |
rayon |
✅ | Parallel table row decoding, worth about 4x on a big table |
serde |
Convert table rows to and from your own structs |
Benchmarks
cargo bench --features fs,serde,rayon times opening a file, reading a table
and decoding its rows, against the Gaia fixture under tests/. It reports the
fastest of several runs and skips when the fixture is absent.
Changelog
What has changed between releases is in CHANGELOG.md.
Documentation
Every public item is documented, and #![deny(missing_docs)] keeps it that way.
The API docs are on docs.rs, built with every feature
enabled so the serde, tokio and gzip parts are visible.
Design Goals
- Safety — eliminate undefined behavior and unsafe FFI
- Portability — run anywhere Rust runs
- Ergonomics — minimal boilerplate
- Performance — streaming-friendly, low overhead
- Familiarity — CFITSIO-inspired, Rust-native
Supported FITS Features
| Feature | Status | Notes |
|---|---|---|
| Primary HDU | ✅ | |
| Extension HDUs | ✅ | |
| Image HDU | ✅ | Any number of axes; planes beyond the second are indexed |
| Binary tables | ✅ | serde converts rows to and from your structs |
| ASCII tables | ✅ | Read, written, streamed and serde-mapped like binary ones |
| Variable-length array columns | ✅ | TFORMn P and Q, read and written through the heap |
| Complex columns | ✅ | TFORMn C and M |
| Column scaling | ✅ | TSCALn, TZEROn and TNULLn applied both ways |
| Unsigned columns | ✅ | The TZEROn convention, at all four integer widths |
| Multidimensional columns | ✅ | TDIMn read and written, nesting as deep as it says |
| Undefined image pixels | ✅ | BLANK reads as NaN rather than as black |
| Header read | ✅ | CONTINUE long values and HIERARCH keywords included |
| Header write | ✅ | Mandatory cards filled in and ordered as the standard asks |
| Header editing | ✅ | set_card and remove_card by keyword, writing HIERARCH and CONTINUE as needed |
| Image write | ✅ | Any number of axes, then save or to_vec |
| Table write | ✅ | set_table / set_rows, for both table kinds |
| Building files | ✅ | push_extension and remove_extension |
| Gzip decompression | ✅ | .fits.gz files and gzipped buffers alike |
| Streaming image reads | ✅ | stream_normalised_image, via the tokio feature |
| Streaming table rows | ✅ | stream_table_rows, via the tokio feature |
| WCS conventions | ✅ | CDi_j, PCi_j and CDELTn/CROTAn, with LONPOLE and LATPOLE |
| WCS projections | ✅ | TAN, SIN, ARC, STG, ZEA, CAR, MER, CEA, AIT, MOL |
| WCS distortions | ✅ | SIP and TPV, both applied and inverted |
| Non-celestial axes | ✅ | A cube's third axis and beyond, linear or -LOG |
| CHECKSUM and DATASUM | ✅ | Written on save; checksum::verify checks an HDU |
| Random groups | ✅ | group_count and read_group, with PSCALn and PZEROn |
| Compressed image read | ✅ | RICE_1, HCOMPRESS_1, PLIO_1, GZIP_1/2, NOCOMPRESS, any number of axes |
| Compressed image write | ✅ | RICE_1, HCOMPRESS_1, PLIO_1, GZIP_1/2 and NOCOMPRESS, through ImageHDU::compress |
| Quantised floating point | ✅ | ZQUANTIZ dithering read and written, ZBLANK included |
| HCOMPRESS smoothing | ✅ | SMOOTH honoured, matching the reference implementation |
| Conic WCS projections | 🚧 | COE, COD and the rest say so rather than guessing |
License
Licensed under either of:
- Apache License, Version 2.0
- MIT License
at your option.
Contributing
Issues, discussions, and pull requests are welcome. Please open an issue for large changes or new features.
Acknowledgements
Inspired by CFITSIO and the FITS standard maintained by NASA/HEASARC.