From 191dd0255d284ca92c7806881733212e265df7c9 Mon Sep 17 00:00:00 2001 From: Chris Cochrun Date: Mon, 15 Sep 2025 11:00:38 -0500 Subject: [PATCH 1/2] remove pdf module for inserting the handles as a slide field This ensures that there isn't a need to duplicate tracking which index we have and which one is currently active, instead we pre create all the handles. --- src/core/presentations.rs | 37 +++++++-- src/core/slide.rs | 15 ++++ src/ui/mod.rs | 1 - src/ui/pdf.rs | 161 -------------------------------------- src/ui/presenter.rs | 40 +++++----- 5 files changed, 65 insertions(+), 189 deletions(-) delete mode 100644 src/ui/pdf.rs diff --git a/src/core/presentations.rs b/src/core/presentations.rs index 19f9166..cb6a5e4 100644 --- a/src/core/presentations.rs +++ b/src/core/presentations.rs @@ -1,6 +1,7 @@ +use cosmic::widget::image::Handle; use crisp::types::{Keyword, Symbol, Value}; use miette::{IntoDiagnostic, Result}; -use mupdf::{Document, Page}; +use mupdf::{Colorspace, Document, Matrix, Page}; use serde::{Deserialize, Serialize}; use sqlx::{ pool::PoolConnection, prelude::FromRow, query, sqlite::SqliteRow, @@ -131,13 +132,36 @@ impl ServiceTrait for Presentation { let background = Background::try_from(self.path.clone()) .into_diagnostic()?; debug!(?background); - let doc = Document::open(background.path.as_path()) + let document = Document::open(background.path.as_path()) .into_diagnostic()?; - debug!(?doc); - let pages = doc.page_count().into_diagnostic()?; + debug!(?document); + let pages = document.pages().into_diagnostic()?; debug!(?pages); + let pages: Vec = pages + .filter_map(|page| { + let Some(page) = page.ok() else { + return None; + }; + let matrix = Matrix::IDENTITY; + let colorspace = Colorspace::device_rgb(); + let Ok(pixmap) = page + .to_pixmap(&matrix, &colorspace, true, true) + .into_diagnostic() + else { + error!("Can't turn this page into pixmap"); + return None; + }; + debug!(?pixmap); + Some(Handle::from_rgba( + pixmap.width(), + pixmap.height(), + pixmap.samples().to_vec(), + )) + }) + .collect(); + let mut slides: Vec = vec![]; - for page in 0..pages { + for (index, page) in pages.into_iter().enumerate() { let slide = SlideBuilder::new() .background( Background::try_from(self.path.clone()) @@ -151,7 +175,8 @@ impl ServiceTrait for Presentation { .video_loop(false) .video_start_time(0.0) .video_end_time(0.0) - .pdf_index(page as u32) + .pdf_index(index as u32) + .pdf_page(page) .build()?; slides.push(slide); } diff --git a/src/core/slide.rs b/src/core/slide.rs index 97ad589..bf897ff 100644 --- a/src/core/slide.rs +++ b/src/core/slide.rs @@ -1,3 +1,4 @@ +use cosmic::widget::image::Handle; // use cosmic::dialog::ashpd::url::Url; use crisp::types::{Keyword, Symbol, Value}; use iced_video_player::Video; @@ -34,6 +35,8 @@ pub struct Slide { video_end_time: f32, pdf_index: u32, #[serde(skip)] + pdf_page: Option, + #[serde(skip)] pub text_svg: Option, } @@ -326,6 +329,10 @@ impl Slide { self.audio.clone() } + pub fn pdf_page(&self) -> Option { + self.pdf_page.clone() + } + pub fn pdf_index(&self) -> u32 { self.pdf_index } @@ -547,6 +554,8 @@ pub struct SlideBuilder { video_end_time: Option, pdf_index: Option, #[serde(skip)] + pdf_page: Option, + #[serde(skip)] text_svg: Option, } @@ -629,6 +638,11 @@ impl SlideBuilder { self } + pub(crate) fn pdf_page(mut self, pdf_page: Handle) -> Self { + let _ = self.pdf_page.insert(pdf_page); + self + } + pub(crate) fn pdf_index( mut self, pdf_index: impl Into, @@ -674,6 +688,7 @@ impl SlideBuilder { video_end_time, text_svg: self.text_svg, pdf_index: self.pdf_index.unwrap_or_default(), + pdf_page: self.pdf_page, ..Default::default() }) } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 4719bc0..8372371 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -2,7 +2,6 @@ use crate::core::model::LibraryKind; pub mod double_ended_slider; pub mod library; -pub mod pdf; pub mod presenter; pub mod slide_editor; pub mod song_editor; diff --git a/src/ui/pdf.rs b/src/ui/pdf.rs deleted file mode 100644 index 60e9fe5..0000000 --- a/src/ui/pdf.rs +++ /dev/null @@ -1,161 +0,0 @@ -use std::path::Path; - -use cosmic::iced::ContentFit; -use cosmic::iced::Length; -use cosmic::widget::image; -use cosmic::widget::image::Handle; -use cosmic::Element; -use miette::IntoDiagnostic; -use miette::Result; -use miette::Severity; -use mupdf::Colorspace; -use mupdf::Document; -use mupdf::Matrix; -use tracing::debug; -use tracing::error; - -#[derive(Debug, Clone, Default)] -pub struct PdfViewer { - document: Option, - pages: Option>, - current_page: Option, - current_index: usize, -} - -pub enum Message {} - -impl PdfViewer { - pub fn with_pdf(pdf: impl AsRef) -> Result { - let pdf_path = pdf.as_ref(); - let document = Document::open(pdf_path).into_diagnostic()?; - let pages = document.pages().into_diagnostic()?; - let pages: Vec = pages - .filter_map(|page| { - let Some(page) = page.ok() else { - return None; - }; - let matrix = Matrix::IDENTITY; - let colorspace = Colorspace::device_rgb(); - let Ok(pixmap) = page - .to_pixmap(&matrix, &colorspace, true, true) - .into_diagnostic() - else { - error!("Can't turn this page into pixmap"); - return None; - }; - let handle = pixmap.samples().to_vec(); - Some(Handle::from_bytes(handle)) - }) - .collect(); - let Some(page) = document.pages().into_diagnostic()?.next() - else { - return Err(miette::miette!( - severity = Severity::Warning, - "There isn't a first page here" - )); - }; - let page = page.into_diagnostic()?; - let matrix = Matrix::IDENTITY; - let colorspace = Colorspace::device_rgb(); - let pixmap = page - .to_pixmap(&matrix, &colorspace, true, true) - .into_diagnostic()?; - let handle = pixmap.samples().to_vec(); - Ok(Self { - document: Some(document), - pages: Some(pages), - current_index: 0, - current_page: Some(Handle::from_bytes(handle)), - }) - } - - pub fn insert_pdf( - &mut self, - pdf: impl AsRef, - ) -> Result<()> { - let pdf_path = pdf.as_ref(); - let document = Document::open(pdf_path).into_diagnostic()?; - let pages = document.pages().into_diagnostic()?; - - let pages: Vec = pages - .filter_map(|page| { - let Some(page) = page.ok() else { - return None; - }; - let matrix = Matrix::IDENTITY; - let colorspace = Colorspace::device_rgb(); - let Ok(pixmap) = page - .to_pixmap(&matrix, &colorspace, true, true) - .into_diagnostic() - else { - error!("Can't turn this page into pixmap"); - return None; - }; - debug!(?pixmap); - Some(Handle::from_rgba( - pixmap.width(), - pixmap.height(), - pixmap.samples().to_vec(), - )) - }) - .collect(); - let Some(page) = document.pages().into_diagnostic()?.next() - else { - return Err(miette::miette!( - severity = Severity::Warning, - "There isn't a first page here" - )); - }; - self.current_page = pages.get(0).map(|h| h.to_owned()); - self.document = Some(document); - self.pages = Some(pages); - self.current_index = 0; - debug!(?self); - Ok(()) - } - - pub fn next_page(&mut self) -> Result<()> { - let Some(ref pages) = self.pages else { - return Err(miette::miette!("No pages in doc")); - }; - let Some(page) = pages.get(self.current_index + 1) else { - return Err(miette::miette!("There isn't a next page")); - }; - self.current_page = Some(page.to_owned()); - self.current_index += 1; - Ok(()) - } - - pub fn previous_page(&mut self) -> Result<()> { - if self.current_index == 0 { - return Err(miette::miette!("You are at the first page")); - } - let Some(ref pages) = self.pages else { - return Err(miette::miette!("No pages in doc")); - }; - let Some(page) = pages.get(self.current_index - 1) else { - return Err(miette::miette!( - "There isn't a previous page" - )); - }; - self.current_page = Some(page.to_owned()); - self.current_index -= 1; - Ok(()) - } - - pub fn view(&self, index: u32) -> Option> { - let Some(pages) = &self.pages else { - return None; - }; - let Some(handle) = pages.get(index as usize) else { - return None; - }; - Some( - image(handle) - .width(Length::Fill) - .height(Length::Fill) - .content_fit(ContentFit::Contain) - .into(), - ) - } -} diff --git a/src/ui/presenter.rs b/src/ui/presenter.rs index ea268cc..cb42d95 100644 --- a/src/ui/presenter.rs +++ b/src/ui/presenter.rs @@ -53,7 +53,6 @@ pub(crate) struct Presenter { hovered_slide: Option<(usize, usize)>, scroll_id: Id, current_font: Font, - pdf_viewer: PdfViewer, } pub(crate) enum Action { @@ -174,7 +173,6 @@ impl Presenter { }, scroll_id: Id::unique(), current_font: cosmic::font::default(), - pdf_viewer: PdfViewer::default(), } } @@ -225,11 +223,6 @@ impl Presenter { self.reset_video(); } - if slide.background().kind == BackgroundKind::Pdf { - self.pdf_viewer - .insert_pdf(&slide.background().path); - } - let offset = AbsoluteOffset { x: { if self.current_slide_index > 2 { @@ -411,7 +404,6 @@ impl Presenter { slide_view( &self.current_slide, &self.video, - &self.pdf_viewer, self.current_font, false, true, @@ -422,7 +414,6 @@ impl Presenter { slide_view( &self.current_slide, &self.video, - &self.pdf_viewer, self.current_font, false, false, @@ -459,7 +450,6 @@ impl Presenter { let container = slide_view( &slide, &self.video, - &self.pdf_viewer, font, true, false, @@ -722,7 +712,6 @@ fn scale_font(font_size: f32, width: f32) -> f32 { pub(crate) fn slide_view<'a>( slide: &'a Slide, video: &'a Option