Changelog#

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[1.1.0] - Unreleased#

Added#

  • control/python: Camera streams can apply backpressure instead of discarding frames. StreamOptions::on_full / OnFull::Block stalls the producer until the consumer frees a buffer slot, guaranteeing no frames are lost on the host. OnFull::EvictOldest discards the oldest buffered frame so the producer never stalls.

  • python: Buffering is configured on the camera, via the Camera.stream_options property in Python, rather than per stream() call. This means that customization is easy for any pipeline.

  • python: CameraStream.dropped(), the number of frames discarded locally because the consumer fell behind. Always 0 under OnFull::Block.

  • DataProductsMeta (with output_data: Option<OutputDataType>) and a new ImageMeta.data_products field. IEEE 4001-2025 (7.1.1, Table 5) defines “Output data” (Raw Data, Partially Corrected Data, Relative Radiometric, Absolute Radiometric, Reflectance) as a separate Data Products Basics item from RadiometricMeta.unit’s “Radiometric unit of measurement” (DN, Reflectance, W/(m2nm sr), …); previously only the latter was represented. This is purely additive: the new field defaults to None/unset and existing files and code are unaffected.

  • MeasurementUnit gained the remaining units IEEE 4001-2025 (7.1.1, Table 5) defines for “Radiometric unit of measurement”: Dn, RadianceNmSr (W/(m2 nm sr)), RadianceUmSr (W/(m2 um sr)), and Microflick. Previously only Reflectance of that list was representable. The new variants are appended so the existing repr(u8) discriminants (and therefore the C enum values) are unchanged. MeasurementUnit’s string parsing is now case-insensitive, matching WavelengthUnit and Interleave.

Changed#

  • control/python: A read that hits its wait_timeout now fails with ControlError::Timeout (TimeoutError in Python) instead of looking like the end of the stream, and the default wait_timeout is 1 s. Iterating stops the stream on a timeout, while get_frame leaves it running so the call can be retried.

  • control/python: Camera streams now buffer 20 frames with OnFull::Block by default. In 1.0 the queue was unbounded, so a slow consumer grew memory without limit; now it stalls the camera instead, and the loss is reported in meta.dropped. Behaviour is unchanged when the consumer keeps up.

  • control: Camera images now report radiometric.unit as MeasurementUnit::Dn (previously Raw) and set data_products.output_data to RawData. Camera ENVI files therefore contain measurement units = DN, which 1.0 readers do not recognise. Code comparing the unit to MeasurementUnit.Raw should check for Dn instead.

  • python: repr(DType) now prints f32 instead of hsi.f32.

Fixed#

  • io: The ENVI parser now correctly parses all metadata fields. Most of these would just have been parsed into the extras field in 1.0.

  • io: The ENVI parser now correctly writes all metadata fields. Many of these would have been lost in 1.0.

  • control: Starting a stream shortly after stopping one failed with an opaque UnexpectedEof. The camera holds the video device for 100-200 ms after /api/stop returns and closes the new connection without sending a header; the handshake is now retried until the camera is ready.

  • control: The first frame of every stream was reported as a lost line and preceded by a black placeholder, because frame sequence numbers were assumed to start at 0 when the camera starts at 1. The first frame now establishes the baseline.

  • control: Black frames standing in for lines the camera failed to deliver carried the sequence number of the frame after the gap, producing duplicate meta.seq values. They now carry the sequence number of the line they replace, so meta.seq stays contiguous across a camera-side loss. Their meta.timestamp is still the one of the frame after the gap.

  • control: Handshake failures and connections dropped mid-capture reported the same bare I/O error; both now include the camera address, the handshake attempts made and the frames produced so far.

  • control: Reading in evicting or unbuffered mode could hand a pipeline fewer frames than it asked for. A producer that fails now ends the stream with its own error instead of leaving the reader waiting, and Python iteration raises that error rather than silently stopping.

