fitskit
Pure-Rust, zero-dependency reader and writer for FITS v4.0 — the Flexible Image Transport System format used throughout astronomy.
fitskit reads and writes the full FITS v4.0 standard — primary and extension HDUs, images, ASCII tables, and binary tables (including variable-length arrays) — with no external dependencies in the default build and no C toolchain required. It decodes every tile-compressed image type in the standard (RICE, GZIP, PLIO, HCOMPRESS) and — uniquely among pure-Rust FITS crates — writes RICE- and GZIP-compressed images that cfitsio's funpack reads back byte-for-byte.
Features
- All standard HDU types — Primary, IMAGE, ASCII
TABLE,BINTABLE - Full read and write — round-trip files, bytes, or any
Read/Write - All BITPIX types — 8, 16, 32, 64, -32, -64
- BSCALE/BZERO — raw and scaled access, with the unsigned-integer convention
- Variable-length arrays —
PandQheap descriptors in binary tables - CHECKSUM/DATASUM — ones-complement integrity computation and verification
- Tile-compressed images (read) — RICE_1, GZIP_1, GZIP_2, PLIO_1, and HCOMPRESS_1, including float quantization with subtractive dithering; decoded bit-exactly against cfitsio's
funpack - Tile-compressed images (write) — encode RICE_1 and GZIP_1/GZIP_2 (integer and float); output verified byte-exact through
funpack - Zero dependencies by default — optional
imageandgzipfeatures pull in pure-Rust crates only
Installation
[]
= "0.2"
Usage
Reading a FITS file
use ;
let fits = from_file?;
let primary = fits.primary;
println!;
if let Image = &primary.data
for hdu in fits.extensions
# Ok::
Writing a FITS file
use ;
let pixels: = .map.collect;
let img = new;
let mut fits = with_primary_image;
fits.primary_mut.header.set;
fits.to_file?;
# Ok::
Building a binary table
use ;
let table = new
.add_column
.add_column
.add_column
.push_row
.push_row
.build;
let mut fits = with_empty_primary;
fits.push_extension;
# let _ = fits.to_bytes;
Reading a tile-compressed image
Tile-compressed images are stored on disk as a BINTABLE extension (the FITS
Tiled Image Compression convention). Hdu::as_compressed_image cheaply detects
them; decompress reassembles the full image lazily.
use FitsFile;
let fits = from_file?;
for hdu in fits.extensions
# Ok::
Writing a tile-compressed image
ImageData::compress produces a compressed-image BINTABLE HDU ready to push
into a file. The output is read back byte-for-byte by cfitsio's funpack.
use ;
let pixels: = .map.collect;
let img = new;
// Default options: RICE_1, one tile per row, lossless for integers.
let hdu = img.compress?;
let mut fits = with_empty_primary;
fits.push_extension;
fits.to_file?;
# Ok::
gzipfeature: theGZIP_1/GZIP_2algorithms (e.g.CompressOptions { algorithm: CompressionType::Gzip1, .. }when writing, or decoding a GZIP-compressed tile on read) require thegzipfeature;RICE_1works without it. Build with--features gziporfitskit = { version = "0.2", features = ["gzip"] }.
Converting to/from the image crate (feature image)
With the image feature, ImageData converts to and from the image crate's DynamicImage — e.g. to save a FITS image as a PNG, or to ingest a raster as FITS. Build with fitskit = { version = "0.2", features = ["image"] }.
use ;
let fits = from_file?;
if let Image = &fits.primary.data
# Ok::
Checksums
use ;
let img = new;
let fits = with_primary_image;
// Write with CHECKSUM/DATASUM keywords
let bytes = fits.to_bytes_with_checksum?;
// Verify on read
let fits2 = from_bytes?;
fits2.primary.verify_datasum?;
# Ok::
World Coordinate System (WCS)
With the wcs feature, parse a two-axis celestial WCS straight from a header and
map between 1-based FITS pixel coordinates and world coordinates in
degrees. The spherical-projection math is backed by the zero-dependency
mapproj crate.
use FitsFile;
let fits = from_file?;
let wcs = fits.primary.header.wcs?;
// Pixel (1-based) -> world (lon, lat) in degrees
let = wcs.pixel_to_world.unwrap;
// ...and back to pixel
let = wcs.world_to_pixel.unwrap;
# Ok::
Supported: the common 2-axis celestial case — CTYPEn = xxx--CCC for any
projection mapproj implements (TAN, SIN, ARC, ZEA, STG, AIT, MER,
CAR, CEA, SFL, MOL, conics, …), with the linear transform from CDi_j or
PCi_j + CDELTi (CD takes precedence). SIP distortions and 3+-axis / spectral
WCS are out of scope.
Core types
A FITS file is an ordered sequence of Header-Data Units (HDUs). fitskit mirrors that structure directly:
| Type | Role |
|---|---|
FitsFile |
Top-level container — an ordered Vec<Hdu>. Reads/writes files, byte slices, or any Read/Write; builder methods (with_primary_image, with_empty_primary, push_extension, to_file, to_bytes, to_bytes_with_checksum). |
Hdu |
One Header-Data Unit: a Header plus an HduData payload. as_compressed_image() exposes a tile-compressed image stored in a BINTABLE. |
HduData |
The payload enum: Empty, Image(ImageData), AsciiTable(AsciiTable), BinTable(BinTable). |
Header |
Ordered list of Keywords with typed accessors (get_int, get_float, get_string, get_bool) and set. |
Keyword / HeaderValue |
An 80-byte header card and its typed value (with CONTINUE long-string handling). |
ImageData / PixelData |
Image axes plus a typed pixel buffer (U8/I16/I32/I64/F32/F64); raw access and BSCALE/BZERO-scaled access (scaled_values). |
BinTable / BinColumn / BinColumnType / BinCellValue |
Binary-table model — columns, rows, and heap (variable-length arrays); built with BinTableBuilder. |
AsciiTable |
ASCII TABLE model with TFORMn column parsing and TSCALn/TZEROn scaling. |
CompressedImage / CompressionType / TileGeometry / Quantize |
Read-side view over a tile-compressed image: detect the algorithm and geometry, then decompress() to an ImageData. |
CompressOptions |
Write-side encode options (algorithm, tiling, quantization, dithering) for ImageData::compress / compress_image. |
Bitpix |
The BITPIX data type (8/16/32/64/-32/-64). |
Error / Result |
Crate error type and result alias. |
Decoding is done eagerly at read time (big-endian → native), except tile-compressed
images, which are decoded lazily on decompress() so the original compressed tiles
are preserved for a lossless round-trip write.
Feature flags
| Flag | Default | Description |
|---|---|---|
| (none) | ✓ | Core read/write, all HDU types, RICE_1 / PLIO_1 / HCOMPRESS_1 decompression, and RICE_1 compression — zero dependencies |
image |
Conversion between ImageData and the image crate's DynamicImage |
|
gzip |
GZIP_1/GZIP_2 tile compression and decompression via the pure-Rust miniz_oxide crate |
|
wcs |
Two-axis celestial World Coordinate System pixel ⇄ world transforms (Wcs, Header::wcs) via the zero-dependency mapproj crate |
The default build stays dependency-free; RICE_1, PLIO_1, and HCOMPRESS_1 decompression and RICE_1 compression all work without any feature (only GZIP_1/GZIP_2 need the gzip feature).
Why fitskit?
Among Rust FITS crates, fitskit fills a specific niche — pure Rust, zero default dependencies, full read + write including tables, complete compressed-image reading, and compressed-image writing, with no C toolchain to install. No other pure-Rust crate writes compressed FITS.
| Crate | Pure Rust | Write | Tables | Compressed read | Compressed write | Notes |
|---|---|---|---|---|---|---|
fitsio |
✗ | ✓ | ✓ | ✓ | ✓ | Wraps the cfitsio C library; needs a C toolchain |
fitsrs |
✓ | ✗ | partial | — | ✗ | Read-only |
fitrs |
✓ | ✓ | ✗ | ✗ | ✗ | Dormant; no table support |
| fitskit | ✓ | ✓ | ✓ | ✓ (all types) | ✓ (RICE/GZIP) | Zero default deps; no C dependency |
Supported / not supported
Supported
- Primary + extension HDUs; images, ASCII tables, binary tables (read + write)
- All BITPIX types; BSCALE/BZERO scaling and the unsigned-integer convention
- Variable-length arrays (
P/Qdescriptors) in binary tables - CHECKSUM/DATASUM computation and verification
- Tile-compressed image reading: RICE_1, GZIP_1, GZIP_2, PLIO_1, and
HCOMPRESS_1 — for integer and floating-point images, including quantization
with subtractive dithering (
NO_DITHER/SUBTRACTIVE_DITHER_1/SUBTRACTIVE_DITHER_2) - Tile-compressed image writing: RICE_1 and GZIP_1/GZIP_2 — integer
(lossless) and float (lossless via GZIP, or lossy quantized + dithered);
output verified byte-exact through cfitsio's
funpack - Two-axis celestial WCS pixel ⇄ world transforms (
wcsfeature) for the commonCTYPEn = xxx--CCCcase, linear transform fromCDi_jorPCi_j+CDELTi
Not supported
- Encoding
PLIO_1orHCOMPRESS_1(these decode only) - HCOMPRESS image smoothing (
SMOOTH≠ 0) on decode - Random groups (deprecated in FITS v4.0)
- WCS: SIP distortions, 3+-axis / spectral WCS,
PVi_mprojection parameters, and non-degreeCUNIT(thewcsfeature handles the 2-axis celestial linear- projection case only)