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.
This commit is contained in:
Chris Cochrun 2025-09-15 11:00:38 -05:00
parent ad14135ddf
commit 191dd0255d
5 changed files with 65 additions and 189 deletions

View file

@ -1,6 +1,7 @@
use cosmic::widget::image::Handle;
use crisp::types::{Keyword, Symbol, Value}; use crisp::types::{Keyword, Symbol, Value};
use miette::{IntoDiagnostic, Result}; use miette::{IntoDiagnostic, Result};
use mupdf::{Document, Page}; use mupdf::{Colorspace, Document, Matrix, Page};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{ use sqlx::{
pool::PoolConnection, prelude::FromRow, query, sqlite::SqliteRow, pool::PoolConnection, prelude::FromRow, query, sqlite::SqliteRow,
@ -131,13 +132,36 @@ impl ServiceTrait for Presentation {
let background = Background::try_from(self.path.clone()) let background = Background::try_from(self.path.clone())
.into_diagnostic()?; .into_diagnostic()?;
debug!(?background); debug!(?background);
let doc = Document::open(background.path.as_path()) let document = Document::open(background.path.as_path())
.into_diagnostic()?; .into_diagnostic()?;
debug!(?doc); debug!(?document);
let pages = doc.page_count().into_diagnostic()?; let pages = document.pages().into_diagnostic()?;
debug!(?pages); debug!(?pages);
let pages: Vec<Handle> = 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<Slide> = vec![]; let mut slides: Vec<Slide> = vec![];
for page in 0..pages { for (index, page) in pages.into_iter().enumerate() {
let slide = SlideBuilder::new() let slide = SlideBuilder::new()
.background( .background(
Background::try_from(self.path.clone()) Background::try_from(self.path.clone())
@ -151,7 +175,8 @@ impl ServiceTrait for Presentation {
.video_loop(false) .video_loop(false)
.video_start_time(0.0) .video_start_time(0.0)
.video_end_time(0.0) .video_end_time(0.0)
.pdf_index(page as u32) .pdf_index(index as u32)
.pdf_page(page)
.build()?; .build()?;
slides.push(slide); slides.push(slide);
} }

View file

@ -1,3 +1,4 @@
use cosmic::widget::image::Handle;
// use cosmic::dialog::ashpd::url::Url; // use cosmic::dialog::ashpd::url::Url;
use crisp::types::{Keyword, Symbol, Value}; use crisp::types::{Keyword, Symbol, Value};
use iced_video_player::Video; use iced_video_player::Video;
@ -34,6 +35,8 @@ pub struct Slide {
video_end_time: f32, video_end_time: f32,
pdf_index: u32, pdf_index: u32,
#[serde(skip)] #[serde(skip)]
pdf_page: Option<Handle>,
#[serde(skip)]
pub text_svg: Option<TextSvg>, pub text_svg: Option<TextSvg>,
} }
@ -326,6 +329,10 @@ impl Slide {
self.audio.clone() self.audio.clone()
} }
pub fn pdf_page(&self) -> Option<Handle> {
self.pdf_page.clone()
}
pub fn pdf_index(&self) -> u32 { pub fn pdf_index(&self) -> u32 {
self.pdf_index self.pdf_index
} }
@ -547,6 +554,8 @@ pub struct SlideBuilder {
video_end_time: Option<f32>, video_end_time: Option<f32>,
pdf_index: Option<u32>, pdf_index: Option<u32>,
#[serde(skip)] #[serde(skip)]
pdf_page: Option<Handle>,
#[serde(skip)]
text_svg: Option<TextSvg>, text_svg: Option<TextSvg>,
} }
@ -629,6 +638,11 @@ impl SlideBuilder {
self 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( pub(crate) fn pdf_index(
mut self, mut self,
pdf_index: impl Into<u32>, pdf_index: impl Into<u32>,
@ -674,6 +688,7 @@ impl SlideBuilder {
video_end_time, video_end_time,
text_svg: self.text_svg, text_svg: self.text_svg,
pdf_index: self.pdf_index.unwrap_or_default(), pdf_index: self.pdf_index.unwrap_or_default(),
pdf_page: self.pdf_page,
..Default::default() ..Default::default()
}) })
} }

View file

@ -2,7 +2,6 @@ use crate::core::model::LibraryKind;
pub mod double_ended_slider; pub mod double_ended_slider;
pub mod library; pub mod library;
pub mod pdf;
pub mod presenter; pub mod presenter;
pub mod slide_editor; pub mod slide_editor;
pub mod song_editor; pub mod song_editor;

View file

@ -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<Document>,
pages: Option<Vec<Handle>>,
current_page: Option<Handle>,
current_index: usize,
}
pub enum Message {}
impl PdfViewer {
pub fn with_pdf(pdf: impl AsRef<Path>) -> Result<Self> {
let pdf_path = pdf.as_ref();
let document = Document::open(pdf_path).into_diagnostic()?;
let pages = document.pages().into_diagnostic()?;
let pages: Vec<Handle> = 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<Path>,
) -> Result<()> {
let pdf_path = pdf.as_ref();
let document = Document::open(pdf_path).into_diagnostic()?;
let pages = document.pages().into_diagnostic()?;
let pages: Vec<Handle> = 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<Element<Message>> {
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(),
)
}
}

