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;