[gegl] npy: Port npy-save operation to GIO
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] npy: Port npy-save operation to GIO
- Date: Sat, 29 Apr 2017 16:52:14 +0000 (UTC)
commit 684c18fbfb21ca53cf3d266b1b1469b63ad3e5ea
Author: Martin Blanchard <tchaik gmx com>
Date: Sat Jun 4 18:05:15 2016 +0200
npy: Port npy-save operation to GIO
Make use of gegl_gio_open_output_stream() service. No more direct
fopen() call for output.
https://bugzilla.gnome.org/show_bug.cgi?id=764005
operations/external/npy-save.c | 215 +++++++++++++++++++++++++++-------------
1 files changed, 145 insertions(+), 70 deletions(-)
---
diff --git a/operations/external/npy-save.c b/operations/external/npy-save.c
index e4016e9..89d7bc8 100644
--- a/operations/external/npy-save.c
+++ b/operations/external/npy-save.c
@@ -29,7 +29,7 @@
#ifdef GEGL_PROPERTIES
property_file_path (path, _("File"), "")
- description (_("Target path and filename, use '-' for stdout."))
+ description (_("Target path and filename, use '-' for stdout"))
#else
@@ -37,93 +37,169 @@ property_file_path (path, _("File"), "")
#define GEGL_OP_NAME npy_save
#define GEGL_OP_C_SOURCE npy-save.c
-#include "gegl-op.h"
-#include <stdio.h>
+#include <gegl-op.h>
+#include <gegl-gio-private.h>
+#include <string.h>
-static int npywrite_header(FILE *fp, int width, int height, int num_channels)
+static gsize
+write_to_stream (GOutputStream *stream,
+ const gchar* data,
+ gsize size)
+{
+ GError *error = NULL;
+ gboolean success;
+ gsize written;
+
+ g_assert (stream);
+
+ success = g_output_stream_write_all (G_OUTPUT_STREAM (stream),
+ (const void *) data, size, &written,
+ NULL, &error);
+ if (!success || error != NULL)
+ {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ return 0;
+ }
+
+ return written;
+}
+
+static gint
+write_header (GOutputStream *stream,
+ gint width,
+ gint height,
+ gint nb_components,
+ gint bytes_per_pixel)
{
- const gchar* format;
- gsize header_len;
gchar *header;
+ gsize length;
+
+ // Write header and version number (1.0)
+ write_to_stream (stream, "\x93NUMPY\x01\x00", 8);
- // Write header and version number to file
- fwrite("\223NUMPY"
- "\001\000"
- , 1, 8, fp);
-
-
- if (num_channels == 3)
- format = "{'descr': '<f4', 'fortran_order': False, 'shape': (%d, %d, 3), } \n";
+ if (nb_components == 3)
+ {
+ header = g_strdup_printf ("{'descr': '<f4', 'fortran_order': False,"
+ " 'shape': (%d, %d, 3), } \n", height, width);
+ }
else
- format = "{'descr': '<f4', 'fortran_order': False, 'shape': (%d, %d), } \n";
-
- header = g_strdup_printf(format, height, width);
- header_len = strlen(header);
- fwrite(&header_len, 2, 1, fp);
- fwrite(header, header_len, 1, fp);
- g_free(header);
-
+ {
+ header = g_strdup_printf ("{'descr': '<f4', 'fortran_order': False,"
+ " 'shape': (%d, %d), } \n", height, width);
+ }
+
+ length = strlen (header);
+
+ write_to_stream (stream, (const char *) &length, 2);
+ write_to_stream (stream, header, length);
+
+ g_free (header);
+ return 0;
+}
+
+static gint
+save_array (GOutputStream *stream,
+ GeglBuffer *input,
+ const GeglRectangle *result,
+ const Babl *format)
+{
+ gint bytes_per_pixel, bytes_per_row;
+ gint x = result->x, y = result->y;
+ gint width = result->width - result->x;
+ gint height = result->height - result->y;
+ gint column_stride = 32;
+ gchar *buffer;
+ gint nb_components ,row;
+
+ nb_components = babl_format_get_n_components (format);
+ bytes_per_pixel = babl_format_get_bytes_per_pixel (format);
+
+ write_header (stream, width, height, nb_components, bytes_per_pixel);
+
+ bytes_per_row = bytes_per_pixel * width;
+
+ buffer = g_try_new (gchar, bytes_per_row * column_stride);
+
+ g_assert (buffer != NULL);
+
+ for (row = 0; row < height; row += column_stride)
+ {
+ GeglRectangle tile = { x, 0, width, 0 };
+
+ tile.y = y + row;
+ tile.height = MIN (column_stride, height - row);
+
+ gegl_buffer_get (input, &tile, 1.0, format, buffer,
+ GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+ write_to_stream (stream, buffer, bytes_per_row * tile.height);
+ }
+
+ g_free (buffer);
return 0;
}
static gboolean
-process (GeglOperation *operation,
- GeglBuffer *input,
- const GeglRectangle *rect,
- gint level)
+export_numpy (GeglOperation *operation,
+ GeglBuffer *input,
+ const GeglRectangle *result,
+ GOutputStream *stream)
{
- GeglProperties *o = GEGL_PROPERTIES (operation);
+ const Babl *input_format, *output_format;
+ gint nb_components;
- FILE *fp;
- guchar *data;
- gsize bpc;
- gsize numbytes_scanline;
- gsize numchannels;
- gboolean ret = FALSE;
- gint row;
- gint slice_thickness = 32;
- const Babl *output_format;
- const Babl *input_format = gegl_buffer_get_format(input);
-
- // Get the current format and use it to decide whether to save
- // the output in color or gray level formats.
- bpc = sizeof(gfloat);
- if (babl_format_get_n_components(input_format) >= 3)
+ input_format = gegl_buffer_get_format (input);
+ nb_components = babl_format_get_n_components (input_format);
+ if (nb_components >= 3)
{
- numchannels = 3;
- output_format = babl_format("RGB float");
+ output_format = babl_format ("RGB float");
+ nb_components = 3;
}
else
{
- numchannels = 1;
output_format = babl_format ("Y float");
+ nb_components = 1;
}
- numbytes_scanline = rect->width * numchannels * bpc;
-
- fp = (!strcmp (o->path, "-") ? stdout : fopen(o->path, "wb") );
+ return !save_array (stream, input, result, output_format);
+}
- npywrite_header(fp, rect->width, rect->height, numchannels);
+static gboolean
+process (GeglOperation *operation,
+ GeglBuffer *input,
+ const GeglRectangle *result,
+ gint level)
+{
+ GeglProperties *o = GEGL_PROPERTIES (operation);
+ GOutputStream *stream;
+ GFile *file = NULL;
+ GError *error = NULL;
+ gboolean status = TRUE;
- data = g_malloc (numbytes_scanline * slice_thickness);
-
- for (row=0; row < rect->height; row+= slice_thickness)
+ stream = gegl_gio_open_output_stream (NULL, o->path, &file, &error);
+ if (stream == NULL)
{
- GeglRectangle rect_slice;
- rect_slice.x = rect->x;
- rect_slice.width = rect->width;
- rect_slice.y = rect->y+row;
- rect_slice.height = MIN(slice_thickness, rect->height-row);
-
- gegl_buffer_get (input, &rect_slice, 1.0, output_format, data,
- GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+ status = FALSE;
+ g_warning ("%s", error->message);
+ goto cleanup;
+ }
- fwrite(data, numbytes_scanline, rect_slice.height, fp);
+ if (!export_numpy (operation, input, result, stream))
+ {
+ status = FALSE;
+ g_warning ("could not export NumPy file");
+ goto cleanup;
}
- g_free (data);
+cleanup:
+ if (stream != NULL)
+ g_object_unref (stream);
+
+ if (file != NULL)
+ g_object_unref (file);
- return ret;
+ return status;
}
static void
@@ -135,16 +211,15 @@ gegl_op_class_init (GeglOpClass *klass)
operation_class = GEGL_OPERATION_CLASS (klass);
sink_class = GEGL_OPERATION_SINK_CLASS (klass);
- sink_class->process = process;
+ sink_class->process = process;
sink_class->needs_full = TRUE;
gegl_operation_class_set_keys (operation_class,
- "name", "gegl:npy-save",
- "title", _("NPY File Saver"),
- "categories", "output",
- "description",
- _("NPY image saver (Numerical python file saver.)"),
- NULL);
+ "name", "gegl:npy-save",
+ "title", _("NumPy File Saver"),
+ "categories", "output",
+ "description", _("NumPy (Numerical Python) image saver"),
+ NULL);
gegl_operation_handlers_register_saver (
".npy", "gegl:npy-save");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]