redeye 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6f0acad32d2e9ee0122e452c3cff1f4823cd4193
4
+ data.tar.gz: fbc4592fd714bf7bbddd1a4e0631484e8f56b590
5
+ SHA512:
6
+ metadata.gz: d481371139a391fa4b863e11b65b8b6599da2cf7d021a25f92250a2f835d018cda834c490baa5b72a6d479ca58a64bc07092ffc7c4d8fae60c425680a264f2df
7
+ data.tar.gz: 6211f766b9827c43c6001e7f0b30ac9ce47b1389059fa590a93e70a10cd34f7117e1d091f8c2b03037ea7fc1b33d1f4d888fb618e5606f6c0c9204f30e8cd2ec
@@ -0,0 +1,5 @@
1
+ redye
2
+ =====
3
+
4
+ Simple Ruby / GdkPixbuf redeye correction library
5
+
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ gem 'rake-compiler'
3
+ require 'rake/extensiontask'
4
+ BASE_DIR = Dir.pwd
5
+ require 'rubygems/package_task'
6
+ require 'rake/testtask'
7
+
8
+ exts = []
9
+
10
+ namespace :prepare do
11
+ FileList["ext/*/*.cr"].each do |cr|
12
+ dir = File.dirname(cr)
13
+ name = File.basename(dir)
14
+ desc "Generate source for #{name}"
15
+ task(name.intern) do
16
+ sh 'rubber-generate', '--build-dir', dir, cr
17
+ end
18
+ end
19
+ end
20
+
21
+ spec = Gem::Specification.new do |s|
22
+ s.name = "redeye"
23
+ s.author = "Geoff Youngs"
24
+ s.email = "git@intersect-uk.co.uk"
25
+ s.version = "1.0.0"
26
+ s.homepage = "http://github.com/geoffyoungs/redeye"
27
+ s.summary = "Redeye correction for Gdk::Pixbuf"
28
+ s.add_dependency("rubber-generate", ">= 0.0.17")
29
+ s.add_dependency("glib2", ">= 1.1.9")
30
+ s.add_dependency("gdk_pixbuf2", ">= 1.1.9")
31
+ s.platform = Gem::Platform::RUBY
32
+ s.extensions = FileList["ext/*/extconf.rb"]
33
+ s.files = FileList['ext/*/*.{c,h,cr,rd}'] + ['Rakefile', 'README.md'] + FileList['lib/**/*.rb']
34
+ s.description = <<-EOF
35
+ Redeye correction methods for redeye
36
+ EOF
37
+ end
38
+ Gem::PackageTask.new(spec) do |pkg|
39
+ pkg.need_tar = true
40
+ end
41
+ Rake::ExtensionTask.new("redeye", spec)
42
+
43
+ Rake::TestTask.new do |t|
44
+ t.test_files = FileList['test/*_test.rb']
45
+ end
46
+
47
+ task :default, :compile
48
+
@@ -0,0 +1,102 @@
1
+ require 'mkmf'
2
+ use_gems = false
3
+ begin
4
+ require 'mkmf-gnome2'
5
+ rescue LoadError
6
+ use_gems = true
7
+ end
8
+
9
+ if use_gems or Object.const_defined?('Gem')
10
+ require 'rubygems'
11
+ gem 'glib2'
12
+ require 'mkmf-gnome2'
13
+ %w[rbglib.h rbgtk.h rbpango.h rbatk.h].each do |header|
14
+ Gem.find_files(header).each do |f|
15
+ $CFLAGS += " '-I#{File.dirname(f)}'"
16
+ end
17
+ end
18
+ end
19
+ # Look for headers in {gem_root}/ext/{package}
20
+ if use_gems
21
+ %w[
22
+ glib2 gdk_pixbuf2 atk gtk2 ].each do |package|
23
+ require package
24
+ $CFLAGS += " -I"+Gem.loaded_specs[package].full_gem_path+"/ext/"+package
25
+ end
26
+ end
27
+ if RbConfig::CONFIG.has_key?('rubyhdrdir')
28
+ $CFLAGS += " -I" + RbConfig::CONFIG['rubyhdrdir']+'/ruby'
29
+ end
30
+
31
+ $CFLAGS += " -I."
32
+ have_func("rb_errinfo")
33
+ PKGConfig.have_package("gtk+-2.0") or exit(-1)
34
+ have_header("gdk-pixbuf/gdk-pixbuf.h") or exit(-1)
35
+
36
+ STDOUT.print("checking for new allocation framework... ") # for ruby-1.7
37
+ if Object.respond_to? :allocate
38
+ STDOUT.print "yes
39
+ "
40
+ $defs << "-DHAVE_OBJECT_ALLOCATE"
41
+ else
42
+ STDOUT.print "no
43
+ "
44
+ end
45
+
46
+ top = File.expand_path(File.dirname(__FILE__) + '/..') # XXX
47
+ $CFLAGS += " " + ['glib/src'].map{|d|
48
+ "-I" + File.join(top, d)
49
+ }.join(" ")
50
+
51
+ have_func("rb_define_alloc_func") # for ruby-1.8
52
+
53
+ #set_output_lib('libruby-redeye.a')
54
+ if /cygwin|mingw/ =~ RUBY_PLATFORM
55
+ top = "../.."
56
+ [
57
+ ["glib/src", "ruby-glib2"],
58
+ ].each{|d,l|
59
+ $LDFLAGS << sprintf(" -L%s/%s", top, d)
60
+ $libs << sprintf(" -l%s", l)
61
+ }
62
+ end
63
+ begin
64
+ srcdir = File.expand_path(File.dirname($0))
65
+
66
+ begin
67
+
68
+ obj_ext = "."+$OBJEXT
69
+
70
+ $libs = $libs.split(/ /).uniq.join(' ')
71
+ $source_files = Dir.glob(sprintf("%s/*.c", srcdir)).map{|fname|
72
+ fname[0, srcdir.length+1] = ''
73
+ fname
74
+ }
75
+ $objs = $source_files.collect do |item|
76
+ item.gsub(/.c$/, obj_ext)
77
+ end
78
+
79
+ #
80
+ # create Makefile
81
+ #
82
+ $defs << "-DRUBY_REDEYE_COMPILATION"
83
+ # $CFLAGS << $defs.join(' ')
84
+ create_makefile("redeye", srcdir)
85
+ raise Interrupt if not FileTest.exist? "Makefile"
86
+
87
+ File.open("Makefile", "a") do |mfile|
88
+ $source_files.each do |e|
89
+ mfile.print sprintf("%s: %s
90
+ ", e.gsub(/.c$/, obj_ext), e)
91
+ end
92
+ end
93
+ ensure
94
+ #Dir.chdir ".."
95
+ end
96
+
97
+ #create_top_makefile()
98
+ rescue Interrupt
99
+ print " [error] " + $!.to_s + "
100
+ "
101
+ end
102
+
@@ -0,0 +1,885 @@
1
+ #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
2
+ /* Includes */
3
+ #include <ruby.h>
4
+ #include <stdlib.h>
5
+ #include <stdio.h>
6
+ #include <string.h>
7
+ #include "gdk-pixbuf/gdk-pixbuf.h"
8
+
9
+ /* Setup types */
10
+ /* Try not to clash with other definitions of bool... */
11
+ typedef int rubber_bool;
12
+ #define bool rubber_bool
13
+
14
+ /* Prototypes */
15
+ #include "rbglib.h"
16
+
17
+ #include "rbgtk.h"
18
+
19
+ #if defined(G_PLATFORM_WIN32) && !defined(RUBY_GTK2_STATIC_COMPILATION)
20
+ # ifdef RUBY_GTK2_COMPILATION
21
+ # define RUBY_GTK2_VAR __declspec(dllexport)
22
+ # else
23
+ # define RUBY_GTK2_VAR extern __declspec(dllimport)
24
+ # endif
25
+ #else
26
+ # define RUBY_GTK2_VAR extern
27
+ #endif
28
+
29
+ RUBY_GTK2_VAR VALUE mGtk;
30
+ RUBY_GTK2_VAR VALUE mGdk;
31
+
32
+ #define RBGTK_INITIALIZE(obj,gtkobj) (rbgtk_initialize_gtkobject(obj, GTK_OBJECT(gtkobj)))
33
+ static VALUE cRedEye;
34
+ static VALUE
35
+ RedEye___alloc__(VALUE self);
36
+ static VALUE
37
+ RedEye_initialize(VALUE self, VALUE __v_pixbuf, VALUE __v_minX, VALUE __v_minY, VALUE __v_maxX, VALUE __v_maxY);
38
+ static VALUE
39
+ RedEye_identify_blobs(int __p_argc, VALUE *__p_argv, VALUE self);
40
+ static VALUE
41
+ RedEye_correct_blob(VALUE self, VALUE __v_blob_id);
42
+ static VALUE
43
+ RedEye_highlight_blob(int __p_argc, VALUE *__p_argv, VALUE self);
44
+ static VALUE
45
+ RedEye_preview_blob(int __p_argc, VALUE *__p_argv, VALUE self);
46
+ static VALUE
47
+ RedEye_preview(VALUE self);
48
+ static VALUE
49
+ RedEye_pixbuf(VALUE self);
50
+ static VALUE structRegion;
51
+
52
+ /* Inline C code */
53
+
54
+
55
+ #define assert(x) if (!(x)) { rb_raise(rb_eRuntimeError, "Assertion: '%s' failed.", #x); }
56
+
57
+ typedef struct {
58
+ char red,green,blue;
59
+ } rgb_t;
60
+
61
+ typedef struct {
62
+ int minX, maxX, minY, maxY;
63
+ int width, height;
64
+ int noPixels, mergeWith;
65
+ } region_info;
66
+
67
+ typedef struct {
68
+ struct {
69
+ int minX, maxX, minY, maxY;
70
+ int width, height;
71
+ } area;
72
+ struct {
73
+ int *data;
74
+ region_info *region;
75
+ int len, size;
76
+ } regions;
77
+ int *mask;
78
+ GdkPixbuf *pixbuf, *preview;
79
+ } redeyeop_t;
80
+
81
+ #define MIN_RED_VAL 20
82
+
83
+ static inline VALUE
84
+ unref_pixbuf(GdkPixbuf *pixbuf)
85
+ {
86
+ volatile VALUE pb = Qnil;
87
+
88
+ pb = GOBJ2RVAL(pixbuf);
89
+
90
+ g_object_unref(pixbuf);
91
+
92
+ return pb;
93
+ }
94
+
95
+ static void identify_possible_redeye_pixels(redeyeop_t *op,
96
+ double green_sensitivity, double blue_sensitivity,
97
+ int min_red_val)
98
+ {
99
+ guchar *data = gdk_pixbuf_get_pixels(op->pixbuf);
100
+ int rowstride = gdk_pixbuf_get_rowstride(op->pixbuf);
101
+ int pixWidth = gdk_pixbuf_get_has_alpha(op->pixbuf) ? 4 : 3;
102
+
103
+ int y, ry = 0, x, rx = 0;
104
+ for ( y = op->area.minY; y < op->area.maxY; y++ )
105
+ {
106
+ guchar *thisLine = data + (rowstride * y);
107
+ guchar *pixel;
108
+
109
+ pixel = thisLine + (op->area.minX * pixWidth);
110
+ rx = 0;
111
+
112
+ for ( x = op->area.minX; x < op->area.maxX; x++ )
113
+ {
114
+
115
+ int r,g,b;
116
+
117
+ r = pixel[0];
118
+ g = pixel[1];
119
+ b = pixel[2];
120
+
121
+ gboolean threshMet;
122
+
123
+ threshMet = (((double)r) > (green_sensitivity * (double)g)) &&
124
+ (((double)r) > (blue_sensitivity * (double)b)) &&
125
+ (r > min_red_val);
126
+
127
+ if(threshMet)
128
+ op->mask[ rx + ry ] = r;
129
+ else
130
+ op->mask[ rx + ry ] = 0; /* MEMZERO should have done its job ? */
131
+
132
+ pixel += pixWidth;
133
+ rx ++;
134
+ }
135
+
136
+ ry += op->area.width;
137
+ }
138
+ }
139
+
140
+
141
+ inline int group_at(redeyeop_t *op, int px, int py)
142
+ {
143
+ int index, region;
144
+
145
+ if (px < 0 || py < 0)
146
+ return 0;
147
+
148
+ index = px + ( py * op->area.width );
149
+
150
+ if (index < 0)
151
+ return 0;
152
+ if (index > (op->area.width * op->area.height))
153
+ return 0;
154
+
155
+ region = op->regions.data[ index ];
156
+ if (region > 0) {
157
+ if (op->regions.region[ region ].mergeWith) {
158
+ return op->regions.region[ region ].mergeWith;
159
+ } else {
160
+ return region;
161
+ }
162
+ } else {
163
+ return 0;
164
+ }
165
+ }
166
+
167
+ #define group_for(x,y) group_at(op, x, y)
168
+
169
+ static void identify_blob_groupings(redeyeop_t *op)
170
+ {
171
+ volatile int next_blob_id = 1, blob_id, y, x;
172
+
173
+
174
+ for( y = 0; y < op->area.height; y++ )
175
+ {
176
+ for ( x = 0; x < op->area.width; x++ )
177
+ {
178
+ if (op->mask[ x + (y * op->area.width) ] > 0) {
179
+ gboolean existing = FALSE;
180
+ int sx, sy, group = 0;
181
+ // Target pixel is true
182
+ blob_id = 0;
183
+
184
+ for (sy = y; sy >= y - 1; sy --) {
185
+ sx = (sy == y) ? x : x + 1;
186
+ for (; sx >= (x - 1); sx --) {
187
+ /*if ((sx >= x) && (sy >= y))
188
+ goto blob_scan_done;*/
189
+
190
+ if (sx >= 0 && sy >= 0)
191
+ group = group_for(sx, sy);
192
+
193
+ if (group) {
194
+ existing = TRUE;
195
+ if (blob_id) {
196
+ int target = MIN(blob_id, group);
197
+ int from = MAX(blob_id, group);
198
+
199
+ if (op->regions.region[target].mergeWith > 0) {
200
+ // Already merged
201
+ target = op->regions.region[target].mergeWith;
202
+ }
203
+ op->regions.region[from].mergeWith = target;
204
+
205
+ // Merge blob_id & group
206
+ }
207
+ blob_id = group;
208
+ }
209
+ }
210
+ }
211
+
212
+ if (blob_id == 0)
213
+ { // Allocate new group
214
+ blob_id = next_blob_id;
215
+ op->regions.region[blob_id].minX = x;
216
+ op->regions.region[blob_id].maxX = x;
217
+ op->regions.region[blob_id].minY = y;
218
+ op->regions.region[blob_id].maxY = y;
219
+ op->regions.region[blob_id].width = 1;
220
+ op->regions.region[blob_id].height = 1;
221
+ op->regions.region[blob_id].noPixels = 1;
222
+ op->regions.region[blob_id].mergeWith = 0;
223
+
224
+ next_blob_id ++;
225
+ op->regions.len = next_blob_id;
226
+
227
+ if (next_blob_id >= op->regions.size) {
228
+ int extra, new_size;
229
+
230
+ /*
231
+ * Realloc in increasingly large chunks to reduce memory fragmentation
232
+ */
233
+ extra = op->regions.size;
234
+ new_size = op->regions.size + extra;
235
+
236
+ REALLOC_N(op->regions.region, region_info, new_size);
237
+
238
+ op->regions.size = new_size;
239
+ }
240
+ }
241
+
242
+ if (existing)
243
+ {
244
+ op->regions.region[blob_id].minX = MIN(x, op->regions.region[blob_id].minX);
245
+ op->regions.region[blob_id].maxX = MAX(x, op->regions.region[blob_id].maxX);
246
+ op->regions.region[blob_id].minY = MIN(y, op->regions.region[blob_id].minY);
247
+ op->regions.region[blob_id].maxY = MAX(y, op->regions.region[blob_id].maxY);
248
+ op->regions.region[blob_id].width = op->regions.region[blob_id].maxX -
249
+ op->regions.region[blob_id].minX + 1;
250
+ op->regions.region[blob_id].height = op->regions.region[blob_id].maxY -
251
+ op->regions.region[blob_id].minY + 1;
252
+ op->regions.region[blob_id].noPixels ++;
253
+ }
254
+
255
+ op->regions.data[ x + (y * op->area.width) ] = blob_id;
256
+ }
257
+ }
258
+ }
259
+ /*FILE *fp = fopen("regions.txt","w");*/
260
+ for (y = 0; y < op->area.height; y++) {
261
+ for (x = 0; x < op->area.width; x++) {
262
+ int g = group_at(op, x, y); // Returns the merged group...
263
+ op->regions.data[ x + (y * op->area.width) ] = g;
264
+ /*
265
+ if (op->regions.len <= 0xf || 1)
266
+ {
267
+ if (g == 0)
268
+ fprintf(fp, " ");
269
+ else
270
+ fprintf(fp, "%x", g);
271
+ }
272
+ else
273
+ {
274
+ if (g == 0)
275
+ fprintf(fp, " ");
276
+ else
277
+ fprintf(fp, "%x ", g);
278
+ }*/
279
+ }
280
+ /*fprintf(fp, "\n");*/
281
+ }
282
+ /*fclose(fp);*/
283
+ }
284
+ #define NO_REGIONS_DEFAULT 20
285
+ #define MIN_ID 1
286
+
287
+
288
+ static redeyeop_t *new_redeye(void)
289
+ {
290
+ redeyeop_t *ptr = ALLOC(redeyeop_t);
291
+ MEMZERO(ptr, redeyeop_t, 1);
292
+ return ptr;
293
+ }
294
+
295
+ static void free_redeye(redeyeop_t *ptr)
296
+ {
297
+ if (ptr->mask)
298
+ free(ptr->mask);
299
+ if (ptr->regions.data);
300
+ free(ptr->regions.data);
301
+ if (ptr->regions.region);
302
+ free(ptr->regions.region);
303
+ if (ptr->pixbuf)
304
+ g_object_unref(ptr->pixbuf);
305
+ if (ptr->preview)
306
+ g_object_unref(ptr->preview);
307
+ free(ptr);
308
+ }
309
+
310
+
311
+ inline gboolean in_region(redeyeop_t *op, int x, int y, int blob_id)
312
+ {
313
+ int index;
314
+
315
+ if ( x < op->area.minX || x > op->area.maxX ||
316
+ y < op->area.minY || y > op->area.maxY )
317
+ return FALSE;
318
+
319
+ index = (x - op->area.minX) + ((y - op->area.minY) * op->area.width);
320
+
321
+ return op->regions.data[index] == blob_id;
322
+ }
323
+
324
+ inline double alpha_level_for_pixel(redeyeop_t *op, int x, int y, int blob_id)
325
+ {
326
+ int j = 0, c = 0, xm, ym;
327
+
328
+ if (in_region(op, x, y, blob_id))
329
+ return 1.0;
330
+
331
+ for ( xm = -2; xm <= 2; xm++ )
332
+ {
333
+ for ( ym = -2; ym <= 2; ym ++ )
334
+ {
335
+ c ++;
336
+ if (xm == 0 && ym == 0)
337
+ continue;
338
+ if (in_region(op, x+xm, y+ym, blob_id))
339
+ j ++;
340
+ }
341
+ }
342
+
343
+ return ((double)j)/((double)c);
344
+ }
345
+
346
+ inline char col(double val)
347
+ {
348
+ if (val < 0) return 0;
349
+ if (val > 255) return 255;
350
+ return val;
351
+
352
+ }
353
+
354
+ static GdkPixbuf *redeye_preview(redeyeop_t *op, gboolean reset)
355
+ {
356
+ int width, height;
357
+ width = op->area.width;
358
+ height = op->area.height;
359
+
360
+ if (width + op->area.minX > gdk_pixbuf_get_width(op->pixbuf)) {
361
+ width = gdk_pixbuf_get_width(op->pixbuf) - op->area.minX;
362
+ }
363
+ if (height + op->area.minY > gdk_pixbuf_get_height(op->pixbuf)) {
364
+ height = gdk_pixbuf_get_height(op->pixbuf) - op->area.minY;
365
+ }
366
+
367
+ if ( op->preview == NULL )
368
+ {
369
+ GdkPixbuf *sub = NULL;
370
+ sub = gdk_pixbuf_new_subpixbuf(op->pixbuf, op->area.minX, op->area.minY,
371
+ width, height);
372
+
373
+ op->preview = gdk_pixbuf_copy(sub);
374
+ g_object_unref(sub);
375
+ } else if (reset) {
376
+ gdk_pixbuf_copy_area(op->pixbuf, op->area.minX, op->area.minY,
377
+ width, height, op->preview, 0, 0);
378
+ }
379
+
380
+ return op->preview;
381
+ }
382
+
383
+ static void desaturate_blob(redeyeop_t *op, int blob_id)
384
+ {
385
+ int y, x;
386
+ int minX, minY, maxX, maxY;
387
+
388
+ minY = MAX(0, op->area.minY + op->regions.region[blob_id].minY - 1);
389
+ maxY = MIN(op->area.maxY + op->regions.region[blob_id].maxY + 1,
390
+ gdk_pixbuf_get_height(op->pixbuf)-1);
391
+ minX = MAX(0, op->area.minX + op->regions.region[blob_id].minX - 1);
392
+ maxX = MIN(op->area.maxX + op->regions.region[blob_id].maxX + 1,
393
+ gdk_pixbuf_get_width(op->pixbuf)-1);
394
+
395
+ guchar *data = gdk_pixbuf_get_pixels(op->pixbuf);
396
+ int rowstride = gdk_pixbuf_get_rowstride(op->pixbuf);
397
+ int pixWidth = gdk_pixbuf_get_has_alpha(op->pixbuf) ? 4 : 3;
398
+
399
+ for ( y = minY; y <= maxY; y++ )
400
+ {
401
+ guchar *thisLine = data + (rowstride * y);
402
+ guchar *pixel;
403
+
404
+ pixel = thisLine + (minX * pixWidth);
405
+
406
+ for ( x = minX; x <= maxX; x++ )
407
+ {
408
+
409
+ double alpha = alpha_level_for_pixel(op, x, y, blob_id);
410
+ int r,g,b,grey;
411
+
412
+ r = pixel[0];
413
+ g = pixel[1];
414
+ b = pixel[2];
415
+
416
+ if (alpha > 0)
417
+ {
418
+ grey = alpha * ((double)( 5 * (double)r + 60 * (double)g + 30 * (double)b)) / 100.0 +
419
+ (1 - alpha) * r;
420
+
421
+ pixel[0] = col((grey * alpha) + (1-alpha) * r);
422
+ pixel[1] = col((grey * alpha) + (1-alpha) * g);
423
+ pixel[2] = col((grey * alpha) + (1-alpha) * b);
424
+ }
425
+
426
+ pixel += pixWidth;
427
+ }
428
+ }
429
+
430
+ }
431
+
432
+ static void highlight_blob(redeyeop_t *op, int blob_id, int colour)
433
+ {
434
+ int y, x;
435
+ int minX, minY, maxX, maxY;
436
+ int hr, hg, hb;
437
+
438
+ hr = (colour >> 16) & 0xff;
439
+ hg = (colour >> 8) & 0xff;
440
+ hb = (colour) & 0xff;
441
+
442
+ minY = MAX(0, op->area.minY - 1);
443
+ maxY = MIN(op->area.maxY + 1, gdk_pixbuf_get_height(op->pixbuf)-1);
444
+ minX = MAX(0, op->area.minX - 1);
445
+ maxX = MIN(op->area.maxX + 1, gdk_pixbuf_get_width(op->pixbuf)-1);
446
+
447
+ guchar *data = gdk_pixbuf_get_pixels(op->pixbuf);
448
+ int rowstride = gdk_pixbuf_get_rowstride(op->pixbuf);
449
+ int pixWidth = gdk_pixbuf_get_has_alpha(op->pixbuf) ? 4 : 3;
450
+
451
+ for ( y = minY; y <= maxY; y++ )
452
+ {
453
+ guchar *thisLine = data + (rowstride * y);
454
+ guchar *pixel;
455
+
456
+ pixel = thisLine + (minX * pixWidth);
457
+
458
+ for ( x = minX; x <= maxX; x++ )
459
+ {
460
+
461
+ double alpha = alpha_level_for_pixel(op, x, y, blob_id);
462
+ int r,g,b;
463
+
464
+ r = (pixel[0]);
465
+ g = (pixel[1]);
466
+ b = (pixel[2]);
467
+
468
+
469
+ if (alpha > 0)
470
+ {
471
+
472
+ pixel[0] = col((1-alpha) * r + (alpha * hr));
473
+ pixel[1] = col((1-alpha) * g + (alpha * hg));
474
+ pixel[2] = col((1-alpha) * b + (alpha * hb));
475
+ }
476
+
477
+ pixel += pixWidth;
478
+ }
479
+ }
480
+
481
+ }
482
+
483
+
484
+ static void preview_blob(redeyeop_t *op, int blob_id, int colour, gboolean reset_preview)
485
+ {
486
+ int y, x;
487
+ int minX, minY, maxX, maxY;
488
+ int hr, hg, hb;
489
+
490
+ redeye_preview(op, reset_preview);
491
+
492
+ hr = (colour >> 16) & 0xff;
493
+ hg = (colour >> 8) & 0xff;
494
+ hb = (colour) & 0xff;
495
+
496
+ minY = 0;
497
+ maxY = gdk_pixbuf_get_height(op->preview)-1;
498
+ minX = 0;
499
+ maxX = gdk_pixbuf_get_width(op->preview)-1;
500
+
501
+ guchar *data = gdk_pixbuf_get_pixels(op->preview);
502
+ int rowstride = gdk_pixbuf_get_rowstride(op->preview);
503
+ int pixWidth = gdk_pixbuf_get_has_alpha(op->preview) ? 4 : 3;
504
+
505
+ for ( y = minY; y <= maxY; y++ )
506
+ {
507
+ guchar *thisLine = data + (rowstride * y);
508
+ guchar *pixel;
509
+
510
+ pixel = thisLine + (minX * pixWidth);
511
+
512
+ for ( x = minX; x <= maxX; x++ )
513
+ {
514
+
515
+ double alpha = alpha_level_for_pixel(op, x + op->area.minX, y + op->area.minY, blob_id);
516
+ int r,g,b;
517
+
518
+ r = (pixel[0]);
519
+ g = (pixel[1]);
520
+ b = (pixel[2]);
521
+
522
+
523
+ if (alpha > 0)
524
+ {
525
+
526
+ pixel[0] = col((1-alpha) * r + (alpha * hr));
527
+ pixel[1] = col((1-alpha) * g + (alpha * hg));
528
+ pixel[2] = col((1-alpha) * b + (alpha * hb));
529
+ }
530
+
531
+ pixel += pixWidth;
532
+ }
533
+ }
534
+
535
+ }
536
+
537
+
538
+ /* Code */
539
+ static VALUE
540
+ RedEye___alloc__(VALUE self)
541
+ {
542
+ VALUE __p_retval = Qnil;
543
+
544
+ #line 536 "/home/geoff/Projects/redeye/ext/redeye/redeye.cr"
545
+ do { __p_retval = Data_Wrap_Struct(self, NULL, free_redeye, new_redeye()); goto out; } while(0);
546
+ out:
547
+ return __p_retval;
548
+ }
549
+
550
+ static VALUE
551
+ RedEye_initialize(VALUE self, VALUE __v_pixbuf, VALUE __v_minX, VALUE __v_minY, VALUE __v_maxX, VALUE __v_maxY)
552
+ {
553
+ GdkPixbuf * pixbuf; GdkPixbuf * __orig_pixbuf;
554
+ int minX; int __orig_minX;
555
+ int minY; int __orig_minY;
556
+ int maxX; int __orig_maxX;
557
+ int maxY; int __orig_maxY;
558
+ __orig_pixbuf = pixbuf = GDK_PIXBUF(RVAL2GOBJ(__v_pixbuf));
559
+ __orig_minX = minX = NUM2INT(__v_minX);
560
+ __orig_minY = minY = NUM2INT(__v_minY);
561
+ __orig_maxX = maxX = NUM2INT(__v_maxX);
562
+ __orig_maxY = maxY = NUM2INT(__v_maxY);
563
+
564
+ #line 540 "/home/geoff/Projects/redeye/ext/redeye/redeye.cr"
565
+
566
+ do {
567
+ redeyeop_t * op ;
568
+ Data_Get_Struct(self, redeyeop_t, op);
569
+ op->pixbuf = pixbuf;
570
+ op->preview = NULL;
571
+ g_object_ref(op->pixbuf);
572
+ op->area.minX = minX;
573
+ op->area.maxX = maxX;
574
+ op->area.minY = minY;
575
+ op->area.maxY = maxY;
576
+ op->area.width = maxX - minX + 1;
577
+ op->area.height = maxY - minY + 1;
578
+ assert(op->pixbuf != NULL);
579
+ assert(op->area.maxX <= gdk_pixbuf_get_width(op->pixbuf));
580
+ assert(op->area.minX >= 0);
581
+ assert(op->area.minX < op->area.maxX);
582
+ assert(op->area.maxY <= gdk_pixbuf_get_height(op->pixbuf));
583
+ assert(op->area.minY >= 0);
584
+ assert(op->area.minY < op->area.maxY);
585
+ op->mask = ALLOC_N(int, op->area.width * op->area.height);
586
+ op->regions.data = ALLOC_N(int, op->area.width * op->area.height);
587
+ op->regions.region = ALLOC_N(region_info, NO_REGIONS_DEFAULT);
588
+ op->regions.len = 0;
589
+ op->regions.size = NO_REGIONS_DEFAULT;
590
+
591
+
592
+ } while(0);
593
+
594
+ ;
595
+ return Qnil;
596
+ }
597
+
598
+ static VALUE
599
+ RedEye_identify_blobs(int __p_argc, VALUE *__p_argv, VALUE self)
600
+ {
601
+ VALUE __p_retval = Qnil;
602
+ VALUE __v_green_sensitivity = Qnil;
603
+ double green_sensitivity; double __orig_green_sensitivity;
604
+ VALUE __v_blue_sensitivity = Qnil;
605
+ double blue_sensitivity; double __orig_blue_sensitivity;
606
+ VALUE __v_min_red_val = Qnil;
607
+ int min_red_val; int __orig_min_red_val;
608
+
609
+ /* Scan arguments */
610
+ rb_scan_args(__p_argc, __p_argv, "03",&__v_green_sensitivity, &__v_blue_sensitivity, &__v_min_red_val);
611
+
612
+ /* Set defaults */
613
+ if (__p_argc > 0)
614
+ __orig_green_sensitivity = green_sensitivity = NUM2DBL(__v_green_sensitivity);
615
+ else
616
+ green_sensitivity = 2.0;
617
+
618
+ if (__p_argc > 1)
619
+ __orig_blue_sensitivity = blue_sensitivity = NUM2DBL(__v_blue_sensitivity);
620
+ else
621
+ blue_sensitivity = 0.0;
622
+
623
+ if (__p_argc > 2)
624
+ __orig_min_red_val = min_red_val = NUM2INT(__v_min_red_val);
625
+ else
626
+ min_red_val = MIN_RED_VAL;
627
+
628
+
629
+ #line 575 "/home/geoff/Projects/redeye/ext/redeye/redeye.cr"
630
+
631
+ do {
632
+ redeyeop_t * op ;
633
+ Data_Get_Struct(self, redeyeop_t, op);
634
+ MEMZERO(op->mask, int, op->area.width * op->area.height);
635
+ MEMZERO(op->regions.data, int, op->area.width * op->area.height);
636
+ identify_possible_redeye_pixels(op, green_sensitivity, blue_sensitivity, min_red_val);
637
+ identify_blob_groupings(op);
638
+ volatile VALUE ary =
639
+ rb_ary_new2(op->regions.len);
640
+ int i ;
641
+ for (i = MIN_ID;
642
+ i < op->regions.len;
643
+ i++) { region_info * r =
644
+ &op->regions.region[i];
645
+ /* Ignore CCD noise */ if (r->noPixels < 2) continue;
646
+ rb_ary_push(ary, rb_struct_new(structRegion, self, INT2NUM(i), INT2NUM(r->minX), INT2NUM(r->minY), INT2NUM(r->maxX), INT2NUM(r->maxY), INT2NUM(r->width), INT2NUM(r->height), INT2NUM(r->noPixels)));
647
+ } do { __p_retval = ary; goto out; } while(0);
648
+
649
+ } while(0);
650
+
651
+ out:
652
+ return __p_retval;
653
+ }
654
+
655
+ static VALUE
656
+ RedEye_correct_blob(VALUE self, VALUE __v_blob_id)
657
+ {
658
+ int blob_id; int __orig_blob_id;
659
+ __orig_blob_id = blob_id = NUM2INT(__v_blob_id);
660
+
661
+ #line 600 "/home/geoff/Projects/redeye/ext/redeye/redeye.cr"
662
+
663
+ do {
664
+ redeyeop_t * op ;
665
+ Data_Get_Struct(self, redeyeop_t, op);
666
+ if (op->regions.len <= blob_id) rb_raise(rb_eIndexError, "Only %i blobs in region - %i is invalid", op->regions.len, blob_id);
667
+ desaturate_blob(op, blob_id);
668
+
669
+
670
+ } while(0);
671
+
672
+ return Qnil;
673
+ }
674
+
675
+ static VALUE
676
+ RedEye_highlight_blob(int __p_argc, VALUE *__p_argv, VALUE self)
677
+ {
678
+ VALUE __v_blob_id = Qnil;
679
+ int blob_id; int __orig_blob_id;
680
+ VALUE __v_col = Qnil;
681
+ int col; int __orig_col;
682
+
683
+ /* Scan arguments */
684
+ rb_scan_args(__p_argc, __p_argv, "11",&__v_blob_id, &__v_col);
685
+
686
+ /* Set defaults */
687
+ __orig_blob_id = blob_id = NUM2INT(__v_blob_id);
688
+
689
+ if (__p_argc > 1)
690
+ __orig_col = col = NUM2INT(__v_col);
691
+ else
692
+ col = 0x00ff00;
693
+
694
+
695
+ #line 612 "/home/geoff/Projects/redeye/ext/redeye/redeye.cr"
696
+
697
+ do {
698
+ redeyeop_t * op ;
699
+ Data_Get_Struct(self, redeyeop_t, op);
700
+ if (op->regions.len <= blob_id) rb_raise(rb_eIndexError, "Only %i blobs in region - %i is invalid", op->regions.len, blob_id);
701
+ highlight_blob(op, blob_id, col);
702
+
703
+
704
+ } while(0);
705
+
706
+ return Qnil;
707
+ }
708
+
709
+ static VALUE
710
+ RedEye_preview_blob(int __p_argc, VALUE *__p_argv, VALUE self)
711
+ {
712
+ VALUE __p_retval = Qnil;
713
+ VALUE __v_blob_id = Qnil;
714
+ int blob_id; int __orig_blob_id;
715
+ VALUE __v_col = Qnil;
716
+ int col; int __orig_col;
717
+ VALUE __v_reset_preview = Qnil;
718
+ gboolean reset_preview; gboolean __orig_reset_preview;
719
+
720
+ /* Scan arguments */
721
+ rb_scan_args(__p_argc, __p_argv, "12",&__v_blob_id, &__v_col, &__v_reset_preview);
722
+
723
+ /* Set defaults */
724
+ __orig_blob_id = blob_id = NUM2INT(__v_blob_id);
725
+
726
+ if (__p_argc > 1)
727
+ __orig_col = col = NUM2INT(__v_col);
728
+ else
729
+ col = 0x00ff00;
730
+
731
+ if (__p_argc > 2)
732
+ __orig_reset_preview = reset_preview = RTEST(__v_reset_preview);
733
+ else
734
+ reset_preview = TRUE;
735
+
736
+
737
+ #line 623 "/home/geoff/Projects/redeye/ext/redeye/redeye.cr"
738
+
739
+ do {
740
+ redeyeop_t * op ;
741
+ Data_Get_Struct(self, redeyeop_t, op);
742
+ if (op->regions.len <= blob_id) rb_raise(rb_eIndexError, "Only %i blobs in region - %i is invalid", op->regions.len, blob_id);
743
+ preview_blob(op, blob_id, col, reset_preview);
744
+ do { __p_retval = GOBJ2RVAL(GDK_PIXBUF(op->preview)); goto out; } while(0);
745
+
746
+ } while(0);
747
+
748
+ out:
749
+ return __p_retval;
750
+ }
751
+
752
+ static VALUE
753
+ RedEye_preview(VALUE self)
754
+ {
755
+ VALUE __p_retval = Qnil;
756
+
757
+ #line 635 "/home/geoff/Projects/redeye/ext/redeye/redeye.cr"
758
+
759
+ do {
760
+ redeyeop_t * op ;
761
+ Data_Get_Struct(self, redeyeop_t, op);
762
+ do { __p_retval = GOBJ2RVAL(GDK_PIXBUF(redeye_preview(op, FALSE))); goto out; } while(0);
763
+
764
+ } while(0);
765
+
766
+ out:
767
+ return __p_retval;
768
+ }
769
+
770
+ static VALUE
771
+ RedEye_pixbuf(VALUE self)
772
+ {
773
+ VALUE __p_retval = Qnil;
774
+
775
+ #line 642 "/home/geoff/Projects/redeye/ext/redeye/redeye.cr"
776
+
777
+ do {
778
+ redeyeop_t * op ;
779
+ Data_Get_Struct(self, redeyeop_t, op);
780
+ do { __p_retval = GOBJ2RVAL(GDK_PIXBUF(op->pixbuf)); goto out; } while(0);
781
+
782
+ } while(0);
783
+
784
+ out:
785
+ return __p_retval;
786
+ }
787
+
788
+ static VALUE
789
+ Region_ratio(VALUE self)
790
+ {
791
+ VALUE __p_retval = Qnil;
792
+
793
+ #line 497 "/home/geoff/Projects/redeye/ext/redeye/redeye.cr"
794
+ int width,height;
795
+ double min,max,ratio;
796
+ width = NUM2INT(rb_struct_getmember(self, rb_intern("width")));
797
+ height = NUM2INT(rb_struct_getmember(self, rb_intern("height")));
798
+ min = (double)MIN(width,height);
799
+ max = (double)MAX(width,height);
800
+ ratio = (min / max);
801
+ do { __p_retval = rb_float_new(ratio); goto out; } while(0);
802
+ out:
803
+ return __p_retval;
804
+ }
805
+
806
+ static VALUE
807
+ Region_density(VALUE self)
808
+ {
809
+ VALUE __p_retval = Qnil;
810
+
811
+ #line 507 "/home/geoff/Projects/redeye/ext/redeye/redeye.cr"
812
+
813
+ do {
814
+ int noPixels, width, height;
815
+ double density ;
816
+ noPixels = NUM2INT(rb_struct_getmember(self, rb_intern("noPixels")));
817
+ width = NUM2INT(rb_struct_getmember(self, rb_intern("width")));
818
+ height = NUM2INT(rb_struct_getmember(self, rb_intern("height")));
819
+ density = ((double)noPixels / (double)(width * height));
820
+ do { __p_retval = rb_float_new(density); goto out; } while(0);
821
+
822
+ } while(0);
823
+
824
+ out:
825
+ return __p_retval;
826
+ }
827
+
828
+ static VALUE
829
+ Region_squareish_query(int __p_argc, VALUE *__p_argv, VALUE self)
830
+ {
831
+ VALUE __p_retval = Qnil;
832
+ VALUE __v_min_ratio = Qnil;
833
+ double min_ratio; double __orig_min_ratio;
834
+ VALUE __v_min_density = Qnil;
835
+ double min_density; double __orig_min_density;
836
+
837
+ /* Scan arguments */
838
+ rb_scan_args(__p_argc, __p_argv, "02",&__v_min_ratio, &__v_min_density);
839
+
840
+ /* Set defaults */
841
+ if (__p_argc > 0)
842
+ __orig_min_ratio = min_ratio = NUM2DBL(__v_min_ratio);
843
+ else
844
+ min_ratio = 0.5;
845
+
846
+ if (__p_argc > 1)
847
+ __orig_min_density = min_density = NUM2DBL(__v_min_density);
848
+ else
849
+ min_density = 0.5;
850
+
851
+
852
+ #line 518 "/home/geoff/Projects/redeye/ext/redeye/redeye.cr"
853
+ int noPixels, width, height;
854
+ double min, max, ratio, density;
855
+ noPixels = NUM2INT(rb_struct_getmember(self, rb_intern("noPixels")));
856
+ width = NUM2INT(rb_struct_getmember(self, rb_intern("width")));
857
+ height = NUM2INT(rb_struct_getmember(self, rb_intern("height")));
858
+ min = (double)MIN(width,height);
859
+ max = (double)MAX(width,height);
860
+ ratio = (min / max);
861
+ density = ((double)noPixels / (double)(width * height));
862
+ do { __p_retval = ((((ratio >= min_ratio) && (density > min_density))) ? Qtrue : Qfalse); goto out; } while(0);
863
+ out:
864
+ return __p_retval;
865
+ }
866
+
867
+ /* Init */
868
+ void
869
+ Init_redeye(void)
870
+ {
871
+ cRedEye = rb_define_class("RedEye", rb_cObject);
872
+ rb_define_alloc_func(cRedEye, RedEye___alloc__);
873
+ rb_define_method(cRedEye, "initialize", RedEye_initialize, 5);
874
+ rb_define_method(cRedEye, "identify_blobs", RedEye_identify_blobs, -1);
875
+ rb_define_method(cRedEye, "correct_blob", RedEye_correct_blob, 1);
876
+ rb_define_method(cRedEye, "highlight_blob", RedEye_highlight_blob, -1);
877
+ rb_define_method(cRedEye, "preview_blob", RedEye_preview_blob, -1);
878
+ rb_define_method(cRedEye, "preview", RedEye_preview, 0);
879
+ rb_define_method(cRedEye, "pixbuf", RedEye_pixbuf, 0);
880
+ structRegion = rb_struct_define("Region", "op", "id", "minX", "minY", "maxX", "maxY", "width", "height", "noPixels", NULL);
881
+ rb_define_const(cRedEye, "Region", structRegion);
882
+ rb_define_method(structRegion, "ratio", Region_ratio, 0);
883
+ rb_define_method(structRegion, "density", Region_density, 0);
884
+ rb_define_method(structRegion, "squareish?", Region_squareish_query, -1);
885
+ }