add gamma correction suggested by coni
[booh] / ext / rbbooh.c
1 /*
2  *                         *  BOOH  *
3  *
4  * A.k.a `Best web-album Of the world, Or your money back, Humerus'.
5  *
6  * The acronyn sucks, however this is a tribute to Dragon Ball by
7  * Akira Toriyama, where the last enemy beaten by heroes of Dragon
8  * Ball is named "Boo". But there was already a free software project
9  * called Boo, so this one will be it "Booh". Or whatever.
10  *
11  *
12  * Copyright (c) 2005 Guillaume Cottenceau
13  *
14  * This software may be freely redistributed under the terms of the GNU
15  * public license version 2.
16  *
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., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23 #include <math.h>
24
25 #define GDK_PIXBUF_ENABLE_BACKEND
26 #include <gdk-pixbuf/gdk-pixbuf.h>
27 #include <gdk-pixbuf/gdk-pixdata.h>
28 #include "rbgobject.h"
29
30 #define _SELF(s) GDK_PIXBUF(RVAL2GOBJ(s)) 
31
32 static VALUE
33 whitebalance(self, level)
34     VALUE self, level; 
35 {
36         double red_filter[256], blue_filter[256];
37         int i, x, y;
38         guchar* pixels = gdk_pixbuf_get_pixels(_SELF(self));
39         int rowstride = gdk_pixbuf_get_rowstride(_SELF(self));
40
41         double factor = 1 + fabs(NUM2DBL(level))/100;
42         if (NUM2DBL(level) < 0) {
43                 factor = 1/factor;
44         }
45
46         for (i = 0; i < 256; i++) {
47                 red_filter[i]  = pow(((double)i)/255, 1/factor) * 255;
48                 blue_filter[i] = pow(((double)i)/255, factor) * 255;
49         }
50     
51         for (y = 0; y < gdk_pixbuf_get_height(_SELF(self)); y++) {
52                 guchar* pixline = &(pixels[rowstride*y]);
53                 for (x = 0; x < gdk_pixbuf_get_width(_SELF(self)); x++) {
54                         pixline[x*3]   = red_filter[pixline[x*3]];
55                         pixline[x*3+2] = blue_filter[pixline[x*3+2]];
56                 }
57         }
58
59         return self;
60 }
61
62 static VALUE
63 gammacorrect(self, level)
64     VALUE self, level; 
65 {
66         double filter[256];
67         int i, x, y;
68         guchar* pixels = gdk_pixbuf_get_pixels(_SELF(self));
69         int rowstride = gdk_pixbuf_get_rowstride(_SELF(self));
70
71         double factor = 1 + fabs(NUM2DBL(level))/100;
72         if (NUM2DBL(level) > 0) {
73                 factor = 1/factor;
74         }
75
76         for (i = 0; i < 256; i++) {
77                 filter[i] = pow(((double)i)/255, factor) * 255;
78         }
79     
80         for (y = 0; y < gdk_pixbuf_get_height(_SELF(self)); y++) {
81                 guchar* pixline = &(pixels[rowstride*y]);
82                 for (x = 0; x < gdk_pixbuf_get_width(_SELF(self)); x++) {
83                         pixline[x*3]   = filter[pixline[x*3]];
84                         pixline[x*3+1] = filter[pixline[x*3+1]];
85                         pixline[x*3+2] = filter[pixline[x*3+2]];
86                 }
87         }
88
89         return self;
90 }
91
92 void 
93 Init_gtkadds()
94 {
95     RGObjClassInfo* cinfo = (RGObjClassInfo*)rbgobj_lookup_class_by_gtype(GDK_TYPE_PIXBUF, Qnil);
96     rb_define_method(cinfo->klass, "whitebalance!", whitebalance, 1); 
97     rb_define_method(cinfo->klass, "gammacorrect!", gammacorrect, 1); 
98 }