diff --git a/src/decoder/formats/mod.rs b/src/decoder/formats/mod.rs index 496600a..83c2480 100644 --- a/src/decoder/formats/mod.rs +++ b/src/decoder/formats/mod.rs @@ -4,6 +4,6 @@ mod svg; pub use heif::Heif; pub use image_rs_other::ImageRsOther; -pub use svg::Svg; +pub use svg::{Svg, RSVG_MAX_SIZE}; use super::{Decoder, UpdateSender}; diff --git a/src/decoder/formats/svg.rs b/src/decoder/formats/svg.rs index 54f6a22..18aab0c 100644 --- a/src/decoder/formats/svg.rs +++ b/src/decoder/formats/svg.rs @@ -11,6 +11,10 @@ use gtk::prelude::*; use std::path::PathBuf; use std::sync::Arc; +/// Current librsvg limit on maximum dimensions. See +/// +pub const RSVG_MAX_SIZE: u32 = 32_767; + #[derive(Debug)] pub struct Svg { thread_handle: std::thread::JoinHandle<()>, @@ -106,9 +110,7 @@ impl Svg { tile_instructions.tiling.scaled_dimensions(); // librsvg does not currently support larger images - // - // TODO: We are only creating tiles, maybe this check in librsvg is wrong? - if total_height > 32_767 || total_width > 32_767 { + if total_height > RSVG_MAX_SIZE || total_width > RSVG_MAX_SIZE { continue; } diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index b40d292..deac114 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -15,6 +15,8 @@ use gtk::graphene; use std::io::Read; use std::sync::Arc; +pub use formats::RSVG_MAX_SIZE; + #[derive(Clone, Copy, Debug)] pub enum ImageFormat { ImageRs(image_rs::ImageFormat), diff --git a/src/widgets/image.rs b/src/widgets/image.rs index 70f0644..f8feaa5 100644 --- a/src/widgets/image.rs +++ b/src/widgets/image.rs @@ -87,6 +87,7 @@ mod imp { pub file_monitor: RefCell>, pub tiles: Arc>, pub decoder: RefCell>>, + pub format: RefCell>, /// Set to true when image is ready for displaying pub is_loaded: Cell, @@ -710,8 +711,8 @@ impl LpImage { DecoderUpdate::Error(err) => { self.set_error(err); } - DecoderUpdate::Format(_) => { - // TODO: Store and use in image properties + DecoderUpdate::Format(format) => { + imp.format.replace(Some(format)); } } } @@ -961,14 +962,29 @@ impl LpImage { decoder::tiling::zoom_normalize(self.zoom()) } + /// Maximal zoom allowed for this image + fn max_zoom(&self) -> f64 { + if let Some(decoder::ImageFormat::Svg) = dbg!(self.format()) { + let (width, height) = self.original_dimensions(); + // Avoid division by 0 + let long_side = f64::max(1., i32::max(width, height) as f64); + // Limit to maz size supported by rsvg + f64::min(MAX_ZOOM_LEVEL, decoder::RSVG_MAX_SIZE as f64 / long_side) + } else { + MAX_ZOOM_LEVEL + } + } + /// Set zoom level aiming for given position or center if not available fn set_zoom_aiming(&self, mut zoom: f64, aiming: Option<(f64, f64)>) { + let max_zoom = self.max_zoom(); + // allow some deviation from max value for rubberbanding - if zoom > MAX_ZOOM_LEVEL { - let max_deviation = MAX_ZOOM_LEVEL * ZOOM_FACTOR_MAX_RUBBERBAND; - let deviation = zoom / MAX_ZOOM_LEVEL; + if zoom > max_zoom { + let max_deviation = max_zoom * ZOOM_FACTOR_MAX_RUBBERBAND; + let deviation = zoom / max_zoom; zoom = f64::min( - MAX_ZOOM_LEVEL * deviation.powf(RUBBERBANDING_EXPONENT), + max_zoom * deviation.powf(RUBBERBANDING_EXPONENT), max_deviation, ); } @@ -1136,8 +1152,9 @@ impl LpImage { /// Zoom to specific level with animation pub fn zoom_to(&self, mut zoom: f64) { - if zoom >= MAX_ZOOM_LEVEL { - zoom = MAX_ZOOM_LEVEL; + let max_zoom = self.max_zoom(); + if zoom >= max_zoom { + zoom = max_zoom; self.set_max_zoom(true); } else { self.set_max_zoom(false); @@ -1413,6 +1430,11 @@ impl LpImage { Some(gdk::ContentProvider::for_value(&list.to_value())) } + /// Image format + pub fn format(&self) -> Option { + *self.imp().format.borrow() + } + /// Returns decoding error if one occured pub fn error(&self) -> Option { self.imp().error.borrow().clone()