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 /* Cairo output driver. */
106 struct output_driver driver;
108 /* User parameters. */
109 PangoFontDescription *fonts[XR_N_FONTS];
111 int width; /* Page width minus margins. */
112 int length; /* Page length minus margins and header. */
114 int left_margin; /* Left margin in inch/(72 * XR_POINT). */
115 int right_margin; /* Right margin in inch/(72 * XR_POINT). */
116 int top_margin; /* Top margin in inch/(72 * XR_POINT). */
117 int bottom_margin; /* Bottom margin in inch/(72 * XR_POINT). */
119 int min_break[TABLE_N_AXES]; /* Min cell size to break across pages. */
120 int object_spacing; /* Space between output objects. */
122 struct cell_color bg; /* Background color */
123 struct cell_color fg; /* Foreground color */
124 bool transparent; /* true -> do not render background */
125 bool systemcolors; /* true -> do not change colors */
127 int initial_page_number;
129 struct page_heading headings[2]; /* Top and bottom headings. */
130 int headings_height[2];
132 /* Internal state. */
133 struct xr_fsm_style *style;
135 int char_width, char_height;
137 cairo_surface_t *surface;
138 int page_number; /* Current page number. */
143 static const struct output_driver_class cairo_driver_class;
145 static void xr_driver_destroy_fsm (struct xr_driver *);
146 static void xr_driver_run_fsm (struct xr_driver *);
148 /* Output driver basics. */
150 static struct xr_driver *
151 xr_driver_cast (struct output_driver *driver)
153 assert (driver->class == &cairo_driver_class);
154 return UP_CAST (driver, struct xr_driver, driver);
157 static struct driver_option *
158 opt (struct output_driver *d, struct string_map *options, const char *key,
159 const char *default_value)
161 return driver_option_get (d, options, key, default_value);
164 static PangoFontDescription *
165 parse_font (const char *font, int default_size, bool bold, bool italic)
167 if (!c_strcasecmp (font, "Monospaced"))
170 PangoFontDescription *desc = pango_font_description_from_string (font);
174 /* If the font description didn't include an explicit font size, then set it
175 to DEFAULT_SIZE, which is in inch/72000 units. */
176 if (!(pango_font_description_get_set_fields (desc) & PANGO_FONT_MASK_SIZE))
177 pango_font_description_set_size (desc,
178 (default_size / 1000.0) * PANGO_SCALE);
180 pango_font_description_set_weight (desc, (bold
182 : PANGO_WEIGHT_NORMAL));
183 pango_font_description_set_style (desc, (italic
185 : PANGO_STYLE_NORMAL));
190 static PangoFontDescription *
191 parse_font_option (struct output_driver *d, struct string_map *options,
192 const char *key, const char *default_value,
193 int default_size, bool bold, bool italic)
195 char *string = parse_string (opt (d, options, key, default_value));
196 PangoFontDescription *desc = parse_font (string, default_size, bold, italic);
199 msg (MW, _("`%s': bad font specification"), string);
201 /* Fall back to DEFAULT_VALUE, which had better be a valid font
203 desc = parse_font (default_value, default_size, bold, italic);
204 assert (desc != NULL);
212 apply_options (struct xr_driver *xr, struct string_map *o)
214 struct output_driver *d = &xr->driver;
216 /* In inch/72000 units used by parse_paper_size() and parse_dimension(). */
217 int left_margin, right_margin;
218 int top_margin, bottom_margin;
219 int paper_width, paper_length;
221 int min_break[TABLE_N_AXES];
223 /* Scale factor from inch/72000 to inch/(72 * XR_POINT). */
224 const double scale = XR_POINT / 1000.;
228 for (i = 0; i < XR_N_FONTS; i++)
229 if (xr->fonts[i] != NULL)
230 pango_font_description_free (xr->fonts[i]);
232 font_size = parse_int (opt (d, o, "font-size", "10000"), 1000, 1000000);
233 xr->fonts[XR_FONT_FIXED] = parse_font_option
234 (d, o, "fixed-font", "monospace", font_size, false, false);
235 xr->fonts[XR_FONT_PROPORTIONAL] = parse_font_option (
236 d, o, "prop-font", "sans serif", font_size, false, false);
238 xr->fg = parse_color (opt (d, o, "foreground-color", "#000000000000"));
239 xr->bg = parse_color (opt (d, o, "background-color", "#FFFFFFFFFFFF"));
241 xr->transparent = parse_boolean (opt (d, o, "transparent", "false"));
242 xr->systemcolors = parse_boolean (opt (d, o, "systemcolors", "false"));
244 /* Get dimensions. */
245 parse_paper_size (opt (d, o, "paper-size", ""), &paper_width, &paper_length);
246 left_margin = parse_dimension (opt (d, o, "left-margin", ".5in"));
247 right_margin = parse_dimension (opt (d, o, "right-margin", ".5in"));
248 top_margin = parse_dimension (opt (d, o, "top-margin", ".5in"));
249 bottom_margin = parse_dimension (opt (d, o, "bottom-margin", ".5in"));
251 min_break[H] = parse_dimension (opt (d, o, "min-hbreak", NULL)) * scale;
252 min_break[V] = parse_dimension (opt (d, o, "min-vbreak", NULL)) * scale;
254 int object_spacing = (parse_dimension (opt (d, o, "object-spacing", NULL))
257 /* Convert to inch/(XR_POINT * 72). */
258 xr->left_margin = left_margin * scale;
259 xr->right_margin = right_margin * scale;
260 xr->top_margin = top_margin * scale;
261 xr->bottom_margin = bottom_margin * scale;
262 xr->width = (paper_width - left_margin - right_margin) * scale;
263 xr->length = (paper_length - top_margin - bottom_margin) * scale;
264 xr->min_break[H] = min_break[H] >= 0 ? min_break[H] : xr->width / 2;
265 xr->min_break[V] = min_break[V] >= 0 ? min_break[V] : xr->length / 2;
266 xr->object_spacing = object_spacing >= 0 ? object_spacing : XR_POINT * 12;
268 /* There are no headings so headings_height can stay 0. */
271 static struct xr_driver *
272 xr_allocate (const char *name, int device_type, struct string_map *o,
275 struct xr_driver *xr = xzalloc (sizeof *xr);
276 struct output_driver *d = &xr->driver;
278 output_driver_init (d, &cairo_driver_class, name, device_type);
280 /* This is a nasty kluge for an issue that does not make sense. On any
281 surface other than a screen (e.g. for output to PDF or PS or SVG), the
282 fonts are way too big by default. A "9-point" font seems to appear about
283 16 points tall. We use a scale factor for these surfaces to help, but the
284 underlying issue is a mystery. */
285 xr->font_scale = font_scale;
287 apply_options (xr, o);
293 pango_to_xr (int pango)
295 return (XR_POINT != PANGO_SCALE
296 ? ceil (pango * (1. * XR_POINT / PANGO_SCALE))
303 return (XR_POINT != PANGO_SCALE
304 ? ceil (xr * (1. / XR_POINT * PANGO_SCALE))
309 xr_measure_fonts (cairo_t *cairo, PangoFontDescription *fonts[XR_N_FONTS],
310 int *char_width, int *char_height)
314 for (int i = 0; i < XR_N_FONTS; i++)
316 PangoLayout *layout = pango_cairo_create_layout (cairo);
317 pango_layout_set_font_description (layout, fonts[i]);
319 pango_layout_set_text (layout, "0", 1);
322 pango_layout_get_size (layout, &cw, &ch);
323 *char_width = MAX (*char_width, pango_to_xr (cw));
324 *char_height = MAX (*char_height, pango_to_xr (ch));
326 g_object_unref (G_OBJECT (layout));
331 get_layout_height (PangoLayout *layout)
334 pango_layout_get_size (layout, &w, &h);
339 xr_render_page_heading (cairo_t *cairo, const PangoFontDescription *font,
340 const struct page_heading *ph, int page_number,
341 int width, bool draw, int base_y)
343 PangoLayout *layout = pango_cairo_create_layout (cairo);
344 pango_layout_set_font_description (layout, font);
347 for (size_t i = 0; i < ph->n; i++)
349 const struct page_paragraph *pp = &ph->paragraphs[i];
351 char *markup = output_driver_substitute_heading_vars (pp->markup,
353 pango_layout_set_markup (layout, markup, -1);
356 pango_layout_set_alignment (
358 (pp->halign == TABLE_HALIGN_LEFT ? PANGO_ALIGN_LEFT
359 : pp->halign == TABLE_HALIGN_CENTER ? PANGO_ALIGN_CENTER
360 : pp->halign == TABLE_HALIGN_MIXED ? PANGO_ALIGN_LEFT
361 : PANGO_ALIGN_RIGHT));
362 pango_layout_set_width (layout, xr_to_pango (width));
366 cairo_translate (cairo, 0, xr_to_pt (y + base_y));
367 pango_cairo_show_layout (cairo, layout);
368 cairo_restore (cairo);
371 y += pango_to_xr (get_layout_height (layout));
374 g_object_unref (G_OBJECT (layout));
380 xr_measure_headings (cairo_surface_t *surface,
381 const PangoFontDescription *font,
382 const struct page_heading headings[2],
383 int width, int object_spacing, int height[2])
385 cairo_t *cairo = cairo_create (surface);
387 for (int i = 0; i < 2; i++)
389 int h = xr_render_page_heading (cairo, font, &headings[i], -1,
392 /* If the top heading is nonempty, add some space below it. */
400 cairo_destroy (cairo);
405 xr_check_fonts (cairo_surface_t *surface,
406 PangoFontDescription *fonts[XR_N_FONTS],
407 int usable_width, int usable_length)
409 cairo_t *cairo = cairo_create (surface);
410 int char_width, char_height;
411 xr_measure_fonts (cairo, fonts, &char_width, &char_height);
412 cairo_destroy (cairo);
415 enum { MIN_WIDTH = 3, MIN_LENGTH = 3 };
416 if (usable_width / char_width < MIN_WIDTH)
418 msg (ME, _("The defined page is not wide enough to hold at least %d "
419 "characters in the default font. In fact, there's only "
420 "room for %d characters."),
421 MIN_WIDTH, usable_width / char_width);
424 if (usable_length / char_height < MIN_LENGTH)
426 msg (ME, _("The defined page is not long enough to hold at least %d "
427 "lines in the default font. In fact, there's only "
428 "room for %d lines."),
429 MIN_LENGTH, usable_length / char_height);
436 xr_set_cairo (struct xr_driver *xr, cairo_t *cairo)
440 cairo_set_line_width (xr->cairo, xr_to_pt (XR_LINE_WIDTH));
442 xr_measure_fonts (xr->cairo, xr->fonts, &xr->char_width, &xr->char_height);
444 if (xr->style == NULL)
446 xr->style = xmalloc (sizeof *xr->style);
447 *xr->style = (struct xr_fsm_style) {
449 .size = { [H] = xr->width, [V] = xr->length },
450 .min_break = { [H] = xr->min_break[H], [V] = xr->min_break[V] },
451 .use_system_colors = xr->systemcolors,
452 .transparent = xr->transparent,
453 .font_scale = xr->font_scale,
456 for (size_t i = 0; i < XR_N_FONTS; i++)
457 xr->style->fonts[i] = pango_font_description_copy (xr->fonts[i]);
460 if (!xr->systemcolors)
461 cairo_set_source_rgb (xr->cairo,
462 xr->fg.r / 255.0, xr->fg.g / 255.0, xr->fg.b / 255.0);
465 static struct output_driver *
466 xr_create (struct file_handle *fh, enum settings_output_devices device_type,
467 struct string_map *o, enum xr_output_type file_type)
469 const char *file_name = fh_get_file_name (fh);
470 struct xr_driver *xr = xr_allocate (file_name, device_type, o, 72.0 / 128.0);
471 double width_pt = xr_to_pt (xr->width + xr->left_margin + xr->right_margin);
472 double length_pt = xr_to_pt (xr->length + xr->top_margin + xr->bottom_margin);
473 if (file_type == XR_PDF)
474 xr->surface = cairo_pdf_surface_create (file_name, width_pt, length_pt);
475 else if (file_type == XR_PS)
476 xr->surface = cairo_ps_surface_create (file_name, width_pt, length_pt);
477 else if (file_type == XR_SVG)
478 xr->surface = cairo_svg_surface_create (file_name, width_pt, length_pt);
482 cairo_status_t status = cairo_surface_status (xr->surface);
483 if (status != CAIRO_STATUS_SUCCESS)
485 msg (ME, _("error opening output file `%s': %s"),
486 file_name, cairo_status_to_string (status));
490 if (!xr_check_fonts (xr->surface, xr->fonts, xr->width, xr->length))
498 output_driver_destroy (&xr->driver);
502 static struct output_driver *
503 xr_pdf_create (struct file_handle *fh, enum settings_output_devices device_type,
504 struct string_map *o)
506 return xr_create (fh, device_type, o, XR_PDF);
509 static struct output_driver *
510 xr_ps_create (struct file_handle *fh, enum settings_output_devices device_type,
511 struct string_map *o)
513 return xr_create (fh, device_type, o, XR_PS);
516 static struct output_driver *
517 xr_svg_create (struct file_handle *fh, enum settings_output_devices device_type,
518 struct string_map *o)
520 return xr_create (fh, device_type, o, XR_SVG);
524 xr_destroy (struct output_driver *driver)
526 struct xr_driver *xr = xr_driver_cast (driver);
529 xr_driver_destroy_fsm (xr);
531 if (xr->cairo != NULL)
533 cairo_surface_finish (xr->surface);
534 cairo_status_t status = cairo_status (xr->cairo);
535 if (status != CAIRO_STATUS_SUCCESS)
536 fprintf (stderr, _("error drawing output for %s driver: %s"),
537 output_driver_get_name (driver),
538 cairo_status_to_string (status));
539 cairo_surface_destroy (xr->surface);
541 cairo_destroy (xr->cairo);
544 for (i = 0; i < XR_N_FONTS; i++)
545 if (xr->fonts[i] != NULL)
546 pango_font_description_free (xr->fonts[i]);
548 xr_fsm_style_unref (xr->style);
553 xr_flush (struct output_driver *driver)
555 struct xr_driver *xr = xr_driver_cast (driver);
557 cairo_surface_flush (cairo_get_target (xr->cairo));
561 xr_update_page_setup (struct output_driver *driver,
562 const struct page_setup *ps)
564 struct xr_driver *xr = xr_driver_cast (driver);
566 xr->initial_page_number = ps->initial_page_number;
567 xr->object_spacing = ps->object_spacing * 72 * XR_POINT;
572 int usable[TABLE_N_AXES];
573 for (int i = 0; i < 2; i++)
574 usable[i] = (ps->paper[i]
575 - (ps->margins[i][0] + ps->margins[i][1])) * 72 * XR_POINT;
577 int headings_height[2];
578 usable[V] -= xr_measure_headings (
579 xr->surface, xr->fonts[XR_FONT_PROPORTIONAL], ps->headings,
580 usable[H], xr->object_spacing, headings_height);
582 enum table_axis h = ps->orientation == PAGE_LANDSCAPE;
583 enum table_axis v = !h;
584 if (!xr_check_fonts (xr->surface, xr->fonts, usable[h], usable[v]))
587 for (int i = 0; i < 2; i++)
589 page_heading_uninit (&xr->headings[i]);
590 page_heading_copy (&xr->headings[i], &ps->headings[i]);
591 xr->headings_height[i] = headings_height[i];
593 xr->width = usable[h];
594 xr->length = usable[v];
595 xr->left_margin = ps->margins[h][0] * 72 * XR_POINT;
596 xr->right_margin = ps->margins[h][1] * 72 * XR_POINT;
597 xr->top_margin = ps->margins[v][0] * 72 * XR_POINT;
598 xr->bottom_margin = ps->margins[v][1] * 72 * XR_POINT;
599 cairo_pdf_surface_set_size (xr->surface,
600 ps->paper[h] * 72.0, ps->paper[v] * 72.0);
604 xr_submit (struct output_driver *driver, const struct output_item *output_item)
606 struct xr_driver *xr = xr_driver_cast (driver);
608 if (is_page_setup_item (output_item))
610 xr_update_page_setup (driver,
611 to_page_setup_item (output_item)->page_setup);
617 xr->page_number = xr->initial_page_number - 1;
618 xr_set_cairo (xr, cairo_create (xr->surface));
619 cairo_save (xr->cairo);
620 xr_driver_next_page (xr, xr->cairo);
623 xr_driver_output_item (xr, output_item);
624 while (xr_driver_need_new_page (xr))
626 cairo_restore (xr->cairo);
627 cairo_show_page (xr->cairo);
628 cairo_save (xr->cairo);
629 xr_driver_next_page (xr, xr->cairo);
633 /* Functions for rendering a series of output items to a series of Cairo
634 contexts, with pagination.
636 Used by PSPPIRE for printing, and by the basic Cairo output driver above as
637 its underlying implementation.
639 See the big comment in cairo.h for intended usage. */
641 /* Gives new page CAIRO to XR for output. */
643 xr_driver_next_page (struct xr_driver *xr, cairo_t *cairo)
645 if (!xr->transparent)
648 cairo_set_source_rgb (cairo,
649 xr->bg.r / 255.0, xr->bg.g / 255.0, xr->bg.b / 255.0);
650 cairo_rectangle (cairo, 0, 0, xr->width, xr->length);
652 cairo_restore (cairo);
654 cairo_translate (cairo,
655 xr_to_pt (xr->left_margin),
656 xr_to_pt (xr->top_margin + xr->headings_height[0]));
662 xr_render_page_heading (xr->cairo, xr->fonts[XR_FONT_PROPORTIONAL],
663 &xr->headings[0], xr->page_number, xr->width, true,
664 -xr->headings_height[0]);
665 xr_render_page_heading (xr->cairo, xr->fonts[XR_FONT_PROPORTIONAL],
666 &xr->headings[1], xr->page_number, xr->width, true,
669 xr_driver_run_fsm (xr);
672 /* Start rendering OUTPUT_ITEM to XR. Only valid if XR is not in the middle of
673 rendering a previous output item, that is, only if xr_driver_need_new_page()
676 xr_driver_output_item (struct xr_driver *xr,
677 const struct output_item *output_item)
679 assert (xr->fsm == NULL);
680 xr->fsm = xr_fsm_create (output_item, xr->style, xr->cairo);
681 xr_driver_run_fsm (xr);
684 /* Returns true if XR is in the middle of rendering an output item and needs a
685 new page to be appended using xr_driver_next_page() to make progress,
688 xr_driver_need_new_page (const struct xr_driver *xr)
690 return xr->fsm != NULL;
693 /* Returns true if the current page doesn't have any content yet. */
695 xr_driver_is_page_blank (const struct xr_driver *xr)
701 xr_driver_destroy_fsm (struct xr_driver *xr)
703 xr_fsm_destroy (xr->fsm);
708 xr_driver_run_fsm (struct xr_driver *xr)
712 cairo_save (xr->cairo);
713 cairo_translate (xr->cairo, 0, xr_to_pt (xr->y));
714 int used = xr_fsm_draw_slice (xr->fsm, xr->cairo, xr->length - xr->y);
716 cairo_restore (xr->cairo);
718 if (xr_fsm_is_empty (xr->fsm))
719 xr_driver_destroy_fsm (xr);
723 struct output_driver_factory pdf_driver_factory =
724 { "pdf", "pspp.pdf", xr_pdf_create };
725 struct output_driver_factory ps_driver_factory =
726 { "ps", "pspp.ps", xr_ps_create };
727 struct output_driver_factory svg_driver_factory =
728 { "svg", "pspp.svg", xr_svg_create };
730 static const struct output_driver_class cairo_driver_class =
739 xr_driver_create (cairo_t *cairo, struct string_map *options)
741 struct xr_driver *xr = xr_allocate ("cairo", 0, options, 1.0);
742 xr_set_cairo (xr, cairo);
746 /* Destroy XR, which should have been created with xr_driver_create(). Any
747 cairo_t added to XR is not destroyed, because it is owned by the client. */
749 xr_driver_destroy (struct xr_driver *xr)
754 output_driver_destroy (&xr->driver);
758 xr_draw_chart (const struct chart_item *chart_item, cairo_t *cr,
759 double x, double y, double width, double height)
761 struct xrchart_geometry geom;
764 cairo_translate (cr, x, y + height);
765 cairo_scale (cr, 1.0, -1.0);
766 xrchart_geometry_init (cr, &geom, width, height);
767 if (is_boxplot (chart_item))
768 xrchart_draw_boxplot (chart_item, cr, &geom);
769 else if (is_histogram_chart (chart_item))
770 xrchart_draw_histogram (chart_item, cr, &geom);
771 else if (is_np_plot_chart (chart_item))
772 xrchart_draw_np_plot (chart_item, cr, &geom);
773 else if (is_piechart (chart_item))
774 xrchart_draw_piechart (chart_item, cr, &geom);
775 else if (is_barchart (chart_item))
776 xrchart_draw_barchart (chart_item, cr, &geom);
777 else if (is_roc_chart (chart_item))
778 xrchart_draw_roc (chart_item, cr, &geom);
779 else if (is_scree (chart_item))
780 xrchart_draw_scree (chart_item, cr, &geom);
781 else if (is_spreadlevel_plot_chart (chart_item))
782 xrchart_draw_spreadlevel (chart_item, cr, &geom);
783 else if (is_scatterplot_chart (chart_item))
784 xrchart_draw_scatterplot (chart_item, cr, &geom);
787 xrchart_geometry_free (cr, &geom);
793 xr_draw_png_chart (const struct chart_item *item,
794 const char *file_name_template, int number,
795 const struct cell_color *fg,
796 const struct cell_color *bg)
798 const int width = 640;
799 const int length = 480;
801 cairo_surface_t *surface;
802 cairo_status_t status;
803 const char *number_pos;
807 number_pos = strchr (file_name_template, '#');
808 if (number_pos != NULL)
809 file_name = xasprintf ("%.*s%d%s.png", (int) (number_pos - file_name_template),
810 file_name_template, number, number_pos + 1);
812 file_name = xasprintf ("%s.png", file_name_template);
814 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, length);
815 cr = cairo_create (surface);
817 cairo_set_source_rgb (cr, bg->r / 255.0, bg->g / 255.0, bg->b / 255.0);
820 cairo_set_source_rgb (cr, fg->r / 255.0, fg->g / 255.0, fg->b / 255.0);
822 xr_draw_chart (item, cr, 0.0, 0.0, width, length);
824 status = cairo_surface_write_to_png (surface, file_name);
825 if (status != CAIRO_STATUS_SUCCESS)
826 msg (ME, _("error writing output file `%s': %s"),
827 file_name, cairo_status_to_string (status));
830 cairo_surface_destroy (surface);
837 xr_draw_eps_chart (const struct chart_item *item,
838 const char *file_name_template, int number,
839 const struct cell_color *fg,
840 const struct cell_color *bg)
842 const int width = 640;
843 const int length = 480;
845 cairo_surface_t *surface;
846 const char *number_pos;
850 number_pos = strchr (file_name_template, '#');
851 if (number_pos != NULL)
852 file_name = xasprintf ("%.*s%d%s.eps", (int) (number_pos - file_name_template),
853 file_name_template, number, number_pos + 1);
855 file_name = xasprintf ("%s.eps", file_name_template);
857 surface = cairo_ps_surface_create (file_name, width, length);
858 cairo_ps_surface_set_eps (surface, true);
859 cr = cairo_create (surface);
861 cairo_set_source_rgb (cr, bg->r / 255.0, bg->g / 255.0, bg->b / 255.0);
864 cairo_set_source_rgb (cr, fg->r / 255.0, fg->g / 255.0, fg->b / 255.0);
866 xr_draw_chart (item, cr, 0.0, 0.0, width, length);
869 cairo_surface_destroy (surface);