adding pdf rendering
Some checks are pending
/ test (push) Waiting to run

This commit is contained in:
Chris Cochrun 2025-09-15 09:29:27 -05:00
parent 6532666c56
commit ad14135ddf
6 changed files with 177 additions and 78 deletions

View file

@ -11,26 +11,42 @@ use miette::Severity;
use mupdf::Colorspace;
use mupdf::Document;
use mupdf::Matrix;
use mupdf::Page;
use tracing::debug;
use tracing::error;
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
pub struct PdfViewer {
document: Option<Document>,
pages: Option<Vec<Page>>,
current_page: Option<Page>,
pages: Option<Vec<Handle>>,
current_page: Option<Handle>,
current_index: usize,
handle: Option<Handle>,
}
enum Message {}
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<Page> =
pages.filter_map(|page| page.ok()).collect();
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!(
@ -48,9 +64,8 @@ impl PdfViewer {
Ok(Self {
document: Some(document),
pages: Some(pages),
current_page: Some(page),
current_index: 0,
handle: Some(Handle::from_bytes(handle)),
current_page: Some(Handle::from_bytes(handle)),
})
}
@ -61,8 +76,29 @@ impl PdfViewer {
let pdf_path = pdf.as_ref();
let document = Document::open(pdf_path).into_diagnostic()?;
let pages = document.pages().into_diagnostic()?;
let pages: Vec<Page> =
pages.filter_map(|page| page.ok()).collect();
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!(
@ -70,18 +106,11 @@ impl PdfViewer {
"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();
self.current_page = pages.get(0).map(|h| h.to_owned());
self.document = Some(document);
self.pages = Some(pages);
self.current_page = Some(page);
self.current_index = 0;
self.handle = Some(Handle::from_bytes(handle));
debug!(?self);
Ok(())
}
@ -92,15 +121,8 @@ impl PdfViewer {
let Some(page) = pages.get(self.current_index + 1) else {
return Err(miette::miette!("There isn't a next page"));
};
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();
self.current_page = Some(page.to_owned());
self.current_index += 1;
self.handle = Some(Handle::from_bytes(handle));
Ok(())
}
@ -116,20 +138,16 @@ impl PdfViewer {
"There isn't a previous page"
));
};
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();
self.current_page = Some(page.to_owned());
self.current_index -= 1;
self.handle = Some(Handle::from_bytes(handle));
Ok(())
}
pub fn view(&self) -> Option<Element<Message>> {
let Some(handle) = self.handle.clone() else {
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(

View file

@ -174,6 +174,7 @@ impl Presenter {
},
scroll_id: Id::unique(),
current_font: cosmic::font::default(),
pdf_viewer: PdfViewer::default(),
}
}
@ -206,7 +207,8 @@ impl Presenter {
Message::SlideChange(slide) => {
let slide_text = slide.text();
debug!(slide_text, "slide changed");
debug!("comparing background...");
let bg = slide.background().clone();
debug!(?bg, "comparing background...");
let backgrounds_match =
self.current_slide.background()
== slide.background();
@ -223,6 +225,11 @@ 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 {
@ -404,6 +411,7 @@ impl Presenter {
slide_view(
&self.current_slide,
&self.video,
&self.pdf_viewer,
self.current_font,
false,
true,
@ -414,6 +422,7 @@ impl Presenter {
slide_view(
&self.current_slide,
&self.video,
&self.pdf_viewer,
self.current_font,
false,
false,
@ -450,6 +459,7 @@ impl Presenter {
let container = slide_view(
&slide,
&self.video,
&self.pdf_viewer,
font,
true,
false,
@ -636,7 +646,6 @@ impl Presenter {
fn reset_video(&mut self) {
match self.current_slide.background().kind {
BackgroundKind::Image => self.video = None,
BackgroundKind::Video => {
let path = &self.current_slide.background().path;
if path.exists() {
@ -660,6 +669,7 @@ impl Presenter {
self.video = None;
}
}
_ => self.video = None,
}
}
@ -712,6 +722,7 @@ fn scale_font(font_size: f32, width: f32) -> f32 {
pub(crate) fn slide_view<'a>(
slide: &'a Slide,
video: &'a Option<Video>,
pdf_viewer: &'a PdfViewer,
font: Font,
delegate: bool,
hide_mouse: bool,
@ -788,6 +799,18 @@ pub(crate) fn slide_view<'a>(
Container::new(Space::new(0, 0))
}
}
BackgroundKind::Pdf => Container::new(
if let Some(pdf) = pdf_viewer.view(slide.pdf_index())
{
pdf.map(|_| Message::None)
} else {
Space::new(0.0, 0.0).into()
},
)
.center_x(width)
.center_y(size.height)
.clip(true),
BackgroundKind::Html => todo!(),
};
let stack = stack!(
black,