2
# -*- mode: python py-indent-offset: 2; indent-tabs-mode: nil -*-
4
# Gimp image compositing
5
# Copyright (C) 2003 Helvetix Victorinox, <helvetix@gimp.org>
7
# This program is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 2 of the License, or
10
# (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with this program; if not, write to the Free Software
19
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30
# This programme creates C code for gluing a collection of compositing
31
# functions into an array indexed by compositing function, and the
32
# pixel formats of its arguments.
34
# I make some assuptions about the names of the compositing functions.
36
# I look into the namespace of a set of object files and figure out
37
# from them what compositing functions are implemented. This let's me
38
# build a table with the right cells populated with either the special
39
# compositing functions, or to use a generically implemented
40
# compositing function.
43
# These are in the same order as they appear in the
44
# ./app/base/base-enums.h GimpLayerModeEffects enumeration, because we
45
# (probably unwisely) use the value of the enumeration as an index
48
# XXX I'd like some python functions that let me rummage around in C code....
51
"GIMP_COMPOSITE_NORMAL",
52
"GIMP_COMPOSITE_DISSOLVE",
53
"GIMP_COMPOSITE_BEHIND",
54
"GIMP_COMPOSITE_MULTIPLY",
55
"GIMP_COMPOSITE_SCREEN",
56
"GIMP_COMPOSITE_OVERLAY",
57
"GIMP_COMPOSITE_DIFFERENCE",
58
"GIMP_COMPOSITE_ADDITION",
59
"GIMP_COMPOSITE_SUBTRACT",
60
"GIMP_COMPOSITE_DARKEN",
61
"GIMP_COMPOSITE_LIGHTEN",
63
"GIMP_COMPOSITE_SATURATION",
64
"GIMP_COMPOSITE_COLOR_ONLY",
65
"GIMP_COMPOSITE_VALUE",
66
"GIMP_COMPOSITE_DIVIDE",
67
"GIMP_COMPOSITE_DODGE",
68
"GIMP_COMPOSITE_BURN",
69
"GIMP_COMPOSITE_HARDLIGHT",
70
"GIMP_COMPOSITE_SOFTLIGHT",
71
"GIMP_COMPOSITE_GRAIN_EXTRACT",
72
"GIMP_COMPOSITE_GRAIN_MERGE",
73
"GIMP_COMPOSITE_COLOR_ERASE",
74
"GIMP_COMPOSITE_ERASE" ,
75
"GIMP_COMPOSITE_REPLACE" ,
76
"GIMP_COMPOSITE_ANTI_ERASE",
77
"GIMP_COMPOSITE_BLEND",
78
"GIMP_COMPOSITE_SHADE",
79
"GIMP_COMPOSITE_SWAP",
80
"GIMP_COMPOSITE_SCALE",
81
"GIMP_COMPOSITE_CONVERT",
86
"GIMP_PIXELFORMAT_V8",
87
"GIMP_PIXELFORMAT_VA8",
88
"GIMP_PIXELFORMAT_RGB8",
89
"GIMP_PIXELFORMAT_RGBA8",
90
# "GIMP_PIXELFORMAT_V16",
91
# "GIMP_PIXELFORMAT_VA16",
92
# "GIMP_PIXELFORMAT_RGB16",
93
# "GIMP_PIXELFORMAT_RGBA16"
94
# "GIMP_PIXELFORMAT_V32",
95
# "GIMP_PIXELFORMAT_VA32",
96
# "GIMP_PIXELFORMAT_RGB32",
97
# "GIMP_PIXELFORMAT_RGBA32"
98
"GIMP_PIXELFORMAT_ANY",
103
s = string.replace(mode.lower(), "gimp_composite_", "")
106
def pixel_depth_name(pixel_format):
107
s = string.replace(pixel_format.lower(), "gimp_pixelformat_", "")
111
pp = pprint.PrettyPrinter(indent=4)
114
def functionnameify(filename):
115
f = os.path.basename(filename)
116
f = string.replace(f, ".o", "")
117
f = string.replace(f, ".c", "")
118
f = string.replace(f, ".h", "")
119
f = string.replace(f, "-", "_")
122
def filenameify(filename):
123
f = os.path.basename(filename)
124
f = string.replace(f, ".o", "")
125
f = string.replace(f, ".c", "")
126
f = string.replace(f, ".h", "")
129
def print_function_table(fpout, name, function_table, requirements=[]):
131
if len(function_table) < 1:
134
print >>fpout, 'static struct install_table {'
135
print >>fpout, ' GimpCompositeOperation mode;'
136
print >>fpout, ' GimpPixelFormat A;'
137
print >>fpout, ' GimpPixelFormat B;'
138
print >>fpout, ' GimpPixelFormat D;'
139
print >>fpout, ' void (*function)(GimpCompositeContext *);'
140
#print >>fpout, ' char *name;'
141
print >>fpout, '} _%s[] = {' % (functionnameify(name))
143
for r in requirements:
144
print >>fpout, '#if %s' % (r)
147
for mode in composite_modes:
148
for A in filter(lambda pf: pf != "GIMP_PIXELFORMAT_ANY", pixel_format):
149
for B in filter(lambda pf: pf != "GIMP_PIXELFORMAT_ANY", pixel_format):
150
for D in filter(lambda pf: pf != "GIMP_PIXELFORMAT_ANY", pixel_format):
151
key = "%s_%s_%s_%s" % (string.lower(mode), pixel_depth_name(A), pixel_depth_name(B), pixel_depth_name(D))
152
if function_table.has_key(key):
153
print >>fpout, ' { %s, %s, %s, %s, %s }, ' % (mode, A, B, D, function_table[key][0])
160
for r in requirements:
161
print >>fpout, '#endif'
164
print >>fpout, ' { 0, 0, 0, 0, NULL }'
169
def print_function_table_name(fpout, name, function_table):
172
print >>fpout, 'char *%s_name[%s][%s][%s][%s] = {' % (functionnameify(name), "GIMP_COMPOSITE_N", "GIMP_PIXELFORMAT_N", "GIMP_PIXELFORMAT_N", "GIMP_PIXELFORMAT_N")
173
for mode in composite_modes:
174
print >>fpout, ' { /* %s */' % (mode)
175
for A in filter(lambda pf: pf != "GIMP_PIXELFORMAT_ANY", pixel_format):
176
print >>fpout, ' { /* A = %s */' % (pixel_depth_name(A))
177
for B in filter(lambda pf: pf != "GIMP_PIXELFORMAT_ANY", pixel_format):
178
print >>fpout, ' /* %-6s */ {' % (pixel_depth_name(B)),
179
for D in filter(lambda pf: pf != "GIMP_PIXELFORMAT_ANY", pixel_format):
180
key = "%s_%s_%s_%s" % (string.lower(mode), pixel_depth_name(A), pixel_depth_name(B), pixel_depth_name(D))
181
if function_table.has_key(key):
182
print >>fpout, '"%s", ' % (function_table[key][0]),
184
print >>fpout, '"%s", ' % (""),
194
print >>fpout, '};\n'
198
def load_function_table(filename):
199
nmx = ns.nmx(filename)
201
gimp_composite_function = dict()
203
for mode in composite_modes:
204
for A in filter(lambda pf: pf != "GIMP_PIXELFORMAT_ANY", pixel_format):
205
for B in filter(lambda pf: pf != "GIMP_PIXELFORMAT_ANY", pixel_format):
206
for D in filter(lambda pf: pf != "GIMP_PIXELFORMAT_ANY", pixel_format):
207
key = "%s_%s_%s_%s" % (string.lower(mode), pixel_depth_name(A), pixel_depth_name(B), pixel_depth_name(D))
209
for a in ["GIMP_PIXELFORMAT_ANY", A]:
210
for b in ["GIMP_PIXELFORMAT_ANY", B]:
211
for d in ["GIMP_PIXELFORMAT_ANY", D]:
212
key = "%s_%s_%s_%s" % (string.lower(mode), pixel_depth_name(a), pixel_depth_name(b), pixel_depth_name(d))
214
f = nmx.exports_re(key + ".*")
215
if f != None: gimp_composite_function["%s_%s_%s_%s" % (string.lower(mode), pixel_depth_name(A), pixel_depth_name(B), pixel_depth_name(D))] = [f]
224
return (gimp_composite_function)
227
def merge_function_tables(tables):
228
main_table = copy.deepcopy(tables[0][1])
231
#print >>sys.stderr, t[0]
232
for mode in composite_modes:
233
for A in filter(lambda pf: pf != "GIMP_PIXELFORMAT_ANY", pixel_format):
234
for B in filter(lambda pf: pf != "GIMP_PIXELFORMAT_ANY", pixel_format):
235
for D in filter(lambda pf: pf != "GIMP_PIXELFORMAT_ANY", pixel_format):
236
key = "%s_%s_%s_%s" % (string.lower(mode), pixel_depth_name(A), pixel_depth_name(B), pixel_depth_name(D))
237
if t[1].has_key(key):
238
#print >>sys.stderr, "%s = %s::%s" % (key, t[0], t[1][key])
239
main_table[key] = t[1][key]
250
def gimp_composite_regression(fpout, function_tables, options):
252
# XXX move all this out to C code, instead of here.
253
print >>fpout, '#include "config.h"'
255
print >>fpout, '#include <stdio.h>'
256
print >>fpout, '#include <stdlib.h>'
257
print >>fpout, '#include <string.h>'
259
print >>fpout, '#include <sys/time.h>'
261
print >>fpout, '#include <glib-object.h>'
263
print >>fpout, '#include "base/base-types.h"'
265
print >>fpout, '#include "gimp-composite.h"'
267
print >>fpout, '#include "gimp-composite-regression.h"'
268
print >>fpout, '#include "gimp-composite-util.h"'
269
print >>fpout, '#include "gimp-composite-generic.h"'
270
print >>fpout, '#include "%s.h"' % (filenameify(options.file))
273
print >>fpout, '%s_test (int iterations, int n_pixels)' % (functionnameify(options.file))
276
for r in options.requires:
277
print >>fpout, '#if %s' % (r)
280
print >>fpout, ' GimpCompositeContext generic_ctx;'
281
print >>fpout, ' GimpCompositeContext special_ctx;'
282
print >>fpout, ' double ft0;'
283
print >>fpout, ' double ft1;'
284
print >>fpout, ' gimp_rgba8_t *rgba8D1;'
285
print >>fpout, ' gimp_rgba8_t *rgba8D2;'
286
print >>fpout, ' gimp_rgba8_t *rgba8A;'
287
print >>fpout, ' gimp_rgba8_t *rgba8B;'
288
print >>fpout, ' gimp_rgba8_t *rgba8M;'
289
print >>fpout, ' gimp_va8_t *va8A;'
290
print >>fpout, ' gimp_va8_t *va8B;'
291
print >>fpout, ' gimp_va8_t *va8M;'
292
print >>fpout, ' gimp_va8_t *va8D1;'
293
print >>fpout, ' gimp_va8_t *va8D2;'
294
print >>fpout, ' int i;'
297
print >>fpout, ' printf("\\nRunning %s tests...\\n");' % (functionnameify(options.file))
298
print >>fpout, ' if (%s_init () == 0)' % (functionnameify(options.file))
300
print >>fpout, ' printf("%s: Instruction set is not available.\\n");' % (functionnameify(options.file))
301
print >>fpout, ' return (0);'
306
print >>fpout, ' rgba8A = gimp_composite_regression_random_rgba8(n_pixels+1);'
307
print >>fpout, ' rgba8B = gimp_composite_regression_random_rgba8(n_pixels+1);'
308
print >>fpout, ' rgba8M = gimp_composite_regression_random_rgba8(n_pixels+1);'
309
print >>fpout, ' rgba8D1 = (gimp_rgba8_t *) calloc(sizeof(gimp_rgba8_t), n_pixels+1);'
310
print >>fpout, ' rgba8D2 = (gimp_rgba8_t *) calloc(sizeof(gimp_rgba8_t), n_pixels+1);'
311
print >>fpout, ' va8A = (gimp_va8_t *) calloc(sizeof(gimp_va8_t), n_pixels+1);'
312
print >>fpout, ' va8B = (gimp_va8_t *) calloc(sizeof(gimp_va8_t), n_pixels+1);'
313
print >>fpout, ' va8M = (gimp_va8_t *) calloc(sizeof(gimp_va8_t), n_pixels+1);'
314
print >>fpout, ' va8D1 = (gimp_va8_t *) calloc(sizeof(gimp_va8_t), n_pixels+1);'
315
print >>fpout, ' va8D2 = (gimp_va8_t *) calloc(sizeof(gimp_va8_t), n_pixels+1);'
317
print >>fpout, ' for (i = 0; i < n_pixels; i++)'
319
print >>fpout, ' va8A[i].v = i;'
320
print >>fpout, ' va8A[i].a = 255-i;'
321
print >>fpout, ' va8B[i].v = i;'
322
print >>fpout, ' va8B[i].a = i;'
323
print >>fpout, ' va8M[i].v = i;'
324
print >>fpout, ' va8M[i].a = i;'
328
#pp.pprint(function_tables)
330
generic_table = function_tables
332
composite_modes.sort();
334
for mode in composite_modes:
335
for A in filter(lambda pf: pf != "GIMP_PIXELFORMAT_ANY", pixel_format):
336
for B in filter(lambda pf: pf != "GIMP_PIXELFORMAT_ANY", pixel_format):
337
for D in filter(lambda pf: pf != "GIMP_PIXELFORMAT_ANY", pixel_format):
338
key = "%s_%s_%s_%s" % (string.lower(mode), pixel_depth_name(A), pixel_depth_name(B), pixel_depth_name(D))
339
if function_tables.has_key(key):
342
print >>fpout, ' gimp_composite_context_init (&special_ctx, %s, %s, %s, %s, %s, n_pixels, (unsigned char *) %sA, (unsigned char *) %sB, (unsigned char *) %sB, (unsigned char *) %sD2);' % (
343
mode, A, B, D, D, pixel_depth_name(A), pixel_depth_name(B), pixel_depth_name(D), pixel_depth_name(D))
345
print >>fpout, ' gimp_composite_context_init (&generic_ctx, %s, %s, %s, %s, %s, n_pixels, (unsigned char *) %sA, (unsigned char *) %sB, (unsigned char *) %sB, (unsigned char *) %sD1);' % (
346
mode, A, B, D, D, pixel_depth_name(A), pixel_depth_name(B), pixel_depth_name(D), pixel_depth_name(D))
348
print >>fpout, ' ft0 = gimp_composite_regression_time_function (iterations, %s, &generic_ctx);' % ("gimp_composite_dispatch")
349
print >>fpout, ' ft1 = gimp_composite_regression_time_function (iterations, %s, &special_ctx);' % (generic_table[key][0])
350
print >>fpout, ' if (gimp_composite_regression_compare_contexts ("%s", &generic_ctx, &special_ctx))' % (mode_name(mode))
353
print >>fpout, ' printf("%s_%s_%s_%s failed\\n");' % (mode_name(mode), pixel_depth_name(A), pixel_depth_name(B), pixel_depth_name(D))
354
print >>fpout, ' return (1);'
356
print >>fpout, ' gimp_composite_regression_timer_report ("%s_%s_%s_%s", ft0, ft1);' % (mode_name(mode), pixel_depth_name(A), pixel_depth_name(B), pixel_depth_name(D))
363
for r in options.requires:
364
print >>fpout, '#endif'
367
print >>fpout, ' return (0);'
372
print >>fpout, 'main (int argc, char *argv[])'
374
print >>fpout, ' int iterations;'
375
print >>fpout, ' int n_pixels;'
377
print >>fpout, ' srand (314159);'
379
print >>fpout, ' putenv ("GIMP_COMPOSITE=0x1");'
381
print >>fpout, ' iterations = %d;' % options.iterations
382
print >>fpout, ' n_pixels = %d;' % options.n_pixels
384
print >>fpout, ' argv++, argc--;'
385
print >>fpout, ' while (argc >= 2)'
387
print >>fpout, ' if (argc > 1 && (strcmp (argv[0], "--iterations") == 0 || strcmp (argv[0], "-i") == 0))'
389
print >>fpout, ' iterations = atoi(argv[1]);'
390
print >>fpout, ' argc -= 2, argv++; argv++;'
392
print >>fpout, ' else if (argc > 1 && (strcmp (argv[0], "--n-pixels") == 0 || strcmp (argv[0], "-n") == 0))'
394
print >>fpout, ' n_pixels = atoi (argv[1]);'
395
print >>fpout, ' argc -= 2, argv++; argv++;'
397
print >>fpout, ' else'
399
print >>fpout, ' printf("Usage: gimp-composites-*-test [-i|--iterations n] [-n|--n-pixels n]");'
400
print >>fpout, ' exit(1);'
404
print >>fpout, ' gimp_composite_generic_install ();'
406
print >>fpout, ' return (%s_test (iterations, n_pixels));' % (functionnameify(options.file))
412
def gimp_composite_installer_install2(fpout, name, function_table, requirements=[]):
414
print >>fpout, 'gboolean'
415
print >>fpout, '%s_install (void)' % (functionnameify(name))
418
if len(function_table) > 1:
419
print >>fpout, ' static struct install_table *t = _%s;' % (functionnameify(name))
421
print >>fpout, ' if (%s_init ())' % functionnameify(name)
423
print >>fpout, ' for (t = &_%s[0]; t->function != NULL; t++)' % (functionnameify(name))
425
print >>fpout, ' gimp_composite_function[t->mode][t->A][t->B][t->D] = t->function;'
427
print >>fpout, ' return (TRUE);'
430
print >>fpout, ' /* nothing to do */'
434
print >>fpout, ' return (FALSE);'
438
def gimp_composite_hfile(fpout, name, function_table):
439
print >>fpout, '/* THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT */'
440
print >>fpout, '/* REGENERATE BY USING make-installer.py */'
442
print >>fpout, 'void %s_install (void);' % (functionnameify(name))
444
print >>fpout, 'typedef void (*%s_table[%s][%s][%s][%s]);' % (functionnameify(name), "GIMP_COMPOSITE_N", "GIMP_PIXELFORMAT_N", "GIMP_PIXELFORMAT_N", "GIMP_PIXELFORMAT_N")
448
def gimp_composite_cfile(fpout, name, function_table, requirements=[]):
449
print >>fpout, '/* THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT */'
450
print >>fpout, '/* REGENERATE BY USING make-installer.py */'
451
print >>fpout, '#include "config.h"'
452
print >>fpout, '#include <glib-object.h>'
453
print >>fpout, '#include <stdlib.h>'
454
print >>fpout, '#include <stdio.h>'
455
print >>fpout, '#include "base/base-types.h"'
456
print >>fpout, '#include "gimp-composite.h"'
458
print >>fpout, '#include "%s.h"' % (filenameify(name))
461
print_function_table(fpout, name, function_table, requirements)
463
gimp_composite_installer_install2(fpout, name, function_table, requirements)
467
###########################################
469
op = optparse.OptionParser(version="$Revision: 1.17 $")
470
op.add_option('-f', '--file', action='store', type='string', dest='file', default=None,
471
help='the input object file')
472
op.add_option('-t', '--test', action='store_true', dest='test', default=False,
473
help='generate regression testing code')
474
op.add_option('-i', '--iterations', action='store', type='int', dest='iterations', default=10,
475
help='number of iterations in regression tests')
476
op.add_option('-n', '--n-pixels', action='store', type="int", dest='n_pixels', default=1024*8192+16+1,
477
help='number of pixels in each regression test iteration')
478
op.add_option('-r', '--requires', action='append', type='string', dest='requires', default=[],
479
help='cpp #if conditionals')
480
options, args = op.parse_args()
482
table = load_function_table(options.file)
484
gimp_composite_cfile(open(filenameify(options.file) + "-installer.c", "w"), options.file, table, options.requires)
486
if options.test == True:
487
gimp_composite_regression(open(filenameify(options.file) + "-test.c", "w"), table, options)