fb_gdkpixbuf.c (7815B)
1 /* $Id$ */ 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 }