1 #include "config.h"
2 #include <gegl-plugin.h>
3 
4 static GList *
gegl_operations_build(GList * list,GType type)5 gegl_operations_build (GList *list, GType type)
6 {
7   GeglOperationClass *klass;
8   GType *ops;
9   guint  children;
10   gint   no;
11 
12   if (!type)
13     return list;
14 
15   klass = g_type_class_ref (type);
16   if (klass->name != NULL)
17     list = g_list_prepend (list, klass);
18 
19   ops = g_type_children (type, &children);
20 
21   for (no=0; no<children; no++)
22     {
23       list = gegl_operations_build (list, ops[no]);
24     }
25   if (ops)
26     g_free (ops);
27   return list;
28 }
29 
compare_operation_names(gconstpointer a,gconstpointer b)30 static gint compare_operation_names (gconstpointer a,
31                                      gconstpointer b)
32 {
33   const GeglOperationClass *klassA, *klassB;
34 
35   klassA = a;
36   klassB = b;
37 
38   return strcmp (klassA->name, klassB->name);
39 }
40 
gegl_operations(void)41 static GList *gegl_operations (void)
42 {
43   static GList *operations = NULL;
44   if (!operations)
45     {
46       operations = gegl_operations_build (NULL, GEGL_TYPE_OPERATION);
47       operations = g_list_sort (operations, compare_operation_names);
48     }
49   return operations;
50 }
51 
52 GeglColor *
53 gegl_param_spec_color_get_default (GParamSpec *self);
54 
55 /* convert operation name to path of example image */
56 static gchar*
operation_to_path(const gchar * op_name)57 operation_to_path (const gchar *op_name)
58 {
59   gchar *cleaned = g_strdup (op_name);
60   gchar *filename, *output_path;
61 
62   g_strdelimit (cleaned, ":", '-');
63   filename = g_strconcat (cleaned, ".png", NULL);
64   output_path = g_build_path (G_DIR_SEPARATOR_S, "images", "examples", filename, NULL);
65 
66   g_free (cleaned);
67   g_free (filename);
68 
69   return output_path;
70 }
71 
json_escape_string(const char * description)72 static void json_escape_string (const char *description)
73 {
74   const char *p;
75   if (!description)
76     return;
77   for (p = description; *p; p++)
78   {
79     switch (*p)
80     {
81       case '"':
82       case '\\':
83       case '/':
84         g_print ("\\%c", *p);
85         break;
86       case '\n':
87         g_print ("\\n");
88         break;
89       default:
90         g_print ("%c", *p);
91     }
92   }
93 }
94 
95 static void
json_list_pads(GType type,const gchar * opname)96 json_list_pads (GType type, const gchar *opname)
97 {
98   GeglNode *gegl = gegl_node_new ();
99   GeglNode *node = gegl_node_new_child (gegl,
100                             "operation", opname,
101                             NULL);
102   gchar **input_pads;
103   gchar **output_pads;
104 
105   int i;
106 
107   input_pads = gegl_node_list_input_pads (node);
108   output_pads = gegl_node_list_output_pads (node);
109 
110   if (input_pads && input_pads[0])
111   {
112     gboolean first = TRUE;
113     g_print (" ,'input-pads':[\n");
114     for (i = 0; input_pads[i]; i++)
115     {
116       if (first)
117       {
118         first = FALSE;
119       }
120       else
121       g_print (",");
122 
123       g_print ("'%s'\n", input_pads[i]);
124     }
125     g_print (" ]");
126     g_free (input_pads);
127   }
128 
129   if (output_pads && output_pads[0])
130   {
131     gboolean first = TRUE;
132     g_print (" ,'output-pads':[\n");
133     for (i = 0; output_pads[i]; i++)
134     {
135       if (first)
136       {
137         first = FALSE;
138       }
139       else
140       g_print (",");
141 
142       g_print ("'%s'\n", output_pads[i]);
143     }
144     g_print (" ]");
145     g_free (output_pads);
146   }
147 
148   g_object_unref (gegl);
149 }
150 
151 static void
json_list_properties(GType type,const gchar * opname)152 json_list_properties (GType type, const gchar *opname)
153 {
154   GParamSpec **self;
155   GParamSpec **parent;
156   guint n_self;
157   guint n_parent;
158   gint prop_no;
159   gboolean first_prop = TRUE;
160 
161   g_print (",'properties':[\n");
162 
163   if (!type)
164     return;
165 
166   self = g_object_class_list_properties (
167             G_OBJECT_CLASS (g_type_class_ref (type)),
168             &n_self);
169   parent = g_object_class_list_properties (
170             /*G_OBJECT_CLASS (g_type_class_peek_parent (g_type_class_ref (type))),*/
171             G_OBJECT_CLASS (g_type_class_ref (GEGL_TYPE_OPERATION)),
172             &n_parent);
173 
174 
175   for (prop_no=0;prop_no<n_self;prop_no++)
176     {
177       gint parent_no;
178       gboolean found=FALSE;
179       for (parent_no=0;parent_no<n_parent;parent_no++)
180         if (self[prop_no]==parent[parent_no])
181           found=TRUE;
182       /* only print properties if we are an addition compared to
183        * GeglOperation
184        */
185       if (!found)
186         {
187           const gchar *type_name = g_type_name (G_OBJECT_TYPE (self[prop_no]));
188 
189           if (first_prop)
190           {
191             first_prop = FALSE;
192             g_print(" { 'name':'%s'\n", g_param_spec_get_name (self[prop_no]));
193           }
194           else
195             g_print(",{'name':'%s'\n", g_param_spec_get_name (self[prop_no]));
196 
197           g_print("  ,'label':\"");
198             json_escape_string (g_param_spec_get_nick (self[prop_no]));
199           g_print ("\"\n");
200 
201           if(strstr (type_name, "Param"))
202           {
203             type_name = strstr (type_name, "Param");
204             type_name+=5;
205           }
206 
207           g_print("  ,'type':'");
208           {
209             for (const char *p = type_name; *p; p++)
210               g_print("%c", g_ascii_tolower (*p));
211           }
212           g_print("'\n");
213 
214           if (g_type_is_a (G_PARAM_SPEC_VALUE_TYPE (self[prop_no]), G_TYPE_DOUBLE))
215             {
216               gdouble default_value = G_PARAM_SPEC_DOUBLE (self[prop_no])->default_value;
217               gdouble min = G_PARAM_SPEC_DOUBLE (self[prop_no])->minimum;
218               gdouble max = G_PARAM_SPEC_DOUBLE (self[prop_no])->maximum;
219 
220               if (default_value<-10000000)
221                 g_print ("  ,'default':'-inf'\n");
222               else if (default_value>10000000)
223                 g_print ("  ,'default':'+inf'\n");
224               else
225                 g_print ("  ,'default':'%2.2f'\n", default_value);
226 
227               if (min<-10000000)
228                 g_print ("  ,'minimum':'-inf'\n");
229               else
230                 g_print ("  ,'minimum':'%2.2f'\n", min);
231 
232               if (max>10000000)
233                 g_print ("  ,'maximum':'+inf'\n");
234               else
235                 g_print ("  ,'maximum':'%2.2f'\n", max);
236 
237               if (GEGL_IS_PARAM_SPEC_DOUBLE (self[prop_no]))
238               {
239                 GeglParamSpecDouble *pspec =
240                               GEGL_PARAM_SPEC_DOUBLE (self[prop_no]);
241 
242                 if (pspec->ui_minimum < -10000000)
243                   g_print ("  ,'ui-minimum':'-inf'\n");
244                 else
245                   g_print ("  ,'ui-minimum':'%2.2f'\n", pspec->ui_minimum);
246 
247                 if (pspec->ui_maximum > 10000000)
248                   g_print ("  ,'ui-maximum':'+inf'\n");
249                 else
250                   g_print ("  ,'ui-maximum':'%2.2f'\n", pspec->ui_maximum);
251 
252                 g_print ("  ,'ui-gamma':'%2.2f'\n", pspec->ui_gamma);
253                 g_print ("  ,'ui-step-small':'%2.2f'\n", pspec->ui_step_small);
254                 g_print ("  ,'ui-step-big':'%2.2f'\n", pspec->ui_step_big);
255                 g_print ("  ,'ui-digits':'%i'\n", pspec->ui_digits);
256               }
257 
258             }
259           else if (g_type_is_a (G_PARAM_SPEC_VALUE_TYPE (self[prop_no]), G_TYPE_INT))
260             {
261               gint default_value = G_PARAM_SPEC_INT (self[prop_no])->default_value;
262               gint min = G_PARAM_SPEC_INT (self[prop_no])->minimum;
263               gint max = G_PARAM_SPEC_INT (self[prop_no])->maximum;
264 
265               if (default_value<-10000000)
266                 g_print ("  ,'default':'-inf'\n");
267               else if (default_value>10000000)
268                 g_print ("  ,'default':'+inf'\n");
269               else
270                 g_print ("  ,'default':'%i'\n", default_value);
271 
272               if (min<-10000000)
273                 g_print ("  ,'minimum':'-inf'\n");
274               else
275                 g_print ("  ,'minimum':'%i'\n", min);
276 
277               if (max>10000000)
278                 g_print ("  ,'maximum':'+inf'\n");
279               else
280                 g_print ("  ,'maximum':'%i'\n", max);
281 
282               if (GEGL_IS_PARAM_SPEC_INT (self[prop_no]))
283               {
284                 GeglParamSpecInt *pspec =
285                               GEGL_PARAM_SPEC_INT (self[prop_no]);
286 
287                 if (pspec->ui_minimum < -10000000)
288                   g_print ("  ,'ui-minimum':'-inf'\n");
289                 else
290                   g_print ("  ,'ui-minimum':'%i'\n", pspec->ui_minimum);
291 
292                 if (pspec->ui_maximum > 10000000)
293                   g_print ("  ,'ui-maximum':'+inf'\n");
294                 else
295                   g_print ("  ,'ui-maximum':'%i'\n", pspec->ui_maximum);
296 
297                 g_print ("  ,'ui-gamma':'%2.2f'\n", pspec->ui_gamma);
298                 g_print ("  ,'ui-step-small':'%i'\n", pspec->ui_step_small);
299                 g_print ("  ,'ui-step-big':'%i'\n", pspec->ui_step_big);
300               }
301 
302             }
303           else if (g_type_is_a (G_PARAM_SPEC_VALUE_TYPE (self[prop_no]), G_TYPE_BOOLEAN))
304             {
305               g_print ("  ,'default':'%s'\n", G_PARAM_SPEC_BOOLEAN (self[prop_no])->default_value?"True":"False");
306             }
307           else if (g_type_is_a (G_PARAM_SPEC_VALUE_TYPE (self[prop_no]), G_TYPE_STRING))
308             {
309               const gchar *string = G_PARAM_SPEC_STRING (self[prop_no])->default_value;
310 
311               g_print ("  ,'default':\"");
312               json_escape_string (string);
313               g_print ("\"\n");
314 
315             }
316           else if (g_type_is_a (G_PARAM_SPEC_VALUE_TYPE (self[prop_no]), GEGL_TYPE_COLOR))
317             {
318               GeglColor *color = gegl_param_spec_color_get_default (self[prop_no]);
319               if (color)
320                 {
321                   gchar *string;
322 
323                   g_object_get (color, "string", &string, NULL);
324                   g_print ("  ,'default':\"");
325                   json_escape_string (string);
326                   g_print ("\"\n");
327                   g_free (string);
328                 }
329             }
330           else
331             {
332             }
333 
334           if (g_param_spec_get_blurb (self[prop_no]) &&
335               g_param_spec_get_blurb (self[prop_no])[0]!='\0')
336           {
337             g_print ("  ,'description':\"");
338 
339             json_escape_string (g_param_spec_get_blurb (self[prop_no]));
340             g_print ("\"\n");
341           }
342 
343       {
344         guint count;
345         gchar **property_keys = gegl_operation_list_property_keys (
346             opname,
347             g_param_spec_get_name (self[prop_no]),
348 
349             &count);
350 
351         if (property_keys)
352         {
353           int i;
354           if (property_keys[0])
355           {
356             /* XXX: list is in reverse order */
357             for (i = 0; property_keys[i]; i++)
358             {
359               g_print ("  ,'%s':'%s'\n",
360                     property_keys[i],
361                     gegl_operation_get_property_key (opname,
362                                       g_param_spec_get_name (self[prop_no]),
363                                                 property_keys[i]));
364             }
365           }
366           g_free (property_keys);
367         }
368       }
369 
370           g_print(" }");
371         }
372     }
373   if (self)
374     g_free (self);
375   if (parent)
376     g_free (parent);
377   g_print ("]");
378 }
379 
380 gint
main(gint argc,gchar ** argv)381 main (gint argc, gchar **argv)
382 {
383   GList      *operations;
384   GList      *iter;
385   gboolean first = TRUE;
386 
387   gegl_init (&argc, &argv);
388 
389   g_object_set (gegl_config (),
390                 "application-license", "GPL3",
391                 NULL);
392 
393 
394   operations = gegl_operations ();
395 
396   g_print ("window.opdb=[\n");
397 
398   for (iter=operations;iter;iter = g_list_next (iter))
399     {
400       GeglOperationClass *klass = iter->data;
401 
402       const char *name = gegl_operation_class_get_key (klass, "name");
403       const char *categoris = gegl_operation_class_get_key (klass, "categories");
404 
405       if (first)
406         first = FALSE;
407       else
408         g_print (",");
409 
410       g_print ("{'op':'%s'\n", name);
411 
412       if (klass->compat_name)
413         g_print (",'compat-op':'%s'\n", klass->compat_name);
414 
415       if (klass->opencl_support)
416         g_print (",'opencl-support':'true'\n");
417 
418       g_print (",'parent':'%s'\n",
419           g_type_name (g_type_parent(G_OBJECT_CLASS_TYPE(klass))));
420 
421       {
422         char *image = operation_to_path (name);
423 
424         if (g_file_test (image, G_FILE_TEST_EXISTS))
425           g_print (",'image':'%s'\n", image);
426         g_free (image);
427       }
428 
429       {
430         gchar *commandline = g_strdup_printf (
431             "sh -c \"(cd " TOP_SRCDIR ";grep -r '\\\"%s\\\"' operations) | grep operations | grep -v '~:' | grep '\\\"name\\\"' | cut -f 1 -d ':'\"",
432              name);
433         gchar *output = NULL;
434 
435         if (g_spawn_command_line_sync (commandline, &output, NULL, NULL, NULL))
436         {
437           if (strlen(output))
438             {
439               output[strlen(output)-1] = 0;
440               g_print (
441       ",'source':'https://git.gnome.org/browse/gegl/tree/%s'\n", output);
442             }
443           g_free (output);
444         }
445 
446         g_free (commandline);
447       }
448 
449       if (categoris)
450       {
451         const gchar *ptr = categoris;
452           gboolean first = TRUE;
453         g_print (",'categories':[");
454 
455         while (ptr && *ptr)
456           {
457             gchar category[64]="";
458             gint i=0;
459             while (*ptr && *ptr!=':' && i<63)
460               {
461                 category[i++]=*(ptr++);
462                 category[i]='\0';
463               }
464             if (*ptr==':')
465               ptr++;
466             {
467               if (first)
468                 first = FALSE;
469               else
470                 g_print (",");
471               g_print ("'%s'", category);
472             }
473           }
474         g_print ("]\n");
475       }
476 
477       json_list_properties (G_OBJECT_CLASS_TYPE (klass), name);
478       json_list_pads (G_OBJECT_CLASS_TYPE (klass), name);
479 
480       {
481         guint nkeys;
482         gchar **keys = gegl_operation_list_keys (name, &nkeys);
483 
484         if (keys)
485           {
486             for (gint i = 0; keys[i]; i++)
487               {
488                 const gchar *value = gegl_operation_get_key (name, keys[i]);
489 
490                 if (g_str_equal (keys[i], "categories") ||
491                     g_str_equal (keys[i], "cl-source") ||
492                     g_str_equal (keys[i], "source") ||
493                     g_str_equal (keys[i], "name")
494                     )
495                   continue;
496 
497                 g_print (",\"%s\":\"", keys[i]);
498                 json_escape_string (value);
499                 g_print ("\"\n");
500               }
501             g_free (keys);
502           }
503       }
504 
505       g_print (" }\n");
506     }
507   g_print ("]\n");
508 
509   return 0;
510 }
511