fix: render figure images during docx export (#2175)
Some checks are pending
tinymist::auto_tag / auto-tag (push) Waiting to run
tinymist::ci / announce (push) Blocked by required conditions
tinymist::ci / Duplicate Actions Detection (push) Waiting to run
tinymist::ci / Check Clippy, Formatting, Completion, Documentation, and Tests (Linux) (push) Waiting to run
tinymist::ci / Check Minimum Rust version and Tests (Windows) (push) Waiting to run
tinymist::ci / prepare-build (push) Waiting to run
tinymist::ci / build (push) Blocked by required conditions
tinymist::gh_pages / build-gh-pages (push) Waiting to run

fix https://github.com/Myriad-Dreamin/tinymist/issues/2104
This commit is contained in:
Hong Jiarong 2025-10-13 02:56:17 +08:00 committed by GitHub
parent 80ae0e5277
commit 1ca1d82901
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 145 additions and 26 deletions

View file

@ -0,0 +1,5 @@
#figure(
```md
markdown
```,
)

View file

@ -0,0 +1,17 @@
---
source: crates/typlite/src/tests.rs
expression: "conv(world, ConvKind::Md { for_docs: false })"
input_file: crates/typlite/src/fixtures/integration/figure_raw.typ
---
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body><m1document><m1figure caption=""><m1raw lang="md" block="true" text="markdown"></m1raw></m1figure></m1document></body>
</html>
=====
<p align="center"><figure class="figure"><pre><code class="language-md">markdown</code></pre>
</figure></p>

View file

@ -2,7 +2,6 @@
source: crates/typlite/src/tests.rs
expression: "conv(world, ConvKind::Md { for_docs: false })"
input_file: crates/typlite/src/fixtures/integration/ieee.typ
snapshot_kind: text
---
<!DOCTYPE html>
<html>
@ -43,18 +42,48 @@ In Figure 1 you can see a common representation of the Sun, which is a star tha
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distinguique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et collaudata est, cum id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum.
| Planet | Distance (million km) |
| --- | --- |
| Mercury | 57.9 |
| Venus | 108.2 |
| Earth | 149.6 |
| Mars | 227.9 |
| Jupiter | 778.6 |
| Saturn | 1,433.5 |
| Uranus | 2,872.5 |
| Neptune | 4,495.1 |
<p align="center"><figure class="figure"><p></p>
<p align="center"><figure class="figure"><table>
<thead>
<tr>
<th>Planet</th>
<th>Distance (million km)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mercury</td>
<td>57.9</td>
</tr>
<tr>
<td>Venus</td>
<td>108.2</td>
</tr>
<tr>
<td>Earth</td>
<td>149.6</td>
</tr>
<tr>
<td>Mars</td>
<td>227.9</td>
</tr>
<tr>
<td>Jupiter</td>
<td>778.6</td>
</tr>
<tr>
<td>Saturn</td>
<td>1,433.5</td>
</tr>
<tr>
<td>Uranus</td>
<td>2,872.5</td>
</tr>
<tr>
<td>Neptune</td>
<td>4,495.1</td>
</tr>
</tbody>
</table>
</figure></p>
In Table 1, you see the planets of the solar system and their average distance from the Sun. The distances were calculated with Equation 1 that we presented in Section II.

View file

@ -0,0 +1,25 @@
---
source: crates/typlite/src/tests.rs
expression: "conv(world, ConvKind::LaTeX)"
input_file: crates/typlite/src/fixtures/integration/figure_raw.typ
---
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body><m1document><m1figure caption=""><m1raw lang="md" block="true" text="markdown"></m1raw></m1figure></m1document></body>
</html>
=====
\begin{center}
\begin{figure}[htbp]
\centering
\begin{lstlisting}[language=md]
markdown
\end{lstlisting}
\end{figure}
\end{center}

View file

@ -48,6 +48,9 @@ In Figure 1 you can see a common representation of the Sun, which is a star tha
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distinguique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et collaudata est, cum id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum.
\begin{center}
\begin{figure}[htbp]
\centering
\begin{table}[htbp]
\centering
\begin{tabular}{cc}
@ -66,9 +69,6 @@ Neptune & 4,495.1 \\
\end{tabular}
\end{table}
\begin{center}
\begin{figure}[htbp]
\centering
\caption{The Planets of the Solar System and Their Average Distance from the Sun}
\end{figure}

