Skip to main content

ppocr_rs/
ocr_result.rs

1use std::fmt::{self, Write};
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
6pub struct Point {
7    pub x: u32,
8    pub y: u32,
9}
10
11#[derive(Debug, Serialize, Deserialize)]
12pub struct TextBox {
13    pub points: Vec<Point>,
14    pub score: f32,
15}
16
17impl fmt::Display for TextBox {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        write!(
20            f,
21            "TextBox [score({}), [x: {}, y: {}], [x: {}, y: {}], [x: {}, y: {}], [x: {}, y: {}]]",
22            self.score,
23            self.points[0].x,
24            self.points[0].y,
25            self.points[1].x,
26            self.points[1].y,
27            self.points[2].x,
28            self.points[2].y,
29            self.points[3].x,
30            self.points[3].y,
31        )
32    }
33}
34
35#[derive(Debug, Default)]
36pub struct Angle {
37    pub index: i32,
38    pub score: f32,
39}
40
41impl fmt::Display for Angle {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        let header = if self.index >= 0 {
44            "Angle"
45        } else {
46            "AngleDisabled"
47        };
48        write!(
49            f,
50            "{}[Index({}), Score({})]",
51            header, self.index, self.score
52        )
53    }
54}
55
56/// Bounding box di una singola parola dentro una `TextLine`. Il `box_points`
57/// è un quadrilatero a 4 corner (top-left, top-right, bottom-right, bottom-
58/// left) nello spazio dell'IMMAGINE ORIGINALE — coerente con
59/// `TextBlock.box_points`. `score` = media dei max-prob CTC dei char del
60/// word.
61///
62/// Popolato solo se `OcrOptions { return_word_box: true }`. Quando l'opzione
63/// è disabilitata (default per back-compat), `TextBlock.words = Vec::new()`.
64#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct WordBox {
66    pub text:       String,
67    pub box_points: Vec<Point>,
68    pub score:      f32,
69}
70
71#[derive(Debug, Default)]
72pub struct TextLine {
73    pub text:       String,
74    pub text_score: f32,
75    /// Parole identificate via CTC timestep tracking + grouping su
76    /// alphanumeric. Coordinate nello spazio dell'IMMAGINE ORIGINALE (post
77    /// inverse-warp). Vec vuoto se `return_word_box=false` o se la linea
78    /// è ruotata 90° (`crop_h >= crop_w * 3/2`, edge case non supportato
79    /// per word-level — il line-level resta valido).
80    pub words:      Vec<WordBox>,
81}
82
83impl fmt::Display for TextLine {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        write!(
86            f,
87            "TextLine[Text({}),TextScore({}),Words({})]",
88            self.text, self.text_score, self.words.len()
89        )
90    }
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct TextBlock {
95    pub box_points: Vec<Point>,
96    pub box_score: f32,
97
98    pub angle_index: i32,
99    pub angle_score: f32,
100
101    pub text: String,
102    pub text_score: f32,
103
104    /// Parole con bbox individuali. Vedi [`WordBox`]. Vec vuoto se
105    /// `return_word_box=false` (default).
106    #[serde(default)]
107    pub words: Vec<WordBox>,
108}
109
110#[derive(Serialize, Deserialize)]
111pub struct OcrResult {
112    pub text_blocks: Vec<TextBlock>,
113    /// Rotazione applicata alla pagina prima dell'OCR (0, 90, 180, 270 gradi).
114    /// 0 se nessuna correzione orientamento è stata eseguita.
115    #[serde(default)]
116    pub page_angle: u32,
117}
118
119impl fmt::Display for OcrResult {
120    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121        let mut str_builder = String::with_capacity(0);
122        for text_block in &self.text_blocks {
123            write!(
124                str_builder,
125                "TextBlock[BoxPointsLen({}), BoxScore({}), AngleIndex({}), AngleScore({}), Text({}), TextScore({})]",
126                text_block.box_points.len(),
127                text_block.box_score,
128                text_block.angle_index,
129                text_block.angle_score,
130                text_block.text,
131                text_block.text_score
132            )?;
133        }
134        f.write_str(&str_builder)
135    }
136}