Expand description
Read and write MRC-2014 files — the standard in cryo-EM and structural biology. Handles byte-order, type conversion, and compression so you can focus on your science. SIMD-accelerated, mmap-enabled.
§Basic usage
These APIs are all you need for everyday work. They return typed data (zero-copy borrowed views) and auto-detect compression, endianness, and the file’s voxel mode.
§Quick start
use mrc::{read_as, write_as};
// Read an entire volume in one call
let (header, data): (_, Vec<f32>) = read_as("density.mrc")?;
println!("{}×{}×{} volume, {} voxels",
header.nx, header.ny, header.nz, data.len());
// Write a volume in one call
write_as("output.mrc", &data, [512, 512, 256])?;§Reading data
Open any MRC file — compression, byte order, and voxel type are detected automatically. No need to specify gzip, endianness, or mode.
use mrc::{open, Reader};
let reader = open("tilt_series.mrc")?;
println!("{}×{}×{} voxels, mode {:?}",
reader.shape().nx, reader.shape().ny, reader.shape().nz,
reader.mode());Then choose an iteration method. Each returns DataBlock chunks
whose DataView variant is determined by the file’s mode at runtime
— no compile-time guessing, no ModeMismatch errors:
| Method | Returns | Use case |
|---|---|---|
slices | one Z-plane at a time | 2D processing per slice |
slabs | k Z-planes | Batch processing |
tiles | arbitrary 3D blocks | Local analysis |
subregion | single block by coordinate | Random access |
read_volume | entire volume | Full-volume processing |
volumes | sub-volumes | Volume stacks (ISPG 401+) |
for slice in reader.slices() {
let block = slice?;
match block.data() {
mrc::DataView::Float32(data) => { /* process f32 slice */ }
mrc::DataView::Int16(data) => { /* process i16 slice */ }
_ => {} /* other modes handled transparently */
}
}Or use convert::<f32>() — the fire-and-forget
option that reads any mode as f32:
for slice in reader.convert::<f32>().slices() {
let block = slice?;
println!("z={}: {} voxels", block.offset[2], block.data.len());
}
// Full volume in one call:
let block = reader.convert::<f32>().read_volume()?;The same iterators — slabs,
tiles, subregion — work with
convert::<f32>() too, as do
with_complex_strategy
and with_m0_interpretation.
§Writing data
Use create() to get a WriterBuilder, set shape and mode,
then call finish. Write data block by block
— each write_data_block encodes and writes
immediately (streaming, no intermediate buffering):
use mrc::{create, DataBlock, OwnedData};
let mut writer = create("output.mrc")
.shape([256, 256, 128])
.mode::<f32>()
.finish()?;
let block = DataBlock::Owned {
offset: [0, 0, 0],
shape: [256, 256, 1],
data: OwnedData::Float32(vec![0.0f32; 256 * 256]),
};
writer.write_data_block(&block)?;
writer.update_header_stats()?;
writer.finalize()?;For a single call, use write_as() or Writer::set_data:
use mrc::write_as;
let data = vec![0.0f32; 256 * 256 * 128];
write_as("output.mrc", &data, [256, 256, 128])?;The writer lifecycle:
- Write blocks with
write_data_blockorwrite_block_asfor auto-conversion. - Call
update_header_statsto fill indmin/dmax/dmean/rms. - Require
finalize— rewrites the header with final metadata.
§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.
| Mode | Rust type | Typical use |
|---|---|---|
Int8 (0) | i8 | Binary masks |
Int16 (1) | i16 | Raw cryo-EM density |
Float32 (2) | f32 | Processed / reconstructed density |
Int16Complex (3) | Int16Complex | Complex data (i16 real + i16 imag) |
Float32Complex (4) | Float32Complex | Complex data (f32 real + f32 imag) |
Uint16 (6) | u16 | Segmentation labels |
Float16 (12) | f16 | Half-precision storage (feature f16) |
Packed4Bit (101) | u8 via slices_u8 | 4-bit packed data |
When you don’t know the mode ahead of time, use
convert::<f32>() which converts any mode to f32.
§Compression auto-detection
Reader::open reads the first two bytes to detect compression:
| Magic bytes | Format |
|---|---|
\x1f\x8b | Gzip |
BZ | Bzip2 |
| anything else | Plain |
Plain files use mmap (zero-copy) or buffered I/O. Compressed files
are fully decompressed into memory on open (capped at 256 GiB).
Use Reader::open_gzip_with_limit or
[Reader::open_bzip2_with_limit] for a custom limit.
§Large files
Reader::open automatically uses memory-mapped I/O (requires the
mmap feature). Same iterator API, zero-copy DataBlock views,
OS-managed paging. For very large compressed files, decompress with
gunzip/bunzip2 first, then use plain Reader::open for mmap.
§Reading from memory / streams
When data is already in memory (e.g. from a camera readout or network
stream), use Reader::from_reader or Reader::from_bytes:
use mrc::Reader;
use std::io::Cursor;
let bytes = std::fs::read("density.mrc")?;
let reader = Reader::from_reader(Cursor::new(bytes))?;§Troubleshooting
| Error | Likely cause | What to try |
|---|---|---|
InvalidHeader | Not an MRC file | mrc validate file.mrc or try Reader::open_permissive |
FileSizeMismatch | Truncated / trailing garbage | Re-download or run mrc validate |
ModeMismatch | Block type != file mode | Use Writer::write_block_as for auto-conversion |
BoundsError | Block outside volume | Check offset + shape ≤ dimensions |
UnsupportedMode | Mode needs f16 feature | Enable f16 or convert with another tool |
§Advanced API
These APIs give you lower-level access to raw bytes, headers, extended metadata, and validation. They are intended for tools, pipelines, and developers who need more control than the basic iterators provide.
§Raw byte access
⚠️ The returned bytes are raw on-disk bytes — file byte order,
no endian correction, no type conversion. Use reader.endian()
and reader.mode() to interpret them correctly.
For typed zero-copy access, use subregion /
slices for the basic API, or
convert::<f32>() for fire-and-forget conversion.
| Method | Returns | Copy cost |
|---|---|---|
raw_bytes | &[u8] — whole data region | zero-copy |
read_block_bytes_cow | [Cow<[u8]>] — sub-block | zero-copy for contiguous XY slabs |
read_block_bytes | Vec<u8> — sub-block | always copies |
Contiguous = offset [0, y, z], shape [nx, ny, sz]. Any
sub-XY offset or shape forces a row-by-row gather into owned memory.
⚠️ read_block_bytes always returns an owned Vec, even for
contiguous blocks. For large volumes this causes a full copy of the
block. Use read_block_bytes_cow when you want to avoid the
allocation, or use subregion /
slices for typed zero-copy access.
use std::borrow::Cow;
// Zero-copy: borrows from mmap for contiguous blocks
let cow: Cow<[u8]> = reader.read_block_bytes_cow([0, 0, 0], [256, 256, 64])?;
// Always owned: allocates + copies even for contiguous blocks
let bytes: Vec<u8> = reader.read_block_bytes([0, 0, 0], [256, 256, 64])?;§Permissive mode / quirky files
Common microscope quirks (NVERSION left at 0, "MAP\0" instead of
"MAP ") are handled transparently by open().
For severely non-standard files, use
Reader::open_permissive which turns non-critical header issues
into warnings instead of hard errors, and allows opening files that
are shorter than the header declares. Use is_truncated
to detect truncated data:
let (reader, warnings) = mrc::Reader::open_permissive("legacy.mrc")?;
for w in &warnings { eprintln!("note: {w}"); }
if reader.is_truncated() {
eprintln!("warning: file is incomplete");
}Permissive variants Reader::from_reader_permissive and
Reader::from_bytes_permissive are also available for in-memory
data.
§Special-mode reads (Packed4Bit and Mode 0)
These modes have no Voxel implementation — there is no single
Rust type that maps to them safely at compile time — so dedicated
methods read directly as u8 or f32:
slices_u8/slabs_u8— unpackPacked4Bitnibbles, or narrow Uint16, tou8read_volume_u8— fullPacked4Bitvolume asu8slices_mode0/slabs_mode0— read Mode 0 asf32, signed or unsigned
§Headers
The Header struct mirrors the 1024-byte MRC-2014 fixed header.
Every field is a typed public member.
use mrc::Header;
let h = Header::new();
assert_eq!(h.map, *b"MAP ");For fluent construction, use HeaderBuilder:
use mrc::HeaderBuilder;
let header = HeaderBuilder::new()
.shape([512, 512, 256])
.mode::<f32>()
.cell_lengths(1.0, 1.0, 1.0)
.build()?;Three validation levels:
validate— quick yes / novalidate_detailed— specific diagnosisvalidate_permissive— warnings
Volume type helpers (configure ispg and mz):
let mut h = Header::new();
h.nx = 64; h.ny = 64; h.nz = 120;
h.mx = 64; h.my = 64; h.mz = 30;
h.set_volume_stack(30);
assert!(h.is_volume_stack());
assert_eq!(h.logical_shape(), [4, 30, 64, 64]);Key computed properties:
voxel_size(), sampling(),
cell_lengths(), cell_angles(),
cell_volume(), density_stats(),
logical_shape(), exttyp(),
get_labels(), detect_endian(),
is_standard_map(), decode_from_bytes(),
encode_to_bytes().
§Extended headers
Many MRC files carry metadata after the fixed header identified by
a 4-byte exttyp field. Use parse_extended_header
for auto-detection:
use mrc::ExtHeaderData;
match reader.parse_extended_header() {
ExtHeaderData::Fei1(records) => {
println!("FEI1 tilt series ({} records)", records.len());
for r in &records {
println!(" tilt {:.1}°, defocus {:.1} µm",
r.alpha_tilt, r.defocus);
}
}
ExtHeaderData::None => println!("No recognized extended header"),
_ => {}
}Typed convenience methods: fei1_metadata,
fei2_metadata, ccp4_records,
mrco_records, seri_records,
agar_records, imod_metadata.
§Validation
validate_full checks header, file size, endianness, data
statistics, and NaN/Inf. Returns a ValidationReport:
use mrc::{validate_full, Severity};
let report = mrc::validate_full("protein.mrc", false)?;
if !report.is_valid() {
for issue in &report.issues {
if issue.severity == Severity::Error {
eprintln!("[{}] {}", issue.category, issue.message);
}
}
}Use validate_reader if the file is already open.
§Error types
Fallible functions return Result<T, Error>. Match on variants:
use mrc::Error;
fn describe(err: &Error) -> &str {
match err {
Error::Io(_) => "I/O failure",
Error::InvalidHeader => "not a valid MRC file",
Error::ModeMismatch { .. } => "wrong voxel type for this file",
Error::BoundsError { .. } => "block outside volume",
Error::FileSizeMismatch { .. } => "file truncated or has trailing data",
_ => "other",
}
}HeaderValidationError gives fine-grained header diagnostics.
§Feature flags
| Feature | Description | Default |
|---|---|---|
mmap | Memory-mapped readers and writers | ✅ |
f16 | Half-precision float via the half crate | ✅ |
simd | AVX2 / NEON acceleration | ✅ |
parallel | Parallel decode/convert/encode via rayon | ✅ |
gzip | Gzip-compressed I/O | ✅ |
bzip2 | Bzip2-compressed I/O | ❌ |
ndarray | Return volumes as ndarray::Array3<T> | ❌ |
serde | Serialize/Deserialize support | ❌ |
use ndarray::Array3;
let arr: Array3<f32> = reader.convert::<f32>().to_ndarray()?;
println!("{}×{}×{} array", arr.shape()[0], arr.shape()[1], arr.shape()[2]);§Endianness
MRC files encode byte order via a 4-byte MACHST stamp at file offset 212.
FileEndian represents the detected byte order:
use mrc::FileEndian;
let stamp: [u8; 4] = [0x44, 0x44, 0x00, 0x00]; // little-endian
assert_eq!(FileEndian::from_machst(&stamp), FileEndian::LittleEndian);New files are always little-endian. The crate has a fallback: if the MODE field is invalid under the detected endianness, the opposite byte order is tried (handles files with a wrong MACHST stamp).
§Philosophy
This crate does one thing — read and write MRC files. It does no
array arithmetic, image processing, or type conversion beyond
MRC-specific shortcuts (convert::<f32>(), slices_mode0,
slices_u8). Leave those to crates like ndarray, or your own code.
Structs§
- Agar
Record - Agard extended header record.
- Ccp4
Record - A single CCP4 symmetry record — an 80-character text line containing space group symmetry operators.
- Convert
Reader - Auto-conversion wrapper returned by
Reader::convert. A reader wrapper that auto-converts all voxel data to typeT. - Fei1
Metadata - Common FEI1 metadata fields.
- Fei2
Metadata - FEI2 metadata extends FEI1 with additional v2 fields.
- Float32
Complex - A complex number with 32-bit float real and imaginary components.
- Header
- Mirror of the 1024-byte MRC-2014 fixed header.
- Header
Builder - Builder for constructing validated MRC headers.
- Imod
Info - IMOD-specific metadata parsed from the
extrablock (bytes 56-63). - Imod
Metadata - IMOD-specific metadata parsed from the main header’s
extrabytes. - Int16
Complex - A complex number with 16-bit signed integer real and imaginary components.
- Mrco
Record - A legacy MRCO extended header record.
- Reader
- Consolidated MRC reader with automatic mmap/buffered backend selection. MRC file reader with automatic backend selection.
- Seri
Record - SerialEM extended header record.
- Validation
Issue - Validation report types and comprehensive file checker. A single validation issue found during file inspection.
- Validation
Report - Validation report types and comprehensive file checker. Structured result of a full MRC file validation.
- 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.
- Compression
Level - Compression level for compressed MRC writers.
- Data
Block - A block of voxel data with a 3D offset and shape, returned by the default (non-convert) reader methods.
- Data
View - Borrowed typed slice into an MRC volume’s raw data.
- Error
- The top-level error type for MRC I/O operations.
- ExtHeader
Data - Parsed extended header data, dispatched by
ExtHeaderType. - ExtHeader
Type - Known extended header types identified by the 4-byte EXTTYP field.
- File
Endian - Endianness of MRC file data. Endianness of MRC file data.
- Header
Validation Error - Errors that can occur during detailed header validation.
- Imod
Image Type - IMOD image type classification from the
idtypefield. - M0Interpretation
- Interpretation of Mode 0 (8-bit) data for legacy files.
- Mode
- MRC data mode defining the on-disk representation of voxel values.
- Owned
Data - Owned typed data — returned when a copy is unavoidable (sub-block scatter/gather, endian mismatch).
- Severity
- Validation report types and comprehensive file checker. Severity of a validation issue.
Constants§
- AGAR_
RECORD_ SIZE - Size of a single AGAR record, in bytes.
- CCP4_
RECORD_ SIZE - Size of a single CCP4 symmetry record, in bytes.
- DEFAULT_
MAX_ DECOMPRESSED_ BYTES - Default decompression safety limit for gzip/bzip2 files (256 GiB).
- FEI1_
RECORD_ SIZE - Size of a single FEI1 metadata record, in bytes.
- FEI2_
RECORD_ SIZE - Size of a single FEI2 metadata record, in bytes.
- MRCO_
RECORD_ SIZE - Size of a single MRCO record, in bytes.
- SERI_
RECORD_ SIZE - Size of a single SERI (SerialEM) 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_
agar_ records - Parse extended header bytes as typed records.
- parse_
ccp4_ records - Parse extended header bytes as typed records.
- parse_
fei1_ records - Parse a raw extended header byte slice as a vector of FEI1 records.
- parse_
fei2_ records - Parse a raw extended header byte slice as a vector of FEI2 records.
- parse_
imod_ metadata - Parse IMOD metadata from the main header’s
extrabytes. - parse_
mrco_ records - Parse extended header bytes as typed records.
- parse_
seri_ records - Parse extended header bytes as typed records.
- read_as
- Read an entire MRC volume into a
Vec<T>with auto-mode detection. - reinterpret_
m0 - Reinterpret Mode 0 (8-bit) data as signed or unsigned and convert to
f32. - validate_
full - Validation report types and comprehensive file checker. Run comprehensive validation on an MRC file.
- validate_
reader - Validation report types and comprehensive file checker.
Run comprehensive validation on an already-opened
Reader. - write_
as - Write an entire MRC volume from a
&[T]with a single call.