df-ocr-switcher 0.1.0

Document OCR pipeline in pure Rust: scanned PDF / multi-page TIFF / image → Markdown. PaddleOCR PP-OCRv6 and Tesseract 5.5 as interchangeable engines, PP-DocLayoutV3 layout for both.
Documentation
//! Trait comune e tipi condivisi per tutti gli engine OCR.
//!
//! Layout analysis (PP-DocLayoutV3) e orientamento (PP-LCNet) sono SEMPRE
//! eseguiti da ppocr-rs, indipendentemente dall'engine di text recognition.
//! L'engine scambiabile riguarda solo il passo "immagine → testo + bbox".

use image::RgbImage;
use ppocr_rs::{LayoutAnalyzer, SemanticClass};
use serde::{Deserialize, Serialize};

use crate::error::Result;

pub mod ppocr;
#[cfg(feature = "tesseract-engine")]
pub mod tesseract;

// ─── Tipi comuni ─────────────────────────────────────────────────────────────

/// Parola singola con AABB e confidence.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OcrWord {
    pub text:       String,
    pub x1: u32, pub y1: u32, pub x2: u32, pub y2: u32,
    pub confidence: f32,
    /// Indice in `OcrPageResult.layout_boxes`; -1 se nessuna regione.
    pub layout_idx: i32,
}

/// Blocco di testo (linea o paragrafo) già assemblato.
/// Il testo è già riconosciuto; bbox AABB del blocco intero.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OcrBlock {
    pub text:       String,
    pub x1: u32, pub y1: u32, pub x2: u32, pub y2: u32,
    pub confidence: f32,
    /// Indice in `OcrPageResult.layout_boxes`; -1 se orfano.
    pub layout_idx: i32,
}

/// Regione di layout rilevata da PP-DocLayoutV3.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OcrLayoutBox {
    /// Classe grezza PP-DocLayoutV3 (es. `"Text"`, `"Title"`, `"Table"`, …).
    pub class_name:    String,
    /// Categoria semantica semplificata (8 classi).
    pub semantic:      SemanticClass,
    pub x1: u32, pub y1: u32, pub x2: u32, pub y2: u32,
    /// Ordine di lettura assegnato dal modello; -1 se non disponibile.
    pub reading_order: i32,
}

/// Tabella strutturata estratta da una regione `SemanticClass::Table`.
/// Disponibile solo con `PpOcrEngine` (richiede SLANeXt model).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OcrTable {
    /// Indice in `OcrPageResult.layout_boxes` della regione sorgente.
    pub layout_idx: i32,
    /// Tabella in GitHub Flavored Markdown (righe `| cell | cell |`).
    /// Stringa vuota se la struttura non è riconoscibile.
    pub gfm: String,
}

/// Formula matematica estratta da una regione `SemanticClass::Equation`.
/// Disponibile solo con `PpOcrEngine` + `enable_formula_decoder = true`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OcrFormula {
    /// Indice in `OcrPageResult.layout_boxes` della regione sorgente.
    pub layout_idx: i32,
    /// Stringa LaTeX. Vuota se il decoder è disabilitato o fallisce.
    pub latex: String,
}

/// Risultato OCR per una singola pagina.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OcrPageResult {
    /// Gradi di rotazione applicati (0/90/180/270). 0 = già upright.
    pub page_angle:   u32,
    pub page_width:   u32,
    pub page_height:  u32,
    /// Layout boxes ordinati per `reading_order`.
    pub layout_boxes: Vec<OcrLayoutBox>,
    /// Blocchi di testo (line-level).
    pub blocks:       Vec<OcrBlock>,
    /// Parole word-level (solo se l'engine supporta `return_word_box`).
    pub words:        Vec<OcrWord>,
    /// Tabelle strutturate GFM (solo `PpOcrEngine` con SLANeXt caricato).
    pub tables:       Vec<OcrTable>,
    /// Formule LaTeX (solo `PpOcrEngine` con `enable_formula_decoder`).
    pub formulas:     Vec<OcrFormula>,
}

// ─── Trait ───────────────────────────────────────────────────────────────────

/// Interfaccia comune per engine OCR.
///
/// L'engine riceve sempre un'immagine già upright (rotazione gestita dal
/// [`crate::pipeline::DocPipeline`]) e un `LayoutAnalyzer` da ppocr-rs.
/// Restituisce [`OcrPageResult`] con blocks e opzionalmente words.
pub trait OcrEngine: Send {
    fn process_page(
        &mut self,
        img:    &RgbImage,
        layout: &mut LayoutAnalyzer,
    ) -> Result<OcrPageResult>;
}