image: Limit SVG zoom to RSVG limits
See <https://gitlab.gnome.org/GNOME/librsvg/-/issues/938> for details about the problem. Closes #88
This commit is contained in:
parent
dfebfb7470
commit
a0ce234946
4 changed files with 38 additions and 12 deletions
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ use gtk::prelude::*;
|
|||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Current librsvg limit on maximum dimensions. See
|
||||
/// <https://gitlab.gnome.org/GNOME/librsvg/-/issues/938>
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ mod imp {
|
|||
pub file_monitor: RefCell<Option<gio::FileMonitor>>,
|
||||
pub tiles: Arc<ArcSwap<tiling::TilingStore>>,
|
||||
pub decoder: RefCell<Option<Arc<Decoder>>>,
|
||||
pub format: RefCell<Option<decoder::ImageFormat>>,
|
||||
|
||||
/// Set to true when image is ready for displaying
|
||||
pub is_loaded: Cell<bool>,
|
||||
|
|
@ -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<decoder::ImageFormat> {
|
||||
*self.imp().format.borrow()
|
||||
}
|
||||
|
||||
/// Returns decoding error if one occured
|
||||
pub fn error(&self) -> Option<String> {
|
||||
self.imp().error.borrow().clone()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue