xisf-header
Rust crate that reads and writes XISF
(Extensible Image Serialization Format) image-file headers: it extracts the
embedded FITS keywords and XISF <Property> elements, supports
create/read/update/delete on both, and serializes a header back into an XISF
container.
The crate is header-only: it parses and emits the 16-byte XISF preamble plus the UTF-8 XML header, and never reads image/pixel data.
Features
- Parse an XISF header from bytes or a file. The
XISF0100signature, the little-endian XML-length field (capped at 8 MiB), and UTF-8 encoding are validated. - Strict keyword access. A bare name must be unique or the accessor returns
Error::Ambiguous; repeated keywords (e.g.HISTORY) are addressed with an(name, n)key or theget_all/counthelpers. - Typed reads and writes. One generic
get::<T>over the open [FromField] trait (String,f64,i64,u32,bool, and a date/time), withget_str/get_f64/… wrappers; writes takeimpl IntoValue, so the Rust type chooses string vs. bare-literal formatting. <Property>round-trip. XISF properties keep theirtype,comment, andformatattributes verbatim;Stringproperties stored as child text are read. Values are stored raw (XISF properties are not FITS-quoted).- Two serialization outputs.
to_bytes(&hints)for a self-contained container andto_header_bytes(&hints)for the header block alone. - No
unsafe. Dependencies are pure Rust (no C/sys crates):quick-xml,thiserror,time, and optionalserde. MSRV 1.82.
Install
[]
= "0.2"
Optional features
-
serde— deriveSerialize/DeserializeonHeader,FitsKeyword,Property, and the value types:= { = "0.2", = ["serde"] }
Usage
Parse a header and read keywords
use Header;
let bytes = read?;
let header = parse?;
// Typed reads are strict: `?` surfaces a duplicate-keyword ambiguity; the inner
// `Option` is `None` when the keyword is absent or unreadable as that type.
let exposure = header.get_f64?;
let image_type = header.get_str?;
// XISF <Property> access.
let focal_length_m = header.;
# Ok::
Create, read, update, delete
use Header;
let mut header = new;
// `set` upserts: update a unique keyword in place, or append when absent. The
// Rust type of the value chooses its on-disk form — strings are quoted,
// numbers and logicals are bare literals.
header.set?;
header.set_comment?;
header.set?;
header.set?;
assert_eq!;
assert_eq!;
header.set?; // update
header.remove?; // delete
# Ok::
Repeated keywords
use Header;
let mut header = new;
header.append?;
header.append?;
// A bare name is ambiguous once it repeats — select an occurrence instead.
assert!;
assert_eq!;
assert_eq!;
# Ok::
XISF properties
use Header;
let mut header = new;
// Plain `set_property` creates a `String` property; an explicit XISF type is
// kept on the property and survives round-trips.
header.set_property?;
header.set_property_with_type?;
assert_eq!;
assert_eq!;
assert_eq!;
# Ok::
Controlled numeric formatting
use ;
let mut header = new;
header.set?; // fixed-point, 2 decimals
assert_eq!;
# Ok::
Write a container and round-trip through a file
use ;
let mut header = new;
header.set?;
let hints = default;
// Emit a complete container, or just the header block.
let bytes = header.to_bytes;
assert_eq!;
header.write_to_file?;
let reloaded = read_from_file?;
assert_eq!;
# remove_file.ok;
# Ok::
Edit a file's header in place
use ;
update_file?;
# Ok::
Warning:
to_bytes/write_to_file/update_fileemit a self-contained, header-only container: the data block is zero-filled fromStructuralHints, and XML elements the crate does not model (Metadata,Resolution, thumbnails, …) are not re-emitted. Do not point them at files whose pixel data must be kept. To edit a real image's header, emitto_header_bytes(&hints)and append the file's original data yourself.
Documentation
Full API documentation is generated from the source doc comments and published
at docs.rs/xisf-header for every release
(all features enabled). Build it locally with cargo doc --no-deps --all-features --open. Every public item is documented; CI fails the build on
missing or broken documentation.
License
Licensed under the Apache License, Version 2.0.