1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use std::sync::Arc;
use custom_error::custom_error;
use serde_urlencoded as urlencoded;
use image_properties::PffHeader;
use image_properties::Reply;
use crate::dezoomer::*;
use crate::pff::image_properties::{HeaderInfo, ImageInfo, InitialServletRequestParams, RequestType, TileIndices};
mod image_properties;
pub enum PFF {
    Init,
    WithHeader(HeaderInfo),
}
impl Default for PFF { fn default() -> Self { PFF::Init } }
custom_error! {pub PffError
    DecodeError{source: serde_urlencoded::de::Error} = "Invalid meta information file: {source}",
    EncodeError{source: serde_urlencoded::ser::Error} = "Unable to generate URL: {source}",
}
impl From<PffError> for DezoomerError {
    fn from(err: PffError) -> Self {
        DezoomerError::Other { source: err.into() }
    }
}
impl Dezoomer for PFF {
    fn name(&self) -> &'static str {
        "pff"
    }
    fn zoom_levels(&mut self, data: &DezoomerInput) -> Result<ZoomLevels, DezoomerError> {
        let mut parts = data.uri.splitn(2, '?');
        let base_url = parts.next().ok_or_else(|| self.wrong_dezoomer())?.to_string();
        let params_str = parts.next().ok_or_else(|| self.wrong_dezoomer())?;
        match self {
            PFF::Init => {
                let init_params: InitialServletRequestParams =
                    urlencoded::from_str(params_str).map_err(PffError::from)?;
                let file = init_params.file;
                if init_params.request_type != RequestType::Metadata as u8 {
                    let uri = format!("{}?file={}&requestType={}", base_url, file, RequestType::Metadata as u8);
                    return Err(DezoomerError::NeedsData { uri });
                }
                let DezoomerInputWithContents { contents, .. } = data.with_contents()?;
                let reply: Reply<PffHeader> =
                    serde_urlencoded::from_bytes(contents).map_err(PffError::from)?;
                let header_info = HeaderInfo { base_url, file, header: reply.reply_data };
                let uri = header_info.tiles_index_url();
                *self = PFF::WithHeader(header_info);
                Err(DezoomerError::NeedsData { uri })
            },
            PFF::WithHeader(header_info) => {
                let DezoomerInputWithContents { contents, .. } = data.with_contents()?;
                let reply: Reply<TileIndices> =
                    urlencoded::from_bytes(contents).map_err(PffError::from)?;
                Ok(zoom_levels(ImageInfo {
                    header_info: header_info.clone(),
                    tiles: reply.reply_data,
                }))
            }
        }
    }
}
fn zoom_levels(info: ImageInfo) -> ZoomLevels {
    let info = Arc::new(info);
    let header = &info.header_info.header;
    let mut size = Vec2d { x: header.width, y: header.height };
    let mut tiles_before = 0;
    let mut levels = vec![];
    while size.x >= header.tile_size && size.y >= header.tile_size {
        let level = PffZoomLevel {
            image_info: Arc::clone(&info),
            tiles_before,
            size,
        };
        tiles_before += level.tile_count();
        size = size.ceil_div(Vec2d { x: 2, y: 2 });
        levels.push(Box::new(level) as ZoomLevel);
    }
    levels
}
struct PffZoomLevel {
    image_info: Arc<ImageInfo>,
    tiles_before: u32,
    size: Vec2d,
}
impl TilesRect for PffZoomLevel {
    fn size(&self) -> Vec2d { self.size }
    fn tile_size(&self) -> Vec2d {
        let size = self.image_info.header_info.header.tile_size;
        Vec2d { x: size, y: size }
    }
    fn tile_url(&self, pos: Vec2d) -> String {
        let num_tiles_x = (self.size().ceil_div(self.tile_size())).x;
        let i = self.tiles_before + pos.x + pos.y * num_tiles_x;
        self.image_info.tile_url(i as usize)
    }
}
impl std::fmt::Debug for PffZoomLevel {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.write_str("Zoomify PFF")
    }
}