Add support for PNG images in .spv files.
[pspp] / src / output / spv / spv-writer.c
index db8d03dfbffee47f320e29b6db962895b9a829db..c5a600571a8e869a4ceb5d6700c43e4a1fd0a7ce 100644 (file)
@@ -294,9 +294,6 @@ void
 spv_writer_put_text (struct spv_writer *w, const struct text_item *text,
                      const char *command_id)
 {
-  if (text->type == TEXT_ITEM_EJECT_PAGE)
-    w->need_page_break = true;
-
   bool initial_depth = w->heading_depth;
   if (!initial_depth)
     spv_writer_open_file (w);
@@ -325,6 +322,54 @@ spv_writer_put_text (struct spv_writer *w, const struct text_item *text,
   if (!initial_depth)
     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)
+{
+  w->need_page_break = true;
+}
 \f
 #define H TABLE_HORZ
 #define V TABLE_VERT
@@ -525,7 +570,7 @@ put_value_mod (struct buf *buf, const struct pivot_value *value,
       /* Footnotes. */
       put_u32 (buf, value->n_footnotes);
       for (size_t i = 0; i < value->n_footnotes; i++)
-        put_u16 (buf, value->footnotes[i]->idx);
+        put_u16 (buf, value->footnote_indexes[i]);
 
       /* Subscripts. */
       put_u32 (buf, value->n_subscripts);
@@ -552,9 +597,10 @@ put_value_mod (struct buf *buf, const struct pivot_value *value,
 }
 
 static void
-put_format (struct buf *buf, const struct fmt_spec *f)
+put_format (struct buf *buf, const struct fmt_spec *f, bool honor_small)
 {
-  put_u32 (buf, (fmt_to_io (f->type) << 16) | (f->w << 8) | f->d);
+  int type = f->type == FMT_F && honor_small ? 40 : fmt_to_io (f->type);
+  put_u32 (buf, (type << 16) | (f->w << 8) | f->d);
 }
 
 static int
@@ -582,7 +628,7 @@ put_value (struct buf *buf, const struct pivot_value *value)
         {
           put_byte (buf, 2);
           put_value_mod (buf, value, NULL);
-          put_format (buf, &value->numeric.format);
+          put_format (buf, &value->numeric.format, value->numeric.honor_small);
           put_double (buf, value->numeric.x);
           put_string (buf, value->numeric.var_name);
           put_string (buf, value->numeric.value_label);
@@ -592,7 +638,7 @@ put_value (struct buf *buf, const struct pivot_value *value)
         {
           put_byte (buf, 1);
           put_value_mod (buf, value, NULL);
-          put_format (buf, &value->numeric.format);
+          put_format (buf, &value->numeric.format, value->numeric.honor_small);
           put_double (buf, value->numeric.x);
         }
       break;
@@ -600,8 +646,11 @@ put_value (struct buf *buf, const struct pivot_value *value)
     case PIVOT_VALUE_STRING:
       put_byte (buf, 4);
       put_value_mod (buf, value, NULL);
-      put_format (buf,
-                  &(struct fmt_spec) { FMT_A, strlen (value->string.s), 0 });
+      size_t len = strlen (value->string.s);
+      if (value->string.hex)
+        put_format (buf, &(struct fmt_spec) { FMT_AHEX, len * 2, 0 }, false);
+      else
+        put_format (buf, &(struct fmt_spec) { FMT_A, len, 0 }, false);
       put_string (buf, value->string.value_label);
       put_string (buf, value->string.var_name);
       put_show_values (buf, value->string.show);
@@ -684,7 +733,7 @@ put_category (struct buf *buf, const struct pivot_category *c)
   else
     {
       put_bytes (buf, "\0\0\1", 3);
-      put_u32 (buf, 0);
+      put_u32 (buf, 0);         /* x23 */
       put_u32 (buf, -1);
       put_u32 (buf, c->n_subs);
       for (size_t i = 0; i < c->n_subs; i++)
@@ -695,9 +744,9 @@ put_category (struct buf *buf, const struct pivot_category *c)
 static void
 put_y0 (struct buf *buf, const struct pivot_table *table)
 {
-  put_u32 (buf, table->epoch);
-  put_byte (buf, table->decimal);
-  put_byte (buf, table->grouping);
+  put_u32 (buf, table->settings.epoch);
+  put_byte (buf, table->settings.decimal);
+  put_byte (buf, ',');
 }
 
 static void
@@ -705,22 +754,30 @@ put_custom_currency (struct buf *buf, const struct pivot_table *table)
 {
   put_u32 (buf, 5);
   for (int i = 0; i < 5; i++)
-    put_string (buf, table->ccs[i]);
+    {
+      enum fmt_type types[5] = { FMT_CCA, FMT_CCB, FMT_CCC, FMT_CCD, FMT_CCE };
+      char *cc = fmt_number_style_to_string (fmt_settings_get_style (
+                                               &table->settings, types[i]));
+      put_string (buf, cc);
+      free (cc);
+    }
 }
 
 static void
 put_x1 (struct buf *buf, const struct pivot_table *table)
 {
-  put_bytes (buf, "\0\1\0", 3);
-  put_byte (buf, 0);
+  put_byte (buf, 0);            /* x14 */
+  put_byte (buf, table->show_title ? 1 : 10);
+  put_byte (buf, 0);            /* x16 */
+  put_byte (buf, 0);            /* lang */
   put_show_values (buf, table->show_variables);
   put_show_values (buf, table->show_values);
-  put_u32 (buf, -1);
-  put_u32 (buf, -1);
+  put_u32 (buf, -1);            /* x18 */
+  put_u32 (buf, -1);            /* x19 */
   for (int i = 0; i < 17; i++)
     put_byte (buf, 0);
-  put_bool (buf, false);
-  put_byte (buf, 1);
+  put_bool (buf, false);        /* x20 */
+  put_byte (buf, table->show_caption);
 }
 
 static void
@@ -733,9 +790,8 @@ put_x2 (struct buf *buf)
 }
 
 static void
-put_x3 (struct buf *buf, const struct pivot_table *table)
+put_y1 (struct buf *buf, const struct pivot_table *table)
 {
-  put_bytes (buf, "\1\0\4\0\0\0", 6);
   put_string (buf, table->command_c);
   put_string (buf, table->command_local);
   put_string (buf, table->language);
@@ -743,6 +799,26 @@ put_x3 (struct buf *buf, const struct pivot_table *table)
   put_string (buf, table->locale);
   put_bytes (buf, "\0\0\1\1", 4);
   put_y0 (buf, table);
+}
+
+static void
+put_y2 (struct buf *buf, const struct pivot_table *table)
+{
+  put_custom_currency (buf, table);
+  put_byte (buf, '.');
+  put_bool (buf, 0);
+}
+
+static void
+put_x3 (struct buf *buf, const struct pivot_table *table)
+{
+  put_byte (buf, 1);
+  put_byte (buf, 0);
+  put_byte (buf, 4);            /* x21 */
+  put_byte (buf, 0);
+  put_byte (buf, 0);
+  put_byte (buf, 0);
+  put_y1 (buf, table);
   put_double (buf, table->small);
   put_byte (buf, 1);
   put_string (buf, table->dataset);
@@ -750,11 +826,7 @@ put_x3 (struct buf *buf, const struct pivot_table *table)
   put_u32 (buf, 0);
   put_u32 (buf, table->date);
   put_u32 (buf, 0);
-
-  /* Y2. */
-  put_custom_currency (buf, table);
-  put_byte (buf, '.');
-  put_bool (buf, 0);
+  put_y2 (buf, table);
 }
 
 static void
@@ -770,10 +842,10 @@ put_light_table (struct buf *buf, uint64_t table_id,
   put_bool (buf, table->rotate_outer_row_labels);
   put_bool (buf, true);
   put_u32 (buf, 0x15);
-  put_u32 (buf, table->sizing[H].range[0]);
-  put_u32 (buf, table->sizing[H].range[1]);
-  put_u32 (buf, table->sizing[V].range[0]);
-  put_u32 (buf, table->sizing[V].range[1]);
+  put_u32 (buf, table->look->width_ranges[H][0]);
+  put_u32 (buf, table->look->width_ranges[H][1]);
+  put_u32 (buf, table->look->width_ranges[V][0]);
+  put_u32 (buf, table->look->width_ranges[V][1]);
   put_u64 (buf, table_id);
 
   /* Titles. */
@@ -795,7 +867,7 @@ put_light_table (struct buf *buf, uint64_t table_id,
   /* Areas. */
   for (size_t i = 0; i < PIVOT_N_AREAS; i++)
     {
-      const struct table_area_style *a = &table->areas[i];
+      const struct table_area_style *a = &table->look->areas[i];
       put_byte (buf, i + 1);
       put_byte (buf, 0x31);
       put_string (buf, (a->font_style.typeface
@@ -838,7 +910,7 @@ put_light_table (struct buf *buf, uint64_t table_id,
   put_be32 (buf, PIVOT_N_BORDERS);
   for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
     {
-      const struct table_border_style *b = &table->borders[i];
+      const struct table_border_style *b = &table->look->borders[i];
       put_be32 (buf, i);
       put_be32 (buf, (b->stroke == TABLE_STROKE_NONE ? 0
                       : b->stroke == TABLE_STROKE_SOLID ? 1
@@ -858,14 +930,14 @@ put_light_table (struct buf *buf, uint64_t table_id,
   /* Print Settings. */
   uint32_t ps_start = start_count (buf);
   put_be32 (buf, 1);
-  put_bool (buf, table->print_all_layers);
-  put_bool (buf, table->paginate_layers);
-  put_bool (buf, table->shrink_to_fit[H]);
-  put_bool (buf, table->shrink_to_fit[V]);
-  put_bool (buf, table->top_continuation);
-  put_bool (buf, table->bottom_continuation);
-  put_be32 (buf, table->n_orphan_lines);
-  put_bestring (buf, table->continuation);
+  put_bool (buf, table->look->print_all_layers);
+  put_bool (buf, table->look->paginate_layers);
+  put_bool (buf, table->look->shrink_to_fit[H]);
+  put_bool (buf, table->look->shrink_to_fit[V]);
+  put_bool (buf, table->look->top_continuation);
+  put_bool (buf, table->look->bottom_continuation);
+  put_be32 (buf, table->look->n_orphan_lines);
+  put_bestring (buf, table->look->continuation);
   end_count_u32 (buf, ps_start);
 
   /* Table Settings. */
@@ -873,10 +945,10 @@ put_light_table (struct buf *buf, uint64_t table_id,
   put_be32 (buf, 1);
   put_be32 (buf, 4);
   put_be32 (buf, 0);            /* XXX current_layer */
-  put_bool (buf, table->omit_empty);
-  put_bool (buf, table->row_labels_in_corner);
-  put_bool (buf, !table->show_numeric_markers);
-  put_bool (buf, table->footnote_marker_superscripts);
+  put_bool (buf, table->look->omit_empty);
+  put_bool (buf, table->look->row_labels_in_corner);
+  put_bool (buf, !table->look->show_numeric_markers);
+  put_bool (buf, table->look->footnote_marker_superscripts);
   put_byte (buf, 0);
   uint32_t keep_start = start_count (buf);
   put_be32 (buf, 0);            /* n-row-breaks */
@@ -887,7 +959,7 @@ put_light_table (struct buf *buf, uint64_t table_id,
   put_be32 (buf, 0);            /* n-column-point-keeps */
   end_count_be32 (buf, keep_start);
   put_bestring (buf, table->notes);
-  put_bestring (buf, table->table_look);
+  put_bestring (buf, table->look->name);
   for (size_t i = 0; i < 82; i++)
     put_byte (buf, 0);
   end_count_u32 (buf, ts_start);
@@ -928,9 +1000,9 @@ put_light_table (struct buf *buf, uint64_t table_id,
     {
       const struct pivot_dimension *d = table->dimensions[i];
       put_value (buf, d->root->name);
-      put_byte (buf, 0);
+      put_byte (buf, 0);        /* x1 */
       put_byte (buf, x2[i]);
-      put_u32 (buf, 2);
+      put_u32 (buf, 2);         /* x3 */
       put_bool (buf, !d->root->show_label);
       put_bool (buf, d->hide_all_labels);
       put_bool (buf, 1);
@@ -982,14 +1054,9 @@ spv_writer_put_table (struct spv_writer *w, const struct pivot_table *table)
 
   start_container (w);
 
-  char *title = pivot_value_to_string (table->title,
-                                       SETTINGS_VALUE_SHOW_DEFAULT,
-                                       SETTINGS_VALUE_SHOW_DEFAULT);
-
-  char *subtype = pivot_value_to_string (table->subtype,
-                                         SETTINGS_VALUE_SHOW_DEFAULT,
-                                         SETTINGS_VALUE_SHOW_DEFAULT);
-
+  char *title = pivot_value_to_string (table->title, table);
+  char *subtype = pivot_value_to_string (table->subtype, table);
+  
   start_elem (w, "label");
   write_text (w, title);
   end_elem (w);