use crate::core::text::BoundingBox;
use crate::utils::Point2D;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LayoutResult {
pub page_size: PageSize,
pub blocks: Vec<Block>,
pub text_regions: Vec<TextRegion>,
pub images: Vec<ImageRegion>,
pub tables: Vec<Table>,
pub reading_order: ReadingOrder,
pub orientation: PageOrientation,
pub confidence: f32,
pub metadata: HashMap<String, String>,
}
impl LayoutResult {
pub fn new(page_size: PageSize) -> Self {
Self {
page_size,
blocks: Vec::new(),
text_regions: Vec::new(),
images: Vec::new(),
tables: Vec::new(),
reading_order: ReadingOrder::TopToBottom,
orientation: PageOrientation::Portrait,
confidence: 0.0,
metadata: HashMap::new(),
}
}
pub fn text_blocks(&self) -> Vec<&Block> {
self.blocks
.iter()
.filter(|b| b.block_type == BlockType::Text)
.collect()
}
pub fn image_blocks(&self) -> Vec<&Block> {
self.blocks
.iter()
.filter(|b| b.block_type == BlockType::Image)
.collect()
}
pub fn table_blocks(&self) -> Vec<&Block> {
self.blocks
.iter()
.filter(|b| b.block_type == BlockType::Table)
.collect()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct PageSize {
pub width: u32,
pub height: u32,
pub dpi: u32,
}
impl PageSize {
pub fn new(width: u32, height: u32, dpi: u32) -> Self {
Self { width, height, dpi }
}
pub fn aspect_ratio(&self) -> f32 {
self.width as f32 / self.height as f32
}
pub fn is_landscape(&self) -> bool {
self.width > self.height
}
pub fn is_portrait(&self) -> bool {
self.height > self.width
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Block {
pub id: String,
pub block_type: BlockType,
pub bounding_box: BoundingBox,
pub content: BlockContent,
pub properties: BlockProperties,
pub confidence: f32,
}
impl Block {
pub fn new(id: String, block_type: BlockType, bounding_box: BoundingBox) -> Self {
Self {
id,
block_type,
bounding_box,
content: BlockContent::Empty,
properties: BlockProperties::default(),
confidence: 0.0,
}
}
pub fn area(&self) -> u32 {
self.bounding_box.area() as u32
}
pub fn center(&self) -> Point2D {
self.bounding_box.center()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum BlockType {
Text,
Image,
Table,
Header,
Footer,
Sidebar,
Unknown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum BlockContent {
Empty,
Text(String),
Image { path: String, format: String },
Table {
rows: Vec<Vec<String>>,
headers: Vec<String>,
},
Mixed(Vec<BlockContent>),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BlockProperties {
pub priority: u32,
pub level: u32,
pub alignment: TextAlignment,
pub margins: Margins,
pub padding: Margins,
pub background_color: Option<Color>,
pub text_color: Option<Color>,
}
impl Default for BlockProperties {
fn default() -> Self {
Self {
priority: 0,
level: 0,
alignment: TextAlignment::Left,
margins: Margins::zero(),
padding: Margins::zero(),
background_color: None,
text_color: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TextRegion {
pub id: String,
pub bounding_box: BoundingBox,
pub text: String,
pub properties: TextRegionProperties,
pub confidence: f32,
}
impl TextRegion {
pub fn new(id: String, bounding_box: BoundingBox, text: String) -> Self {
Self {
id,
bounding_box,
text,
properties: TextRegionProperties::default(),
confidence: 0.0,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TextRegionProperties {
pub font_family: Option<String>,
pub font_size: f32,
pub font_weight: FontWeight,
pub font_style: FontStyle,
pub text_color: Option<Color>,
pub background_color: Option<Color>,
pub line_height: f32,
pub letter_spacing: f32,
pub word_spacing: f32,
}
impl Default for TextRegionProperties {
fn default() -> Self {
Self {
font_family: None,
font_size: 12.0,
font_weight: FontWeight::Normal,
font_style: FontStyle::Normal,
text_color: None,
background_color: None,
line_height: 1.0,
letter_spacing: 0.0,
word_spacing: 0.0,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageRegion {
pub id: String,
pub bounding_box: BoundingBox,
pub properties: ImageRegionProperties,
pub confidence: f32,
}
impl ImageRegion {
pub fn new(id: String, bounding_box: BoundingBox) -> Self {
Self {
id,
bounding_box,
properties: ImageRegionProperties::default(),
confidence: 0.0,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImageRegionProperties {
pub format: String,
pub width: u32,
pub height: u32,
pub dpi: u32,
pub quality: f32,
pub orientation: ImageOrientation,
}
impl Default for ImageRegionProperties {
fn default() -> Self {
Self {
format: "unknown".to_string(),
width: 0,
height: 0,
dpi: 72,
quality: 1.0,
orientation: ImageOrientation::Normal,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Table {
pub id: String,
pub bounding_box: BoundingBox,
pub structure: TableStructure,
pub properties: TableProperties,
pub confidence: f32,
}
impl Table {
pub fn new(id: String, bounding_box: BoundingBox) -> Self {
Self {
id,
bounding_box,
structure: TableStructure::default(),
properties: TableProperties::default(),
confidence: 0.0,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TableStructure {
pub rows: usize,
pub columns: usize,
pub cells: Vec<Vec<TableCell>>,
pub headers: Vec<String>,
}
impl Default for TableStructure {
fn default() -> Self {
Self {
rows: 0,
columns: 0,
cells: Vec::new(),
headers: Vec::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TableCell {
pub content: String,
pub bounding_box: BoundingBox,
pub row_span: usize,
pub column_span: usize,
pub properties: CellProperties,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CellProperties {
pub alignment: TextAlignment,
pub background_color: Option<Color>,
pub text_color: Option<Color>,
pub borders: Borders,
}
impl Default for CellProperties {
fn default() -> Self {
Self {
alignment: TextAlignment::Left,
background_color: None,
text_color: None,
borders: Borders::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TableProperties {
pub alignment: TextAlignment,
pub borders: Borders,
pub background_color: Option<Color>,
pub header_background_color: Option<Color>,
}
impl Default for TableProperties {
fn default() -> Self {
Self {
alignment: TextAlignment::Left,
borders: Borders::default(),
background_color: None,
header_background_color: None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ReadingOrder {
TopToBottom,
LeftToRight,
RightToLeft,
BottomToTop,
MultiColumn,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum PageOrientation {
Portrait,
Landscape,
PortraitUpsideDown,
LandscapeUpsideDown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum TextAlignment {
Left,
Right,
Center,
Justified,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum FontWeight {
Normal,
Bold,
Light,
Medium,
Heavy,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum FontStyle {
Normal,
Italic,
Oblique,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ImageOrientation {
Normal,
Rotated90,
Rotated180,
Rotated270,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl Color {
pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
Self { r, g, b, a }
}
pub fn rgb(r: u8, g: u8, b: u8) -> Self {
Self { r, g, b, a: 255 }
}
pub fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
Self { r, g, b, a }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Margins {
pub top: u32,
pub right: u32,
pub bottom: u32,
pub left: u32,
}
impl Margins {
pub fn new(top: u32, right: u32, bottom: u32, left: u32) -> Self {
Self {
top,
right,
bottom,
left,
}
}
pub fn zero() -> Self {
Self {
top: 0,
right: 0,
bottom: 0,
left: 0,
}
}
pub fn uniform(value: u32) -> Self {
Self {
top: value,
right: value,
bottom: value,
left: value,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Borders {
pub top: Border,
pub right: Border,
pub bottom: Border,
pub left: Border,
}
impl Default for Borders {
fn default() -> Self {
Self {
top: Border::default(),
right: Border::default(),
bottom: Border::default(),
left: Border::default(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Border {
pub width: u32,
pub color: Color,
pub style: BorderStyle,
}
impl Default for Border {
fn default() -> Self {
Self {
width: 0,
color: Color::rgb(0, 0, 0),
style: BorderStyle::Solid,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum BorderStyle {
Solid,
Dashed,
Dotted,
Double,
}