also use libexif for sorting a directory according to EXIF date, makes operation...
[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 #include <libexif/exif-data.h>
33
34 static VALUE
35 whitebalance(self, level)
36     VALUE self, level; 
37 {
38         double red_filter[256], blue_filter[256];
39         int i, x, y;
40         guchar* pixels = gdk_pixbuf_get_pixels(_SELF(self));
41         int rowstride = gdk_pixbuf_get_rowstride(_SELF(self));
42
43         double factor = 1 + fabs(NUM2DBL(level))/100;
44         if (NUM2DBL(level) < 0) {
45                 factor = 1/factor;
46         }
47
48         for (i = 0; i < 256; i++) {
49                 red_filter[i]  = pow(((double)i)/255, 1/factor) * 255;
50                 blue_filter[i] = pow(((double)i)/255, factor) * 255;
51         }
52     
53         for (y = 0; y < gdk_pixbuf_get_height(_SELF(self)); y++) {
54                 guchar* pixline = &(pixels[rowstride*y]);
55                 for (x = 0; x < gdk_pixbuf_get_width(_SELF(self)); x++) {
56                         pixline[x*3]   = red_filter[pixline[x*3]];
57                         pixline[x*3+2] = blue_filter[pixline[x*3+2]];
58                 }
59         }
60
61         return self;
62 }
63
64 static VALUE
65 gammacorrect(self, level)
66     VALUE self, level; 
67 {
68         double filter[256];
69         int i, x, y;
70         guchar* pixels = gdk_pixbuf_get_pixels(_SELF(self));
71         int rowstride = gdk_pixbuf_get_rowstride(_SELF(self));
72
73         double factor = 1 + fabs(NUM2DBL(level))/100;
74         if (NUM2DBL(level) > 0) {
75                 factor = 1/factor;
76         }
77
78         for (i = 0; i < 256; i++) {
79                 filter[i] = pow(((double)i)/255, factor) * 255;
80         }
81     
82         for (y = 0; y < gdk_pixbuf_get_height(_SELF(self)); y++) {
83                 guchar* pixline = &(pixels[rowstride*y]);
84                 for (x = 0; x < gdk_pixbuf_get_width(_SELF(self)); x++) {
85                         pixline[x*3]   = filter[pixline[x*3]];
86                         pixline[x*3+1] = filter[pixline[x*3+1]];
87                         pixline[x*3+2] = filter[pixline[x*3+2]];
88                 }
89         }
90
91         return self;
92 }
93
94 static ExifEntry* exif_entry(VALUE filename, ExifTag tag, ExifData** data) {
95         unsigned int i;
96
97         *data = exif_data_new_from_file(StringValuePtr(filename));
98         if (*data == NULL) {
99                 fprintf(stderr, "libexif failed loading file '%s'\n", StringValuePtr(filename));
100                 return NULL;
101         }
102
103         for (i = 0; i < EXIF_IFD_COUNT; i++) {
104                 ExifEntry* entry = exif_content_get_entry((*data)->ifd[i], tag);
105                 if (entry) {
106                         return entry;
107                 }
108         }
109
110         return NULL;
111 }
112
113 static VALUE exif_orientation(VALUE module, VALUE filename) {
114         ExifData* data = NULL;
115         ExifEntry* entry;
116
117         entry = exif_entry(filename, EXIF_TAG_ORIENTATION, &data);
118
119         if (entry != NULL) {
120                 VALUE ret;
121                 ExifByteOrder o;
122                 ExifShort v_short;
123                 if (!entry || !entry->parent || !entry->parent->parent)
124                         return Qnil;
125                 o = exif_data_get_byte_order(entry->parent->parent);
126                 v_short = exif_get_short(entry->data, o);
127                 ret = INT2NUM(v_short);
128                 exif_data_free(data);
129                 return ret;
130         }
131         
132         if (data)
133                 exif_data_free(data);
134         return Qnil;
135 }
136
137 static VALUE exif_datetimeoriginal(VALUE module, VALUE filename) {
138         ExifData* data = NULL;
139         ExifEntry* entry;
140
141         entry = exif_entry(filename, EXIF_TAG_DATE_TIME_ORIGINAL, &data);
142
143         if (entry != NULL) {
144                 VALUE ret = rb_str_new((const char*) entry->data, entry->size);
145                 exif_data_free(data);
146                 return ret;
147         }
148
149         if (data)
150                 exif_data_free(data);
151         return Qnil;
152 }
153
154
155
156 void 
157 Init_libadds()
158 {
159     RGObjClassInfo* cinfo = (RGObjClassInfo*)rbgobj_lookup_class_by_gtype(GDK_TYPE_PIXBUF, Qnil);
160     rb_define_method(cinfo->klass, "whitebalance!", whitebalance, 1); 
161     rb_define_method(cinfo->klass, "gammacorrect!", gammacorrect, 1); 
162
163     VALUE exif = rb_define_module("Exif");
164     rb_define_module_function(exif, "orientation", exif_orientation, 1);
165     rb_define_module_function(exif, "datetimeoriginal", exif_datetimeoriginal, 1);
166 }