2024-01-01 22:41:56 +01:00
|
|
|
// Copyright (c) 2023-2024 Sophie Herold
|
2023-05-23 01:49:40 +02:00
|
|
|
//
|
|
|
|
|
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
//
|
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
|
|
|
|
|
//! Decode using glycin
|
2023-12-26 22:07:46 +01:00
|
|
|
|
2023-12-06 23:45:02 +01:00
|
|
|
use std::sync::Arc;
|
2023-05-23 01:49:40 +02:00
|
|
|
|
|
|
|
|
use gtk::prelude::*;
|
|
|
|
|
|
2023-12-06 23:45:02 +01:00
|
|
|
use super::*;
|
2023-12-26 22:07:46 +01:00
|
|
|
use crate::decoder::tiling::{self, SharedFrameBuffer};
|
2023-12-06 23:45:02 +01:00
|
|
|
use crate::deps::*;
|
2024-01-01 22:41:56 +01:00
|
|
|
use crate::metadata::Metadata;
|
2023-05-23 01:49:40 +02:00
|
|
|
|
|
|
|
|
pub const FRAME_BUFFER: usize = 3;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct Glycin {
|
|
|
|
|
cancellable: gio::Cancellable,
|
|
|
|
|
next_frame_send: async_channel::Sender<()>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Drop for Glycin {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
self.cancellable.cancel();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Glycin {
|
2023-12-26 22:07:46 +01:00
|
|
|
pub fn new(file: gio::File, updater: UpdateSender, tiles: Arc<SharedFrameBuffer>) -> Self {
|
2023-05-23 01:49:40 +02:00
|
|
|
let cancellable = gio::Cancellable::new();
|
|
|
|
|
let cancellable_ = cancellable.clone();
|
|
|
|
|
|
|
|
|
|
let (next_frame_send, next_frame_recv) = async_channel::bounded(2);
|
|
|
|
|
|
2023-08-04 13:20:41 +02:00
|
|
|
updater.clone().spawn_error_handled(async move {
|
2024-02-08 00:32:09 +01:00
|
|
|
log::trace!("Setting up loader");
|
2024-01-29 22:35:42 +01:00
|
|
|
let mut image_request = glycin::Loader::new(file);
|
2023-05-23 01:49:40 +02:00
|
|
|
|
2023-08-04 13:20:41 +02:00
|
|
|
#[cfg(feature = "disable-glycin-sandbox")]
|
|
|
|
|
image_request.sandbox_mechanism(Some(glycin::SandboxMechanism::NotSandboxed));
|
2023-05-23 01:49:40 +02:00
|
|
|
|
2023-08-04 13:20:41 +02:00
|
|
|
image_request.cancellable(cancellable_);
|
2023-05-23 01:49:40 +02:00
|
|
|
|
2023-08-04 13:20:41 +02:00
|
|
|
let image = image_request.request().await?;
|
2024-02-08 00:32:09 +01:00
|
|
|
log::trace!("Image info received");
|
2023-05-23 01:49:40 +02:00
|
|
|
|
2024-01-01 22:41:56 +01:00
|
|
|
let mut metadata: Metadata = Metadata::default();
|
|
|
|
|
metadata.set_image_info(image.info().details.clone());
|
|
|
|
|
metadata.set_mime_type(image.mime_type());
|
|
|
|
|
updater.send(DecoderUpdate::Metadata(Box::new(metadata)));
|
2023-05-23 01:49:40 +02:00
|
|
|
|
2023-08-04 13:20:41 +02:00
|
|
|
let dimensions = (image.info().width, image.info().height);
|
|
|
|
|
tiles.set_original_dimensions(dimensions);
|
2023-05-23 01:49:40 +02:00
|
|
|
|
2023-08-04 13:20:41 +02:00
|
|
|
let frame = image.next_frame().await?;
|
2023-05-23 01:49:40 +02:00
|
|
|
|
2024-01-01 22:41:56 +01:00
|
|
|
let mut metadata: Metadata = Metadata::default();
|
|
|
|
|
metadata.set_frame_info(frame.details);
|
|
|
|
|
updater.send(DecoderUpdate::Metadata(Box::new(metadata)));
|
2024-01-21 14:19:33 +01:00
|
|
|
tiles.set_original_dimensions((
|
|
|
|
|
frame.texture.width() as u32,
|
|
|
|
|
frame.texture.height() as u32,
|
|
|
|
|
));
|
2024-01-01 22:41:56 +01:00
|
|
|
|
2023-08-04 13:20:41 +02:00
|
|
|
if let Some(delay) = frame.delay {
|
|
|
|
|
updater.send(DecoderUpdate::Animated);
|
2023-05-23 01:49:40 +02:00
|
|
|
|
2023-08-04 13:20:41 +02:00
|
|
|
let position = (0, 0);
|
2023-05-23 01:49:40 +02:00
|
|
|
|
2023-08-04 13:20:41 +02:00
|
|
|
let tile = tiling::Tile {
|
|
|
|
|
position,
|
|
|
|
|
zoom_level: tiling::zoom_to_level(1.),
|
|
|
|
|
bleed: 0,
|
|
|
|
|
texture: frame.texture,
|
|
|
|
|
};
|
2023-05-23 01:49:40 +02:00
|
|
|
|
2023-08-04 13:20:41 +02:00
|
|
|
tiles.push_frame(tile, dimensions, delay);
|
|
|
|
|
updater.send(DecoderUpdate::Redraw);
|
2023-05-23 01:49:40 +02:00
|
|
|
|
2023-08-04 13:20:41 +02:00
|
|
|
loop {
|
|
|
|
|
if next_frame_recv.recv().await.is_ok() {
|
|
|
|
|
loop {
|
|
|
|
|
let frame = image.next_frame().await?;
|
2023-05-23 01:49:40 +02:00
|
|
|
|
2023-08-04 13:20:41 +02:00
|
|
|
let position = (0, 0);
|
2023-05-23 01:49:40 +02:00
|
|
|
|
2023-08-04 13:20:41 +02:00
|
|
|
let tile = tiling::Tile {
|
|
|
|
|
position,
|
|
|
|
|
zoom_level: tiling::zoom_to_level(1.),
|
|
|
|
|
bleed: 0,
|
|
|
|
|
texture: frame.texture,
|
|
|
|
|
};
|
2023-05-23 01:49:40 +02:00
|
|
|
|
2023-09-27 00:47:24 +02:00
|
|
|
tiles.push_frame(tile, dimensions, frame.delay.unwrap_or(delay));
|
2023-05-23 01:49:40 +02:00
|
|
|
|
2023-08-04 13:20:41 +02:00
|
|
|
if tiles.n_frames() >= FRAME_BUFFER {
|
|
|
|
|
break;
|
2023-05-23 01:49:40 +02:00
|
|
|
}
|
|
|
|
|
}
|
2023-08-04 13:20:41 +02:00
|
|
|
} else {
|
|
|
|
|
log::debug!("Animation handler gone");
|
|
|
|
|
return Ok(());
|
2023-05-23 01:49:40 +02:00
|
|
|
}
|
|
|
|
|
}
|
2023-08-04 13:20:41 +02:00
|
|
|
} else {
|
|
|
|
|
let tile = tiling::Tile {
|
|
|
|
|
position: (0, 0),
|
|
|
|
|
zoom_level: tiling::zoom_to_level(1.),
|
|
|
|
|
bleed: 0,
|
|
|
|
|
texture: frame.texture,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
tiles.push(tile);
|
2023-05-23 01:49:40 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-04 13:20:41 +02:00
|
|
|
Ok(())
|
2023-05-23 01:49:40 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Self {
|
|
|
|
|
cancellable,
|
|
|
|
|
next_frame_send,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn fill_frame_buffer(&self) {
|
|
|
|
|
let _result = self.next_frame_send.try_send(());
|
|
|
|
|
}
|
|
|
|
|
}
|