Expand description
Read and write MRC-2014 files — the standard in cryo-EM and structural biology.
This crate handles file I/O, byte-order detection, and type-safe data access so you can focus on your science. It’s fast (SIMD, parallel encoding) and works with plain, gzip, and bzip2 files out of the box.
§Quick example
use mrc::{open, create, VoxelBlock};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let reader = open("protein.mrc")?; // auto-detects compression
for slice in reader.slices_f32() { // converts to f32 for you
let block = slice?;
}
let mut writer = create("output.mrc")
.shape([512, 512, 256])
.mode::<f32>()
.finish()?;
writer.write_block(&VoxelBlock::new(
[0, 0, 0], [512, 512, 1],
vec![0.0f32; 512 * 512],
)?)?;
writer.finalize()?;
Ok(())
}§Reading files
Open any MRC file with open() or Reader::open. Compression is
detected from the file’s magic bytes — no need to tell it gzip or bzip2.
use mrc::Reader;
let reader = Reader::open("tilt_series.mrc")?;
println!("{}×{}×{} voxels, mode {:?}",
reader.shape().nx, reader.shape().ny, reader.shape().nz,
reader.mode());Then pick an iteration method:
slices— one Z-plane at a timeslabs— batches ofkZ-planestiles— arbitrary 3D blockssubregion— a single block by coordinate
Or grab the full volume in one call:
read_volume::<T>()— full volume as anyVoxeltyperead_volume_f32()— full volume, any mode converted tof32
Each yields VoxelBlock<T> — a data chunk with its offset and
shape, so you always know where it belongs.
For density maps stored as integers, use slices_f32
or read_volume_f32() to get f32 with
automatic mode conversion (no need to match the file’s storage type):
It converts every MRC mode to f32 (integer widening, complex→magnitude,
the works):
for slice in reader.slices_f32() {
let block = slice?;
println!("slice {} mean density: {:.2}",
block.offset[2],
block.data.iter().sum::<f32>() / block.data.len() as f32);
}Or read the full volume at once with read_volume_f32()
and wrap with ndarray for numpy-like slicing:
let block = reader.read_volume_f32()?;
let array = ndarray::Array3::from_shape_vec(
[reader.shape().nz, reader.shape().ny, reader.shape().nx],
block.data,
).unwrap();§Large files
When the file does not fit in RAM, use MmapReader (requires the
mmap feature). Same iterator API, zero-copy slab_as,
OS-managed paging.
§Quirky files
Reader::open_permissive opens files with minor header issues as
warnings instead of hard errors — handy for data from older instruments.
let (reader, warnings) = Reader::open_permissive("legacy.mrc")?;
for w in &warnings { eprintln!("note: {w}"); }§Writing files
Use create() to get a WriterBuilder, set the shape and voxel type,
then call finish.
use mrc::create;
let mut writer = create("output.mrc")
.shape([256, 256, 128])
.mode::<f32>()
.finish()?;The lifecycle:
- Write blocks with
write_block. The typeTmatches the file’s mode — a compile-time check that prevents accidentally treating bytes as the wrong kind of number. - Finalize with
finalizeto rewrite the header. - Optionally call
update_header_statsbefore finalize to fill indmin/dmax/dmean/rms.
Four backends through the same builder:
| Backend | Builder method | Best for |
|---|---|---|
Writer | finish() | General use, writes straight to disk |
MmapWriter | finish_mmap() | Very large files (mmap feature) |
GzipWriter | finish_gzip() | Compressed output (gzip feature) |
[Bzip2Writer] | finish_bzip2() | Compressed output (bzip2 feature) |
§Data modes
MRC files encode voxels in one of several numeric modes. Mode
represents them at runtime; Voxel ties each Rust type to its mode
at compile time, catching mismatches before any data is read or written.
| Mode | Rust type | Typical use |
|---|---|---|
Int8 (0) | i8 | Binary masks |
Int16 (1) | i16 | Raw cryo-EM density |
Float32 (2) | f32 | Processed / reconstructed density |
Uint16 (6) | u16 | Segmentation labels |
Float16 (12) | f16 | Half-precision storage (feature f16) |
Complex (Int16Complex, Float32Complex) and packed 4-bit
(Packed4Bit) modes are also available — see their individual docs.
When you don’t know the mode ahead of time, use slices_f32
which converts any mode to f32.
§Headers
The Header struct mirrors the 1024-byte MRC-2014 fixed header.
Every field is a typed public field — dimensions, cell parameters,
axis mapping, density statistics, text labels, and more.
use mrc::Header;
let h = Header::new();
assert_eq!(h.map, *b"MAP ");For fluent construction with validation, use HeaderBuilder:
use mrc::HeaderBuilder;
let header = HeaderBuilder::new()
.shape([512, 512, 256])
.mode::<f32>()
.build()?;Three validation levels:
validate— quick yes / novalidate_detailed— tells you exactly what is wrong viaHeaderValidationErrorvalidate_permissive— warnings for non-critical issues
§Philosophy
This crate does one thing — read and write MRC files. It does not
do array arithmetic, image processing, or type conversion beyond a few
MRC-specific shortcuts (slices_f32, slices_mode0, slices_u8).
Leave those to crates like ndarray, or your own code.
§Feature flags
| Feature | Description | Default |
|---|---|---|
mmap | Memory-mapped readers and writers | ✅ |
f16 | Half-precision float via the half crate | ✅ |
simd | AVX2 / NEON acceleration for integer→f32 | ✅ |
parallel | Parallel encoding via rayon | ✅ |
gzip | Gzip-compressed I/O | ✅ |
bzip2 | Bzip2-compressed I/O | ❌ |
§Advanced topics
§Error handling
Fallible functions return Result<T, Error>. The errors you will
actually hit in practice:
Io— the file could not be read or writtenInvalidHeader— not a valid MRC fileModeMismatch— callingslices::<f32>()on an Int16 file; useslices_f32()insteadBoundsError— read or write outside the volumeFileSizeMismatch— file truncated or has trailing garbage
HeaderValidationError gives fine-grained diagnostics for header
problems (bad dimensions, wrong MAP field, invalid NVERSION …).
§Endianness
MRC files encode byte order via a 4-byte MACHST stamp. FileEndian
handles detection and conversion automatically. New files are always
little-endian, matching modern hardware and the Python mrcfile library.
§FEI extended headers
Data from Thermo Fisher / FEI microscopes often carries FEI1 or FEI2
extended headers — one metadata record per image section.
Fei1Metadata and Fei2Metadata parse these into named fields
(dose, defocus, stage position, pixel size, magnification …).
use mrc::parse_fei1_records;
let bytes = reader.ext_header_bytes();
if let Some(records) = parse_fei1_records(bytes) {
for r in &records {
println!("tilt {:.1}°, defocus {:.1} µm", r.alpha_tilt, r.defocus);
}
}§File validation
validate_full runs comprehensive
checks on a file — header, size, endianness, data statistics (1 %
tolerance), and NaN / Inf scanning. Returns a
ValidationReport with
categorised issues.
If you already have an open Reader, use
validate_reader to avoid
re-opening the file.
Modules§
- validate
- MRC file validation infrastructure.
Structs§
- Fei1
Metadata - FEI extended header metadata types and parsers. Common FEI1 metadata fields.
- Fei2
Metadata - FEI extended header metadata types and parsers. FEI2 metadata extends FEI1 with additional v2 fields.
- Float32
Complex - Header
- Header
Builder - Builder for constructing validated MRC headers.
- Int16
Complex - Mmap
Reader - Memory-mapped MRC reader (requires
mmapfeature). Memory-mapped MRC file reader. - Mmap
Writer - Memory-mapped MRC writer (requires
mmapfeature). Memory-mapped MRC file writer. - Packed4
Bit - 4-bit data packed two values per byte (mode 101).
- Reader
- Buffered MRC reader with lazy slice/slab iterators. In-memory buffered MRC file reader.
- Region
Iter - Lazy iterator over MRC voxel blocks.
Lazy iterator over a volume as a sequence of
VoxelBlocks. - Slab
Stepper - Stepping strategies for
RegionIter. Stepkcontiguous Z-slices at a time ([nx, ny, k]). - Slice
Stepper - Stepping strategies for
RegionIter. Step one Z-plane at a time ([nx, ny, 1]). - Tile
Stepper - Stepping strategies for
RegionIter. Step arbitrary 3D tiles across a volume. - Volume
Shape - Volume geometry in voxels.
- Voxel
Block - A contiguous chunk of voxel data with a 3D offset and shape.
- Writer
- MRC file writer and its builder. MRC file writer using standard file I/O.
- Writer
Builder - MRC file writer and its builder. Builder for configuring and creating a new MRC file writer.
- f16
- Half-precision floating point type (requires
f16feature). A 16-bit floating point type implementing the IEEE 754-2008 standardbinary16a.k.a “half” format.
Enums§
- Complex
ToReal Strategy - Strategy for converting complex numbers to real values.
- Error
- The top-level error type for MRC I/O operations.
- File
Endian - Endianness of MRC file data. Endianness of MRC file data.
- Header
Validation Error - Errors that can occur during detailed header validation.
- M0Interpretation
- Interpretation of Mode 0 (8-bit) data for legacy files.
- Mode
- MRC data mode defining the on-disk representation of voxel values.
Constants§
- FEI1_
RECORD_ SIZE - FEI extended header metadata types and parsers. Size of a single FEI1 metadata record, in bytes.
- FEI2_
RECORD_ SIZE - FEI extended header metadata types and parsers. Size of a single FEI2 metadata record, in bytes.
Traits§
- Voxel
- Trait for MRC voxel types with compile-time mode tracking.
Functions§
- convert_
u8_ slice_ to_ u16 - Widen a
u8slice tou16for writing as Mode 6 (Uint16). - convert_
u16_ slice_ to_ u8 - Narrow a
u16slice tou8, returningErrif any value exceeds 255. - create
- Create a new MRC file for writing.
- open
- Open an MRC file for reading, auto-detecting gzip or bzip2 compression.
- parse_
fei1_ records - FEI extended header metadata types and parsers. Parse a raw extended header byte slice as a vector of FEI1 records.
- parse_
fei2_ records - FEI extended header metadata types and parsers. Parse a raw extended header byte slice as a vector of FEI2 records.
- reinterpret_
m0 - Reinterpret Mode 0 (8-bit) data as signed or unsigned and convert to
f32.
Type Aliases§
- Gzip
Writer - Gzip-compressed MRC writer (requires
gzipfeature). Gzip-compressed MRC file writer.