xisf_rs/image/
resolution.rs1use error_stack::{Result, report, Report, ResultExt};
2use libxml::readonly::RoNode;
3
4use crate::error::{ParseNodeError, ParseNodeErrorKind::{self, *}};
5
6fn report(kind: ParseNodeErrorKind) -> Report<ParseNodeError> {
7 report!(context(kind))
8}
9const fn context(kind: ParseNodeErrorKind) -> ParseNodeError {
10 ParseNodeError::new("Resolution", kind)
11}
12
13#[derive(Clone, Debug)]
18pub enum Resolution {
19 Inch {
21 horizontal: f32,
26 vertical: f32,
31 },
32 Cm {
34 horizontal: f32,
39 vertical: f32,
44 },
45}
46impl Default for Resolution {
48 fn default() -> Self {
49 Self::Inch {
50 horizontal: 72.0,
51 vertical: 72.0,
52 }
53 }
54}
55impl Resolution {
56 pub(crate) fn parse_node(node: RoNode) -> Result<Self, ParseNodeError> {
57 let _span_guard = tracing::debug_span!("Resolution");
58 let mut attrs = node.get_attributes();
59 let children = node.get_child_nodes();
60
61
62 let horizontal = attrs.remove("horizontal")
63 .ok_or(report(MissingAttr))?
64 .trim()
65 .parse::<f32>()
66 .change_context(context(InvalidAttr))
67 .attach_printable("Invalid horizontal attribute: failed to parse as f32")?;
68
69
70 let vertical = attrs.remove("vertical")
71 .ok_or(report(MissingAttr))?
72 .trim()
73 .parse::<f32>()
74 .change_context(context(InvalidAttr))
75 .attach_printable("Invalid horizontal attribute: failed to parse as f32")?;
76
77 let unit = attrs.remove("unit");
78
79 for remaining in attrs.into_iter() {
80 tracing::warn!("Ignoring unrecognized attribute {}=\"{}\"", remaining.0, remaining.1);
81 }
82 for child in children {
83 tracing::warn!("Ignoring unrecognized child node <{}>", child.get_name());
84 }
85
86 match unit.as_deref() {
87 Some("inch") => Ok(Resolution::Inch { horizontal, vertical }),
88 Some("cm") | None => Ok(Resolution::Cm { horizontal, vertical }),
89 Some(bad) => Err(report(InvalidAttr)).attach_printable(format!("Invalid unit attribute: expected one of [inch, cm]; found {bad}")),
90 }
91 }
92}