Deprecated#

  • MeasurementUnit::Raw, MeasurementUnit::Absorbance, and MeasurementUnit::Arbitrary are deprecated: none of them is a unit IEEE 4001-2025 (7.1.1, Table 5) defines for “Radiometric unit of measurement”. Raw in particular conflated the unit with the processing level, which the standard keeps on a separate axis; replace it with MeasurementUnit::Dn plus DataProductsMeta::output_data = OutputDataType::RawData. For the other two, use MeasurementUnit::Unknown and record the unit in ImageMeta::extra. The variants still parse, serialize, and round-trip through ENVI headers, so existing files keep loading; in Python, assigning one to RadiometricMeta.unit or MeasurementInfo.unit (or passing it to their constructors) now raises a DeprecationWarning.

  • RadiometricMeta::scaling is deprecated. It duplicated EncodingMeta::scale_factor, which is the field IEEE P4001 (7.1.1, Table 5) actually defines under Pixel Encoding as “Scale factor”; use EncodingMeta::scale_factor instead. The ENVI reader still accepts the old measurement scaling key, as an alias for the scale factor, and fills both fields. The writer emits EncodingMeta::scale_factor (falling back to RadiometricMeta::scaling if only that is set) under the new reflectance scale factor key, so a header written by 1.1 stores this value under a different key than 1.0 did.

[1.0.0] - 2026-07-06#

First stable release. This consolidates the 1.0.0-beta.1 through 1.0.0-beta.4 pre-releases; there are no code changes since beta.4.

Key changes since the 0.10.x series are summarized below. See the individual beta entries for full detail.

Added#

  • python: Image.ufunc and the @operation decorator now accept a slice_transform callable, enabling custom operations such as SNV or axis reductions that need the full extent of an axis.

  • sdk/python: Deterministic structural UUIDs for image pipeline nodes via Image::uuid / Image.uuid.

  • python: Type stub (.pyi) generation, SimulatedStageController, and the generic StageMachine API exposed to Python.

  • control: Explicit StageController optical parameters (focal length, object distance, pixel pitch, slit width) with derived field-of-view accessors.

Changed#

  • Breaking, python: Major API rename to drop the redundant HS/HSI prefixes (HSImage → Image, InMemoryCube → ImageArray, HSIFile → ImageFile, HSCamera → Camera, HSIHeader → ImageMeta, HSIError → Error).

  • Breaking, python: Python package is now qtec_hv_sdk (suggested usage: import qtec_hv_sdk as hs).

  • Breaking, c-ffi: Renamed the public image API (hv_hs_image_t/hv_hs_image_* → hv_image_t/hv_image_*) and metadata API (hv_hsi_header_t/hv_hsi_header_* → hv_image_meta_t/hv_image_meta_*).

  • Breaking, control: Renamed the hsi-cam crate to hsi-control and CameraError to ControlError; replaced the stage-controller lens-size helper with explicit optical parameters.

  • io: File reads now skip per-plane seeks when a file or plane is contiguous, greatly improving read speed for those slicing patterns.

Fixed#

  • sdk: Metadata attached with Image.with_meta is now carried onto the streaming/write path (previously dropped when writing, e.g. to ENVI).

  • sdk: Strided slices with an open-ended stop now allocate ceil(n / step) elements, and binary operations propagate upstream errors instead of panicking.

  • python: CameraStream.get_frame releases the GIL while waiting for frames, preventing deadlocks.

Removed#

  • python: write_meta function (no longer has a use case).

  • docs: The WASM-based live demo and bundled pyodide wheels.

[1.0.0-beta.4] - 2026-06-12#

Added#

  • python: Added a StageController.stage_machine property exposing the underlying StageMachine.

Changed#

  • control: The stage return move now uses a fixed return velocity of 100 mm/s instead of the configured streaming velocity.

  • package: Updated cargo deny advisory ignores for pyo3 (RUSTSEC-2026-0176 and RUSTSEC-2026-0177); neither advisory is reachable from our usage.

Fixed#

  • sdk: Metadata attached with Image.with_meta is now carried onto the streaming/write path. Previously the override was only visible through Image.meta, so writing the image (e.g. to ENVI) silently used the source’s original header and dropped changes such as wavelength information.

[1.0.0-beta.3] - 2026-06-11#

Added#

  • python: Image.ufunc now accepts an optional slice_transform callable that maps the requested 2D output plane slice to the input plane slice fetched from the parent, allowing custom operations such as SNV or axis reductions that need the full extent of an axis regardless of the requested output slice. When set, the operation receives the requested output plane slice as a third argument and trims its own output.

  • python: util.operation decorator now forwards a slice_transform argument for ergonomic use of the new capability.

  • docs: Added a new section to the “custom operations” guide with details on the new slice_transform argument.

