html2md/
images.rs

1use super::StructuredPrinter;
2use super::TagHandler;
3
4use crate::common::get_tag_attr;
5use crate::dummy::IdentityHandler;
6
7use markup5ever_rcdom::Handle;
8
9use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
10
11const FRAGMENT: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`');
12
13/// Handler for `<img>` tag. Depending on circumstances can produce both
14/// inline HTML-formatted image and Markdown native one
15#[derive(Default)]
16pub struct ImgHandler {
17    block_mode: bool,
18}
19
20impl TagHandler for ImgHandler {
21    fn handle(&mut self, tag: &Handle, printer: &mut StructuredPrinter) {
22        // hack: detect if the image has associated style and has display in block mode
23        let style_tag = get_tag_attr(tag, "src");
24        if let Some(style) = style_tag {
25            if style.contains("display: block") {
26                self.block_mode = true
27            }
28        }
29
30        if self.block_mode {
31            // make image on new paragraph
32            printer.insert_newline();
33            printer.insert_newline();
34        }
35
36        // try to extract attrs
37        let src = get_tag_attr(tag, "src");
38        let alt = get_tag_attr(tag, "alt");
39        let title = get_tag_attr(tag, "title");
40        let height = get_tag_attr(tag, "height");
41        let width = get_tag_attr(tag, "width");
42        let align = get_tag_attr(tag, "align");
43
44        if height.is_some() || width.is_some() || align.is_some() {
45            // need to handle it as inline html to preserve attributes we support
46            let mut identity = IdentityHandler;
47            identity.handle(tag, printer);
48        } else {
49            // need to escape URL if it contains spaces
50            // don't have any geometry-controlling attrs, post markdown natively
51            let mut img_url = src.unwrap_or_default();
52            if img_url.contains(' ') {
53                img_url = utf8_percent_encode(&img_url, FRAGMENT).to_string();
54            }
55
56            printer.append_str(&format!(
57                "![{}]({}{})",
58                alt.unwrap_or_default(),
59                &img_url,
60                title
61                    .map(|value| format!(" \"{}\"", value))
62                    .unwrap_or_default()
63            ));
64        }
65    }
66
67    fn after_handle(&mut self, printer: &mut StructuredPrinter) {
68        if self.block_mode {
69            printer.insert_newline();
70            printer.insert_newline();
71        }
72    }
73}