nkscan 0.10.0

A platform-agnostic, performant driver for Nikon film scanners
Documentation
//! Taking one scan pass over the film
//!
//! Every kind of pass, thumbnail, prescan and scan alike, is the same four
//! commands. The I/O lives on [`Session`](crate::session::Session); this module holds the pure types
//! and the decoder builder.

use crate::{
    error::Error,
    protocol::{
        caps::set_window::ColorInterleaving, curves::Curves, data::CooperativeAction, image::Layout,
    },
};

/// A finished scan pass
///
/// The samples are the caller's buffer, so this struct carries only what describes them
#[derive(Debug, Clone)]
pub struct Pass {
    /// The stream's shape, as far as 2-10's formula describes it
    pub layout: Layout,
    /// What the unit asked the host to do with the data, if anything
    pub cooperation: Vec<CooperativeAction>,
    /// Whether every block the layout promised arrived
    pub complete: bool,
    /// How many of them did. A pass can come back short, and one that comes
    /// back with none is a pass the unit gave nothing for
    pub blocks: usize,
    /// Image rows and columns: the sensor (the layout's pixels) and the feed
    /// (its lines)
    pub rows: usize,
    pub cols: usize,
}

/// How far along a pass is, reported once per chunk
///
/// `total` is the layout's own arithmetic and the cooperative modes can make it
/// wrong, so a pass can finish short of it or run past. [`Pass::complete`] is
/// what answers whether everything arrived
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Progress {
    /// Bytes taken off the unit so far
    pub bytes: u64,
    /// Bytes the layout says the pass holds
    pub total: u64,
    /// Blocks the decoder has unscrambled
    pub blocks: usize,
}

/// Build a decoder for a scan pass, applying CCD correction only for multi-line
pub fn decoder<'a>(
    layout: &Layout,
    curves: Option<&'a Curves>,
) -> Result<crate::protocol::decode::Decoder<'a>, Error> {
    let decoder = crate::protocol::decode::Decoder::new(layout)?;
    match curves.filter(|_| {
        layout
            .interleaving
            .contains(ColorInterleaving::MULTILINE_SIMULTANEOUS)
    }) {
        Some(curves) => Ok(decoder.correcting(curves)),
        None => Ok(decoder),
    }
}