From a08d89c334bcdda3fbcecbf2bc739ec8769ef47c Mon Sep 17 00:00:00 2001 From: Thomas White Date: Tue, 21 May 2013 13:55:42 +0200 Subject: ImageStore stuff --- Makefile.am | 11 ++- src/imagestore.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++++ src/imagestore.h | 51 +++++++++++++ src/mainwindow.c | 12 +-- src/presentation.c | 4 + src/presentation.h | 2 + src/render.c | 63 +++++++++++++--- src/render.h | 3 +- src/wrap.c | 29 ++++++- src/wrap.h | 2 +- tests/render_test.c | 4 +- tests/render_test_sc1.c | 4 +- 12 files changed, 353 insertions(+), 28 deletions(-) create mode 100644 src/imagestore.c create mode 100644 src/imagestore.h diff --git a/Makefile.am b/Makefile.am index d80325f..1bc1f29 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,12 +13,14 @@ LDADD = $(top_builddir)/lib/libgnu.la @IGNORE_UNUSED_LIBRARIES_CFLAGS@ \ src_colloquium_SOURCES = src/colloquium.c src/render.c \ src/mainwindow.c src/presentation.c \ src/stylesheet.c src/loadsave.c src/frame.c \ - src/slideshow.c src/wrap.c src/storycode.c + src/slideshow.c src/wrap.c src/storycode.c \ + src/imagestore.c INCLUDES = -Iharfatum/src EXTRA_DIST += src/presentation.h src/render.h src/wrap.h \ - src/stylesheet.h src/loadsave.h src/slideshow.h src/storycode.h + src/stylesheet.h src/loadsave.h src/slideshow.h src/storycode.h \ + src/imagestore.h colloquiumdir = $(datadir)/colloquium colloquium_DATA = data/colloquium.ui @@ -33,7 +35,8 @@ noinst_PROGRAMS = tests/render_test tests/render_test_sc1 TESTS = tests/render_test tests/render_test_sc1 tests_render_test_SOURCES = tests/render_test.c src/render.c src/frame.c \ - src/wrap.c src/storycode.c + src/wrap.c src/storycode.c src/imagestore.c tests_render_test_sc1_SOURCES = tests/render_test_sc1.c src/storycode.c \ - src/render.c src/frame.c src/wrap.c + src/render.c src/frame.c src/wrap.c \ + src/imagestore.c diff --git a/src/imagestore.c b/src/imagestore.c new file mode 100644 index 0000000..fbf123a --- /dev/null +++ b/src/imagestore.c @@ -0,0 +1,196 @@ +/* + * imagestore.c + * + * Copyright © 2013 Thomas White + * + * This file is part of Colloquium. + * + * Colloquium is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "imagestore.h" + +struct image_record +{ + char *filename; + GdkPixbuf *pixbuf[NUM_ISZ_SIZES]; + int w[NUM_ISZ_SIZES]; +}; + + +struct _imagestore +{ + int n_images; + struct image_record *images; + int max_images; +}; + + +static int alloc_images(ImageStore *is, int new_max_images) +{ + struct image_record *images_new; + + images_new = realloc(is->images, + sizeof(struct image_record)*new_max_images); + if ( images_new == NULL ) return 1; + + is->images = images_new; + is->max_images = new_max_images; + return 0; +} + + +ImageStore *imagestore_new() +{ + ImageStore *is; + + is = calloc(1, sizeof(ImageStore)); + if ( is == NULL ) return NULL; + + is->images = NULL; + is->n_images = 0; + is->max_images = 0; + if ( alloc_images(is, 32) ) { + free(is); + return NULL; + } + + return is; +} + + +void imagestore_destroy(ImageStore *is) +{ + int i; + + for ( i=0; in_images; i++ ) { + int j; + free(is->images[i].filename); + for ( j=0; jimages[i].pixbuf[j] != NULL ) { + g_object_unref(is->images[i].pixbuf[j]); + } + } + } + free(is->images); + free(is); +} + + +static GdkPixbuf *add_pixbuf(struct image_record *im, const char *filename, + int w, enum is_size isz) +{ + GError *error = NULL; + printf("Loading '%s' at width %i\n", filename, w); + im->pixbuf[isz] = gdk_pixbuf_new_from_file_at_size(filename, w, -1, + &error); + if ( im->pixbuf[isz] == NULL ) { + fprintf(stderr, "Failed to load image '%s'\n", filename); + return NULL; + } + + im->w[isz] = w; + + return im->pixbuf[isz]; +} + + +static GdkPixbuf *add_new_image(ImageStore *is, const char *filename, int w, + enum is_size isz) +{ + int j; + int idx; + + if ( is->n_images == is->max_images ) { + if ( alloc_images(is, is->max_images+32) ) { + fprintf(stderr, "Couldn't allocate memory.\n"); + return NULL; + } + } + + idx = is->n_images++; + + is->images[idx].filename = strdup(filename); + for ( j=0; jimages[idx].pixbuf[j] = NULL; + is->images[idx].w[j] = 0; + } + + return add_pixbuf(&is->images[idx], filename, w, isz); +} + + +void show_imagestore(ImageStore *is) +{ + int i; + + printf("Store %p contains %i records.\n", is, is->n_images); + + for ( i=0; in_images; i++ ) { + + printf("%s :\n", is->images[i].filename); + printf("ss: %p %i ", is->images[i].pixbuf[ISZ_SLIDESHOW], + is->images[i].w[ISZ_SLIDESHOW]); + printf("ed: %p %i ", is->images[i].pixbuf[ISZ_EDITOR], + is->images[i].w[ISZ_EDITOR]); + printf("th: %p %i ", is->images[i].pixbuf[ISZ_THUMBNAIL], + is->images[i].w[ISZ_THUMBNAIL]); + printf("\n"); + + } +} + + +GdkPixbuf *lookup_image(ImageStore *is, const char *filename, int w, + enum is_size isz) +{ + int i; + int found = 0; + GdkPixbuf *pb; + + for ( i=0; in_images; i++ ) { + if ( strcmp(is->images[i].filename, filename) == 0 ) { + found = 1; + break; + } + } + if ( !found ) { + return add_new_image(is, filename, w, isz); + } + + /* Image already exists, but might not have the right size or + * the right slot filled in */ + + if ( is->images[i].w[isz] == w ) return is->images[i].pixbuf[isz]; + + /* Image is the wrong size or slot is not filled in yet */ + if ( is->images[i].pixbuf[isz] != NULL ) { + g_object_unref(is->images[i].pixbuf[isz]); + is->images[i].pixbuf[isz] = NULL; + } + + /* Slot is not filled in yet */ + pb = add_pixbuf(&is->images[i], filename, w, isz); + return pb; +} diff --git a/src/imagestore.h b/src/imagestore.h new file mode 100644 index 0000000..349a409 --- /dev/null +++ b/src/imagestore.h @@ -0,0 +1,51 @@ +/* + * imagestore.h + * + * Copyright © 2013 Thomas White + * + * This file is part of Colloquium. + * + * Colloquium is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef IMAGESTORE_H +#define IMAGESTORE_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + + +typedef struct _imagestore ImageStore; + +enum is_size { + ISZ_SLIDESHOW = 0, + ISZ_EDITOR = 1, + ISZ_THUMBNAIL = 2, + NUM_ISZ_SIZES +}; + +extern ImageStore *imagestore_new(void); + +extern void imagestore_destroy(ImageStore *is); + +extern GdkPixbuf *lookup_image(ImageStore *is, const char *filename, int w, + enum is_size isz); + +extern void show_imagestore(ImageStore *is); + +#endif /* IMAGESTORE_H */ diff --git a/src/mainwindow.c b/src/mainwindow.c index 7bfceb5..52cd23b 100644 --- a/src/mainwindow.c +++ b/src/mainwindow.c @@ -48,13 +48,13 @@ void rerender_slide(struct presentation *p) free_render_buffers(s); s->rendered_thumb = render_slide(s, s->parent->thumb_slide_width, - p->slide_width, p->slide_height); + p->slide_width, p->slide_height, p->is); s->rendered_edit = render_slide(s, s->parent->edit_slide_width, - p->slide_width, p->slide_height); + p->slide_width, p->slide_height, p->is); s->rendered_proj = render_slide(s, s->parent->proj_slide_width, - p->slide_width, p->slide_height); + p->slide_width, p->slide_height, p->is); } @@ -65,12 +65,14 @@ static void render_edit_and_proj(struct presentation *p) if ( s->rendered_edit == NULL ) { s->rendered_edit = render_slide(s, s->parent->edit_slide_width, - p->slide_width, p->slide_height); + p->slide_width, p->slide_height, + p->is); } if ( s->rendered_proj == NULL ) { s->rendered_proj = render_slide(s, s->parent->proj_slide_width, - p->slide_width, p->slide_height); + p->slide_width, p->slide_height, + p->is); } } diff --git a/src/presentation.c b/src/presentation.c index 328514f..7bf09d9 100644 --- a/src/presentation.c +++ b/src/presentation.c @@ -35,6 +35,7 @@ #include "loadsave.h" #include "mainwindow.h" #include "frame.h" +#include "imagestore.h" static int num_presentations = 0; @@ -54,6 +55,7 @@ void free_presentation(struct presentation *p) /* FIXME: Loads of stuff leaks here */ free(p->filename); + imagestore_destroy(p->is); free(p); if ( final ) { @@ -247,6 +249,8 @@ struct presentation *new_presentation() new->max_selection = 64; if ( alloc_selection(new) ) return NULL; + new->is = imagestore_new(); + return new; } diff --git a/src/presentation.h b/src/presentation.h index 808111f..84b5490 100644 --- a/src/presentation.h +++ b/src/presentation.h @@ -31,6 +31,7 @@ #include #include "stylesheet.h" +#include "imagestore.h" struct slide { @@ -81,6 +82,7 @@ struct presentation GtkWidget **menu_rebuild_list; int n_menu_rebuild; PangoContext *pc; + ImageStore *is; /* Pointers to the current "editing" and "projection" slides */ struct slide *cur_edit_slide; diff --git a/src/render.c b/src/render.c index 3555455..2aea8ec 100644 --- a/src/render.c +++ b/src/render.c @@ -31,6 +31,9 @@ #include #include #include +#include +#include +#include #include "storycode.h" #include "stylesheet.h" @@ -38,12 +41,13 @@ #include "frame.h" #include "render.h" #include "wrap.h" +#include "imagestore.h" static void render_glyph_box(cairo_t *cr, struct wrap_box *box) { cairo_new_path(cr); - cairo_move_to(cr, 0.0, pango_units_to_double(box->ascent)); + cairo_move_to(cr, 0.0, 0.0); if ( box->glyphs == NULL ) { fprintf(stderr, "Box %p has NULL pointer.\n", box); return; @@ -55,6 +59,36 @@ static void render_glyph_box(cairo_t *cr, struct wrap_box *box) } + +static void render_image_box(cairo_t *cr, struct wrap_box *box, ImageStore *is) +{ + GdkPixbuf *pixbuf; + int w; + double ascd; + + ascd = pango_units_to_double(box->ascent); + + cairo_new_path(cr); + cairo_rectangle(cr, 0.0, -ascd, + pango_units_to_double(box->width), + pango_units_to_double(box->height)); + + w = lrint(pango_units_to_double(box->width)); + pixbuf = lookup_image(is, box->filename, w, ISZ_EDITOR); + //show_imagestore(is); + + if ( pixbuf == NULL ) { + cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0); + fprintf(stderr, "Failed to load '%s' at size %i\n", + box->filename, w); + } else { + gdk_cairo_set_source_pixbuf(cr, pixbuf, 0.0, -ascd); + } + + cairo_fill(cr); +} + + static void draw_outline(cairo_t *cr, struct wrap_box *box) { char tmp[32]; @@ -75,7 +109,7 @@ static void draw_outline(cairo_t *cr, struct wrap_box *box) } -static void render_boxes(struct wrap_line *line, cairo_t *cr) +static void render_boxes(struct wrap_line *line, cairo_t *cr, ImageStore *is) { int j; double x_pos = 0.0; @@ -97,7 +131,7 @@ static void render_boxes(struct wrap_line *line, cairo_t *cr) break; case WRAP_BOX_IMAGE : - /* FIXME ! */ + render_image_box(cr, box, is); break; case WRAP_BOX_NOTHING : @@ -141,7 +175,7 @@ static void draw_underfull_marker(cairo_t *cr, struct frame *fr, int i) } -static void render_lines(struct frame *fr, cairo_t *cr) +static void render_lines(struct frame *fr, cairo_t *cr, ImageStore *is) { int i; double y_pos = 0.0; @@ -164,7 +198,11 @@ static void render_lines(struct frame *fr, cairo_t *cr) #endif /* Render the line */ - render_boxes(&fr->lines[i], cr); + cairo_save(cr); + cairo_translate(cr, 0.0, + pango_units_to_double(fr->lines[i].ascent)); + render_boxes(&fr->lines[i], cr, is); + cairo_restore(cr); if ( fr->lines[i].overfull ) { draw_overfull_marker(cr, fr, i); @@ -219,7 +257,7 @@ static void do_background(cairo_t *cr, struct frame *fr) /* Render Level 1 Storycode (no subframes) */ -static int render_sc(struct frame *fr, double scale) +static int render_sc(struct frame *fr, double scale, ImageStore *is) { int i; cairo_t *cr; @@ -266,7 +304,7 @@ static int render_sc(struct frame *fr, double scale) /* Actually render the lines */ cairo_translate(cr, fr->lop.pad_l, fr->lop.pad_t); - render_lines(fr, cr); + render_lines(fr, cr, is); /* Tidy up */ cairo_font_options_destroy(fopts); @@ -277,7 +315,7 @@ static int render_sc(struct frame *fr, double scale) } -static int render_frame(struct frame *fr, double scale) +static int render_frame(struct frame *fr, double scale, ImageStore *is) { int i; @@ -324,14 +362,14 @@ static int render_frame(struct frame *fr, double scale) /* Rounding to get bitmap size */ ch->pix_w = ch->w*scale; ch->pix_h = ch->h*scale; - render_frame(ch, scale); + render_frame(ch, scale, is); ch->x = ch->lop.x + fr->lop.pad_l + ch->lop.margin_l; ch->y = ch->lop.y + fr->lop.pad_t + ch->lop.margin_t; } - render_sc(fr, scale); + render_sc(fr, scale, is); return 0; } @@ -438,7 +476,8 @@ static void composite_slide(struct slide *s, cairo_t *cr, double scale) * * Render the entire slide. */ -cairo_surface_t *render_slide(struct slide *s, int w, double ww, double hh) +cairo_surface_t *render_slide(struct slide *s, int w, double ww, double hh, + ImageStore *is) { cairo_surface_t *surf; cairo_t *cr; @@ -460,7 +499,7 @@ cairo_surface_t *render_slide(struct slide *s, int w, double ww, double hh) s->top->h = hh; s->top->pix_w = w; s->top->pix_h = h; - render_frame(s->top, scale); + render_frame(s->top, scale, is); surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); diff --git a/src/render.h b/src/render.h index 0ddb58d..1fe5041 100644 --- a/src/render.h +++ b/src/render.h @@ -28,9 +28,10 @@ #endif #include "presentation.h" +#include "imagestore.h" extern cairo_surface_t *render_slide(struct slide *s, int w, - double ww, double hh); + double ww, double hh, ImageStore *is); extern void free_render_buffers(struct slide *s); extern void free_render_buffers_except_thumb(struct slide *s); diff --git a/src/wrap.c b/src/wrap.c index 7a1ac67..1b7766d 100644 --- a/src/wrap.c +++ b/src/wrap.c @@ -108,7 +108,10 @@ void get_cursor_pos(struct frame *fr, size_t pos, /* Cursor is on the last line */ line = fr->n_lines-1; } - assert(line >= 0); + if ( line < 0 ) { + printf("Couldn't find cursor.\n"); + return; + } for ( i=0; ilines[i].height; } @@ -315,6 +318,23 @@ static int add_wrap_box(struct wrap_line *line, char *text, size_t offset, } +static void add_image_box(struct wrap_line *line, const char *filename, + size_t offset, int w, int h) +{ + struct wrap_box *box; + + box = &line->boxes[line->n_boxes]; + box->sc_offset = offset; + box->type = WRAP_BOX_IMAGE; + box->space = WRAP_SPACE_NONE; + box->width = pango_units_from_double(w); + box->ascent = pango_units_from_double(h); + box->height = pango_units_from_double(h); + box->filename = strdup(filename); + line->n_boxes++; +} + + static int split_words(struct wrap_line *boxes, PangoContext *pc, char *sc, size_t sc_offset, PangoLanguage *lang, struct sc_font *font) @@ -497,10 +517,13 @@ static void run_sc(const char *sc, struct sc_font *fonts, int *n_fonts, run_sc(b->contents, fonts, n_fonts, max_fonts, pc, boxes, lang); pop_font(fonts, n_fonts, max_fonts); + } else if ( (strcmp(b->name, "image")==0) + && (b->contents != NULL) ) { + /* FIXME: Proper w/h from SC */ + add_image_box(boxes, b->contents, b->offset, + 100.0, 100.0); } - /* FIXME: Handle images */ - } sc_block_list_free(bl); } diff --git a/src/wrap.h b/src/wrap.h index 75af86b..a8f9593 100644 --- a/src/wrap.h +++ b/src/wrap.h @@ -76,7 +76,7 @@ struct wrap_box double col[4]; /* rgba colour */ /* For type == WRAP_BOX_IMAGE */ - /* Nothing yet */ + char *filename; }; diff --git a/tests/render_test.c b/tests/render_test.c index 8a1ab3d..3e50a4c 100644 --- a/tests/render_test.c +++ b/tests/render_test.c @@ -59,7 +59,7 @@ static gboolean draw_sig(GtkWidget *da, cairo_t *cr, gpointer data) cairo_fill(cr); if ( s->rendered_edit != NULL ) cairo_surface_destroy(s->rendered_edit); - s->rendered_edit = render_slide(s, w, w, h); + s->rendered_edit = render_slide(s, w, w, h, NULL); cairo_rectangle(cr, 0.0, 0.0, w, h); cairo_set_source_surface(cr, s->rendered_edit, 0.0, 0.0); cairo_fill(cr); @@ -121,6 +121,7 @@ int main(int argc, char *argv[]) fr2->children = NULL; fr2->num_children = 0; fr2->style = sty2; + fr2->lop_from_style = 1; fr = calloc(1, sizeof(struct frame)); if ( fr == NULL ) return 1; @@ -129,6 +130,7 @@ int main(int argc, char *argv[]) if ( fr->children == NULL ) return 1; fr->children[0] = fr2; fr->style = sty1; + fr->lop_from_style = 1; fr->num_children = 1; s.top = fr; diff --git a/tests/render_test_sc1.c b/tests/render_test_sc1.c index cc4dcfe..337ca1b 100644 --- a/tests/render_test_sc1.c +++ b/tests/render_test_sc1.c @@ -56,7 +56,7 @@ static gboolean draw_sig(GtkWidget *da, cairo_t *cr, gpointer data) cairo_fill(cr); if ( s->rendered_edit != NULL ) cairo_surface_destroy(s->rendered_edit); - s->rendered_edit = render_slide(s, w, w, h); + s->rendered_edit = render_slide(s, w, w, h, NULL); cairo_rectangle(cr, 0.0, 0.0, w, h); cairo_set_source_surface(cr, s->rendered_edit, 0.0, 0.0); cairo_fill(cr); @@ -118,7 +118,9 @@ int main(int argc, char *argv[]) sty2->name = strdup("Subframe1"); fr->style = sty; + fr->lop_from_style = 1; fr->children[0]->style = sty2; + fr->children[0]->lop_from_style = 1; s.top = fr; s.rendered_edit = NULL; -- cgit v1.2.3