Witiko
Witiko

Reputation: 3397

Passing an array to a GIMP module via Script-Fu

Minimal Working Example

I am attempting to pass an array of integers to a GIMP plugin using the Scheme Script-Fu interface. I have a source code file named main.c with the following content:

#include <libgimp/gimp.h>
#include <stdlib.h>
#include <stdio.h>

static void query (void);

static void run (
    const gchar *name,
    gint nparams,
    const GimpParam *param,
    gint *nreturn_vals,
    GimpParam **return_vals
);

const GimpPlugInInfo PLUG_IN_INFO = {
    NULL,  /* init_proc  */
    NULL,  /* quit_proc  */
    query, /* query_proc */
    run,   /* run_proc   */
};

MAIN ()

static void query (void)
{
    static GimpParamDef args[] = {
    {
      GIMP_PDB_INT32,
      "run-mode",
      "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }"
    },
    {
      GIMP_PDB_INT8ARRAY,
      "an array",
      ""
      "an array"
      }
    };

    gimp_install_procedure (
        "my-test-plugin",
        "My test plug-in",
        "Description",
        "Jane Doe <[email protected]>",
        "Copyright (C) Jane Doe\n"
        "http://foo.bar",
        "2017",
        g_strconcat("My test plug-in", "...", NULL),
        "RGB*, GRAY*",
        GIMP_PLUGIN,
        G_N_ELEMENTS (args),
        0,
        args, 
        NULL
    );
}

static void run (
    const gchar *name,
    gint nparams,
    const GimpParam *param,
    gint *nreturn_vals,
    GimpParam **return_vals)
{
    static GimpParam value;
    value.type = GIMP_PDB_STATUS;
    value.data.d_status = GIMP_PDB_SUCCESS;
    *nreturn_vals = 1;
    *return_vals = &value;

    FILE* out = fopen("mylog.log", "w");
    fprintf(out, "Parameter #0:\t%d\nParameter #1:\t", param[0].data.d_int32);
    for (int i = 0; i < 16; ++i)
        fprintf(out, "%d ", param[1].data.d_int8array[i]);
    fprintf(out, "\n");
    fclose(out);
}

I compile and install the file as a GIMP plugin on as follows:

sudo apt install libgimp2.0-dev
gcc `gimptool-2.0 --cflags --libs` main.c
gimptool-2.0 --install-bin ./a.out

I am doing this on a Debian 9 box. When I attempt to run the plugin using the Script-Fu interface:

(my-test-plugin 1 #(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16))

Calling the plugin via Script-Fu

a file named mylog.log gets created with the following content:

Parameter #0:   1
Parameter #1:   1 0 0 0 0 0 0 0 64 201 246 126 174 85 0 0

whereas the following is the expected content:

Parameter #0:   1
Parameter #1:   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

The Real-World Version

I am attempting to use the gimp-plugin-morphop GIMP plugin using the Scheme Script-Fu interface. When I use the GUI, the plugin works as expected:

Hit-or-Miss via GUI #1 Hit-or-Miss via GUI #1

However, when I use the following Script-Fu script:

(plug-in-morphop RUN-NONINTERACTIVE 1 2 6 7
  #(-1 -1 -1 -1 -1 -1 -1
    -1  1 -1 -1 -1  1 -1
    -1 -1  0  0  0 -1 -1
    -1 -1  0  0  0 -1 -1
    -1 -1  0  0  0 -1 -1
    -1  1 -1 -1 -1  1 -1
    -1 -1 -1 -1 -1 -1 -1) 24 2)

the plugin does not produce the expected result:

Hit-or-Miss via Script-Fu #1 Hit-or-Miss via Script-Fu #1

I modified the plugin to see what the actual difference was:

