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 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}