dezoomify_rs/
auto.rs

1use log::{debug, info};
2
3use crate::dezoomer::{Dezoomer, DezoomerError, DezoomerInput, ZoomLevel, ZoomLevels};
4use crate::errors::DezoomerError::NeedsData;
5
6pub fn all_dezoomers(include_generic: bool) -> Vec<Box<dyn Dezoomer>> {
7    let mut dezoomers: Vec<Box<dyn Dezoomer>> = vec![
8        Box::<crate::custom_yaml::CustomDezoomer>::default(),
9        Box::<crate::google_arts_and_culture::GAPDezoomer>::default(),
10        Box::<crate::zoomify::ZoomifyDezoomer>::default(),
11        Box::<crate::iiif::IIIF>::default(),
12        Box::<crate::dzi::DziDezoomer>::default(),
13        Box::<crate::generic::GenericDezoomer>::default(),
14        Box::<crate::pff::PFF>::default(),
15        Box::<crate::krpano::KrpanoDezoomer>::default(),
16        Box::<crate::iipimage::IIPImage>::default(),
17        Box::<crate::nypl::NYPLImage>::default(),
18    ];
19    if include_generic {
20        dezoomers.push(Box::<AutoDezoomer>::default())
21    }
22    dezoomers
23}
24
25pub struct AutoDezoomer {
26    dezoomers: Vec<Box<dyn Dezoomer>>,
27    errors: Vec<(&'static str, DezoomerError)>,
28    successes: Vec<ZoomLevel>,
29    needs_uris: Vec<String>,
30}
31
32impl Default for AutoDezoomer {
33    fn default() -> Self {
34        AutoDezoomer {
35            dezoomers: all_dezoomers(false),
36            errors: vec![],
37            successes: vec![],
38            needs_uris: vec![],
39        }
40    }
41}
42
43impl Dezoomer for AutoDezoomer {
44    fn name(&self) -> &'static str {
45        "auto"
46    }
47
48    fn zoom_levels(&mut self, data: &DezoomerInput) -> Result<ZoomLevels, DezoomerError> {
49        // TO DO: Use drain_filter when it is stabilized
50        let mut i = 0;
51        while i != self.dezoomers.len() {
52            let dezoomer = &mut self.dezoomers[i];
53            let keep = match dezoomer.zoom_levels(data) {
54                Ok(mut levels) => {
55                    info!("dezoomer '{}' found {} zoom levels", dezoomer.name(), levels.len());
56                    self.successes.append(&mut levels);
57                    false
58                }
59                Err(DezoomerError::NeedsData { uri }) => {
60                    info!("dezoomer '{}' requested to load {}", dezoomer.name(), &uri);
61                    if !self.needs_uris.contains(&uri) {
62                        self.needs_uris.push(uri);
63                    }
64                    true
65                }
66                Err(e) => {
67                    debug!("{} cannot process this image: {}", dezoomer.name(), e);
68                    self.errors.push((dezoomer.name(), e));
69                    false
70                }
71            };
72            if keep {
73                i += 1
74            } else {
75                self.dezoomers.remove(i);
76            }
77        }
78        if let Some(uri) = self.needs_uris.pop() {
79            Err(NeedsData { uri })
80        } else if self.successes.is_empty() {
81            info!("No dezoomer can dezoom {:?}", data.uri);
82            let errs = std::mem::take(&mut self.errors);
83            Err(DezoomerError::wrap(AutoDezoomerError(errs)))
84        } else {
85            let successes = std::mem::take(&mut self.successes);
86            Ok(successes)
87        }
88    }
89}
90
91#[derive(Debug)]
92pub struct AutoDezoomerError(Vec<(&'static str, DezoomerError)>);
93
94impl std::error::Error for AutoDezoomerError {}
95
96impl std::fmt::Display for AutoDezoomerError {
97    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
98        if self.0.is_empty() {
99            return writeln!(f, "No dezoomer!");
100        }
101        writeln!(
102            f,
103            "Tried all of the dezoomers, none succeeded. They returned the following errors:\n"
104        )?;
105        for (dezoomer_name, err) in self.0.iter() {
106            writeln!(f, " - {}: {}", dezoomer_name, err)?;
107        }
108        writeln!(f, "\n\
109        dezoomify-rs expects a zoomable image meta-information file URL. \
110        To find this URL, you can use the dezoomify browser extension, which you can download at\n\
111         - https://lovasoa.github.io/dezoomify-extension/ \n\
112        If this doesn't help, then your image may be in a format that is not yet supported by dezoomify-rs.\n\
113        You can ask for a new format to be supported by opening a new issue on \
114        https://github.com/lovasoa/dezoomify-rs/issues")
115    }
116}