dezoomify-rs 2.9.4

Allows downloading zoomable images. Supports several different formats such as zoomify, iiif, and deep zoom images.
Documentation
use image::{DynamicImage, GenericImageView};

use crate::{Vec2d, ZoomError};
use crate::dezoomer::{PostProcessFn, TileReference};
use crate::errors::BufferToImageError;
use crate::network::fetch_uri;

#[derive(Clone)]
pub struct Tile {
    pub image: image::DynamicImage,
    pub position: Vec2d,
}

impl Tile {
    pub fn size(&self) -> Vec2d { self.image.dimensions().into() }
    pub fn bottom_right(&self) -> Vec2d {
        self.size() + self.position
    }
    pub async fn download(
        post_process_fn: PostProcessFn,
        tile_reference: &TileReference,
        client: &reqwest::Client,
    ) -> Result<Tile, ZoomError> {
        let bytes = fetch_uri(&tile_reference.url, client).await?;
        let tile_reference = tile_reference.clone();

        let tile: Result<Tile, BufferToImageError> = tokio::spawn(async move {
            tokio::task::block_in_place(move || {
                let transformed_bytes =
                    if let PostProcessFn::Fn(post_process) = post_process_fn {
                        post_process(&tile_reference, bytes)
                            .map_err(|e| BufferToImageError::PostProcessing { e })?
                    } else {
                        bytes
                    };

                Ok(Tile {
                    image: image::load_from_memory(&transformed_bytes)?,
                    position: tile_reference.position,
                })
            })
        }).await?;
        Ok(tile?)
    }
    pub fn empty(position: Vec2d, size: Vec2d) -> Tile {
        Tile { image: DynamicImage::new_rgba8(size.x, size.y), position }
    }
    pub fn position(&self) -> Vec2d {
        self.position
    }
}

impl std::fmt::Debug for Tile {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("Tile")
            .field("x", &self.position.x)
            .field("y", &self.position.y)
            .field("width", &self.image.width())
            .field("height", &self.image.height())
            .finish()
    }
}

impl PartialEq for Tile {
    fn eq(&self, other: &Self) -> bool {
        self.position == other.position &&
            self.size() == other.size() &&
            self.image.pixels().all(|(x, y, pix)| {
                other.image.get_pixel(x, y) == pix
            })
    }
}