1use crate::{
6 Address, DeepZoomGenerator, Region, Result, Size,
7 errors::OpenSlideError,
8 traits::Slide,
9 utils::{resize_rgb_image, resize_rgba_image},
10};
11use image::{RgbImage, RgbaImage};
12use std::borrow::Borrow;
13
14impl<S: Slide, B: Borrow<S>> DeepZoomGenerator<S, B> {
15 pub fn new(slide: B, tile_size: u32, overlap: u32, limit_bounds: bool) -> Result<Self> {
16 let nb_level = slide.borrow().get_level_count()?;
17
18 let (slide_level_dimensions, l0_offset) = if limit_bounds {
19 let bounds = slide.borrow().get_bounds();
20 let bounds_x = bounds.x.unwrap_or(0);
21 let bounds_y = bounds.y.unwrap_or(0);
22
23 let l0_offset = Address {
26 x: bounds_x,
27 y: bounds_y,
28 };
29
30 let slide_dimensions = slide.borrow().get_level_dimensions(0)?;
32 let slide_dimensions = &slide_dimensions;
33
34 let bounds_width = bounds.width.unwrap_or(slide_dimensions.w);
35 let bounds_height = bounds.height.unwrap_or(slide_dimensions.h);
36
37 let size_scale = (
38 bounds_width as f32 / slide_dimensions.w as f32,
39 bounds_height as f32 / slide_dimensions.h as f32,
40 );
41
42 let slide_level_dimensions: Result<Vec<Size>> = (0..nb_level)
43 .map(|level| match slide.borrow().get_level_dimensions(level) {
44 Ok(size) => Ok(Size {
45 w: (size.w as f32 * size_scale.0).ceil() as _,
46 h: (size.h as f32 * size_scale.1).ceil() as _,
47 }),
48 Err(err) => Err(err),
49 })
50 .collect();
51 (slide_level_dimensions?, l0_offset)
52 } else {
53 let l0_offset = Address { x: 0, y: 0 };
54 let slide_level_dimensions: Result<Vec<Size>> = (0..nb_level)
55 .map(|level| slide.borrow().get_level_dimensions(level))
56 .collect();
57 (slide_level_dimensions?, l0_offset)
58 };
59 let slide_level0_dimensions = slide_level_dimensions[0];
60
61 let level_dimensions = {
64 let mut z_size = Size {
65 w: slide_level0_dimensions.w,
66 h: slide_level0_dimensions.h,
67 };
68 let mut level_dimensions = vec![z_size];
69
70 while z_size.w > 1 || z_size.h > 1 {
71 z_size.w = ((z_size.w as f32 / 2.0).ceil() as u32).max(1) as _;
72 z_size.h = ((z_size.h as f32 / 2.0).ceil() as u32).max(1) as _;
73 level_dimensions.push(z_size);
74 }
75 level_dimensions.reverse();
76 level_dimensions
77 };
78
79 let level_tiles: Vec<Size> = level_dimensions
81 .iter()
82 .map(|Size { w, h }| Size {
83 w: (*w as f32 / tile_size as f32).ceil() as _,
84 h: (*h as f32 / tile_size as f32).ceil() as _,
85 })
86 .collect();
87
88 let level_count = level_dimensions.len();
90
91 let l0_z_downsamples: Vec<f64> = (0..level_count)
93 .map(|level| 2_u64.pow((level_count - level - 1) as _) as f64)
94 .collect();
95
96 let slide_from_dz_level: Result<Vec<u32>> = l0_z_downsamples
98 .iter()
99 .map(|downsample| slide.borrow().get_best_level_for_downsample(*downsample))
100 .collect();
101 let slide_from_dz_level = slide_from_dz_level?;
102
103 let l0_l_downsamples: Result<Vec<f64>> = (0..nb_level)
105 .map(|level| slide.borrow().get_level_downsample(level))
106 .collect();
107 let l0_l_downsamples = l0_l_downsamples?;
108
109 let l_z_downsamples: Vec<f64> = (0..level_count)
110 .map(|dz_level| {
111 l0_z_downsamples[dz_level]
112 / l0_l_downsamples[slide_from_dz_level[dz_level] as usize]
113 })
114 .collect();
115
116 Ok(DeepZoomGenerator {
117 slide,
118 _phantom: Default::default(),
119 tile_size,
120 overlap,
121 l0_offset,
122 level_dimensions,
123 slide_level_dimensions,
124 level_tiles,
125 level_count,
126 slide_from_dz_level,
127 l0_l_downsamples,
128 l_z_downsamples,
129 })
130 }
131
132 pub fn level_count(&self) -> usize {
133 self.level_count
134 }
135
136 pub fn level_tiles(&self) -> &[Size] {
137 &self.level_tiles
138 }
139
140 pub fn level_dimensions(&self) -> &[Size] {
141 &self.level_dimensions
142 }
143
144 pub fn tile_count(&self) -> u32 {
145 self.level_tiles.iter().map(|&size| size.w * size.h).sum()
146 }
147
148 pub fn get_tile_rgba(&self, level: u32, location: Address) -> Result<RgbaImage> {
149 let (region, final_size) = self.get_tile_info(level, location)?;
150
151 let image = self.slide.borrow().read_image_rgba(®ion)?;
152
153 let size = Size {
154 w: image.width(),
155 h: image.height(),
156 };
157
158 if final_size != size {
159 Ok(resize_rgba_image(image, &final_size)?)
160 } else {
161 Ok(image)
162 }
163 }
164
165 pub fn get_tile_rgb(&self, level: u32, location: Address) -> Result<RgbImage> {
166 let (region, final_size) = self.get_tile_info(level, location)?;
167 let image = self.slide.borrow().read_image_rgb(®ion)?;
168
169 let size = Size {
170 w: image.width(),
171 h: image.height(),
172 };
173
174 if final_size != size {
175 Ok(resize_rgb_image(image, &final_size)?)
176 } else {
177 Ok(image)
178 }
179 }
180
181 pub fn get_tile_info(&self, level: u32, address: Address) -> Result<(Region, Size)> {
182 if level as usize >= self.level_count() {
183 return Err(OpenSlideError::CoreError("Invalid level".to_string()));
184 }
185 if address.x >= self.level_tiles[level as usize].w
186 || address.y >= self.level_tiles[level as usize].h
187 {
188 return Err(OpenSlideError::CoreError("Invalid address".to_string()));
189 }
190
191 let level_tiles = self.level_tiles[level as usize];
192 let level_dimensions = self.level_dimensions[level as usize];
193
194 let slide_level = self.slide_from_dz_level[level as usize];
196 let slide_level_dimensions = self.slide_level_dimensions[slide_level as usize];
197
198 let z_overlap_topleft = Address {
200 x: if address.x != 0 { self.overlap } else { 0 },
201 y: if address.y != 0 { self.overlap } else { 0 },
202 };
203
204 let z_overlap_bottomright = Address {
206 x: if address.x != (level_tiles.w - 1) {
207 self.overlap
208 } else {
209 0
210 },
211 y: if address.y != (level_tiles.h - 1) {
212 self.overlap
213 } else {
214 0
215 },
216 };
217
218 let z_size = Size {
220 w: self
221 .tile_size
222 .min(level_dimensions.w - self.tile_size * address.x)
223 + z_overlap_topleft.x
224 + z_overlap_bottomright.x,
225 h: self
226 .tile_size
227 .min(level_dimensions.h - self.tile_size * address.y)
228 + z_overlap_topleft.y
229 + z_overlap_bottomright.y,
230 };
231
232 let z_location = Address {
234 x: address.x * self.tile_size,
235 y: address.y * self.tile_size,
236 };
237
238 let l_location = (
239 self.l_z_downsamples[level as usize] * f64::from(z_location.x - z_overlap_topleft.x),
240 self.l_z_downsamples[level as usize] * f64::from(z_location.y - z_overlap_topleft.y),
241 );
242
243 let l0_location = Address {
245 x: (self.l0_l_downsamples[slide_level as usize] * l_location.0
246 + f64::from(self.l0_offset.x)) as _,
247 y: (self.l0_l_downsamples[slide_level as usize] * l_location.1
248 + f64::from(self.l0_offset.y)) as _,
249 };
250
251 let l_size = Size {
252 w: (slide_level_dimensions.w - l_location.0.ceil() as u32)
253 .min((self.l_z_downsamples[level as usize] * f64::from(z_size.w)).ceil() as _),
254 h: (slide_level_dimensions.h - l_location.1.ceil() as u32)
255 .min((self.l_z_downsamples[level as usize] * f64::from(z_size.h)).ceil() as _),
256 };
257
258 let region = Region {
259 address: l0_location,
260 level: slide_level,
261 size: l_size,
262 };
263
264 Ok((region, z_size))
265 }
266}
267
268pub struct Bounds {
269 pub x: Option<u32>,
270 pub y: Option<u32>,
271 pub width: Option<u32>,
272 pub height: Option<u32>,
273}