// TODO: move implementation in .cc file // TODO: refine api, it's somewhat ugly right now // TODO: should we render in a thread? #ifndef __PDFCUBE__PAGE_HH__ #define __PDFCUBE__PAGE_HH__ #include #include #include namespace pdfcube { /** * @brief The pdfcube::page class is the link between a PopplerPage * and ClutterActor GObjects. * * This class is used to render low and hi res version of a * PopplerPage as GdkPixbufs * * Usually, on start, all the pages will be rendered in a low res * version, while higher res versions will be rendered on demand by * the animations. * * While displaying one page the following page is rendered in high * resolution. No forward animation is possible until the rendering * finishes. * */ class page { public: /** * @brief Ctor. * * This is used internally by pdfcube::document. (FIXME: make * protected and friend of document?) * * @param poppler_page a PopplerPage* * */ page(PopplerPage* poppler_page) : poppler_page_m(poppler_page), low_res_m(NULL), hi_res_m(NULL) { } double aspect_ratio() { double w, h; poppler_page_get_size(poppler_page_m, &w, &h); return w/h; } std::pair size() { double w, h; poppler_page_get_size(poppler_page_m, &w, &h); return std::make_pair(w,h); } enum rendering_mode { LOW_RES, HI_RES }; /** * @brief Renders the PopplerPage on the desired pixbuf. */ void render(rendering_mode mode) { switch(mode) { case LOW_RES: { int w,h; // we assume 4/3 aspect monitor can do better double box_w = 320; double box_h = 240; double aspect = aspect_ratio(); // Check if our slot ratio is less or more than owr own if(box_h > box_w/aspect) { w = box_w; h = w/aspect; } else { h = box_h; w = h*aspect; } if(!low_res_m) low_res_m = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, w, h); poppler_page_render_to_pixbuf(poppler_page_m, 0, 0, w, h, ((double)h)/size().second, 0, low_res_m); break; } case HI_RES: { int w, h; // FIXME: we assume 4/3 aspect monitor. double box_w = 1600; double box_h = 1200; double aspect = aspect_ratio(); // Check if our slot ratio is less or more than owr own if(box_h > box_w/aspect) { w = box_w; h = w/aspect; } else { h = box_h; w = h*aspect; } if(!hi_res_m) hi_res_m = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, w, h); poppler_page_render_to_pixbuf(poppler_page_m, 0, 0, w, h, ((double)h)/size().second, 0, hi_res_m); break; } } }; /** * @brief Frees an unneeded actor. */ void free(rendering_mode mode) { switch(mode) { case LOW_RES: g_object_unref(low_res_m); low_res_m = NULL; break; case HI_RES: g_object_unref(hi_res_m); hi_res_m = NULL; break; } }; /** * @brief Tells if the desired version is available. */ bool has(rendering_mode mode) { switch(mode) { case LOW_RES: return low_res_m != NULL; case HI_RES: return hi_res_m != NULL; } return false; }; /** * @brief Returns the desired actor (on NULL if not present). */ GdkPixbuf* pixbuf(rendering_mode mode) { switch(mode) { case LOW_RES: return low_res_m; case HI_RES: return hi_res_m; } return NULL; } PopplerPageTransitionType transition_type() { PopplerPageTransition* ppt = poppler_page_get_transition(poppler_page_m); if(ppt) return ppt->type; else return POPPLER_PAGE_TRANSITION_REPLACE; } protected: /* * GList PopplerLinkMapping enumerating function */ void link_function(gpointer data, gpointer user_data) { PopplerLinkMapping* link = (PopplerLinkMapping*)data; g_print("Link area (%f,%f)x(%f,%f)\n", link->area.x1, link->area.y1, link->area.x2, link->area.y2); } PopplerPage* poppler_page_m; GdkPixbuf* low_res_m; GdkPixbuf* hi_res_m; }; } #endif