Changed#

  • io: File reads now detect when the whole file or an entire plane can be read contiguously and skip the per-plane seeks used previously, greatly improving read speed for those slicing patterns.

  • sdk: ImageArray now clones individual planes while streaming instead of copying the entire cube up front, avoiding allocating the full cube twice in memory.

  • python: VectorizedUnaryOp now memoises its dummy-input shape/dtype probe, avoiding repeated Python calls when streaming.

  • dynarray: Array creation now pre-allocates vector capacity, reducing reallocations.

Fixed#

  • sdk: Fixed a source slice calculation bug in the binning operation.

  • python: Fixed a few remaining Image.header to Image.meta conversions that were missed in the v1.0 rename (bundled docs example and ml.py).

[1.0.0-beta.2] - 2026-06-03#

Added#

  • sdk: Added deterministic structural UUIDs for image pipeline nodes via the new Image::uuid method.

  • python: Exposed image pipeline UUIDs through the Image.uuid property.

  • control: Added explicit StageController and SimulatedStageController optical parameters for focal length, object distance, pixel pitch, and slit width, plus derived pixel/slit field-of-view accessors.

  • control: Added a ControlNotFound error variant for clearer missing-control failures.

Changed#

  • Breaking, control: Renamed CameraError to ControlError to better match the scope of camera and stage-control errors.

  • Breaking, control: Replaced the stage-controller lens-size helper with explicit focal length, object distance, pixel pitch, and slit width parameters.

  • control: StageController now reports clearer errors when required motion parameters such as velocity/framerate or distance are missing.

  • control: Simulated stage controllers now flip BSQ sources to BIL internally, so image-backed streaming has the expected orientation.

  • examples: Updated the camera example to demonstrate the revised streaming flow.

  • docs: Added missing Python documentation for select_mask, select, select_bands, and preprocessing.savgol.

Fixed#

  • sdk: Strided slices with an open-ended stop now allocate ceil(n / step) elements to match Python/ndarray slice semantics, fixing a broadcast shape error when the axis length is not divisible by the step.

  • sdk: Binary operations now propagate upstream image errors instead of causing a panic.

  • control: Camera stream shutdown now uses timeouts when sending stop/end commands, avoiding hangs in stream teardown.

  • python: CameraStream.get_frame now releases the GIL while waiting for frames, preventing deadlocks from blocking Python.

[1.0.0-beta.1] - 2026-06-03#

Added#

  • python: Type stub generation via a new pystubs CLI driven from build.rs, so the Python API now ships with .pyi stubs.

  • python: Added SimulatedStageController to the control module — wraps any Camera for easy testing of stage-driven applications.

  • python: Exposed the generic StageMachine API to Python.

  • docs: Docs are now built for both current and previous versions, making it possible to keep using old SDK versions.

Changed#

  • Breaking, python: Major API rename for v1.0 to drop the redundant HS/HSI prefixes.

    • HSImage → Image

    • InMemoryCube → ImageArray

    • HSIFile → ImageFile

    • HSCamera → Camera

    • HSIHeader → ImageMeta

    • HSIError → Error

  • Breaking, python: Python package is now qtec_hv_sdk (suggested usage: import qtec_hv_sdk as hs).

  • Breaking, c-ffi: Renamed the public image API for v1.0 (hv_hs_image_t/hv_hs_image_* to hv_image_t/hv_image_*) and metadata API (hv_hsi_header_t/hv_hsi_header_* to hv_image_meta_t/hv_image_meta_*).

  • c-ffi: Restored inspectable public metadata structs with grouped v1 fields on hv_image_meta_t, including camera, spectral, spatial, radiometric, temporal, calibration, sensor, encoding, and display metadata.

  • Breaking, general: Internal hsi-cam crate renamed to hsi-control; it now exports its own Python submodule using the new PyO3 module syntax.

Removed#

  • python: write_meta function (no longer has a use case).

  • docs: The WASM-based live demo, including all bundled pyodide wheels. The CI was running out of space and the demo was already out of date; it can be cherry-picked back from history later if needed.

Fixed#

  • python: Import bug in the annotations submodule.

[0.10.2] - 2026-05-11#

