nmd_core/resource/
image_resource.rs1use std::{fs::{self}, path::PathBuf, str::FromStr};
2
3use getset::{Getters, MutGetters, Setters};
4
5use crate::dossier;
6
7use super::{resource_reference::ResourceReference, source::Source, ResourceError};
8
9
10#[derive(Debug, Getters, MutGetters, Setters, Clone)]
12pub struct ImageResource {
13
14 #[getset(get = "pub", get_mut = "pub", set = "pub")]
15 src: Source,
16
17 #[getset(get = "pub", set = "pub")]
18 mime_type: Option<String>,
19
20 #[getset(get = "pub", set = "pub")]
21 id: Option<ResourceReference>,
22
23 #[getset(get = "pub", set = "pub")]
24 caption: Option<String>,
25
26 #[getset(get = "pub", set = "pub")]
27 style: Option<String>,
28}
29
30impl ImageResource {
31
32 pub fn new(src: Source, mime_type: Option<String>, id: Option<ResourceReference>, caption: Option<String>, style: Option<String>) -> Self {
33
34 Self {
35 src,
36 mime_type,
37 id,
38 caption,
39 style
40 }
41 }
42
43 pub fn inferring_id_if_not_set(mut self, document_name: &impl ToString) -> Result<Self, ResourceError> {
44
45 if self.id.is_none() {
46
47 if let Some(ref caption) = self.caption {
48
49 self.id = Some(ResourceReference::of_internal_from_without_sharp(caption, Some(document_name))?)
50
51 } else {
52
53 match &self.src {
54 Source::Remote { url } => self.id = Some(ResourceReference::of_url(url.as_str())?),
55 Source::Local { path } => self.id = Some(ResourceReference::of_asset(path.to_string_lossy().to_string().as_str())?),
56 Source::Base64String { base64: _ } | Source::Bytes { bytes: _ } => todo!(), }
58
59 }
60 }
61
62 Ok(self)
63 }
64
65 pub fn inferring_mime_type(mut self) -> Result<Self, ResourceError> {
70
71 match &self.src {
72 Source::Remote { url } => {
73 log::debug!("impossible to infer mime type of url: {}", url);
74 },
75 Source::Local { path } => {
76 let mime_type = infer::get_from_path(path)?;
77
78 if let Some(t) = mime_type {
79
80 let mut mime_type = t.mime_type().to_string();
81
82 if mime_type.contains("text/xml") {
84 mime_type = String::from("image/svg+xml");
85 }
86
87 self.set_mime_type(Some(mime_type));
88
89 return Ok(self);
90
91 } else {
92 return Err(ResourceError::InvalidResourceVerbose(format!("image {:?} mime type not found", self.src)));
93 }
94 },
95 Source::Base64String { base64: _ } | Source::Bytes { bytes: _ } => todo!(),
96 }
97
98 Ok(self)
99 }
100
101 pub fn inferring_mime_type_or_nothing(self) -> Self {
103 let backup = self.clone();
104
105 match self.inferring_mime_type() {
106 Ok(ok) => ok,
107 Err(err) => {
108 log::warn!("wrong inferring MIME type of image ({:?}): {}", backup.src(), err.to_string());
109
110 backup
111 },
112 }
113 }
114
115 pub fn elaborating_relative_path_as_dossier_assets(mut self, base_location: &PathBuf) -> Self {
117
118 match &self.src {
119 Source::Local { path } => {
120
121 let mut base_location: PathBuf = base_location.clone();
122
123 if !base_location.is_dir() {
124 base_location = PathBuf::from(base_location.parent().unwrap());
125 }
126
127 if path.is_relative() {
128
129 let mut path = base_location.join(path);
130
131 if !path.exists() {
132
133 let image_file_name = path.file_name().unwrap();
134
135 path = base_location.join(dossier::ASSETS_DIR).join(dossier::IMAGES_DIR).join(image_file_name);
136
137 if !path.exists() {
138
139 log::warn!("image src path {:?} not found also with images dossier assets path, try canonicalize path", path);
140
141 if let Ok(src) = fs::canonicalize(path.clone()) {
142
143 log::info!("canonicalizing ok: {:?} -> {:?}", path, src);
144
145 path = src;
146
147 } else {
148 log::warn!("canonicalizing fails for {:?}", path);
149 }
150 }
151 }
152
153 self.set_src(Source::Local { path });
154 }
155 },
156 _ => (),
157 }
158
159 self
160 }
161
162}
163
164impl FromStr for ImageResource {
165 type Err = ResourceError;
166
167 fn from_str(s: &str) -> Result<Self, Self::Err> {
168 Ok(Self::new(Source::from_str(s)?, None, None, None, None).inferring_mime_type_or_nothing())
169 }
170}
171
172#[cfg(test)]
173mod test {
174
175}