View file

@ -3,4 +3,4 @@ source: crates/typlite/src/tests.rs
expression: hash
input_file: crates/typlite/src/fixtures/integration/figure_caption.typ
---
siphash128_13:57521e02b1a93b78c212f39755cf70f
siphash128_13:894254b508d111b30f77342c90adc20f

View file

@ -3,4 +3,4 @@ source: crates/typlite/src/tests.rs
expression: hash
input_file: crates/typlite/src/fixtures/integration/figure_image.typ
---
siphash128_13:57521e02b1a93b78c212f39755cf70f
siphash128_13:72f9bab3dff17389f9c18b2fc156f55a

View file

@ -3,4 +3,4 @@ source: crates/typlite/src/tests.rs
expression: hash
input_file: crates/typlite/src/fixtures/integration/figure_image_alt.typ
---
siphash128_13:57521e02b1a93b78c212f39755cf70f
siphash128_13:72f9bab3dff17389f9c18b2fc156f55a

View file

@ -0,0 +1,6 @@
---
source: crates/typlite/src/tests.rs
expression: hash
input_file: crates/typlite/src/fixtures/integration/figure_raw.typ
---
siphash128_13:30232e8f06f64239089a80f0f753d388

View file

@ -2,6 +2,5 @@
source: crates/typlite/src/tests.rs
expression: hash
input_file: crates/typlite/src/fixtures/integration/ieee.typ
snapshot_kind: text
---
siphash128_13:914f20b049c227a73ad350294a7d79b3
siphash128_13:47f5f496ccb3e39b89162536a33cc4de

View file

@ -3,4 +3,4 @@ source: crates/typlite/src/tests.rs
expression: hash
input_file: crates/typlite/src/fixtures/integration/outline.typ
---
siphash128_13:60d37f36c1e381dc70a08fa1bca48b73
siphash128_13:7230fb7127284a0103c63b402e7eca68

View file

@ -274,6 +274,22 @@ impl HtmlToAstParser {
self.inline_buffer = prev_buffer;
Ok(())
}
/// Convert element children while capturing both inline and block outputs.
pub fn capture_children(&mut self, element: &HtmlElement) -> Result<(Vec<Node>, Vec<Node>)> {
let prev_buffer = std::mem::take(&mut self.inline_buffer);
let prev_blocks = std::mem::take(&mut self.blocks);
self.convert_children(element)?;
let inline = std::mem::take(&mut self.inline_buffer);
let blocks = std::mem::take(&mut self.blocks);
self.inline_buffer = prev_buffer;
self.blocks = prev_blocks;
Ok((inline, blocks))
}
}
#[derive(Debug, Clone)]

View file

@ -75,10 +75,21 @@ impl HtmlToAstParser {
let attrs = FigureAttr::parse(&element.attrs)?;
let caption = attrs.caption.to_string();
// Find image and body content
let mut body_content = Vec::new();
self.convert_children_into(&mut body_content, element)?;
let body = Box::new(Node::Paragraph(body_content));
let (inline_content, mut block_content) = self.capture_children(element)?;
let mut content_nodes = Vec::new();
if !inline_content.is_empty() {
content_nodes.push(Node::Paragraph(inline_content));
}
content_nodes.append(&mut block_content);
let body = if content_nodes.is_empty() {
Box::new(Node::Paragraph(Vec::new()))
} else if content_nodes.len() == 1 {
Box::new(content_nodes.into_iter().next().unwrap())
} else {
Box::new(Node::Document(content_nodes))
};
// Create figure node with centering
let figure_node = Box::new(FigureNode { body, caption });

View file

@ -448,6 +448,17 @@ impl DocxWriter {
para.property = para.property.clone().align(AlignmentType::Center);
}
}
Node::HtmlElement(element) => {
let start_idx = docx.document.children.len();
for child in &element.children {
docx = self.process_node(docx, child)?;
}
for child in docx.document.children.iter_mut().skip(start_idx) {
if let DocumentChild::Paragraph(para) = child {
para.property = para.property.clone().align(AlignmentType::Center);
}
}
}
other => {
docx = self.process_node(docx, other)?;
// Get the last element and center it if it's a paragraph