aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@bitwiz.org.uk>2013-05-21 13:55:42 +0200
committerThomas White <taw@bitwiz.org.uk>2013-05-21 13:55:42 +0200
commita08d89c334bcdda3fbcecbf2bc739ec8769ef47c (patch)
tree89ef76393b49e1edfe73df57d93d59c6bc02a973
parent589f48b7667fe3ce12ee79709804a1102a2c9474 (diff)
ImageStore stuff
-rw-r--r--Makefile.am11
-rw-r--r--src/imagestore.c196
-rw-r--r--src/imagestore.h51
-rw-r--r--src/mainwindow.c12
-rw-r--r--src/presentation.c4
-rw-r--r--src/presentation.h2
-rw-r--r--src/render.c63
-rw-r--r--src/render.h3
-rw-r--r--src/wrap.c29
-rw-r--r--src/wrap.h2
-rw-r--r--tests/render_test.c4
-rw-r--r--tests/render_test_sc1.c4
12 files changed, 353 insertions, 28 deletions
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 <taw@bitwiz.org.uk>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#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; i<is->n_images; i++ ) {
+ int j;
+ free(is->images[i].filename);
+ for ( j=0; j<NUM_ISZ_SIZES; j++ ) {
+ if ( is->images[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; j<NUM_ISZ_SIZES; j++ ) {
+ is->images[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; i<is->n_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; i<is->n_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 <taw@bitwiz.org.uk>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef IMAGESTORE_H
+#define IMAGESTORE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+
+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 <gtk/gtk.h>
#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 <assert.h>
#include <string.h>
#include <stdlib.h>
+#include <math.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk/gdk.h>
#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; i<line; i++ ) {
*yposd += fr->lines[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;