From 915fcacee4c49f017ab2599b4307198ca3f713d3 Mon Sep 17 00:00:00 2001 From: Thomas White Date: Mon, 4 Mar 2019 23:46:47 +0100 Subject: Thumbnail slide rendering in narrative --- libstorycode/gtk/gtknarrativeview.c | 12 ++++--- libstorycode/gtk/gtknarrativeview.h | 6 ++-- libstorycode/narrative.c | 1 + libstorycode/narrative_priv.h | 5 +++ libstorycode/narrative_render_cairo.c | 65 ++++++++++++++++++++++++++++++----- libstorycode/narrative_render_cairo.h | 3 +- libstorycode/presentation.c | 32 +++++++++++++++-- libstorycode/presentation.h | 3 ++ libstorycode/slide.c | 1 + libstorycode/slide_render_cairo.c | 24 +++++++------ 10 files changed, 121 insertions(+), 31 deletions(-) (limited to 'libstorycode') diff --git a/libstorycode/gtk/gtknarrativeview.c b/libstorycode/gtk/gtknarrativeview.c index 5d89ae5..90915ab 100644 --- a/libstorycode/gtk/gtknarrativeview.c +++ b/libstorycode/gtk/gtknarrativeview.c @@ -126,6 +126,8 @@ static gboolean resize_sig(GtkWidget *widget, GdkEventConfigure *event, GtkNarrativeView *e) { PangoContext *pc; + PangoLanguage *lang; + const char *langname; pc = gdk_pango_context_get(); @@ -133,10 +135,14 @@ static gboolean resize_sig(GtkWidget *widget, GdkEventConfigure *event, e->visible_width = event->width; e->w = e->visible_width; + langname = presentation_get_language(e->p); + lang = pango_language_from_string(langname); + /* Wrap everything with the current width, to get the total height */ narrative_wrap(presentation_get_narrative(e->p), presentation_get_stylesheet(e->p), - pango_language_get_default(), pc, e->w); + lang, gtk_widget_get_pango_context(widget), e->w, + presentation_get_imagestore(e->p)); e->w = e->visible_width; e->h = narrative_get_height(presentation_get_narrative(e->p)); @@ -1012,8 +1018,7 @@ static void update_size_request(GtkNarrativeView *e) } -GtkNarrativeView *gtk_narrative_view_new(Presentation *p, PangoLanguage *lang, - const char *storename) +GtkNarrativeView *gtk_narrative_view_new(Presentation *p) { GtkNarrativeView *nview; GtkTargetEntry targets[1]; @@ -1023,7 +1028,6 @@ GtkNarrativeView *gtk_narrative_view_new(Presentation *p, PangoLanguage *lang, nview->w = 100; nview->h = 100; nview->scroll_pos = 0; - nview->lang = lang; nview->p = p; nview->para_highlight = 0; diff --git a/libstorycode/gtk/gtknarrativeview.h b/libstorycode/gtk/gtknarrativeview.h index 717b0d0..bf596fc 100644 --- a/libstorycode/gtk/gtknarrativeview.h +++ b/libstorycode/gtk/gtknarrativeview.h @@ -33,6 +33,7 @@ #include #include #include +#include #define GTK_TYPE_NARRATIVE_VIEW (gtk_narrative_view_get_type()) @@ -94,7 +95,6 @@ struct _gtknarrativeview Presentation *p; GtkIMContext *im_context; PangoContext *pc; - PangoLanguage *lang; int w; /* Surface size in pixels */ int h; @@ -129,9 +129,7 @@ struct _gtknarrativeviewclass typedef struct _gtknarrativeview GtkNarrativeView; typedef struct _gtknarrativeviewclass GtkNarrativeViewClass; -extern GtkNarrativeView *gtk_narrative_view_new(Presentation *p, - PangoLanguage *lang, - const char *storename); +extern GtkNarrativeView *gtk_narrative_view_new(Presentation *p); extern void gtk_narrative_view_set_logical_size(GtkNarrativeView *e, double w, double h); diff --git a/libstorycode/narrative.c b/libstorycode/narrative.c index 91c87c5..18e2203 100644 --- a/libstorycode/narrative.c +++ b/libstorycode/narrative.c @@ -109,4 +109,5 @@ void narrative_add_slide(Narrative *n, Slide *slide) item->type = NARRATIVE_ITEM_SLIDE; item->slide = slide; + item->slide_thumbnail = NULL; } diff --git a/libstorycode/narrative_priv.h b/libstorycode/narrative_priv.h index 5c0af27..1a461c4 100644 --- a/libstorycode/narrative_priv.h +++ b/libstorycode/narrative_priv.h @@ -62,6 +62,11 @@ struct narrative_item Slide *slide; double slide_w; double slide_h; +#ifdef HAVE_CAIRO + cairo_surface_t *slide_thumbnail; +#else + void *slide_thumbnail; +#endif }; diff --git a/libstorycode/narrative_render_cairo.c b/libstorycode/narrative_render_cairo.c index cd2d872..6024ccc 100644 --- a/libstorycode/narrative_render_cairo.c +++ b/libstorycode/narrative_render_cairo.c @@ -36,6 +36,8 @@ #include "slide.h" #include "narrative.h" #include "stylesheet.h" +#include "imagestore.h" +#include "slide_render_cairo.h" #include "narrative_priv.h" @@ -107,13 +109,51 @@ static void wrap_text(struct narrative_item *item, PangoContext *pc, //pango_layout_set_attributes(item->layout, attrs); //pango_attr_list_unref(attrs); - pango_layout_get_extents(item->layout, NULL, &rect); item->h = pango_units_to_double(rect.height)+item->space_t+item->space_b; } -static void wrap_slide(struct narrative_item *item, Stylesheet *ss) +/* Render a thumbnail of the slide */ +static cairo_surface_t *render_thumbnail(Slide *s, Stylesheet *ss, ImageStore *is, + int w, int h) +{ + cairo_surface_t *surf; + cairo_surface_t *full_surf; + cairo_t *cr; + double logical_w, logical_h; + PangoContext *pc; + const int rh = 1024; /* "reasonably big" height for slide */ + int rw; + + slide_get_logical_size(s, ss, &logical_w, &logical_h); + rw = rh*(logical_w/logical_h); + + /* Render at a reasonably big size. Rendering to a small surface makes + * rounding of text positions (due to font hinting) cause significant + * differences between the thumbnail and "normal" rendering. */ + full_surf = cairo_image_surface_create(CAIRO_FORMAT_RGB24, rw, rh); + cr = cairo_create(full_surf); + cairo_scale(cr, (double)rw/logical_w, (double)rh/logical_h); + pc = pango_cairo_create_context(cr); + slide_render_cairo(s, cr, is, ss, 0, pango_language_get_default(), pc); + g_object_unref(pc); + cairo_destroy(cr); + + /* Scale down to the actual size of the thumbnail */ + surf = cairo_image_surface_create(CAIRO_FORMAT_RGB24, w, h); + cr = cairo_create(surf); + cairo_scale(cr, (double)w/rw, (double)h/rh); + cairo_set_source_surface(cr, full_surf, 0.0, 0.0); + cairo_paint(cr); + cairo_destroy(cr); + + cairo_surface_destroy(full_surf); + return surf; +} + + +static void wrap_slide(struct narrative_item *item, Stylesheet *ss, ImageStore *is) { double w, h; @@ -123,16 +163,21 @@ static void wrap_slide(struct narrative_item *item, Stylesheet *ss) item->space_b = 10.0; slide_get_logical_size(item->slide, ss, &w, &h); - item->slide_h = 320.0; - item->slide_w = item->slide_h*w/h; + item->slide_h = 320.0; /* Actual height of thumbnail */ + item->slide_w = rint(item->slide_h*w/h); item->h = item->slide_h + item->space_t + item->space_b; + if ( item->slide_thumbnail != NULL ) { + cairo_surface_destroy(item->slide_thumbnail); + } + item->slide_thumbnail = render_thumbnail(item->slide, ss, is, + item->slide_w, item->slide_h); } int narrative_wrap(Narrative *n, Stylesheet *stylesheet, PangoLanguage *lang, - PangoContext *pc, double w) + PangoContext *pc, double w, ImageStore *is) { int i; struct length pad[4]; @@ -166,7 +211,7 @@ int narrative_wrap(Narrative *n, Stylesheet *stylesheet, PangoLanguage *lang, break; case NARRATIVE_ITEM_SLIDE : - wrap_slide(&n->items[i], stylesheet); + wrap_slide(&n->items[i], stylesheet, is); break; default : @@ -201,9 +246,13 @@ static void draw_slide(struct narrative_item *item, cairo_t *cr) cairo_user_to_device(cr, &x, &y); x = rint(x); y = rint(y); cairo_device_to_user(cr, &x, &y); - cairo_rectangle(cr, x+0.5, y+0.5, item->slide_w, item->slide_h); - cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0); + cairo_rectangle(cr, x, y, item->slide_w, item->slide_h); + cairo_set_source_surface(cr, item->slide_thumbnail, 0.0, 0.0); + cairo_fill(cr); + + cairo_rectangle(cr, x+0.5, y+0.5, item->slide_w, item->slide_h); + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); cairo_set_line_width(cr, 1.0); cairo_stroke(cr); diff --git a/libstorycode/narrative_render_cairo.h b/libstorycode/narrative_render_cairo.h index ebabb4d..835c5a9 100644 --- a/libstorycode/narrative_render_cairo.h +++ b/libstorycode/narrative_render_cairo.h @@ -32,7 +32,8 @@ extern int narrative_wrap(Narrative *n, Stylesheet *stylesheet, - PangoLanguage *lang, PangoContext *pc, double w); + PangoLanguage *lang, PangoContext *pc, double w, + ImageStore *is); extern double narrative_get_height(Narrative *n); diff --git a/libstorycode/presentation.c b/libstorycode/presentation.c index f81dc84..d49f965 100644 --- a/libstorycode/presentation.c +++ b/libstorycode/presentation.c @@ -31,6 +31,10 @@ #include #include +#ifdef HAVE_PANGO +#include +#endif + #include "presentation.h" #include "stylesheet.h" #include "slide.h" @@ -42,9 +46,11 @@ struct _presentation { Stylesheet *stylesheet; Narrative *narrative; + ImageStore *imagestore; int n_slides; Slide **slides; int max_slides; + const char *language; }; @@ -58,6 +64,12 @@ Presentation *presentation_new() p->slides = NULL; p->n_slides = 0; p->max_slides = 0; + p->imagestore = NULL; +#ifdef HAVE_PANGO + p->language = pango_language_to_string(pango_language_get_default()); +#else + p->language = NULL; +#endif return p; } @@ -68,7 +80,6 @@ Presentation *presentation_load(GFile *file) const char *text; size_t len; Presentation *p; - ImageStore *is; bytes = g_file_load_bytes(file, NULL, NULL, NULL); if ( bytes == NULL ) return NULL; @@ -78,8 +89,8 @@ Presentation *presentation_load(GFile *file) g_bytes_unref(bytes); if ( p == NULL ) return NULL; - is = imagestore_new("."); - imagestore_set_parent(is, g_file_get_parent(file)); + p->imagestore = imagestore_new("."); /* FIXME: From app config */ + imagestore_set_parent(p->imagestore, g_file_get_parent(file)); return p; } @@ -93,6 +104,7 @@ int presentation_save(Presentation *p, GFile *file) void presentation_free(Presentation *p) { + /* FIXME: Free narrative, slides, imagestore */ free(p); } @@ -155,3 +167,17 @@ Narrative *presentation_get_narrative(Presentation *p) if ( p == NULL ) return NULL; return p->narrative; } + + +const char *presentation_get_language(Presentation *p) +{ + if ( p == NULL ) return NULL; + return p->language; +} + + +ImageStore *presentation_get_imagestore(Presentation *p) +{ + if ( p == NULL ) return NULL; + return p->imagestore; +} diff --git a/libstorycode/presentation.h b/libstorycode/presentation.h index d5269b9..3abe91e 100644 --- a/libstorycode/presentation.h +++ b/libstorycode/presentation.h @@ -33,6 +33,7 @@ typedef struct _presentation Presentation; #include "stylesheet.h" #include "narrative.h" +#include "imagestore.h" extern Presentation *presentation_new(void); extern Presentation *presentation_load(GFile *file); @@ -47,5 +48,7 @@ extern int presentation_num_slides(Presentation *p); extern Slide *presentation_slide(Presentation *p, int i); extern Stylesheet *presentation_get_stylesheet(Presentation *p); extern Narrative *presentation_get_narrative(Presentation *p); +extern const char *presentation_get_language(Presentation *p); +extern ImageStore *presentation_get_imagestore(Presentation *p); #endif /* PRESENTATION_H */ diff --git a/libstorycode/slide.c b/libstorycode/slide.c index 9db5995..694f29a 100644 --- a/libstorycode/slide.c +++ b/libstorycode/slide.c @@ -87,6 +87,7 @@ int add_text_item(Slide *s, char **text, int n_text, struct frame_geom geom, if ( item == NULL ) return 1; item->type = slide_item; + item->layouts = NULL; item->paragraphs = malloc(n_text*sizeof(char *)); if ( item->paragraphs == NULL ) { s->n_items--; diff --git a/libstorycode/slide_render_cairo.c b/libstorycode/slide_render_cairo.c index ed9b948..e74a13f 100644 --- a/libstorycode/slide_render_cairo.c +++ b/libstorycode/slide_render_cairo.c @@ -68,8 +68,8 @@ static void render_text(struct slide_item *item, cairo_t *cr, PangoContext *pc, double parent_w, double parent_h) { int i; - double x, y, w, h; - double pad_l, pad_r, pad_t, pad_b; + double x, y, w; + double pad_l, pad_r, pad_t; struct length pad[4]; const char *font; enum alignment align; @@ -81,13 +81,11 @@ static void render_text(struct slide_item *item, cairo_t *cr, PangoContext *pc, x = lcalc(item->geom.x, parent_w); y = lcalc(item->geom.y, parent_h); w = lcalc(item->geom.w, parent_w); - h = lcalc(item->geom.h, parent_h); if ( stylesheet_get_padding(ss, el, pad) ) return; pad_l = lcalc(pad[0], parent_w); pad_r = lcalc(pad[1], parent_w); pad_t = lcalc(pad[2], parent_h); - pad_b = lcalc(pad[3], parent_h); font = stylesheet_get_font(ss, el, fgcol, &align); if ( font == NULL ) return; @@ -200,7 +198,7 @@ int slide_render_cairo(Slide *s, cairo_t *cr, ImageStore *is, Stylesheet *styles slide_get_logical_size(s, stylesheet, &w, &h); /* Overall background */ - cairo_rectangle(cr, 0.0, 0.0, s->logical_w, s->logical_h); + cairo_rectangle(cr, 0.0, 0.0, w, h); switch ( bg ) { case GRAD_NONE: @@ -208,19 +206,23 @@ int slide_render_cairo(Slide *s, cairo_t *cr, ImageStore *is, Stylesheet *styles break; case GRAD_VERT: - patt = cairo_pattern_create_linear(0.0, 0.0, 0.0, s->logical_h); + patt = cairo_pattern_create_linear(0.0, 0.0, 0.0, h); cairo_pattern_add_color_stop_rgb(patt, 0.0, bgcol[0], bgcol[1], bgcol[2]); cairo_pattern_add_color_stop_rgb(patt, 1.0, bgcol2[0], bgcol2[1], bgcol2[2]); cairo_set_source(cr, patt); break; case GRAD_HORIZ: - patt = cairo_pattern_create_linear(0.0, 0.0, s->logical_w, 0.0); + patt = cairo_pattern_create_linear(0.0, 0.0, w, 0.0); cairo_pattern_add_color_stop_rgb(patt, 0.0, bgcol[0], bgcol[1], bgcol[2]); cairo_pattern_add_color_stop_rgb(patt, 1.0, bgcol2[0], bgcol2[1], bgcol2[2]); cairo_set_source(cr, patt); break; + default: + fprintf(stderr, "Unrecognised slide background type %i\n", bg); + break; + } cairo_fill(cr); @@ -230,22 +232,22 @@ int slide_render_cairo(Slide *s, cairo_t *cr, ImageStore *is, Stylesheet *styles case SLIDE_ITEM_TEXT : render_text(&s->items[i], cr, pc, stylesheet, STYEL_SLIDE_TEXT, - s->logical_w, s->logical_h); + w, h); break; case SLIDE_ITEM_IMAGE : render_image(&s->items[i], cr, stylesheet, is, - s->logical_w, s->logical_h); + w, h); break; case SLIDE_ITEM_SLIDETITLE : render_text(&s->items[i], cr, pc, stylesheet, STYEL_SLIDE_SLIDETITLE, - s->logical_w, s->logical_h); + w, h); break; case SLIDE_ITEM_PRESTITLE : render_text(&s->items[i], cr, pc, stylesheet, STYEL_SLIDE_PRESTITLE, - s->logical_w, s->logical_h); + w, h); break; default : -- cgit v1.2.3