// Copyright (c) 2023-2025 Sophie Herold
// Copyright (c) 2023 Julian Hofer
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// SPDX-License-Identifier: GPL-3.0-or-later
//! Decodes several image formats
pub mod formats;
pub mod tiling;
use std::sync::Arc;
use anyhow::Result;
use async_channel as mpsc;
pub use formats::RSVG_MAX_SIZE;
use formats::*;
use self::tiling::SharedFrameBuffer;
use crate::deps::*;
use crate::metadata::Metadata;
#[derive(Clone, Copy, Debug)]
/// Renderer requests new tiles
///
/// This happens for initial loading or when zoom level or viewing area changes.
pub struct TileRequest {
pub viewport: graphene::Rect,
pub area: graphene::Rect,
pub zoom: f64,
}
#[derive(Debug, Clone)]
/// Signals update to the renderer
pub struct UpdateSender {
sender: mpsc::Sender,
}
#[derive(Debug)]
/// Signals for renderer (LpImage)
pub enum DecoderUpdate {
/// Dimensions of image in `TilingSore` available/updated
Dimensions,
/// Metadata available
Metadata(Box),
/// New image data available, redraw
Redraw,
/// Start animation
Animated,
SpecificError(DecoderError),
/// And error occurred during decoding
GenericError(anyhow::Error),
}
#[derive(glib::Enum, Debug, Clone, Copy, Default, PartialEq, Eq)]
#[enum_type(name = "LpDecoderError")]
//#[enum_dynamic(lazy_registration = true)]
#[repr(i32)]
pub enum DecoderError {
/// Image format not supported or unknown
UnsupportedFormat,
/// No glycin-loaders installed
NoLoadersConfigured,
/// Memory limit exceeded
OutOfMemory,
#[default]
None,
}
impl DecoderError {
pub fn is_err(self) -> bool {
matches!(self, Self::None)
}
pub fn is_ok(self) -> bool {
!matches!(self, Self::None)
}
}
impl glib::value::ToValueOptional for DecoderError {
fn to_value_optional(s: Option<&Self>) -> glib::Value {
s.unwrap_or(&Self::None).into()
}
}
impl UpdateSender {
pub fn send(&self, update: DecoderUpdate) {
let result = self.sender.force_send(update);
match result {
Err(err) => tracing::error!("Failed to send update: {err}"),
Ok(Some(msg)) => tracing::error!("Unexpectedly replaced the message {msg:?}"),
_ => {}
}
}
/// Send occurring errors to renderer
pub fn spawn_error_handled(&self, f: F) -> glib::JoinHandle<()>
where
F: std::future::Future