Skip to main content

Crate fovea_io

Crate fovea_io 

Source
Expand description

§fovea-io

Crates.io Documentation License: MIT

fovea-io is the file boundary for fovea: decode PNG, JPEG, and BMP bytes into typed fovea::Image<P> values, then let the core crate enforce pixel semantics from there.

The key idea is simple: I/O tells you what the file contains. It does not silently decide how to process it. Metadata travels with pixels, color conversions are explicit, and unsupported encodes are compile-time errors where possible.

§Install

No codecs are enabled by default. Enable only the formats you need:

cargo add fovea
cargo add fovea-io --features png

Enable every current codec with:

cargo add fovea-io --features all-codecs

§Features

FeatureEnablesPulls in
pngPNG decode + encodepng
jpegJPEG decode + encodejpeg-decoder, jpeg-encoder
bmpBMP decode + encodeno external codec crate
all-codecsPNG, JPEG, and BMPall optional codec dependencies

§The fovea I/O model

bytes → detect/decode → per-codec enum → concrete Image<P> → explicit transforms → encode

load is convenient when you do not know the file format. Per-codec APIs are better when you do know the format, because their image enums are exhaustive spec sheets.

use fovea_io::{ImageFormat, detect_format};

let png_sig = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
assert_eq!(detect_format(&png_sig), Some(ImageFormat::Png));
assert_eq!(detect_format(&[0x00, 0x00]), None);

§Decode once, then work with types

use fovea::image::ImageView;
use fovea_io::png::{self, PngImage};

let bytes = std::fs::read("input.png")?;
let decoded = png::decode(&bytes)?;

match decoded.image {
    PngImage::Srgb8(img) => {
        println!("8-bit sRGB PNG: {}x{}", img.width(), img.height());
        // img is Image<Srgb8>
    }
    PngImage::Srgba8(img) => {
        println!("8-bit sRGBA PNG: {}x{}", img.width(), img.height());
        // img is Image<Srgba8>
    }
    other => {
        println!("supported PNG, different pixel format: {other:?}");
    }
}

After the match, downstream code has concrete pixel types. A resize pipeline can reject gamma-incorrect interpolation; a display path can require display-ready pixels; a camera pipeline can keep raw linear data linear.

§Decode → transform → encode

This is the common shape for file tools:

use fovea::Size;
use fovea::image::Image;
use fovea::pixel::{RgbF32, Srgb8};
use fovea::transform::{Bilinear, SrgbGamma, convert_image, resize};
use fovea_io::png::{self, PngEncodeOptions, PngImage};

let bytes = std::fs::read("photo.png")?;
let decoded = png::decode(&bytes)?;

let srgb: Image<Srgb8> = match decoded.image {
    PngImage::Srgb8(img) => img,
    other => return Err(format!("expected Srgb8 PNG, got {other:?}").into()),
};

// Bilinear resize is done in linear light.
let linear: Image<RgbF32> = convert_image(&srgb, SrgbGamma);
let resized: Image<RgbF32> = resize(&linear, Size::new(800, 600), Bilinear);
let output: Image<Srgb8> = convert_image(&resized, SrgbGamma);

let out_bytes = png::encode(&output, &PngEncodeOptions::default())?;
std::fs::write("photo_800x600.png", out_bytes)?;

The I/O crate does not hide the SrgbGamma step. That is deliberate: decoding surfaces information; your pipeline chooses what to do with it.

§Which entry point?

You know…UseWhy
Nothing except “these are image bytes”load / load_readerDetects PNG/JPEG/BMP by magic bytes and returns DecodedImage.
The file is PNGpng::decode / png::encodeExhaustive PNG pixel enum and PNG metadata.
The file is JPEGjpeg::decode / jpeg::encodeJPEG-specific metadata and supported JPEG pixel shapes.
The file is BMPbmp::decode / bmp::encodeBMP-specific representation without pulling in PNG/JPEG dependencies.
Only the signature mattersdetect_formatCheap format detection without codec features.

§Metadata is not policy

Decoded values carry metadata alongside pixel data. fovea-io reports what the file said; it does not silently linearize, premultiply alpha, apply profiles, or drop ancillary data on your behalf.

That policy keeps I/O predictable:

  • The decode boundary preserves file facts.
  • The transform boundary names semantic changes.
  • The encode boundary checks whether the target format can represent the requested pixel type.

§Crate ecosystem

CratePurpose
foveaCore image types, pixels, transforms, and analysis.
fovea-ioFile codecs for typed fovea images.
fovea-displayDisplay strategies and debug windows.
fovea-examplesRepo-only end-to-end programs using all crates together.

§License

fovea-io itself is licensed under the MIT License.

When the jpeg feature is enabled, this crate depends on jpeg-encoder, which carries an additional IJG (Independent JPEG Group) license requiring this acknowledgement:

This software is based in part on the work of the Independent JPEG Group.

See THIRD-PARTY-LICENSES.txt for full license texts of dependencies and attribution requirements.

Modules§

bmpbmp
BMP decoding and encoding.
jpegjpeg
JPEG decoding and encoding.
pngpng
PNG decoding and encoding.

Enums§

DecodedImage
Universal decoded image — union of all per-codec decoded structs.
ImageFormat
Detected image format based on magic bytes.
IoError
Crate-level I/O error.

Functions§

detect_format
Detect the image format by inspecting the leading magic bytes.
load
Load an image from an in-memory byte slice, auto-detecting the format.
load_reader
Load an image from a streaming reader, auto-detecting the format.