dezoomify_rs/
tile.rs

1use image::{DynamicImage, GenericImageView};
2
3use crate::{Vec2d, ZoomError};
4use crate::dezoomer::{PostProcessFn, TileReference};
5use crate::errors::BufferToImageError;
6use crate::network::fetch_uri;
7
8#[derive(Clone)]
9pub struct Tile {
10    pub image: image::DynamicImage,
11    pub position: Vec2d,
12}
13
14impl Tile {
15    pub fn size(&self) -> Vec2d { self.image.dimensions().into() }
16    pub fn bottom_right(&self) -> Vec2d {
17        self.size() + self.position
18    }
19    pub async fn download(
20        post_process_fn: PostProcessFn,
21        tile_reference: &TileReference,
22        client: &reqwest::Client,
23    ) -> Result<Tile, ZoomError> {
24        let bytes = fetch_uri(&tile_reference.url, client).await?;
25        let tile_reference = tile_reference.clone();
26
27        let tile: Result<Tile, BufferToImageError> = tokio::spawn(async move {
28            tokio::task::block_in_place(move || {
29                let transformed_bytes =
30                    if let PostProcessFn::Fn(post_process) = post_process_fn {
31                        post_process(&tile_reference, bytes)
32                            .map_err(|e| BufferToImageError::PostProcessing { e })?
33                    } else {
34                        bytes
35                    };
36
37                Ok(Tile {
38                    image: image::load_from_memory(&transformed_bytes)?,
39                    position: tile_reference.position,
40                })
41            })
42        }).await?;
43        Ok(tile?)
44    }
45    pub fn empty(position: Vec2d, size: Vec2d) -> Tile {
46        Tile { image: DynamicImage::new_rgba8(size.x, size.y), position }
47    }
48    pub fn position(&self) -> Vec2d {
49        self.position
50    }
51}
52
53impl std::fmt::Debug for Tile {
54    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
55        f.debug_struct("Tile")
56            .field("x", &self.position.x)
57            .field("y", &self.position.y)
58            .field("width", &self.image.width())
59            .field("height", &self.image.height())
60            .finish()
61    }
62}
63
64impl PartialEq for Tile {
65    fn eq(&self, other: &Self) -> bool {
66        self.position == other.position &&
67            self.size() == other.size() &&
68            self.image.pixels().all(|(x, y, pix)| {
69                other.image.get_pixel(x, y) == pix
70            })
71    }
72}