openslide_rs/properties/
openslide.rs1use regex::Regex;
5
6lazy_static! {
7 static ref REGEX_LEVEL_PROPERTIES: Regex =
8 Regex::new(r"level\[([0-9]+)]\.([a-zA-Z]+(?:-[a-zA-Z]+)?)").unwrap();
9}
10
11pub const OPENSLIDE_PROPERTY_NAME_COMMENT: &str = "openslide.comment";
12pub const OPENSLIDE_PROPERTY_NAME_VENDOR: &str = "openslide.vendor";
13pub const OPENSLIDE_PROPERTY_NAME_QUICKHASH1: &str = "openslide.quickhash-1";
14pub const OPENSLIDE_PROPERTY_NAME_BACKGROUND_COLOR: &str = "openslide.background-color";
15pub const OPENSLIDE_PROPERTY_NAME_OBJECTIVE_POWER: &str = "openslide.objective-power";
16pub const OPENSLIDE_PROPERTY_NAME_MPP_X: &str = "openslide.mpp-x";
17pub const OPENSLIDE_PROPERTY_NAME_MPP_Y: &str = "openslide.mpp-y";
18pub const OPENSLIDE_PROPERTY_NAME_BOUNDS_X: &str = "openslide.bounds-x";
19pub const OPENSLIDE_PROPERTY_NAME_BOUNDS_Y: &str = "openslide.bounds-y";
20pub const OPENSLIDE_PROPERTY_NAME_BOUNDS_WIDTH: &str = "openslide.bounds-width";
21pub const OPENSLIDE_PROPERTY_NAME_BOUNDS_HEIGHT: &str = "openslide.bounds-height";
22pub const OPENSLIDE_PROPERTY_LEVEL_COUNT: &str = "openslide.level-count";
23pub const OPENSLIDE_PROPERTY_NAME_ICC_SIZE: &str = "openslide.icc-size";
24
25const OPENSLIDE_PROPERTY_LEVEL_DOWNSAMPLE: &str = "downsample";
26const OPENSLIDE_PROPERTY_LEVEL_HEIGHT: &str = "height";
27const OPENSLIDE_PROPERTY_LEVEL_WIDTH: &str = "width";
28const OPENSLIDE_PROPERTY_LEVEL_TILE_HEIGHT: &str = "tile-height";
29const OPENSLIDE_PROPERTY_LEVEL_TILE_WIDTH: &str = "tile-width";
30
31#[derive(Clone, Debug, Default)]
33pub struct LevelProperties {
34 pub downsample: Option<f32>,
35 pub height: Option<u32>,
36 pub width: Option<u32>,
37 pub tile_height: Option<u32>,
38 pub tile_width: Option<u32>,
39}
40
41#[derive(Clone, Debug, Default)]
44pub struct OpenSlide {
45 pub vendor: Option<String>,
46 pub quickhash_1: Option<String>,
47 pub mpp_x: Option<f32>,
48 pub mpp_y: Option<f32>,
49 pub objective_power: Option<u32>,
50 pub comment: Option<String>,
51 pub level_count: Option<u32>,
52 pub bounds_x: Option<u32>,
53 pub bounds_y: Option<u32>,
54 pub bounds_width: Option<u32>,
55 pub bounds_height: Option<u32>,
56 pub icc_profile_size: Option<u32>,
57 pub background_color: Option<String>,
58 pub levels: Vec<LevelProperties>,
59}
60
61impl OpenSlide {
62 pub(crate) fn new(property_iter: impl Iterator<Item = (String, String)>) -> Self {
67 let mut openslide_property = OpenSlide::default();
68
69 property_iter
70 .filter(|(name, _)| name.starts_with("openslide."))
71 .for_each(|(name, value)| openslide_property.parse_property_name(&name, &value));
72 openslide_property
73 }
74
75 fn parse_property_name(&mut self, name: &str, value: &str) {
76 match name {
77 OPENSLIDE_PROPERTY_NAME_VENDOR => self.vendor = value.parse().ok(),
78 OPENSLIDE_PROPERTY_NAME_QUICKHASH1 => self.quickhash_1 = value.parse().ok(),
79 OPENSLIDE_PROPERTY_NAME_MPP_X => self.mpp_x = value.parse().ok(),
80 OPENSLIDE_PROPERTY_NAME_MPP_Y => self.mpp_y = value.parse().ok(),
81 OPENSLIDE_PROPERTY_NAME_OBJECTIVE_POWER => self.objective_power = value.parse().ok(),
82 OPENSLIDE_PROPERTY_NAME_COMMENT => self.comment = Some(value.to_string()),
83 OPENSLIDE_PROPERTY_LEVEL_COUNT => self.level_count = value.parse().ok(),
84 OPENSLIDE_PROPERTY_NAME_BOUNDS_X => self.bounds_x = value.parse().ok(),
85 OPENSLIDE_PROPERTY_NAME_BOUNDS_Y => self.bounds_y = value.parse().ok(),
86 OPENSLIDE_PROPERTY_NAME_ICC_SIZE => self.icc_profile_size = value.parse().ok(),
87 OPENSLIDE_PROPERTY_NAME_BOUNDS_WIDTH => self.bounds_width = value.parse().ok(),
88 OPENSLIDE_PROPERTY_NAME_BOUNDS_HEIGHT => self.bounds_height = value.parse().ok(),
89 OPENSLIDE_PROPERTY_NAME_BACKGROUND_COLOR => {
90 self.background_color = Some(value.to_string());
91 }
92 _ => {
93 if let Some(cap) = REGEX_LEVEL_PROPERTIES.captures(name) {
94 let level: usize = cap[1].parse().unwrap(); let property = &cap[2]; self.parse_property_levels(level, property, value);
98 }
99 }
100 }
101 }
102
103 fn parse_property_levels(&mut self, level: usize, name: &str, value: &str) {
104 if self.levels.len() < level + 1 {
105 self.levels.resize(level + 1, LevelProperties::default());
106 }
107
108 let level = &mut self.levels[level];
109 match name {
110 OPENSLIDE_PROPERTY_LEVEL_DOWNSAMPLE => level.downsample = value.parse().ok(),
111 OPENSLIDE_PROPERTY_LEVEL_HEIGHT => level.height = value.parse().ok(),
112 OPENSLIDE_PROPERTY_LEVEL_WIDTH => level.width = value.parse().ok(),
113 OPENSLIDE_PROPERTY_LEVEL_TILE_HEIGHT => level.tile_height = value.parse().ok(),
114 OPENSLIDE_PROPERTY_LEVEL_TILE_WIDTH => level.tile_width = value.parse().ok(),
115 _ => {}
116 }
117 }
118}