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