w3m

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/w3m.git/
Log | Files | Refs | README

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 }