This also allows us to save charts to .spv files as images.
The structure of a chart plus its data. Charts do not have a
``light'' format.
+@item @file{@var{prefix}_Imagegeneric.png}
+@itemx @file{@var{prefix}_PastedObjectgeneric.png}
+@itemx @file{@var{prefix}_imageData.bin}
+A PNG image referenced by an @code{object} element (in the first two
+cases) or an @code{image} element (in the final case). @xref{SPV
+Structure object and image Elements}.
+
@item @file{@var{prefix}_pmml.scf}
@itemx @file{@var{prefix}_stats.scf}
@item @file{@var{prefix}_model.xml}
* SPV Structure table Element::
* SPV Structure graph Element::
* SPV Structure model Element::
+* SPV Structure object and image Elements::
* SPV Structure tree Element::
* SPV Structure Path Elements::
* SPV Structure pageSetup Element::
Alternatively, @code{pmmlContainerPath} and @code{statsContainerPath}
name Zip members with @file{.scf} extension.
+@node SPV Structure object and image Elements
+@subsection The @code{object} and @code{image} Elements
+
+@example
+object :type[object_type]=(unknown)? :uri => EMPTY
+
+image :VDPId :commandName => dataPath
+@end example
+
+These two elements represent an image in PNG format. They are
+equivalent and the corpus contains examples of both. The only
+difference is the syntax: for @code{object}, the @code{uri} attribute
+names the Zip member that contains a PNG file; for @code{image}, the
+text of the inner @code{dataPath} element names the Zip member.
+
+PSPP writes @code{object} in output but there is no strong reason to
+choose this form.
+
+The corpus only contains PNG image files.
+
@node SPV Structure tree Element
@subsection The @code{tree} Element
#endif
#include "output/chart-item-provider.h"
#include "output/driver-provider.h"
+#include "output/image-item.h"
#include "output/message-item.h"
#include "output/options.h"
#include "output/pivot-output.h"
if (is_table_item (output_item))
ascii_output_table_item (a, to_table_item (output_item));
#ifdef HAVE_CAIRO
+ else if (is_image_item (output_item) && a->chart_file_name != NULL)
+ {
+ struct image_item *image_item = to_image_item (output_item);
+ char *file_name = xr_write_png_image (
+ image_item->image, a->chart_file_name, ++a->chart_cnt);
+ if (file_name != NULL)
+ {
+ struct text_item *text_item;
+
+ text_item = text_item_create_nocopy (
+ TEXT_ITEM_LOG,
+ xasprintf (_("See %s for an image."), file_name),
+ NULL);
+
+ ascii_submit (driver, &text_item->output_item);
+ text_item_unref (text_item);
+ free (file_name);
+ }
+ }
else if (is_chart_item (output_item) && a->chart_file_name != NULL)
{
struct chart_item *chart_item = to_chart_item (output_item);
src/output/driver-provider.h \
src/output/driver.c \
src/output/driver.h \
+ src/output/image-item.c \
+ src/output/image-item.h \
src/output/tex-glyphs.c \
src/output/tex-glyphs.h \
src/output/tex-parsing.c \
cairo_restore (cr);
}
-char *
-xr_draw_png_chart (const struct chart_item *item,
- const char *file_name_template, int number,
- const struct cell_color *fg,
- const struct cell_color *bg)
+cairo_surface_t *
+xr_draw_image_chart (const struct chart_item *item,
+ const struct cell_color *fg,
+ const struct cell_color *bg)
{
const int width = 640;
const int length = 480;
- cairo_surface_t *surface;
- cairo_status_t status;
- const char *number_pos;
- char *file_name;
- cairo_t *cr;
-
- number_pos = strchr (file_name_template, '#');
- if (number_pos != NULL)
- file_name = xasprintf ("%.*s%d%s.png", (int) (number_pos - file_name_template),
- file_name_template, number, number_pos + 1);
- else
- file_name = xasprintf ("%s.png", file_name_template);
-
- surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, length);
- cr = cairo_create (surface);
+ cairo_surface_t *surface = cairo_image_surface_create (
+ CAIRO_FORMAT_RGB24, width, length);
+ cairo_t *cr = cairo_create (surface);
cairo_set_source_rgb (cr, bg->r / 255.0, bg->g / 255.0, bg->b / 255.0);
cairo_paint (cr);
cairo_set_source_rgb (cr, fg->r / 255.0, fg->g / 255.0, fg->b / 255.0);
-
xr_draw_chart (item, cr, width, length);
- status = cairo_surface_write_to_png (surface, file_name);
+ cairo_destroy (cr);
+
+ return surface;
+}
+
+char *
+xr_write_png_image (cairo_surface_t *surface,
+ const char *file_name_template, int number)
+{
+ const char *number_pos = strchr (file_name_template, '#');
+ char *file_name;
+ if (number_pos != NULL)
+ file_name = xasprintf ("%.*s%d%s.png",
+ (int) (number_pos - file_name_template),
+ file_name_template, number, number_pos + 1);
+ else
+ file_name = xasprintf ("%s.png", file_name_template);
+
+ cairo_status_t status = cairo_surface_write_to_png (surface, file_name);
if (status != CAIRO_STATUS_SUCCESS)
msg (ME, _("error writing output file `%s': %s"),
file_name, cairo_status_to_string (status));
- cairo_destroy (cr);
- cairo_surface_destroy (surface);
-
return file_name;
}
+char *
+xr_draw_png_chart (const struct chart_item *item,
+ const char *file_name_template, int number,
+ const struct cell_color *fg,
+ const struct cell_color *bg)
+{
+ cairo_surface_t *surface = xr_draw_image_chart (item, fg, bg);
+ char *file_name = xr_write_png_image (surface, file_name_template, number);
+ cairo_surface_destroy (surface);
+ return file_name;
+}
char *
xr_draw_eps_chart (const struct chart_item *item,
void xr_draw_chart (const struct chart_item *, cairo_t *,
double width, double height);
+cairo_surface_t *xr_draw_image_chart (const struct chart_item *,
+ const struct cell_color *fg,
+ const struct cell_color *bg);
+char *xr_write_png_image (cairo_surface_t *,
+ const char *file_name_template, int number);
+
char *xr_draw_png_chart (const struct chart_item *,
const char *file_name_template, int number,
const struct cell_color *fg,
#include "output/charts/scree.h"
#include "output/charts/spreadlevel-plot.h"
#include "output/group-item.h"
+#include "output/image-item.h"
#include "output/message-item.h"
#include "output/page-eject-item.h"
#include "output/page-setup-item.h"
struct output_item *item;
if (is_table_item (item_)
|| is_chart_item (item_)
+ || is_image_item (item_)
|| is_page_eject_item (item_))
item = output_item_ref (item_);
else if (is_message_item (item_))
NOT_REACHED ();
assert (is_table_item (item)
|| is_chart_item (item)
+ || is_image_item (item)
|| is_page_eject_item (item));
size_t *layer_indexes = NULL;
w = CHART_WIDTH;
h = CHART_HEIGHT;
}
+ else if (is_image_item (fsm->item))
+ {
+ cairo_surface_t *image = to_image_item (fsm->item)->image;
+ w = cairo_image_surface_get_width (image);
+ h = cairo_image_surface_get_height (image);
+ }
else
NOT_REACHED ();
: x * XR_POINT);
}
+static void
+draw_image (cairo_surface_t *image, cairo_t *cr)
+{
+ cairo_save (cr);
+ cairo_set_source_surface (cr, image, 0, 0);
+ cairo_rectangle (cr, 0, 0, cairo_image_surface_get_width (image),
+ cairo_image_surface_get_height (image));
+ cairo_clip (cr);
+ cairo_paint (cr);
+ cairo_restore (cr);
+}
+
void
xr_fsm_draw_region (struct xr_fsm *fsm, cairo_t *cr,
int x, int y, int w, int h)
mul_XR_POINT (w), mul_XR_POINT (h));
fsm->cairo = NULL;
}
+ else if (is_image_item (fsm->item))
+ draw_image (to_image_item (fsm->item)->image, cr);
else if (is_chart_item (fsm->item))
xr_draw_chart (to_chart_item (fsm->item), cr, CHART_WIDTH, CHART_HEIGHT);
else if (is_page_eject_item (fsm->item))
return chart_height;
}
+static int
+xr_fsm_draw_image (struct xr_fsm *fsm, int space)
+{
+ cairo_surface_t *image = to_image_item (fsm->item)->image;
+ int width = cairo_image_surface_get_width (image) * XR_POINT;
+ int height = cairo_image_surface_get_height (image) * XR_POINT;
+ if (!width || !height)
+ goto error;
+
+ if (height > fsm->rp.size[V])
+ {
+ double scale = fsm->rp.size[V] / (double) height;
+ width *= scale;
+ height *= scale;
+ if (!width || !height)
+ goto error;
+
+ cairo_scale (fsm->cairo, scale, scale);
+ }
+
+ if (width > fsm->rp.size[H])
+ {
+ double scale = fsm->rp.size[H] / (double) width;
+ width *= scale;
+ height *= scale;
+ if (!width || !height)
+ goto error;
+
+ cairo_scale (fsm->cairo, scale, scale);
+ }
+
+ if (space < height)
+ return 0;
+
+ draw_image (image, fsm->cairo);
+ fsm->done = true;
+ return height;
+
+error:
+ fsm->done = true;
+ return 0;
+}
+
static int
xr_fsm_draw_eject (struct xr_fsm *fsm, int space)
{
fsm->cairo = cr;
int used = (is_table_item (fsm->item) ? xr_fsm_draw_table (fsm, space)
: is_chart_item (fsm->item) ? xr_fsm_draw_chart (fsm, space)
+ : is_image_item (fsm->item) ? xr_fsm_draw_image (fsm, space)
: is_page_eject_item (fsm->item) ? xr_fsm_draw_eject (fsm, space)
: (abort (), 0));
fsm->cairo = NULL;
#endif
#include "output/chart-item.h"
#include "output/driver-provider.h"
+#include "output/image-item.h"
#include "output/message-item.h"
#include "output/options.h"
#include "output/output-item-provider.h"
html_output_table (html, table_item);
}
#ifdef HAVE_CAIRO
+ else if (is_image_item (output_item) && html->chart_file_name != NULL)
+ {
+ struct image_item *image_item = to_image_item (output_item);
+ char *file_name = xr_write_png_image (
+ image_item->image, html->chart_file_name, ++html->chart_cnt);
+ if (file_name != NULL)
+ {
+ fprintf (html->file, "<img src=\"%s\">", file_name);
+ free (file_name);
+ }
+ }
else if (is_chart_item (output_item) && html->chart_file_name != NULL)
{
struct chart_item *chart_item = to_chart_item (output_item);
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+
+ This program 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/>. */
+
+#include <config.h>
+
+#include "output/image-item.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "libpspp/cast.h"
+#include "libpspp/compiler.h"
+#include "output/driver.h"
+#include "output/output-item-provider.h"
+
+#include "gl/xalloc.h"
+#include "gl/xvasprintf.h"
+
+#ifdef HAVE_CAIRO
+/* Creates and returns a new image item containing IMAGE. Takes ownership of
+ IMAGE. */
+struct image_item *
+image_item_create (cairo_surface_t *image)
+{
+ struct image_item *item = xmalloc (sizeof *item);
+ *item = (struct image_item) {
+ .output_item = OUTPUT_ITEM_INITIALIZER (&image_item_class),
+ .image = image,
+ };
+ return item;
+}
+#endif
+
+/* Submits ITEM to the configured output drivers, and transfers ownership to
+ the output subsystem. */
+void
+image_item_submit (struct image_item *item)
+{
+ output_submit (&item->output_item);
+}
+
+struct image_item *
+image_item_unshare (struct image_item *old)
+{
+ assert (old->output_item.ref_cnt > 0);
+ if (!image_item_is_shared (old))
+ return old;
+ image_item_unref (old);
+
+ struct image_item *new = xmalloc (sizeof *new);
+ *new = (struct image_item) {
+ .output_item = OUTPUT_ITEM_CLONE_INITIALIZER (&old->output_item),
+#ifdef HAVE_CAIRO
+ .image = cairo_surface_reference (old->image),
+#endif
+ };
+ return new;
+}
+\f
+static const char *
+image_item_get_label (const struct output_item *output_item UNUSED)
+{
+ return "Image";
+}
+
+static void
+image_item_destroy (struct output_item *output_item)
+{
+ struct image_item *item = to_image_item (output_item);
+#ifdef HAVE_CAIRO
+ cairo_surface_destroy (item->image);
+#endif
+ free (item);
+}
+
+const struct output_item_class image_item_class =
+ {
+ image_item_get_label,
+ image_item_destroy,
+ };
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+
+ This program 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 OUTPUT_IMAGE_ITEM_H
+#define OUTPUT_IMAGE_ITEM_H 1
+
+#ifdef HAVE_CAIRO
+#include <cairo.h>
+#endif
+#include <stdbool.h>
+#include "output/output-item.h"
+
+struct image_item
+ {
+ struct output_item output_item; /* Superclass */
+#ifdef HAVE_CAIRO
+ cairo_surface_t *image;
+#endif
+ };
+
+#ifdef HAVE_CAIRO
+struct image_item *image_item_create (cairo_surface_t *);
+#endif
+
+struct image_item *image_item_unshare (struct image_item *);
+\f
+/* This boilerplate for image_item, a subclass of output_item, was
+ autogenerated by mk-class-boilerplate. */
+
+#include <assert.h>
+#include "libpspp/cast.h"
+
+extern const struct output_item_class image_item_class;
+
+/* Returns true if SUPER is a image_item, otherwise false. */
+static inline bool
+is_image_item (const struct output_item *super)
+{
+ return super->class == &image_item_class;
+}
+
+/* Returns SUPER converted to image_item. SUPER must be a image_item, as
+ reported by is_image_item. */
+static inline struct image_item *
+to_image_item (const struct output_item *super)
+{
+ assert (is_image_item (super));
+ return UP_CAST (super, struct image_item, output_item);
+}
+
+/* Returns INSTANCE converted to output_item. */
+static inline struct output_item *
+image_item_super (const struct image_item *instance)
+{
+ return CONST_CAST (struct output_item *, &instance->output_item);
+}
+
+/* Increments INSTANCE's reference count and returns INSTANCE. */
+static inline struct image_item *
+image_item_ref (const struct image_item *instance)
+{
+ return to_image_item (output_item_ref (&instance->output_item));
+}
+
+/* Decrements INSTANCE's reference count, then destroys INSTANCE if
+ the reference count is now zero. */
+static inline void
+image_item_unref (struct image_item *instance)
+{
+ output_item_unref (&instance->output_item);
+}
+
+/* Returns true if INSTANCE's reference count is greater than 1,
+ false otherwise. */
+static inline bool
+image_item_is_shared (const struct image_item *instance)
+{
+ return output_item_is_shared (&instance->output_item);
+}
+
+void image_item_submit (struct image_item *);
+\f
+#endif /* output/image-item.h */
#include "data/file-handle-def.h"
#include "libpspp/cast.h"
+#ifdef HAVE_CAIRO
+#include "output/cairo-chart.h"
+#endif
+#include "output/chart-item.h"
#include "output/group-item.h"
#include "output/page-eject-item.h"
#include "output/page-setup-item.h"
if (table_item->pt)
spv_writer_put_table (spv->writer, table_item->pt);
}
+#ifdef HAVE_CAIRO
+ else if (is_chart_item (output_item))
+ {
+ cairo_surface_t *surface = xr_draw_image_chart (
+ to_chart_item (output_item),
+ &(struct cell_color) CELL_COLOR_BLACK,
+ &(struct cell_color) CELL_COLOR_WHITE);
+ if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS)
+ spv_writer_put_image (spv->writer, surface);
+ cairo_surface_destroy (surface);
+ }
+#endif
else if (is_text_item (output_item))
{
char *command_id = output_get_command_name ();
printf ("model\n");
break;
- case SPV_ITEM_OBJECT:
- printf ("object type=\"%s\" uri=\"%s\"\n", item->object_type, item->uri);
+ case SPV_ITEM_IMAGE:
+ printf ("image in %s\n", item->png_member);
break;
case SPV_ITEM_TREE:
spv_writer_close_file (w, "");
}
+#ifdef HAVE_CAIRO
+static cairo_status_t
+write_to_zip (void *zw_, const unsigned char *data, unsigned int length)
+{
+ struct zip_writer *zw = zw_;
+
+ zip_writer_add_write (zw, data, length);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+spv_writer_put_image (struct spv_writer *w, cairo_surface_t *image)
+{
+ bool initial_depth = w->heading_depth;
+ if (!initial_depth)
+ spv_writer_open_file (w);
+
+ char *uri = xasprintf ("%010d_Imagegeneric.png", ++w->n_tables);
+
+ start_container (w);
+
+ start_elem (w, "label");
+ write_text (w, "Image");
+ end_elem (w);
+
+ start_elem (w, "object");
+ write_attr (w, "type", "unknown");
+ write_attr (w, "uri", uri);
+ end_elem (w); /* object */
+ end_elem (w); /* container */
+
+ if (!initial_depth)
+ spv_writer_close_file (w, "");
+
+ zip_writer_add_start (w->zw, uri);
+ cairo_surface_write_to_png_stream (image, write_to_zip, w->zw);
+ zip_writer_add_finish (w->zw);
+
+ free (uri);
+}
+#endif
+
void
spv_writer_eject_page (struct spv_writer *w)
{
struct spv_writer;
struct text_item;
+#ifdef HAVE_CAIRO
+#include <cairo.h>
+#endif
+
#include "libpspp/compiler.h"
char *spv_writer_open (const char *filename, struct spv_writer **)
const char *command_id);
void spv_writer_put_table (struct spv_writer *, const struct pivot_table *);
+#ifdef HAVE_CAIRO
+void spv_writer_put_image (struct spv_writer *, cairo_surface_t *);
+#endif
+
void spv_writer_eject_page (struct spv_writer *);
#endif /* output/spv/spv-writer.h */
case SPV_ITEM_TABLE: return "table";
case SPV_ITEM_GRAPH: return "graph";
case SPV_ITEM_MODEL: return "model";
- case SPV_ITEM_OBJECT: return "object";
+ case SPV_ITEM_IMAGE: return "image";
default: return "**error**";
}
}
case SPV_ITEM_MODEL:
return SPV_CLASS_MODELS;
- case SPV_ITEM_OBJECT:
+ case SPV_ITEM_IMAGE:
return SPV_CLASS_OTHER;
case SPV_ITEM_TREE:
return item->text;
}
+bool
+spv_item_is_image (const struct spv_item *item)
+{
+ return item->type == SPV_ITEM_IMAGE;
+}
+
+#ifdef HAVE_CAIRO
+static cairo_status_t
+read_from_zip_member (void *zm_, unsigned char *data, unsigned int length)
+{
+ struct zip_member *zm = zm_;
+ if (!zm)
+ return CAIRO_STATUS_READ_ERROR;
+
+ while (length > 0)
+ {
+ int n = zip_member_read (zm, data, length);
+ if (n <= 0)
+ return CAIRO_STATUS_READ_ERROR;
+
+ data += n;
+ length -= n;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_surface_t *
+spv_item_get_image (const struct spv_item *item_)
+{
+ struct spv_item *item = CONST_CAST (struct spv_item *, item_);
+ assert (spv_item_is_image (item));
+
+ if (!item->image)
+ {
+ struct zip_member *zm = zip_member_open (item->spv->zip,
+ item->png_member);
+ item->image = cairo_image_surface_create_from_png_stream (
+ read_from_zip_member, zm);
+ if (zm)
+ zip_member_finish (zm);
+ }
+
+ return item->image;
+}
+#endif
+
struct spv_item *
spv_item_next (const struct spv_item *item)
{
pivot_value_destroy (item->text);
- free (item->object_type);
- free (item->uri);
+ free (item->png_member);
+#ifdef HAVE_CAIRO
+ if (item->image)
+ cairo_surface_destroy (item->image);
+#endif
free (item);
}
{
if (spv_item_is_table (item))
spv_item_get_table (item);
+#ifdef HAVE_CAIRO
+ else if (spv_item_is_image (item))
+ spv_item_get_image (item);
+#endif
}
bool
else if (spvsx_is_object (content))
{
struct spvsx_object *object = spvsx_cast_object (content);
- item->type = SPV_ITEM_OBJECT;
- item->object_type = xstrdup (object->type);
- item->uri = xstrdup (object->uri);
+ item->type = SPV_ITEM_IMAGE;
+ item->png_member = xstrdup (object->uri);
}
else if (spvsx_is_image (content))
{
struct spvsx_image *image = spvsx_cast_image (content);
- item->type = SPV_ITEM_OBJECT;
- item->object_type = xstrdup ("image");
- item->uri = xstrdup (image->data_path->text);
+ item->type = SPV_ITEM_IMAGE;
+ item->png_member = xstrdup (image->data_path->text);
}
else if (spvsx_is_tree (content))
- {
- struct spvsx_tree *tree = spvsx_cast_tree (content);
- item->type = SPV_ITEM_TREE;
- item->object_type = xstrdup ("tree");
- item->uri = xstrdup (tree->data_path->text);
- }
+ item->type = SPV_ITEM_TREE;
else
NOT_REACHED ();
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+
+#ifdef HAVE_CAIRO
+#include <cairo.h>
+#endif
+
#include "libpspp/compiler.h"
struct fmt_spec;
SPV_ITEM_TABLE,
SPV_ITEM_GRAPH,
SPV_ITEM_MODEL,
- SPV_ITEM_OBJECT,
+ SPV_ITEM_IMAGE,
SPV_ITEM_TREE,
};
/* SPV_ITEM_TEXT only. */
struct pivot_value *text;
- /* SPV_ITEM_OBJECT only. */
- char *object_type;
- char *uri;
+ /* SPV_ITEM_IMAGE only. */
+ char *png_member;
+#ifdef HAVE_CAIRO
+ cairo_surface_t *image;
+#endif
};
void spv_item_format_path (const struct spv_item *, struct string *);
bool spv_item_is_text (const struct spv_item *);
const struct pivot_value *spv_item_get_text (const struct spv_item *);
+bool spv_item_is_image (const struct spv_item *);
+#ifdef HAVE_CAIRO
+cairo_surface_t *spv_item_get_image (const struct spv_item *);
+#endif
+
bool spv_item_is_visible (const struct spv_item *);
#define SPV_ITEM_FOR_EACH(ITER, ROOT) \
const struct spv_item *spv_item_get_parent (const struct spv_item *);
size_t spv_item_get_level (const struct spv_item *);
-const char *spv_item_get_member_name (const struct spv_item *);
const char *spv_item_get_command_id (const struct spv_item *);
const char *spv_item_get_subtype (const struct spv_item *);
text[pageParagraph_text] :type=(title | text) => TEXT
-object :type :uri => EMPTY
+object :type[object_type]=(unknown)? :uri => EMPTY
image :VDPId :commandName => dataPath
#endif
#include "output/chart-item.h"
#include "output/driver-provider.h"
+#include "output/image-item.h"
#include "output/message-item.h"
#include "output/options.h"
#include "output/output-item-provider.h"
tex_output_table (tex, table_item);
}
#ifdef HAVE_CAIRO
+ else if (is_image_item (output_item) && tex->chart_file_name != NULL)
+ {
+ struct image_item *image_item = to_image_item (output_item);
+ char *file_name = xr_write_png_image (
+ image_item->image, tex->chart_file_name, tex->chart_cnt++);
+ if (file_name != NULL)
+ {
+ shipout (&tex->token_list, "\\includegraphics{%s}\n", file_name);
+ tex->require_graphics = true;
+ free (file_name);
+ }
+ }
else if (is_chart_item (output_item) && tex->chart_file_name != NULL)
{
struct chart_item *chart_item = to_chart_item (output_item);
#include "data/dataset.h"
#include "libpspp/version.h"
#include "output/group-item.h"
+#include "output/image-item.h"
#include "output/pivot-table.h"
#include "output/spv/spv.h"
#include "output/spv/spv-output.h"
spv_text_submit (items[i]);
else if (items[i]->type == SPV_ITEM_TABLE)
pivot_table_submit (pivot_table_ref (spv_item_get_table (items[i])));
+ else if (items[i]->type == SPV_ITEM_IMAGE)
+ {
+ cairo_surface_t *image = spv_item_get_image (items[i]);
+ image_item_submit (image_item_create (cairo_surface_reference (
+ image)));
+ }
prev_heading = heading;
}
dump_heading_transition (prev_heading, spv_get_root (spv));
#include <config.h>
+#ifdef HAVE_CAIRO
+#include <cairo.h>
+#endif
#include <getopt.h>
#include <limits.h>
#include <stdlib.h>
#include "libpspp/string-set.h"
#include "output/driver.h"
#include "output/group-item.h"
+#include "output/image-item.h"
#include "output/page-setup-item.h"
#include "output/pivot-table.h"
#include "output/spv/light-binary-parser.h"
case SPV_ITEM_MODEL:
break;
- case SPV_ITEM_OBJECT:
+ case SPV_ITEM_IMAGE:
+#ifdef HAVE_CAIRO
+ image_item_submit (image_item_create (cairo_surface_reference (
+ spv_item_get_image (item))));
+#endif
break;
case SPV_ITEM_TREE:
if (!spv_item_is_visible (item))
printf (" (hidden)");
- if (show_member_names && (item->xml_member || item->bin_member))
+
+ if (show_member_names)
{
- if (item->xml_member && item->bin_member)
- printf (" in %s and %s", item->xml_member, item->bin_member);
- else if (item->xml_member)
- printf (" in %s", item->xml_member);
- else if (item->bin_member)
- printf (" in %s", item->bin_member);
+ const char *members[] = {
+ item->xml_member,
+ item->bin_member,
+ item->png_member,
+ };
+ size_t n = 0;
+
+ for (size_t i = 0; i < sizeof members / sizeof *members; i++)
+ if (members[i])
+ printf (" %s %s", n++ == 0 ? "in" : "and", members[i]);
}
putchar ('\n');
}