Added#

  • python: Added bindings for set_bit_mode and get_bit_mode.

  • fix: Dark frame generation to handle multiple multiple data types.

  • fix: Use stream.stop() after exiting stream.

[0.10.1] - 2026-05-07#

Added#

  • annotations module for working with annotations. The module is compatible with files produced by Hypervision Explorer

  • Images now have a new method select_mask_from_descriptor which uses a descriptor as a mask.

  • Generic StageMachine interface to support multiple linear recording stage types.

  • Add move_direction to StageController for continuous movement.

  • python: The annotations module and select_mask_from_descriptor method are also available in the Python API.

  • python: Add move_direction to StageController.

Changed#

  • Added optional n_frames parameter to CameraInterface::stream (HSCamera.stream in Python).

Fixed#

  • Full camera buffers previously lead to a block (caused by a data race) in the camera thread. The streams now use timeouts to keep checking for stop-commands even when the frame buffer is full.

  • Slicing error in PAM/ENVI and TIFF files causing stepped slices to fail fixed.

[0.10.0] - 2026-04-15#

Added#

  • HSIStream now has a stop method for stopping infinite streams.

  • The SDK now has logging support.

  • Frames now contain metadata with the frame’s sequence number, timestamp, and whether it was dropped.

  • python: Stream type now supports stopping using either a stop method or the with statement.

  • python: Added support for direct camera streaming through the CameraStream type. The API is the same as Stream.

  • python: Logging is integrated with the Python logging module.

  • python: Stream types now return a FrameMeta object along with the frame data on new frames.

  • python: HSImage.ufunc as well as the @operation decorator now accept a FrameMeta object as the first argument.

  • python: Added a throughput test script for benchmarking camera connection performance.

  • c-ffi: Added hv_frame_meta type to support the new internal API.

Changed#

  • Dropped camera frames are now inserted as blank frames to maintain correct spatial information.

  • Buffers between threads are now bounded with a fixed size of 64 elements.

Fixed#

  • Fixed bug in ImgCamera which caused the bands to be incorrectly chosen for BSQ images.

  • python: Fixed bug in the preprocessing module causing the snv and savgol functions to not work.

[0.9.2] - 2026-03-10#

Added#

  • toggle_lights method added to StageController (also in the Python API)

  • Added get_analog_gain/set_analog_gain methods to HSCamera in the Python API.

Changed#

  • HSCamera and StageController now report connection errors clearly and immediately upon object creation.

[0.9.1] - 2026-02-18#

Added#

  • set_lights method to StageController. Activates lights and autoimatically deactivates them after a specified duration. Exposed timed light control via the Python extension.

[0.9.0] - 2026-01-29#

Added#

  • StageController is now available in the Python API.

  • Basic 2D Convolution operation along the streaming axis of an image. This operation is not fully generic wrt. interleave which limits its use in streaming applications.

  • New debug_info method on HSImage to print information about a given image/operation. In Python, this is available through the __repr__ dunder method.

  • New parents method on HSImage to get any parents of a given image/operation. This can be used to reconstruct the graph of dependents for an output operation. The get_tree method in the Python API exemplifies how this can be done.

Changed#

  • Dot products are more efficient for certain interleaves and when slicing along the second dimension of a 2d matrix.

  • Binning now simply calculates the sum of the binned values instead of the mean. This makes the operation more generic and averaging can still easily be performed afterwards.

Fixed#

  • The select_mask operation now correctly handles slicing. A number of bugs prevented this from working properly with certain combinations of interleave and other operations.

[0.8.3] - 2025-12-04#

Changed#

  • HSIError::DynArrayError errors now display the inner error as part of its message

Fixed#

  • Bug in the band selection logic. The end index of slices is exclusive but this was not corrected for previously.

[0.8.2] - 2025-11-10#

Changed#

  • New public repository

Fixed#

  • Bug in the band selection logic. The band selection did not calculate the indices correctly, which caused out-of-bounds errors.

[0.8.1] - 2025-10-24#

Fixed#

  • The C/C++ reference in the docs is now included correctly.

  • The documentation’s live demo has been fixed.

[0.8.0] - 2025-10-22#

