Intial commit
[profile/ivi/w3m.git] / w3mimg / fb / fb_gdkpixbuf.c
1 /* $Id: fb_gdkpixbuf.c,v 1.21 2004/11/08 17:14:06 ukai Exp $ */
2 /**************************************************************************
3                 fb_gdkpixbuf.c 0.3 Copyright (C) 2002, hito
4  **************************************************************************/
5
6 #include "config.h"
7 #if defined(USE_GTK2)
8 #include <glib-object.h>
9 #include <gdk/gdk.h>
10 #endif
11 #include <gdk-pixbuf/gdk-pixbuf.h>
12 #include "fb.h"
13 #include "fb_img.h"
14
15 static void draw(FB_IMAGE * img, int x, int y, int w, int h,
16                  GdkPixbuf * pixbuf);
17 static GdkPixbuf *resize_image(GdkPixbuf * pixbuf, int width, int height);
18
19 #if defined(USE_GTK2)
20 static int
21 get_animation_size(GdkPixbufAnimation * animation, int *w, int *h, int *delay)
22 {
23     GdkPixbufAnimationIter *iter;
24     int n, i, d = -1;
25     GTimeVal time;
26
27     g_get_current_time(&time);
28     iter = gdk_pixbuf_animation_get_iter(animation, &time);
29     *w = gdk_pixbuf_animation_get_width(animation);
30     *h = gdk_pixbuf_animation_get_height(animation);
31     for (i = 1; 
32          gdk_pixbuf_animation_iter_on_currently_loading_frame(iter) != TRUE; 
33          i++) {
34         int tmp;
35         tmp = gdk_pixbuf_animation_iter_get_delay_time(iter);
36         g_time_val_add(&time, tmp * 1000);
37         if (tmp > d)
38             d = tmp;
39         gdk_pixbuf_animation_iter_advance(iter, &time);
40     }
41     if (delay)
42         *delay = d;
43     n = i;
44     g_object_unref(G_OBJECT(iter));
45     return n;
46 }
47 #else
48 static int
49 get_animation_size(GdkPixbufAnimation * animation, int *w, int *h, int *delay)
50 {
51     GList *frames;
52     int iw, ih, n, i, d = -1;
53
54     frames = gdk_pixbuf_animation_get_frames(animation);
55     n = gdk_pixbuf_animation_get_num_frames(animation);
56     *w = gdk_pixbuf_animation_get_width(animation);
57     *h = gdk_pixbuf_animation_get_height(animation);
58     for (i = 0; i < n; i++) {
59         GdkPixbufFrame *frame;
60         GdkPixbuf *pixbuf;
61         int tmp;
62
63         frame = (GdkPixbufFrame *) g_list_nth_data(frames, i);
64         tmp = gdk_pixbuf_frame_get_delay_time(frame);
65         if (tmp > d)
66             d = tmp;
67         pixbuf = gdk_pixbuf_frame_get_pixbuf(frame);
68         iw = gdk_pixbuf_frame_get_x_offset(frame)
69             + gdk_pixbuf_get_width(pixbuf);
70         ih = gdk_pixbuf_frame_get_y_offset(frame)
71             + gdk_pixbuf_get_height(pixbuf);
72         if (iw > *w)
73             *w = iw;
74         if (ih > *h)
75             *h = ih;
76     }
77     if (delay)
78         *delay = d;
79     return n;
80 }
81 #endif
82
83 void
84 fb_image_init()
85 {
86 #if defined(USE_GTK2)
87     g_type_init();
88 #endif
89 }
90
91 int
92 get_image_size(char *filename, int *w, int *h)
93 {
94     GdkPixbufAnimation *animation;
95     if (filename == NULL)
96         return 1;
97 #if defined(USE_GTK2)
98     animation = gdk_pixbuf_animation_new_from_file(filename, NULL);
99 #else
100     animation = gdk_pixbuf_animation_new_from_file(filename);
101 #endif
102     if (animation == NULL)
103         return 1;
104     get_animation_size(animation, w, h, NULL);
105 #if defined(USE_GTK2)
106     g_object_unref(G_OBJECT(animation));
107 #else
108     gdk_pixbuf_animation_unref(animation);
109 #endif
110     return 0;
111 }
112
113 FB_IMAGE **
114 fb_image_load(char *filename, int w, int h, int max_anim)
115 {
116     GdkPixbufAnimation *animation;
117 #if defined(USE_GTK2)
118     GdkPixbufAnimationIter *iter;
119     GTimeVal time;
120 #else
121     int i;
122     GList *frames;
123 #endif
124     double ratio_w, ratio_h;
125     int n, j, fw, fh, frame_num, delay;
126     FB_IMAGE **fb_frame = NULL, *tmp_image = NULL;
127
128     if (filename == NULL)
129         return NULL;
130 #if defined(USE_GTK2)
131     animation = gdk_pixbuf_animation_new_from_file(filename, NULL);
132 #else
133     animation = gdk_pixbuf_animation_new_from_file(filename);
134 #endif
135     if (animation == NULL)
136         return NULL;
137     frame_num = n = get_animation_size(animation, &fw, &fh, &delay);
138     if (delay <= 0)
139         max_anim = -1;
140     if (max_anim < 0) {
141         frame_num = (-max_anim > n) ? n : -max_anim;
142     }
143     else if (max_anim > 0) {
144         frame_num = n = (max_anim > n) ? n : max_anim;
145     }
146     if (w < 1 || h < 1) {
147         w = fw;
148         h = fh;
149         ratio_w = ratio_h = 1;
150     }
151     else {
152         ratio_w = 1.0 * w / fw;
153         ratio_h = 1.0 * h / fh;
154     }
155
156     fb_frame = fb_frame_new(w, h, frame_num);
157     if (fb_frame == NULL)
158         goto END;
159
160     tmp_image = fb_image_new(w, h);
161     if (tmp_image == NULL) {
162         fb_frame_free(fb_frame);
163         fb_frame = NULL;
164         goto END;
165     }
166
167     if (bg_r != 0 || bg_g != 0 || bg_b != 0) {
168         fb_image_fill(tmp_image, bg_r, bg_g, bg_b);
169     }
170
171 #if defined(USE_GTK2)
172     g_get_current_time(&time);
173     iter = gdk_pixbuf_animation_get_iter(animation, &time);
174
175     if (max_anim < 0 && n > -max_anim) {
176         max_anim = n + max_anim;
177         for (j = 0; j < max_anim; j++) {
178             g_time_val_add(&time, 
179                            gdk_pixbuf_animation_iter_get_delay_time(iter) * 1000);
180             gdk_pixbuf_animation_iter_advance(iter, &time);
181         }
182     }
183     for (j = 0; j < n; j++) {
184         GdkPixbuf *org_pixbuf, *pixbuf;
185
186         org_pixbuf = gdk_pixbuf_animation_iter_get_pixbuf(iter);
187         pixbuf = resize_image(org_pixbuf, w, h);
188
189         fb_frame[j]->delay = gdk_pixbuf_animation_iter_get_delay_time(iter);
190         g_time_val_add(&time, fb_frame[j]->delay * 1000);
191         draw(fb_frame[j], 0, 0, w, h, pixbuf);
192         if (org_pixbuf != pixbuf)
193             g_object_unref(G_OBJECT(pixbuf));
194         gdk_pixbuf_animation_iter_advance(iter, &time);
195     }
196 #else
197     frames = gdk_pixbuf_animation_get_frames(animation);
198
199     for (j = 0; j < n; j++) {
200         GdkPixbufFrame *frame;
201         GdkPixbuf *org_pixbuf, *pixbuf;
202         int width, height, ofstx, ofsty;
203
204         if (max_anim < 0) {
205             i = (j - n + frame_num > 0) ? (j - n + frame_num) : 0;
206         }
207         else {
208             i = j;
209         }
210         frame = (GdkPixbufFrame *) g_list_nth_data(frames, j);
211         org_pixbuf = gdk_pixbuf_frame_get_pixbuf(frame);
212         ofstx = gdk_pixbuf_frame_get_x_offset(frame);
213         ofsty = gdk_pixbuf_frame_get_y_offset(frame);
214         width = gdk_pixbuf_get_width(org_pixbuf);
215         height = gdk_pixbuf_get_height(org_pixbuf);
216         if (ofstx == 0 && ofsty == 0 && width == fw && height == fh) {
217             pixbuf = resize_image(org_pixbuf, w, h);
218         }
219         else {
220             pixbuf =
221                 resize_image(org_pixbuf, width * ratio_w, height * ratio_h);
222             ofstx *= ratio_w;
223             ofsty *= ratio_h;
224         }
225         width = gdk_pixbuf_get_width(pixbuf);
226         height = gdk_pixbuf_get_height(pixbuf);
227
228         fb_frame[i]->delay = gdk_pixbuf_frame_get_delay_time(frame);
229         fb_image_copy(fb_frame[i], tmp_image);
230         draw(fb_frame[i], ofstx, ofsty, width, height, pixbuf);
231
232         switch (gdk_pixbuf_frame_get_action(frame)) {
233         case GDK_PIXBUF_FRAME_RETAIN:
234             fb_image_copy(tmp_image, fb_frame[i]);
235             break;
236         case GDK_PIXBUF_FRAME_DISPOSE:
237             fb_image_fill(tmp_image, bg_r, bg_g, bg_b);
238             break;
239         case GDK_PIXBUF_FRAME_REVERT:
240             fb_image_copy(tmp_image, fb_frame[0]);
241             break;
242         default:
243             fb_image_copy(tmp_image, fb_frame[0]);
244         }
245
246         if (org_pixbuf != pixbuf)
247             gdk_pixbuf_finalize(pixbuf);
248     }
249 #endif
250   END:
251     if (tmp_image)
252         fb_image_free(tmp_image);
253 #if defined(USE_GTK2)
254     g_object_unref(G_OBJECT(animation));
255 #else
256     gdk_pixbuf_animation_unref(animation);
257 #endif
258     return fb_frame;
259 }
260 static void
261 draw(FB_IMAGE * img, int x, int y, int w, int h, GdkPixbuf * pixbuf)
262 {
263     int i, j, r, g, b, offset, bpp, rowstride;
264     guchar *pixels;
265     gboolean alpha;
266     if (img == NULL || pixbuf == NULL)
267         return;
268     rowstride = gdk_pixbuf_get_rowstride(pixbuf);
269     pixels = gdk_pixbuf_get_pixels(pixbuf);
270     alpha = gdk_pixbuf_get_has_alpha(pixbuf);
271     bpp = rowstride / w;
272     for (j = 0; j < h; j++) {
273         offset = j * rowstride;
274         for (i = 0; i < w; i++, offset += bpp) {
275             r = pixels[offset];
276             g = pixels[offset + 1];
277             b = pixels[offset + 2];
278             if (!alpha || pixels[offset + 3] != 0) {
279                 fb_image_pset(img, i + x, j + y, r, g, b);
280             }
281         }
282     }
283     return;
284 }
285 static GdkPixbuf *
286 resize_image(GdkPixbuf * pixbuf, int width, int height)
287 {
288     GdkPixbuf *resized_pixbuf;
289     int w, h;
290     if (pixbuf == NULL)
291         return NULL;
292     w = gdk_pixbuf_get_width(pixbuf);
293     h = gdk_pixbuf_get_height(pixbuf);
294     if (width < 1 || height < 1)
295         return pixbuf;
296     if (w == width && h == height)
297         return pixbuf;
298     resized_pixbuf =
299         gdk_pixbuf_scale_simple(pixbuf, width, height, GDK_INTERP_HYPER);
300     if (resized_pixbuf == NULL)
301         return NULL;
302     return resized_pixbuf;
303 }