diff --git a/src/morphop-algorithms.c b/src/morphop-algorithms.c
index b927ba3..9dff320 100644
--- a/src/morphop-algorithms.c
+++ b/src/morphop-algorithms.c
@@ -166,7 +166,16 @@ void start_operation(GimpDrawable *drawable, GimpPreview *preview, MorphOpSettin
                GimpPixelRgn src_rgn_c, dst_rgn_c;
                guchar* src_preview_c = NULL, *dst_preview_c = NULL;

+               FILE* log = fopen("morphop-operation.log", "w");
                int i, j;
+               for(i = 0; i < STRELEM_DEFAULT_SIZE; i++) {
+                       for(j = 0; j < STRELEM_DEFAULT_SIZE; j++) {
+                               fprintf(log, "%d ", settings.element.matrix[i][j]);
+                       }
+                       fprintf(log, "\n");
+               }
+               fclose(log);
+
                // white structuring element
                for(i = 0; i < STRELEM_DEFAULT_SIZE; i++) {
                        for(j = 0; j < STRELEM_DEFAULT_SIZE; j++) {

After using the module through the GUI, the morphop-operation.log file contains the following text:

-1 -1 -1 -1 -1 -1 -1 
-1 1 -1 -1 -1 1 -1 
-1 -1 0 0 0 -1 -1 
-1 -1 0 0 0 -1 -1 
-1 -1 0 0 0 -1 -1 
-1 1 -1 -1 -1 1 -1 
-1 -1 -1 -1 -1 -1 -1

as expected. After running the Script-Fu code, the morphop-operation.log file contains the following text:

-1 0 0 86 0 103 114 
-1 64 0 0 0 45 112 
-1 41 64 0 0 105 104 
-1 8 42 33 0 110 111 
-1 95 8 0 112 45 112 
-1 36 95 0 108 109 0 
-1 86 36 0 117 111 32 

where the rightmost six integers on each row appear to be random garbage that changes at every invocation. Since settings.element.matrix is already an internal representation of the received array, I modified the plugin a little further to display the received array directly:

diff --git a/src/morphop.c b/src/morphop.c
index 3895770..cb814b6 100644
--- a/src/morphop.c
+++ b/src/morphop.c
@@ -150,9 +150,16 @@ static void run (
                                }

                                msettings.operator = param[3].data.d_int32;
-                               
+                       
+                               FILE* log = fopen("morphop-init.log", "w");
                                int i;
                                for (i = 0; i < STRELEM_DEFAULT_SIZE * STRELEM_DEFAULT_SIZE; i++) {
+                                       fprintf(log, "%d ", param[5].data.d_int8array[i]);
+                               }
+                               fprintf(log, "\n");
+                               fclose(log);
+
+                               for (i = 0; i < STRELEM_DEFAULT_SIZE * STRELEM_DEFAULT_SIZE; i++) {
                                        msettings.element.matrix[i % STRELEM_DEFAULT_SIZE][(int)ceil((i + 1.0) / STRELEM_DEFAULT_SIZE) - 1] = param[5].data.d_int8array[i];
                                }

After running the Script-Fu code, the morphop-init.log file contains the following text:

255 255 255 255 255 255 255 0 64 169 248 158 193 85 0 0 64 170 248 158 193 85 0 0 33 0 0 0 0 0 0 0 112 108 117 103 45 105 110 45 109 111 114 112 104 111 112 0 32 

The values beyond the eighth appear to be random garbage, although some retain their value across several runs:

255 255 255 255 255 255 255 0 64 89 10 89 79 86 0 0 64 90 10 89 79 86 0 0 33 0 0 0 0 0 0 0 112 108 117 103 45 105 110 45 109 111 114 112 104 111 112 0 32 
255 255 255 255 255 255 255 0 64 217 110 172 167 85 0 0 64 218 110 172 167 85 0 0 33 0 0 0 0 0 0 0 112 108 117 103 45 105 110 45 109 111 114 112 104 111 112 0 32 

To me this signifies that the array is passed in a different format that the one expected by the plug-in. How do I pass an array into a GIMP plug-in via Script-Fu, so that it stays intact?

Upvotes: 2

Views: 912

Answers (1)

lossleader
lossleader

Reputation: 13495

Within the API, it is necessary to pass the size of the array before the array.

--- /tmp/plugin.orig    2017-04-02 16:45:34.902108610 +0200
+++ /tmp/plugin.c   2017-04-02 16:43:26.510105281 +0200
@@ -30,6 +30,11 @@
       "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }"
     },
     {
+      GIMP_PDB_INT32,
+      "array-size",
+      "The array bellow"
+    },
+    {
       GIMP_PDB_INT8ARRAY,
       "an array",
       ""
@@ -69,9 +74,9 @@
     *return_vals = &value;

     FILE* out = fopen("mylog.log", "w");
-    fprintf(out, "Parameter #0:\t%d\nParameter #1:\t", param[0].data.d_int32);
+    fprintf(out, "Parameter #0:\t%d\nParameter #2:\t", param[0].data.d_int32);
     for (int i = 0; i < 16; ++i)
-        fprintf(out, "%d ", param[1].data.d_int8array[i]);
+        fprintf(out, "%d ", param[2].data.d_int8array[i]);
     fprintf(out, "\n");
     fclose(out);
 }

Then:

 > (my-test-plugin 1 16 #(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16))
 (#t)

Results in:

$ cat mylog.log 
Parameter #0:   1
Parameter #2:   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

And you can verify the parameters are implicitly linked by making the size larger than the length:

> (my-test-plugin 1 17 #(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15))
Error: ( : 1) INT8 vector (argument 3) for function my-test-plugin has
size of 15 but expected size of 17

(The preceding parameter being RUN-NONINTERACTIVE (1) or element-size (7), explains the differing amounts of available array contents in your 2 tests.)

Upvotes: 1

Related Questions