Added#

  • sdk: HSImage method stream added - it starts a concurrent stream with a full slice.

  • sdk: Initial experimental support for qamlib-rs (internal use only).

  • c-ffi: Debug format functions added for most types.

  • c-ffi: hv_ensure_dtype method added.

  • c-ffi: You can now edit/get extra metadata in the header with the hv_image_meta_get/hv_image_meta_set methods.

  • python: The python API now supports the stream method and the HSIStream type. Support is still experimental.

  • apps: New cli application hv for performing basic operations. Currently, the application can just show file information.

  • docs: New unified API documentation and guides. Includes a wasm-based demo of the Python API.

Changed#

  • sdk: HSImage method slice_iter changed to stream_slice.

  • sdk: HSImage method slice_array changed to array_slice.

  • sdk: HSImage method plane_axis changed to array_plane.

  • sdk: HSImage method full changed to array_full.

  • sdk: HSImage method plane_axis_crop changed to array_plane_crop.

Deprecated#

  • sdk: HSImage method array_plane_crop is deprecated. Instead, use slice followed by array_plane.

Removed#

  • apps: Old unused applications (hsi-viewer).

Fixed#

  • A critical bug in the camera API that prevented the camera from streaming.

[0.7.3] - 2025-09-27#

Added#

  • Scalar operations for images (both left and right hand side)

  • HSIStream now provides a synchronous mode. This is useful for applying lightweight operations. Most simple operations, including as_dtype, nan_to_num, etc. now use this mode.

  • The C and Python APIs support the added scalar operations.

[0.7.2] - 2025-08-19#

Added#

  • C bindings for the entire SDK.

  • Doxygen documentation for the C bindings.

[0.7.1] - 2025-08-18#

Added#

  • Small PCA/projection sample program.

  • A rust write function similar to the one implemented for the Python API.

Fixed#

  • A bug in InterleaveChangeOperation where the shape was not correctly updated, resulting in broadcasting errors in many cases.

[0.7.0] - 2025-08-10#

This update introduces infinite data streams and integration with the HyperVision 1700 camera.

Added#

  • Initial generic HyperVision camera API.

  • Interface layer for the quark-backend REST API.

  • Image-backed camera type that can simulate a real camera.

  • Initial integration between cameras and the HSImage/HSImageOps API.

  • Initial Python API reflecting the Rust camera APIs.

  • An open function in the Rust API that detects file extension and header/data file for ENVI files. It is an improvement to the Python API version and the Python function now just calls the Rust function internally.

Changed#

  • The framework uses a new ShapeMeta type to allow for infinite streams of hsi data.

  • The Python calibration routines now support setting a target interleave and uses the rust-based ensure_dtype method.

  • Fixed a bug in the PAM header writing code when calculating the PAM shape.

  • The documentation is now published to qtec-mono.

  • The image-tiff fork has been rebased onto the latest main branch (version 0.10)

  • The HSIReader trait has been removed completely. Having individual open methods makes it easier to account for file type differences.

Fixed#

  • A bug in MeanAxisOp, where it would not work correctly in certain instances.

  • A bug in InterleaveChange, where the shape was not calculated correctly for BSQ output.

  • A deprecated use of PyTuple became a bug when updating the pyo3 version.

  • A bug in the PAM header writing code where the shape calculation would be wrong.

  • An issue with the ENVI header parser not working correctly for files with CRLF endings. A new test has been added to check for these special cases.

[0.6.3] - 2025-06-09#

Added#

  • NanToNum operation that replaces NaN values with a specified value.

Changed#

  • predictor in the Python API now replaces nan values with 0 before calling the model’s predict function.

[0.6.2] - 2025-06-01#

Added#

  • Operation decorator for easy adaptation of Python functions into the SDK.

  • Predictor function wrapper for easily integrating scikit-learn models into the framework.

  • Pca-model function wrapper for efficient integration of projection models.

  • Documentation has been updated with new information.

Fixed#

  • The ufunc (VectorizedUnaryOp) operator did not correctly adjust the slice for the source image.

[0.6.1] - 2025-05-23#

Added#

  • New Binning operation.

Changed#

  • Combining slices now skips single indexes, which is more efficient.

  • Streams now return Result for each element, which makes proper error handling possible.

  • Array reconstruction now prints channel-related errors to stderr for easier debugging.

Fixed#

  • Bug in interleave change that caused slices not to be correctly calculated.

  • Added an extra GIL lock to VectorizedUnaryOp which caused segfaults.

[0.6.0] - 2025-05-02#

