1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "output/cairo.h"
21 #include "libpspp/assertion.h"
22 #include "libpspp/cast.h"
23 #include "libpspp/hash-functions.h"
24 #include "libpspp/message.h"
25 #include "libpspp/pool.h"
26 #include "libpspp/start-date.h"
27 #include "libpspp/str.h"
28 #include "libpspp/string-map.h"
29 #include "libpspp/version.h"
30 #include "data/file-handle-def.h"
31 #include "output/cairo-chart.h"
32 #include "output/cairo-fsm.h"
33 #include "output/chart-item-provider.h"
34 #include "output/charts/boxplot.h"
35 #include "output/charts/np-plot.h"
36 #include "output/charts/piechart.h"
37 #include "output/charts/barchart.h"
38 #include "output/charts/plot-hist.h"
39 #include "output/charts/roc-chart.h"
40 #include "output/charts/spreadlevel-plot.h"
41 #include "output/charts/scree.h"
42 #include "output/charts/scatterplot.h"
43 #include "output/driver-provider.h"
44 #include "output/group-item.h"
45 #include "output/message-item.h"
46 #include "output/options.h"
47 #include "output/page-eject-item.h"
48 #include "output/page-setup-item.h"
49 #include "output/render.h"
50 #include "output/table-item.h"
51 #include "output/table.h"
52 #include "output/text-item.h"
54 #include <cairo/cairo-pdf.h>
55 #include <cairo/cairo-ps.h>
56 #include <cairo/cairo-svg.h>
58 #include <cairo/cairo.h>
61 #include <pango/pango-font.h>
62 #include <pango/pango-layout.h>
63 #include <pango/pango.h>
64 #include <pango/pangocairo.h>
67 #include "gl/c-ctype.h"
68 #include "gl/c-strcase.h"
69 #include "gl/intprops.h"
70 #include "gl/minmax.h"
71 #include "gl/xalloc.h"
74 #define _(msgid) gettext (msgid)
76 /* This file uses TABLE_HORZ and TABLE_VERT enough to warrant abbreviating. */
80 /* The unit used for internal measurements is inch/(72 * XR_POINT).
81 (Thus, XR_POINT units represent one point.) */
82 #define XR_POINT PANGO_SCALE
84 /* Conversions to and from points. */
88 return x / (double) XR_POINT;
91 /* Dimensions for drawing lines in tables. */
92 #define XR_LINE_WIDTH (XR_POINT / 2) /* Width of an ordinary line. */
93 #define XR_LINE_SPACE XR_POINT /* Space between double lines. */
103 /* A font for use with Cairo. */
106 PangoFontDescription *desc;
110 /* Cairo output driver. */
113 struct output_driver driver;
115 /* User parameters. */
116 struct xr_font fonts[XR_N_FONTS];
118 int width; /* Page width minus margins. */
119 int length; /* Page length minus margins and header. */
121 int left_margin; /* Left margin in inch/(72 * XR_POINT). */
122 int right_margin; /* Right margin in inch/(72 * XR_POINT). */
123 int top_margin; /* Top margin in inch/(72 * XR_POINT). */
124 int bottom_margin; /* Bottom margin in inch/(72 * XR_POINT). */
126 int min_break[TABLE_N_AXES]; /* Min cell size to break across pages. */
127 int object_spacing; /* Space between output objects. */
129 struct cell_color bg; /* Background color */
130 struct cell_color fg; /* Foreground color */
131 bool transparent; /* true -> do not render background */
132 bool systemcolors; /* true -> do not change colors */
134 int initial_page_number;
136 struct page_heading headings[2]; /* Top and bottom headings. */
137 int headings_height[2];
139 /* Internal state. */
140 struct xr_fsm_style *style;
142 int char_width, char_height;
144 cairo_surface_t *surface;
145 int page_number; /* Current page number. */
150 static const struct output_driver_class cairo_driver_class;
152 static void xr_driver_destroy_fsm (struct xr_driver *);
153 static void xr_driver_run_fsm (struct xr_driver *);
155 /* Output driver basics. */
157 static struct xr_driver *
158 xr_driver_cast (struct output_driver *driver)
160 assert (driver->class == &cairo_driver_class);
161 return UP_CAST (driver, struct xr_driver, driver);
164 static struct driver_option *
165 opt (struct output_driver *d, struct string_map *options, const char *key,
166 const char *default_value)
168 return driver_option_get (d, options, key, default_value);
171 static PangoFontDescription *
172 parse_font (const char *font, int default_size, bool bold, bool italic)
174 if (!c_strcasecmp (font, "Monospaced"))
177 PangoFontDescription *desc = pango_font_description_from_string (font);
181 /* If the font description didn't include an explicit font size, then set it
182 to DEFAULT_SIZE, which is in inch/72000 units. */
183 if (!(pango_font_description_get_set_fields (desc) & PANGO_FONT_MASK_SIZE))
184 pango_font_description_set_size (desc,
185 (default_size / 1000.0) * PANGO_SCALE);
187 pango_font_description_set_weight (desc, (bold
189 : PANGO_WEIGHT_NORMAL));
190 pango_font_description_set_style (desc, (italic
192 : PANGO_STYLE_NORMAL));
197 static PangoFontDescription *
198 parse_font_option (struct output_driver *d, struct string_map *options,
199 const char *key, const char *default_value,
200 int default_size, bool bold, bool italic)
202 char *string = parse_string (opt (d, options, key, default_value));
203 PangoFontDescription *desc = parse_font (string, default_size, bold, italic);
206 msg (MW, _("`%s': bad font specification"), string);
208 /* Fall back to DEFAULT_VALUE, which had better be a valid font
210 desc = parse_font (default_value, default_size, bold, italic);
211 assert (desc != NULL);
219 apply_options (struct xr_driver *xr, struct string_map *o)
221 struct output_driver *d = &xr->driver;
223 /* In inch/72000 units used by parse_paper_size() and parse_dimension(). */
224 int left_margin, right_margin;
225 int top_margin, bottom_margin;
226 int paper_width, paper_length;
228 int min_break[TABLE_N_AXES];
230 /* Scale factor from inch/72000 to inch/(72 * XR_POINT). */
231 const double scale = XR_POINT / 1000.;
235 for (i = 0; i < XR_N_FONTS; i++)
237 struct xr_font *font = &xr->fonts[i];
239 if (font->desc != NULL)
240 pango_font_description_free (font->desc);
243 font_size = parse_int (opt (d, o, "font-size", "10000"), 1000, 1000000);
244 xr->fonts[XR_FONT_FIXED].desc = parse_font_option
245 (d, o, "fixed-font", "monospace", font_size, false, false);
246 xr->fonts[XR_FONT_PROPORTIONAL].desc = parse_font_option (
247 d, o, "prop-font", "sans serif", font_size, false, false);
249 xr->fg = parse_color (opt (d, o, "foreground-color", "#000000000000"));
250 xr->bg = parse_color (opt (d, o, "background-color", "#FFFFFFFFFFFF"));
252 xr->transparent = parse_boolean (opt (d, o, "transparent", "false"));
253 xr->systemcolors = parse_boolean (opt (d, o, "systemcolors", "false"));
255 /* Get dimensions. */
256 parse_paper_size (opt (d, o, "paper-size", ""), &paper_width, &paper_length);
257 left_margin = parse_dimension (opt (d, o, "left-margin", ".5in"));
258 right_margin = parse_dimension (opt (d, o, "right-margin", ".5in"));
259 top_margin = parse_dimension (opt (d, o, "top-margin", ".5in"));
260 bottom_margin = parse_dimension (opt (d, o, "bottom-margin", ".5in"));
262 min_break[H] = parse_dimension (opt (d, o, "min-hbreak", NULL)) * scale;
263 min_break[V] = parse_dimension (opt (d, o, "min-vbreak", NULL)) * scale;
265 int object_spacing = (parse_dimension (opt (d, o, "object-spacing", NULL))
268 /* Convert to inch/(XR_POINT * 72). */
269 xr->left_margin = left_margin * scale;
270 xr->right_margin = right_margin * scale;
271 xr->top_margin = top_margin * scale;
272 xr->bottom_margin = bottom_margin * scale;
273 xr->width = (paper_width - left_margin - right_margin) * scale;
274 xr->length = (paper_length - top_margin - bottom_margin) * scale;
275 xr->min_break[H] = min_break[H] >= 0 ? min_break[H] : xr->width / 2;
276 xr->min_break[V] = min_break[V] >= 0 ? min_break[V] : xr->length / 2;
277 xr->object_spacing = object_spacing >= 0 ? object_spacing : XR_POINT * 12;
279 /* There are no headings so headings_height can stay 0. */
282 static struct xr_driver *
283 xr_allocate (const char *name, int device_type, struct string_map *o,
286 struct xr_driver *xr = xzalloc (sizeof *xr);
287 struct output_driver *d = &xr->driver;
289 output_driver_init (d, &cairo_driver_class, name, device_type);
291 /* This is a nasty kluge for an issue that does not make sense. On any
292 surface other than a screen (e.g. for output to PDF or PS or SVG), the
293 fonts are way too big by default. A "9-point" font seems to appear about
294 16 points tall. We use a scale factor for these surfaces to help, but the
295 underlying issue is a mystery. */
296 xr->font_scale = font_scale;
298 apply_options (xr, o);
304 pango_to_xr (int pango)
306 return (XR_POINT != PANGO_SCALE
307 ? ceil (pango * (1. * XR_POINT / PANGO_SCALE))
314 return (XR_POINT != PANGO_SCALE
315 ? ceil (xr * (1. / XR_POINT * PANGO_SCALE))
320 xr_measure_fonts (cairo_t *cairo, const struct xr_font fonts[XR_N_FONTS],
321 int *char_width, int *char_height)
325 for (int i = 0; i < XR_N_FONTS; i++)
327 PangoLayout *layout = pango_cairo_create_layout (cairo);
328 pango_layout_set_font_description (layout, fonts[i].desc);
330 pango_layout_set_text (layout, "0", 1);
333 pango_layout_get_size (layout, &cw, &ch);
334 *char_width = MAX (*char_width, pango_to_xr (cw));
335 *char_height = MAX (*char_height, pango_to_xr (ch));
337 g_object_unref (G_OBJECT (layout));
342 get_layout_height (PangoLayout *layout)
345 pango_layout_get_size (layout, &w, &h);
350 xr_render_page_heading (cairo_t *cairo, const PangoFontDescription *font,
351 const struct page_heading *ph, int page_number,
352 int width, bool draw, int base_y)
354 PangoLayout *layout = pango_cairo_create_layout (cairo);
355 pango_layout_set_font_description (layout, font);
358 for (size_t i = 0; i < ph->n; i++)
360 const struct page_paragraph *pp = &ph->paragraphs[i];
362 char *markup = output_driver_substitute_heading_vars (pp->markup,
364 pango_layout_set_markup (layout, markup, -1);
367 pango_layout_set_alignment (
369 (pp->halign == TABLE_HALIGN_LEFT ? PANGO_ALIGN_LEFT
370 : pp->halign == TABLE_HALIGN_CENTER ? PANGO_ALIGN_CENTER
371 : pp->halign == TABLE_HALIGN_MIXED ? PANGO_ALIGN_LEFT
372 : PANGO_ALIGN_RIGHT));
373 pango_layout_set_width (layout, xr_to_pango (width));
377 cairo_translate (cairo, 0, xr_to_pt (y + base_y));
378 pango_cairo_show_layout (cairo, layout);
379 cairo_restore (cairo);
382 y += pango_to_xr (get_layout_height (layout));
385 g_object_unref (G_OBJECT (layout));
391 xr_measure_headings (cairo_surface_t *surface,
392 const PangoFontDescription *font,
393 const struct page_heading headings[2],
394 int width, int object_spacing, int height[2])
396 cairo_t *cairo = cairo_create (surface);
398 for (int i = 0; i < 2; i++)
400 int h = xr_render_page_heading (cairo, font, &headings[i], -1,
403 /* If the top heading is nonempty, add some space below it. */
411 cairo_destroy (cairo);
416 xr_check_fonts (cairo_surface_t *surface,
417 const struct xr_font fonts[XR_N_FONTS],
418 int usable_width, int usable_length)
420 cairo_t *cairo = cairo_create (surface);
421 int char_width, char_height;
422 xr_measure_fonts (cairo, fonts, &char_width, &char_height);
423 cairo_destroy (cairo);
426 enum { MIN_WIDTH = 3, MIN_LENGTH = 3 };
427 if (usable_width / char_width < MIN_WIDTH)
429 msg (ME, _("The defined page is not wide enough to hold at least %d "
430 "characters in the default font. In fact, there's only "
431 "room for %d characters."),
432 MIN_WIDTH, usable_width / char_width);
435 if (usable_length / char_height < MIN_LENGTH)
437 msg (ME, _("The defined page is not long enough to hold at least %d "
438 "lines in the default font. In fact, there's only "
439 "room for %d lines."),
440 MIN_LENGTH, usable_length / char_height);
447 xr_set_cairo (struct xr_driver *xr, cairo_t *cairo)
451 cairo_set_line_width (xr->cairo, xr_to_pt (XR_LINE_WIDTH));
453 xr_measure_fonts (xr->cairo, xr->fonts, &xr->char_width, &xr->char_height);
455 for (int i = 0; i < XR_N_FONTS; i++)
457 struct xr_font *font = &xr->fonts[i];
458 font->layout = pango_cairo_create_layout (cairo);
459 pango_layout_set_font_description (font->layout, font->desc);
462 if (xr->style == NULL)
464 xr->style = xmalloc (sizeof *xr->style);
465 *xr->style = (struct xr_fsm_style) {
467 .size = { [H] = xr->width, [V] = xr->length },
468 .min_break = { [H] = xr->min_break[H], [V] = xr->min_break[V] },
469 .use_system_colors = xr->systemcolors,
470 .transparent = xr->transparent,
471 .font_scale = xr->font_scale,
474 for (size_t i = 0; i < XR_N_FONTS; i++)
475 xr->style->fonts[i] = pango_font_description_copy (xr->fonts[i].desc);
478 if (!xr->systemcolors)
479 cairo_set_source_rgb (xr->cairo,
480 xr->fg.r / 255.0, xr->fg.g / 255.0, xr->fg.b / 255.0);
483 static struct output_driver *
484 xr_create (struct file_handle *fh, enum settings_output_devices device_type,
485 struct string_map *o, enum xr_output_type file_type)
487 const char *file_name = fh_get_file_name (fh);
488 struct xr_driver *xr = xr_allocate (file_name, device_type, o, 72.0 / 128.0);
489 double width_pt = xr_to_pt (xr->width + xr->left_margin + xr->right_margin);
490 double length_pt = xr_to_pt (xr->length + xr->top_margin + xr->bottom_margin);
491 if (file_type == XR_PDF)
492 xr->surface = cairo_pdf_surface_create (file_name, width_pt, length_pt);
493 else if (file_type == XR_PS)
494 xr->surface = cairo_ps_surface_create (file_name, width_pt, length_pt);
495 else if (file_type == XR_SVG)
496 xr->surface = cairo_svg_surface_create (file_name, width_pt, length_pt);
500 cairo_status_t status = cairo_surface_status (xr->surface);
501 if (status != CAIRO_STATUS_SUCCESS)
503 msg (ME, _("error opening output file `%s': %s"),
504 file_name, cairo_status_to_string (status));
508 if (!xr_check_fonts (xr->surface, xr->fonts, xr->width, xr->length))
516 output_driver_destroy (&xr->driver);
520 static struct output_driver *
521 xr_pdf_create (struct file_handle *fh, enum settings_output_devices device_type,
522 struct string_map *o)
524 return xr_create (fh, device_type, o, XR_PDF);
527 static struct output_driver *
528 xr_ps_create (struct file_handle *fh, enum settings_output_devices device_type,
529 struct string_map *o)
531 return xr_create (fh, device_type, o, XR_PS);
534 static struct output_driver *
535 xr_svg_create (struct file_handle *fh, enum settings_output_devices device_type,
536 struct string_map *o)
538 return xr_create (fh, device_type, o, XR_SVG);
542 xr_destroy (struct output_driver *driver)
544 struct xr_driver *xr = xr_driver_cast (driver);
547 xr_driver_destroy_fsm (xr);
549 if (xr->cairo != NULL)
551 cairo_surface_finish (xr->surface);
552 cairo_status_t status = cairo_status (xr->cairo);
553 if (status != CAIRO_STATUS_SUCCESS)
554 fprintf (stderr, _("error drawing output for %s driver: %s"),
555 output_driver_get_name (driver),
556 cairo_status_to_string (status));
557 cairo_surface_destroy (xr->surface);
559 cairo_destroy (xr->cairo);
562 for (i = 0; i < XR_N_FONTS; i++)
564 struct xr_font *font = &xr->fonts[i];
566 if (font->desc != NULL)
567 pango_font_description_free (font->desc);
568 if (font->layout != NULL)
569 g_object_unref (font->layout);
572 xr_fsm_style_unref (xr->style);
577 xr_flush (struct output_driver *driver)
579 struct xr_driver *xr = xr_driver_cast (driver);
581 cairo_surface_flush (cairo_get_target (xr->cairo));
585 xr_update_page_setup (struct output_driver *driver,
586 const struct page_setup *ps)
588 struct xr_driver *xr = xr_driver_cast (driver);
590 xr->initial_page_number = ps->initial_page_number;
591 xr->object_spacing = ps->object_spacing * 72 * XR_POINT;
596 int usable[TABLE_N_AXES];
597 for (int i = 0; i < 2; i++)
598 usable[i] = (ps->paper[i]
599 - (ps->margins[i][0] + ps->margins[i][1])) * 72 * XR_POINT;
601 int headings_height[2];
602 usable[V] -= xr_measure_headings (
603 xr->surface, xr->fonts[XR_FONT_PROPORTIONAL].desc, ps->headings,
604 usable[H], xr->object_spacing, headings_height);
606 enum table_axis h = ps->orientation == PAGE_LANDSCAPE;
607 enum table_axis v = !h;
608 if (!xr_check_fonts (xr->surface, xr->fonts, usable[h], usable[v]))
611 for (int i = 0; i < 2; i++)
613 page_heading_uninit (&xr->headings[i]);
614 page_heading_copy (&xr->headings[i], &ps->headings[i]);
615 xr->headings_height[i] = headings_height[i];
617 xr->width = usable[h];
618 xr->length = usable[v];
619 xr->left_margin = ps->margins[h][0] * 72 * XR_POINT;
620 xr->right_margin = ps->margins[h][1] * 72 * XR_POINT;
621 xr->top_margin = ps->margins[v][0] * 72 * XR_POINT;
622 xr->bottom_margin = ps->margins[v][1] * 72 * XR_POINT;
623 cairo_pdf_surface_set_size (xr->surface,
624 ps->paper[h] * 72.0, ps->paper[v] * 72.0);
628 xr_submit (struct output_driver *driver, const struct output_item *output_item)
630 struct xr_driver *xr = xr_driver_cast (driver);
632 if (is_page_setup_item (output_item))
634 xr_update_page_setup (driver,
635 to_page_setup_item (output_item)->page_setup);
641 xr->page_number = xr->initial_page_number - 1;
642 xr_set_cairo (xr, cairo_create (xr->surface));
643 cairo_save (xr->cairo);
644 xr_driver_next_page (xr, xr->cairo);
647 xr_driver_output_item (xr, output_item);
648 while (xr_driver_need_new_page (xr))
650 cairo_restore (xr->cairo);
651 cairo_show_page (xr->cairo);
652 cairo_save (xr->cairo);
653 xr_driver_next_page (xr, xr->cairo);
657 /* Functions for rendering a series of output items to a series of Cairo
658 contexts, with pagination.
660 Used by PSPPIRE for printing, and by the basic Cairo output driver above as
661 its underlying implementation.
663 See the big comment in cairo.h for intended usage. */
665 /* Gives new page CAIRO to XR for output. */
667 xr_driver_next_page (struct xr_driver *xr, cairo_t *cairo)
669 if (!xr->transparent)
672 cairo_set_source_rgb (cairo,
673 xr->bg.r / 255.0, xr->bg.g / 255.0, xr->bg.b / 255.0);
674 cairo_rectangle (cairo, 0, 0, xr->width, xr->length);
676 cairo_restore (cairo);
678 cairo_translate (cairo,
679 xr_to_pt (xr->left_margin),
680 xr_to_pt (xr->top_margin + xr->headings_height[0]));
686 xr_render_page_heading (xr->cairo, xr->fonts[XR_FONT_PROPORTIONAL].desc,
687 &xr->headings[0], xr->page_number, xr->width, true,
688 -xr->headings_height[0]);
689 xr_render_page_heading (xr->cairo, xr->fonts[XR_FONT_PROPORTIONAL].desc,
690 &xr->headings[1], xr->page_number, xr->width, true,
693 xr_driver_run_fsm (xr);
696 /* Start rendering OUTPUT_ITEM to XR. Only valid if XR is not in the middle of
697 rendering a previous output item, that is, only if xr_driver_need_new_page()
700 xr_driver_output_item (struct xr_driver *xr,
701 const struct output_item *output_item)
703 assert (xr->fsm == NULL);
704 xr->fsm = xr_fsm_create (output_item, xr->style, xr->cairo);
705 xr_driver_run_fsm (xr);
708 /* Returns true if XR is in the middle of rendering an output item and needs a
709 new page to be appended using xr_driver_next_page() to make progress,
712 xr_driver_need_new_page (const struct xr_driver *xr)
714 return xr->fsm != NULL;
717 /* Returns true if the current page doesn't have any content yet. */
719 xr_driver_is_page_blank (const struct xr_driver *xr)
725 xr_driver_destroy_fsm (struct xr_driver *xr)
727 xr_fsm_destroy (xr->fsm);
732 xr_driver_run_fsm (struct xr_driver *xr)
736 cairo_save (xr->cairo);
737 cairo_translate (xr->cairo, 0, xr_to_pt (xr->y));
738 int used = xr_fsm_draw_slice (xr->fsm, xr->cairo, xr->length - xr->y);
740 cairo_restore (xr->cairo);
742 if (xr_fsm_is_empty (xr->fsm))
743 xr_driver_destroy_fsm (xr);
747 struct output_driver_factory pdf_driver_factory =
748 { "pdf", "pspp.pdf", xr_pdf_create };
749 struct output_driver_factory ps_driver_factory =
750 { "ps", "pspp.ps", xr_ps_create };
751 struct output_driver_factory svg_driver_factory =
752 { "svg", "pspp.svg", xr_svg_create };
754 static const struct output_driver_class cairo_driver_class =
763 xr_driver_create (cairo_t *cairo, struct string_map *options)
765 struct xr_driver *xr = xr_allocate ("cairo", 0, options, 1.0);
766 xr_set_cairo (xr, cairo);
770 /* Destroy XR, which should have been created with xr_driver_create(). Any
771 cairo_t added to XR is not destroyed, because it is owned by the client. */
773 xr_driver_destroy (struct xr_driver *xr)
778 output_driver_destroy (&xr->driver);
782 xr_draw_chart (const struct chart_item *chart_item, cairo_t *cr,
783 double x, double y, double width, double height)
785 struct xrchart_geometry geom;
788 cairo_translate (cr, x, y + height);
789 cairo_scale (cr, 1.0, -1.0);
790 xrchart_geometry_init (cr, &geom, width, height);
791 if (is_boxplot (chart_item))
792 xrchart_draw_boxplot (chart_item, cr, &geom);
793 else if (is_histogram_chart (chart_item))
794 xrchart_draw_histogram (chart_item, cr, &geom);
795 else if (is_np_plot_chart (chart_item))
796 xrchart_draw_np_plot (chart_item, cr, &geom);
797 else if (is_piechart (chart_item))
798 xrchart_draw_piechart (chart_item, cr, &geom);
799 else if (is_barchart (chart_item))
800 xrchart_draw_barchart (chart_item, cr, &geom);
801 else if (is_roc_chart (chart_item))
802 xrchart_draw_roc (chart_item, cr, &geom);
803 else if (is_scree (chart_item))
804 xrchart_draw_scree (chart_item, cr, &geom);
805 else if (is_spreadlevel_plot_chart (chart_item))
806 xrchart_draw_spreadlevel (chart_item, cr, &geom);
807 else if (is_scatterplot_chart (chart_item))
808 xrchart_draw_scatterplot (chart_item, cr, &geom);
811 xrchart_geometry_free (cr, &geom);
817 xr_draw_png_chart (const struct chart_item *item,
818 const char *file_name_template, int number,
819 const struct cell_color *fg,
820 const struct cell_color *bg)
822 const int width = 640;
823 const int length = 480;
825 cairo_surface_t *surface;
826 cairo_status_t status;
827 const char *number_pos;
831 number_pos = strchr (file_name_template, '#');
832 if (number_pos != NULL)
833 file_name = xasprintf ("%.*s%d%s.png", (int) (number_pos - file_name_template),
834 file_name_template, number, number_pos + 1);
836 file_name = xasprintf ("%s.png", file_name_template);
838 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, length);
839 cr = cairo_create (surface);
841 cairo_set_source_rgb (cr, bg->r / 255.0, bg->g / 255.0, bg->b / 255.0);
844 cairo_set_source_rgb (cr, fg->r / 255.0, fg->g / 255.0, fg->b / 255.0);
846 xr_draw_chart (item, cr, 0.0, 0.0, width, length);
848 status = cairo_surface_write_to_png (surface, file_name);
849 if (status != CAIRO_STATUS_SUCCESS)
850 msg (ME, _("error writing output file `%s': %s"),
851 file_name, cairo_status_to_string (status));
854 cairo_surface_destroy (surface);
861 xr_draw_eps_chart (const struct chart_item *item,
862 const char *file_name_template, int number,
863 const struct cell_color *fg,
864 const struct cell_color *bg)
866 const int width = 640;
867 const int length = 480;
869 cairo_surface_t *surface;
870 const char *number_pos;
874 number_pos = strchr (file_name_template, '#');
875 if (number_pos != NULL)
876 file_name = xasprintf ("%.*s%d%s.eps", (int) (number_pos - file_name_template),
877 file_name_template, number, number_pos + 1);
879 file_name = xasprintf ("%s.eps", file_name_template);
881 surface = cairo_ps_surface_create (file_name, width, length);
882 cairo_ps_surface_set_eps (surface, true);
883 cr = cairo_create (surface);
885 cairo_set_source_rgb (cr, bg->r / 255.0, bg->g / 255.0, bg->b / 255.0);
888 cairo_set_source_rgb (cr, fg->r / 255.0, fg->g / 255.0, fg->b / 255.0);
890 xr_draw_chart (item, cr, 0.0, 0.0, width, length);
893 cairo_surface_destroy (surface);