From b98ca6c9f6ca8bac541fc6d77ec3fe4f94f9a082 Mon Sep 17 00:00:00 2001
From: Julian Mutter <julian.mutter@comumail.de>
Date: Wed, 22 Nov 2023 19:35:16 +0100
Subject: [PATCH] Managed to render to png, still only proof of concept

---
 Cargo.toml   |  2 +-
 src/cache.rs | 15 +++++++--
 src/draw.rs  | 24 ++++++++++++--
 src/ui.rs    | 90 +++++++++++++++++++++++++++++++++++-----------------
 4 files changed, 97 insertions(+), 34 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index a125178..e99a171 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
 
 [dependencies]
 poppler-rs = "0.22"
-cairo-rs = "0.18.3"
+cairo-rs = { version = "0.18.3", features = ["png"] }
 glib-macros = "0.18.3"
 gio = "0.18.3"
 glib = "0.18.3"
diff --git a/src/cache.rs b/src/cache.rs
index 4cb677a..1f1f553 100644
--- a/src/cache.rs
+++ b/src/cache.rs
@@ -1,3 +1,5 @@
+use cairo::ImageSurface;
+use gtk::gdk::Texture;
 use poppler::{Document, Page};
 use std::{
     collections::BTreeMap,
@@ -8,8 +10,10 @@ use std::{
 
 use async_channel::Sender;
 
+use crate::draw;
+
 type PageNumber = usize;
-pub type MyPageType = Page;
+pub type MyPageType = Texture;
 
 pub struct PageCache {
     document: Document,
@@ -39,7 +43,10 @@ impl PageCache {
             }
 
             if let Some(page) = self.document.page(page_number as i32) {
-                self.pages.insert(page_number, Rc::new(page));
+                let pages = vec![Rc::new(page)];
+                let texture = draw::draw_pages_to_texture(&pages, 500, 500);
+
+                self.pages.insert(page_number, Rc::new(texture));
 
                 if self.pages.len() > self.max_num_stored_pages && self.pages.len() > 2 {
                     let _result = self.remove_most_distant_page(page_number);
@@ -76,7 +83,9 @@ impl PageCache {
             }
             CacheCommand::GetCurrentTwoPages { page_left_number } => {
                 if let Some(page_left) = self.get_page(page_left_number) {
+                    println!("got left page");
                     if let Some(page_right) = self.get_page(page_left_number + 1) {
+                        println!("got right page");
                         Some(CacheResponse::TwoPagesRetrieved {
                             page_left,
                             page_right,
@@ -85,6 +94,7 @@ impl PageCache {
                         Some(CacheResponse::SinglePageRetrieved { page: page_left })
                     }
                 } else {
+                    println!("did not get any page");
                     // TODO: if page left was not empty, this could be because page turning was too quick.
                     // In this case, just not rendering the current page is okay, but when no more render requests are available, one would want to wait for the caching
                     None
@@ -140,6 +150,7 @@ where
                 // response_sender.send_blocking(response).unwrap();
                 println!("Command processed, activating receiver....");
                 receiver(response);
+                println!("receiver done");
             }
         }
     });
diff --git a/src/draw.rs b/src/draw.rs
index bf2b04d..4a296bc 100644
--- a/src/draw.rs
+++ b/src/draw.rs
@@ -1,10 +1,27 @@
 use std::{rc::Rc, time::Instant};
 
-use cairo::Context;
+use cairo::{Context, ImageSurface};
+use glib::Bytes;
+use gtk::{
+    ffi::GtkImage,
+    gdk::{ffi::gdk_pixbuf_get_from_surface, Texture},
+    gdk_pixbuf::Pixbuf,
+};
 use poppler::Page;
 
 use crate::ui::DocumentCanvas;
 
+pub fn draw_pages_to_texture(pages: &[Rc<Page>], area_width: i32, area_height: i32) -> Texture {
+    let surface =
+        ImageSurface::create(cairo::Format::Rgb24, area_width as i32, area_height as i32).unwrap();
+    let context = Context::new(&surface).unwrap();
+    draw_pages(pages, &context, area_width, area_height);
+
+    let mut stream: Vec<u8> = Vec::new();
+    surface.write_to_png(&mut stream).unwrap();
+    Texture::from_bytes(&Bytes::from(&stream)).unwrap()
+}
+
 pub fn draw(
     document_canvas: &Option<DocumentCanvas>,
     context: &Context,
@@ -17,12 +34,15 @@ pub fn draw(
         if document_canvas.num_pages.unwrap_or(0) > 1 {
             let mut pages = Vec::new();
             if let Some(page_left) = &document_canvas.left_page {
+                // context
+                //     .set_source_surface(page_left.as_ref(), 0.0, 0.0)
+                //     .unwrap();
                 pages.push(Rc::clone(page_left));
             }
             if let Some(page_right) = &document_canvas.right_page {
                 pages.push(Rc::clone(page_right));
             }
-            draw_pages(&pages, context, area_width, area_height);
+            // draw_pages(&pages, context, area_width, area_height);
         }
 
         println!(
diff --git a/src/ui.rs b/src/ui.rs
index c7b1c7c..6ce0380 100644
--- a/src/ui.rs
+++ b/src/ui.rs
@@ -1,16 +1,19 @@
-use std::{cell::RefCell, path::Path, rc::Rc};
+use std::{cell::RefCell, path::Path, rc::Rc, time::Instant};
 
 use async_channel::Sender;
 use gtk::{
+    ffi::{GtkImage, GtkPicture},
+    gdk::{ffi::gdk_pixbuf_get_from_surface, Texture},
+    gdk_pixbuf::{ffi::GdkPixbuf, Pixbuf},
     glib, Application, ApplicationWindow, Box, Button, DrawingArea, FileChooserAction,
-    FileChooserDialog, HeaderBar, Label, Orientation, ResponseType,
+    FileChooserDialog, HeaderBar, Image, Label, Orientation, ResponseType,
 };
 
 use crate::{
     cache::{self, CacheCommand, MyPageType},
     draw,
 };
-use glib::clone;
+use glib::{clone, Bytes};
 use gtk::prelude::*;
 
 pub struct Ui {
@@ -18,7 +21,8 @@ pub struct Ui {
     bottom_bar: gtk::Box,
     header_bar: gtk::HeaderBar,
     page_indicator: gtk::Label,
-    drawing_area: gtk::DrawingArea,
+    pub drawing_area: gtk::DrawingArea,
+    pub image: Image,
     pub document_canvas: Option<DocumentCanvas>,
 }
 
@@ -178,6 +182,12 @@ impl Ui {
             bottom_bar: Box::builder().hexpand_set(true).build(),
             header_bar: HeaderBar::builder().build(),
             page_indicator: Label::builder().build(),
+            image: Image::builder()
+                .width_request(400)
+                .height_request(300)
+                .hexpand(true)
+                .vexpand(true)
+                .build(),
             drawing_area: DrawingArea::builder()
                 .width_request(400)
                 .height_request(300)
@@ -189,7 +199,8 @@ impl Ui {
         let ui = Rc::new(RefCell::new(ui));
 
         ui.borrow().header_bar.pack_start(&open_file_button);
-        app_wrapper.prepend(&ui.borrow().drawing_area);
+        // app_wrapper.prepend(&ui.borrow().drawing_area);
+        app_wrapper.prepend(&ui.borrow().image);
         app_wrapper.append(&ui.borrow().bottom_bar);
         ui.borrow().bottom_bar.append(&ui.borrow().page_indicator);
 
@@ -205,14 +216,21 @@ impl Ui {
         process_right_click(&mut ui.borrow_mut(), x, y);
              }));
 
-        ui.borrow().drawing_area.add_controller(click_left);
-        ui.borrow().drawing_area.add_controller(click_right);
+        // ui.borrow().drawing_area.add_controller(click_left);
+        // ui.borrow().drawing_area.add_controller(click_right);
+        ui.borrow().image.add_controller(click_left);
+        ui.borrow().image.add_controller(click_right);
 
-        ui.borrow().drawing_area.set_draw_func(
-            glib::clone!(@weak ui => move |_area, context, w, h| {
-                draw::draw(&ui.borrow().document_canvas, context, w, h);
-            }),
-        );
+        // ui.borrow().drawing_area.set_draw_func(
+        //     glib::clone!(@weak ui => move |_area, context, w, h| {
+        //         draw::draw(&ui.borrow().document_canvas, context, w, h);
+        //     }),
+        // );
+        // ui.borrow().image.connect_paintable_notify(
+        //     glib::clone!(@weak ui => @default-panic, move |_| {
+        //         ui.borrow().document_canvas.as_ref().unwrap().cache_surrounding_pages();
+        //     }),
+        // );
 
         ui.borrow()
             .window
@@ -255,23 +273,37 @@ pub fn load_document(file: impl AsRef<Path>, ui: Rc<RefCell<Ui>>) {
     let sender = cache::spawn_async_cache(
         file,
         clone!(@weak ui => move |cache_response| match cache_response {
-            cache::CacheResponse::DocumentLoaded { num_pages } => {
-                ui.borrow_mut().document_canvas.as_mut().unwrap().num_pages = Some(num_pages);
-                update_page_status(&ui.borrow())
-            }
-            cache::CacheResponse::SinglePageRetrieved { page } => {
-                ui.borrow_mut().document_canvas.as_mut().unwrap().left_page = Some(page);
-                ui.borrow_mut().document_canvas.as_mut().unwrap().right_page = None;
-                ui.borrow().drawing_area.queue_draw();
-            }
-            cache::CacheResponse::TwoPagesRetrieved {
-                page_left,
-                page_right,
-            } => {
-                ui.borrow_mut().document_canvas.as_mut().unwrap().left_page = Some(page_left);
-                ui.borrow_mut().document_canvas.as_mut().unwrap().right_page = Some(page_right);
-                ui.borrow().drawing_area.queue_draw();
-            }
+                cache::CacheResponse::DocumentLoaded { num_pages } => {
+                    ui.borrow_mut().document_canvas.as_mut().unwrap().num_pages = Some(num_pages);
+                    update_page_status(&ui.borrow())
+                }
+                cache::CacheResponse::SinglePageRetrieved { page } => {
+                    ui.borrow_mut().document_canvas.as_mut().unwrap().left_page = Some(page);
+                    ui.borrow_mut().document_canvas.as_mut().unwrap().right_page = None;
+                    ui.borrow().drawing_area.queue_draw();
+                }
+                cache::CacheResponse::TwoPagesRetrieved {
+                    page_left,
+                    page_right,
+                } => {
+                    ui.borrow_mut().document_canvas.as_mut().unwrap().left_page = Some(Rc::clone(&page_left));
+                    ui.borrow_mut().document_canvas.as_mut().unwrap().right_page = Some(page_right);
+                    // unsafe{
+                    //     let x = Pixbuf::new();
+                    // gdk_pixbuf_get_from_surface(page_left, 0, 0, page_left.width(), page_left.height());
+                    // }
+                    // ui.borrow_mut().image.bitstre
+                    // ui.borrow().drawing_area.queue_draw();
+                    println!("New Draw");
+                    let begin_of_drawing = Instant::now();
+                    ui.borrow_mut().image.set_from_paintable(Some(page_left.as_ref()));
+                    ui.borrow().image.queue_draw();
+                    println!(
+                        "Finished new drawing in {}ms",
+                        begin_of_drawing.elapsed().as_millis()
+                    );
+                    ui.borrow().document_canvas.as_ref().unwrap().cache_surrounding_pages();
+                }
         }),
     );