Skip to main content

pptx_to_md/
types.rs

1#[derive(Debug)]
2pub struct Presentation {
3    pub metadata: crate::PresentationMetadata,
4    pub slides: Vec<crate::Slide>,
5    pub diagnostics: Vec<ParseDiagnostic>,
6}
7
8#[derive(Debug, Clone)]
9pub enum SlideElement {
10    Text(TextElement, ElementPosition),
11    Table(TableElement, ElementPosition),
12    Image(ImageReference, ElementPosition),
13    List(ListElement, ElementPosition),
14    Unknown,
15}
16
17impl SlideElement {
18    pub fn position(&self) -> ElementPosition {
19        match self {
20            SlideElement::Text(_, pos)
21            | SlideElement::Image(_, pos)
22            | SlideElement::List(_, pos)
23            | SlideElement::Table(_, pos) => *pos,
24            SlideElement::Unknown => ElementPosition::default(),
25        }
26    }
27}
28
29#[derive(Debug, Clone)]
30pub struct ImageReference {
31    pub id: String,
32    pub target: String,
33}
34
35#[derive(Debug, Clone)]
36pub struct TextElement {
37    pub runs: Vec<Run>,
38}
39
40#[derive(Debug, Default, Clone)]
41pub struct Formatting {
42    pub bold: bool,
43    pub italic: bool,
44    pub underlined: bool,
45    pub strikethrough: bool,
46    pub baseline: Baseline,
47    pub font_size_points: Option<f32>,
48    pub lang: String,
49}
50
51#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
52pub enum Baseline {
53    #[default]
54    Normal,
55    Superscript,
56    Subscript,
57}
58
59#[derive(Debug, Clone)]
60pub struct Run {
61    pub text: String,
62    pub formatting: Formatting,
63    pub link_target: Option<String>,
64}
65
66impl Run {
67    pub fn extract(&self) -> String {
68        self.text.to_string()
69    }
70
71    pub fn render_as_md(&self) -> String {
72        crate::markdown::render_run(self)
73    }
74}
75
76#[derive(Debug, Clone)]
77pub struct TableElement {
78    pub rows: Vec<TableRow>,
79}
80
81#[derive(Debug, Clone)]
82pub struct TableRow {
83    pub cells: Vec<TableCell>,
84}
85
86#[derive(Debug, Clone, Default)]
87pub struct TableCell {
88    pub runs: Vec<Run>,
89    pub paragraphs: Vec<Paragraph>,
90    pub row_span: usize,
91    pub column_span: usize,
92    pub covered: bool,
93}
94
95#[derive(Debug, Clone)]
96pub struct ListElement {
97    pub items: Vec<ListItem>,
98}
99
100#[derive(Debug, Clone)]
101pub struct ListItem {
102    pub level: u32,
103    pub is_ordered: bool,
104    pub runs: Vec<Run>,
105}
106
107#[derive(Debug, Clone, Copy, Default, PartialEq)]
108pub struct ElementPosition {
109    pub x: i64,
110    pub y: i64,
111}
112
113#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
114pub struct Bounds {
115    pub x: i64,
116    pub y: i64,
117    pub width: i64,
118    pub height: i64,
119}
120
121impl From<ElementPosition> for Bounds {
122    fn from(position: ElementPosition) -> Self {
123        Self {
124            x: position.x,
125            y: position.y,
126            width: 0,
127            height: 0,
128        }
129    }
130}
131
132#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
133pub enum TextRole {
134    Title,
135    Subtitle,
136    Heading,
137    Body,
138    Caption,
139    #[default]
140    Other,
141}
142
143#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
144pub enum ParagraphAlignment {
145    #[default]
146    Start,
147    Center,
148    End,
149    Justify,
150}
151
152#[derive(Debug, Clone, PartialEq, Eq)]
153pub enum ListKind {
154    Bullet { character: Option<String> },
155    Ordered { style: Option<String>, start: u32 },
156}
157
158#[derive(Debug, Clone, PartialEq, Eq)]
159pub struct ListInfo {
160    pub level: u32,
161    pub kind: ListKind,
162}
163
164#[derive(Debug, Clone, Default)]
165pub struct Paragraph {
166    pub runs: Vec<Run>,
167    pub alignment: ParagraphAlignment,
168    pub list: Option<ListInfo>,
169    pub list_explicit: bool,
170}
171
172impl Paragraph {
173    pub fn plain(runs: Vec<Run>) -> Self {
174        Self {
175            runs,
176            ..Self::default()
177        }
178    }
179
180    pub fn text(&self) -> String {
181        self.runs.iter().map(|run| run.text.as_str()).collect()
182    }
183}
184
185#[derive(Debug, Clone, Default)]
186pub struct TextBlock {
187    pub role: TextRole,
188    pub paragraphs: Vec<Paragraph>,
189}
190
191#[derive(Debug, Clone, Default)]
192pub struct SemanticTableCell {
193    pub paragraphs: Vec<Paragraph>,
194    pub row_span: usize,
195    pub column_span: usize,
196    pub covered: bool,
197}
198
199#[derive(Debug, Clone, Default)]
200pub struct SemanticTableRow {
201    pub cells: Vec<SemanticTableCell>,
202}
203
204#[derive(Debug, Clone, Default)]
205pub struct SemanticTable {
206    pub rows: Vec<SemanticTableRow>,
207}
208
209#[derive(Debug, Clone)]
210pub struct ImageBlock {
211    pub reference: ImageReference,
212    pub alt_text: Option<String>,
213    pub mime_type: Option<String>,
214}
215
216#[derive(Debug, Clone)]
217pub struct UnsupportedBlock {
218    pub kind: String,
219    pub fallback_text: Option<String>,
220}
221
222#[derive(Debug, Clone)]
223pub enum SlideBlockContent {
224    Text(TextBlock),
225    Table(SemanticTable),
226    Image(ImageBlock),
227    Unsupported(UnsupportedBlock),
228}
229
230#[derive(Debug, Clone)]
231pub struct SlideBlock {
232    pub bounds: Bounds,
233    pub source_order: usize,
234    pub content: SlideBlockContent,
235}
236
237#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
238pub enum ReadingOrder {
239    Source,
240    #[default]
241    Spatial,
242}
243
244#[derive(Debug, Clone)]
245pub struct MarkdownOptions {
246    pub reading_order: ReadingOrder,
247    pub include_slide_number_as_comment: bool,
248    pub include_speaker_notes: bool,
249    pub include_comments: bool,
250    pub render_unsupported_comments: bool,
251}
252
253impl Default for MarkdownOptions {
254    fn default() -> Self {
255        Self {
256            reading_order: ReadingOrder::Spatial,
257            include_slide_number_as_comment: true,
258            include_speaker_notes: false,
259            include_comments: false,
260            render_unsupported_comments: true,
261        }
262    }
263}
264
265#[derive(Debug, Clone, Copy, PartialEq, Eq)]
266pub enum DiagnosticSeverity {
267    Warning,
268    Error,
269}
270
271#[derive(Debug, Clone, PartialEq, Eq)]
272pub struct ParseDiagnostic {
273    pub severity: DiagnosticSeverity,
274    pub message: String,
275    pub source: Option<String>,
276}
277
278#[cfg(test)]
279#[path = "../tests/unit/types.rs"]
280mod tests;