From 182ed04eaef3db9d0e07d466b19307e6c1b4aeb9 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 8 Feb 2015 13:38:35 +0000 Subject: Add support for exporting canvas as PDF or PS. git-svn-id: http://svn.drobilla.net/lad/trunk/ganv@5543 a436a847-0d15-0410-975c-d299462d15a1 --- src/Canvas.cpp | 65 ++++++++++++++++++++++++++++++++++++++++ src/ganv-private.h | 2 +- src/group.c | 5 ---- src/text.c | 87 +++++++++++++++++++++--------------------------------- 4 files changed, 100 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/Canvas.cpp b/src/Canvas.cpp index 02bf4f6..c3ed2f6 100644 --- a/src/Canvas.cpp +++ b/src/Canvas.cpp @@ -2586,6 +2586,64 @@ ganv_canvas_arrange(GanvCanvas* canvas) #endif } +int +ganv_canvas_export_image(GanvCanvas* canvas, + const char* filename, + gboolean draw_background) +{ + const char* ext = strrchr(filename, '.'); + if (!ext) { + return 1; + } else if (!strcmp(ext, ".dot")) { + ganv_canvas_export_dot(canvas, filename); + return 0; + } + + cairo_surface_t* rec_surface = cairo_recording_surface_create( + CAIRO_CONTENT_COLOR_ALPHA, NULL); + + // Draw to recording surface + cairo_t* cr = cairo_create(rec_surface); + (*GANV_ITEM_GET_CLASS(canvas->impl->root)->draw)( + canvas->impl->root, cr, + 0, 0, canvas->impl->width, canvas->impl->height); + cairo_destroy(cr); + + // Get draw extent + double x, y, w, h; + cairo_recording_surface_ink_extents(rec_surface, &x, &y, &w, &h); + + // Create image surface with the appropriate size + const double pad = GANV_CANVAS_PAD; + const double img_w = w + pad * 2; + const double img_h = h + pad * 2; + cairo_surface_t* img = NULL; + if (!strcmp(ext, ".svg")) { + img = cairo_svg_surface_create(filename, img_w, img_h); + } else if (!strcmp(ext, ".pdf")) { + img = cairo_pdf_surface_create(filename, img_w, img_h); + } else if (!strcmp(ext, ".ps")) { + img = cairo_ps_surface_create(filename, img_w, img_h); + } else { + cairo_surface_destroy(rec_surface); + return 1; + } + + // Draw recording to image surface + cr = cairo_create(img); + if (draw_background) { + cairo_set_source_rgba(cr, 0, 0, 0, 1.0); + cairo_rectangle(cr, 0, 0, w + 2 * pad, h + 2 * pad); + cairo_fill(cr); + } + cairo_set_source_surface(cr, rec_surface, -x + pad, -y + pad); + cairo_paint(cr); + cairo_destroy(cr); + cairo_surface_destroy(rec_surface); + cairo_surface_destroy(img); + return 0; +} + void ganv_canvas_export_dot(GanvCanvas* canvas, const char* filename) { @@ -3590,6 +3648,13 @@ ganv_canvas_paint_rect(GanvCanvas* canvas, gint x0, gint y0, gint x1, gint y1) double wx1, wy1, ww, wh; ganv_canvas_c2w(canvas, draw_x1, draw_y1, &wx1, &wy1); ganv_canvas_c2w(canvas, draw_width, draw_height, &ww, &wh); + + // Draw background + cairo_set_source_rgba(cr, 0, 0, 0, 1.0); + cairo_rectangle(cr, wx1, wy1, ww, wh); + cairo_fill(cr); + + // Draw root group (*GANV_ITEM_GET_CLASS(canvas->impl->root)->draw)( canvas->impl->root, cr, wx1, wy1, ww, wh); diff --git a/src/ganv-private.h b/src/ganv-private.h index 8f32480..2fc6c00 100644 --- a/src/ganv-private.h +++ b/src/ganv-private.h @@ -237,7 +237,7 @@ typedef struct struct _GanvTextImpl { - cairo_surface_t* surface; + PangoLayout* layout; char* text; GanvTextCoords coords; GanvTextCoords old_coords; diff --git a/src/group.c b/src/group.c index 20ef354..e867cef 100644 --- a/src/group.c +++ b/src/group.c @@ -203,11 +203,6 @@ ganv_group_draw(GanvItem* item, { GanvGroup* group = GANV_GROUP(item); - // Draw background - cairo_set_source_rgba(cr, 0, 0, 0, 1.0); - cairo_rectangle(cr, cx, cy, cw, ch); - cairo_fill(cr); - // TODO: Layered drawing for (GList* list = group->impl->item_list; list; list = list->next) { diff --git a/src/text.c b/src/text.c index 39df696..6dda2e1 100644 --- a/src/text.c +++ b/src/text.c @@ -55,7 +55,7 @@ ganv_text_init(GanvText* text) impl->coords.height = 1.0; impl->old_coords = impl->coords; - impl->surface = NULL; + impl->layout = NULL; impl->text = NULL; impl->color = 0xFFFFFFFF; impl->needs_layout = FALSE; @@ -75,9 +75,9 @@ ganv_text_destroy(GtkObject* object) impl->text = NULL; } - if (impl->surface) { - cairo_surface_destroy(impl->surface); - impl->surface = NULL; + if (impl->layout) { + g_object_unref(impl->layout); + impl->layout = NULL; } if (GTK_OBJECT_CLASS(parent_class)->destroy) { @@ -88,57 +88,36 @@ ganv_text_destroy(GtkObject* object) void ganv_text_layout(GanvText* text) { - GanvTextImpl* impl = text->impl; - GanvItem* item = GANV_ITEM(text); - GanvCanvas* canvas = ganv_item_get_canvas(item); - GtkWidget* widget = GTK_WIDGET(canvas); - double font_size = ganv_canvas_get_font_size(canvas); - guint color = 0xFFFFFFFF; - - GtkStyle* style = gtk_rc_get_style(widget); - PangoFontDescription* font = pango_font_description_copy(style->font_desc); - PangoLayout* layout = gtk_widget_create_pango_layout(widget, impl->text); - PangoContext* context = pango_layout_get_context(layout); - cairo_font_options_t* options = cairo_font_options_copy( - pango_cairo_context_get_font_options(context)); - - pango_font_description_set_size(font, font_size * (double)PANGO_SCALE); - pango_layout_set_font_description(layout, font); - - if (cairo_font_options_get_antialias(options) == CAIRO_ANTIALIAS_SUBPIXEL) { - cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY); + GanvTextImpl* impl = text->impl; + GanvItem* item = GANV_ITEM(text); + GanvCanvas* canvas = ganv_item_get_canvas(item); + GtkWidget* widget = GTK_WIDGET(canvas); + double points = ganv_canvas_get_font_size(canvas); + GtkStyle* style = gtk_rc_get_style(widget); + + if (impl->layout) { + g_object_unref(impl->layout); } + impl->layout = gtk_widget_create_pango_layout(widget, impl->text); - pango_cairo_context_set_font_options(context, options); - cairo_font_options_destroy(options); + PangoFontDescription* font = pango_font_description_copy(style->font_desc); + PangoContext* ctx = pango_layout_get_context(impl->layout); + cairo_font_options_t* opt = cairo_font_options_copy( + pango_cairo_context_get_font_options(ctx)); + + pango_font_description_set_size(font, points * (double)PANGO_SCALE); + pango_layout_set_font_description(impl->layout, font); + pango_cairo_context_set_font_options(ctx, opt); + cairo_font_options_destroy(opt); + pango_font_description_free(font); int width, height; - pango_layout_get_pixel_size(layout, &width, &height); + pango_layout_get_pixel_size(impl->layout, &width, &height); - impl->coords.width = width; + impl->coords.width = width; impl->coords.height = height; + impl->needs_layout = FALSE; - if (impl->surface) { - cairo_surface_destroy(impl->surface); - } - - impl->surface = cairo_image_surface_create( - CAIRO_FORMAT_ARGB32, width, height); - - cairo_t* cr = cairo_create(impl->surface); - - double r, g, b, a; - color_to_rgba(color, &r, &g, &b, &a); - - cairo_set_source_rgba(cr, r, g, b, a); - cairo_move_to(cr, 0, 0); - pango_cairo_show_layout(cr, layout); - - cairo_destroy(cr); - g_object_unref(layout); - pango_font_description_free(font); - - impl->needs_layout = FALSE; ganv_item_request_update(GANV_ITEM(text)); } @@ -293,12 +272,14 @@ ganv_text_draw(GanvItem* item, ganv_text_layout(text); } - // Round to the nearest pixel so text isn't blurry - wx = lrint(wx); - wy = lrint(wy); + guint color = 0xFFFFFFFF; - cairo_set_source_surface(cr, impl->surface, wx, wy); - cairo_paint(cr); + double r, g, b, a; + color_to_rgba(color, &r, &g, &b, &a); + + cairo_set_source_rgba(cr, r, g, b, a); + cairo_move_to(cr, wx, wy); + pango_cairo_show_layout(cr, impl->layout); } static void -- cgit v1.2.1