Added#

  • Data processing is now performed using the HSIStream type which uses Rayon and crossbeam to asynchronously execute pipelines.

  • Slicing is now done using the new SliceElem and SliceDescriptor types that are based specifically on HSI terminology.

  • Slicing shapes are now validated and returns an appropriate error when relevant.

  • Added a mask selection operation, which uses a boolean mask array to select spatial pixels.

Changed#

  • The HSIError::ShapeError variant now has a backtrace. This may be added to other errors in the future.

  • Switched to the nightly compiler.

  • Debug symbols have been removed from the release build.

[0.5.6] - 2025-03-13#

Changed#

  • Package/library name is now qtec-hv-sdk. This prevents naming clashes and increases clarity. The Python import is still hsi.

[0.5.5] - 2025-03-12#

Changed#

  • Now using a manylinux_2_28 based image to build the binary packages.

  • The public package upload now only publishes the binary packages.

[0.5.4] - 2025-03-10#

Changed#

[0.5.3] - 2025-03-03#

Changed#

  • Dynarray version bumped to 0.5.3 to make it equivalent to the rest of the packages. Since they are updated together, this makes versions much simpler to understand.

Fixed#

  • Updated CI to fix Windows build.

[0.5.2] - 2025-02-25#

Added#

  • Interleave change operation

Changed#

  • Select operation now uses Array2 instead of a vector of tuples.

  • The Python API for select now automatically converts Numpy arrays, list of lists, and lists of tuples to Array2 internally.

Fixed#

  • Blas inclusion did not work properly on windows. It has now been made optional and is not used in the automated builds. The current impact on performance is negligible.

  • Modified CI to correctly build for linux/windows distributions and added a source distribution for easy local compilation.

  • Some doc pages didn’t build correctly due to a missing dependency.

[0.5.1] - 2025-01-28#

Added#

  • Select operation that allows passing a list of arbitrary line/sample coordinates to select a spectral subset of an image. Useful for subsampling patterns.

  • random_sample utility function for the Python extension to easily generate random samples (currently with repetition).

Changed#

  • Tiff default interleave is now BSQ, which is the most intuitive format when viewing the files in regular image editors.

Fixed#

  • A few errors in the documentation (recipes section).

[0.5.0] - 2024-11-06#

Added#

  • Matrix-vector and Matrix-matrix product support.

  • Basic tiff support added.

  • Documentation of operations and missing basic types in the Python docs.

  • Header modification operation (will likely change since it is cumbersome to use).

  • Added blas support.

Changed#

  • Mean now uses a memory efficient approach for BSQ. This should be adapted to other reductions.

Fixed#

  • Interleave bugs everywhere

  • Slicing bugs in many places.

[0.4.0] - 2024-08-02#

Added#

  • HSImage trait for a unified interface for image types and operations.

  • HSImageOps trait for arithmetic operations (addition, subtraction, multiplication, division) as well as type changes, numeric clamping, and axis reduction functions (mean, std, var, sum).

  • Lazy slicing through slice_iter for building compound operations.

  • InMemoryCube can now be created directly from an array.

  • (python) Preprocessing module with SNV and reflectance calibration functions.

  • (python) Magic methods implemented for arithmetic operations.

  • (python) Index magic method implemented as lazy slicing.

  • (python) Can create new HSImages from NumPy arrays.

Changed#

  • HSIFile and InMemoryCube now work through the unified HSImage trait.

  • (python) Writing now works directly on HSImage objects.

Fixed#

  • Multiple bugs related to slicing and indexing.

Deprecated#

  • (python) HSIFile is no longer used in the python API.

[0.3.0] - 2024-06-03#

Added#

  • Read individual planes of HSI files.

  • Added in-memory HSI type. The interface is likely to change.

Changed#

  • Refactored crate into several sub-crates for each specific area of functionality.

Fixed#

  • Bug in hsi-cli where the header would not be updated.

  • Bug where files would be read incorrectly.

[0.2.0]#

Added#

  • Conversion between PAM, ENVI, and yaml hyperspectral file formats.

  • Conversion between HSI interleave formats.

  • Memory efficient implementation only reads and processes small chunks of a file at a time.

  • Iterator implementations for processing hyperspectral data.

  • (cli) A simple tool for converting between file formats and interleaves.