html2md/
images.rs

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