View file

@ -53,7 +53,6 @@ pub(crate) struct Presenter {
hovered_slide: Option<(usize, usize)>, hovered_slide: Option<(usize, usize)>,
scroll_id: Id, scroll_id: Id,
current_font: Font, current_font: Font,
pdf_viewer: PdfViewer,
} }
pub(crate) enum Action { pub(crate) enum Action {
@ -174,7 +173,6 @@ impl Presenter {
}, },
scroll_id: Id::unique(), scroll_id: Id::unique(),
current_font: cosmic::font::default(), current_font: cosmic::font::default(),
pdf_viewer: PdfViewer::default(),
} }
} }
@ -225,11 +223,6 @@ impl Presenter {
self.reset_video(); self.reset_video();
} }
if slide.background().kind == BackgroundKind::Pdf {
self.pdf_viewer
.insert_pdf(&slide.background().path);
}
let offset = AbsoluteOffset { let offset = AbsoluteOffset {
x: { x: {
if self.current_slide_index > 2 { if self.current_slide_index > 2 {
@ -411,7 +404,6 @@ impl Presenter {
slide_view( slide_view(
&self.current_slide, &self.current_slide,
&self.video, &self.video,
&self.pdf_viewer,
self.current_font, self.current_font,
false, false,
true, true,
@ -422,7 +414,6 @@ impl Presenter {
slide_view( slide_view(
&self.current_slide, &self.current_slide,
&self.video, &self.video,
&self.pdf_viewer,
self.current_font, self.current_font,
false, false,
false, false,
@ -459,7 +450,6 @@ impl Presenter {
let container = slide_view( let container = slide_view(
&slide, &slide,
&self.video, &self.video,
&self.pdf_viewer,
font, font,
true, true,
false, false,
@ -722,7 +712,6 @@ fn scale_font(font_size: f32, width: f32) -> f32 {
pub(crate) fn slide_view<'a>( pub(crate) fn slide_view<'a>(
slide: &'a Slide, slide: &'a Slide,
video: &'a Option<Video>, video: &'a Option<Video>,
pdf_viewer: &'a PdfViewer,
font: Font, font: Font,
delegate: bool, delegate: bool,
hide_mouse: bool, hide_mouse: bool,
@ -799,17 +788,26 @@ pub(crate) fn slide_view<'a>(
Container::new(Space::new(0, 0)) Container::new(Space::new(0, 0))
} }
} }
BackgroundKind::Pdf => Container::new( BackgroundKind::Pdf => {
if let Some(pdf) = pdf_viewer.view(slide.pdf_index()) if let Some(pdf) = slide.pdf_page() {
{ Container::new(
pdf.map(|_| Message::None) image(pdf)
} else { .content_fit(ContentFit::Cover)
Space::new(0.0, 0.0).into() .width(width)
}, .height(size.height),
) )
.center_x(width) .center_x(width)
.center_y(size.height) .center_y(size.height)
.clip(true), .clip(true)
.into()
} else {
Container::new(Space::new(0.0, 0.0))
.center_x(width)
.center_y(size.height)
.clip(true)
.into()
}
}
BackgroundKind::Html => todo!(), BackgroundKind::Html => todo!(),
}; };
let stack = stack!( let stack = stack!(