1 /* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */
2 
3 /*
4  * GImageView
5  * Copyright (C) 2001 Takuro Ashie
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  *
21  * $Id: gimv_image.c,v 1.68 2004/09/21 08:44:31 makeinu Exp $
22  */
23 
24 #include "gimageview.h"
25 
26 #include <stdio.h>
27 #include <string.h>
28 
29 #include "gimv_anim.h"
30 #include "gimv_image.h"
31 #include "gimv_image_loader.h"
32 #include "gimv_mime_types.h"
33 #include "prefs.h"
34 #include "fileutil.h"
35 #include "gimv_io.h"
36 #include "gimv_image_saver.h"
37 
38 #if defined (HAVE_GDK_PIXBUF)
39 #  include <gdk-pixbuf/gdk-pixbuf.h>
40 #  include "pixbuf_utils.h"
41 typedef GdkPixbuf GimvRawImage;
42 #elif defined (HAVE_GDK_IMLIB)
43 #  include <gdk_imlib.h>
44 typedef GdkImlibImage GimvRawImage;
45 #endif /* HAVE_GDK_PIXBUF */
46 
47 
48 static void gimv_image_class_init    (GimvImageClass *klass);
49 static void gimv_image_init          (GimvImage      *image);
50 static void gimv_image_destroy       (GtkObject      *object);
51 static void gimv_image_backend_init  (void);
52 
53 
54 static GtkObjectClass *parent_class = NULL;
55 
56 
57 GtkType
gimv_image_get_type(void)58 gimv_image_get_type (void)
59 {
60    static GtkType gimv_image_type = 0;
61 
62    if (!gimv_image_type) {
63       static const GtkTypeInfo gimv_image_info = {
64          "GimvImage",
65          sizeof (GimvImage),
66          sizeof (GimvImageClass),
67          (GtkClassInitFunc) gimv_image_class_init,
68          (GtkObjectInitFunc) gimv_image_init,
69          NULL,
70          NULL,
71          (GtkClassInitFunc) NULL,
72       };
73 
74       gimv_image_type = gtk_type_unique (gtk_object_get_type (),
75                                          &gimv_image_info);
76    }
77 
78    return gimv_image_type;
79 }
80 
81 
82 static void
gimv_image_class_init(GimvImageClass * klass)83 gimv_image_class_init (GimvImageClass *klass)
84 {
85    GtkObjectClass *object_class;
86 
87    gimv_image_backend_init ();
88 
89    object_class = (GtkObjectClass *) klass;
90    parent_class = gtk_type_class (gtk_object_get_type ());
91 
92    object_class->destroy  = gimv_image_destroy;
93 }
94 
95 
96 static void
gimv_image_init(GimvImage * image)97 gimv_image_init (GimvImage *image)
98 {
99    image->image           = NULL;
100    image->angle           = GIMV_IMAGE_ROTATE_0;
101    image->flags           = 0;
102    /* image->ref_count       = 1; */
103    image->comments        = NULL;
104    image->additional_data = NULL;
105 
106 #ifdef USE_GTK2
107    gtk_object_ref (GTK_OBJECT (image));
108    gtk_object_sink (GTK_OBJECT (image));
109 #endif
110 }
111 
112 
113 static void
gimv_image_destroy(GtkObject * object)114 gimv_image_destroy (GtkObject *object)
115 {
116    GimvImage *image = GIMV_IMAGE (object);
117    GimvRawImage *rawimage;
118 
119    g_return_if_fail (image);
120 
121    rawimage = (GimvRawImage *) image->image;
122 
123 #if defined (HAVE_GDK_PIXBUF)
124    if (rawimage)
125       gdk_pixbuf_unref (rawimage);
126 #elif defined (HAVE_GDK_IMLIB)
127    gdk_imlib_kill_image (rawimage);
128 #endif /* HAVE_GDK_PIXBUF */
129    image->image = NULL;
130 
131    gimv_image_free_comments (image);
132 
133    if (GTK_OBJECT_CLASS (parent_class)->destroy)
134       (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
135 }
136 
137 
138 GimvImage *
gimv_image_new(void)139 gimv_image_new (void)
140 {
141    GimvImage *image = GIMV_IMAGE (gtk_type_new (GIMV_TYPE_IMAGE));
142    return image;
143 }
144 
145 
146 /****************************************************************************
147  *
148  *  GimvImage methods
149  *
150  ****************************************************************************/
151 void
gimv_image_backend_init(void)152 gimv_image_backend_init (void)
153 {
154 #if defined (HAVE_GDK_PIXBUF)
155 #elif defined (HAVE_GDK_IMLIB)
156    /*
157    GdkImlibInitParams *imlib_param;
158 
159    imlib_param = g_new0 (GdkImlibInitParams, 1);
160 
161    imlib_param->flags = PARAMS_REMAP | PARAMS_FASTRENDER;
162    imlib_param->remap = 0;
163    imlib_param->fastrender = 0;
164    gdk_imlib_init_params(imlib_param);
165    g_free (imlib_param);
166    */
167    gdk_imlib_init ();
168    gtk_widget_push_visual (gdk_imlib_get_visual());
169    gtk_widget_push_colormap (gdk_imlib_get_colormap());
170 #endif /* HAVE_GDK_PIXBUF */
171 }
172 
173 
174 GimvImage *
gimv_image_load_file(const gchar * filename,gboolean animation)175 gimv_image_load_file (const gchar *filename, gboolean animation)
176 {
177    GimvImageLoader *loader;
178    GimvImage *image;
179 
180    loader = gimv_image_loader_new_with_file_name (filename);
181    if (!loader) return NULL;
182 
183    gimv_image_loader_set_as_animation (loader, animation);
184    gimv_image_loader_load (loader);
185    image = gimv_image_loader_get_image (loader);
186    if (image)
187       gimv_image_ref (image);
188    gimv_image_loader_unref (loader);
189 
190    return image;
191 }
192 
193 
194 gboolean
gimv_image_save_file(GimvImage * image,const gchar * filename,const gchar * format)195 gimv_image_save_file  (GimvImage   *image,
196                        const gchar *filename,
197                        const gchar *format)
198 {
199    GimvImageSaver *saver;
200    gboolean retval;
201 
202    saver = gimv_image_saver_new_with_attr (image, filename, format);
203    /* gimv_image_saver_set_param (data, use_specific_data) */
204    retval = gimv_image_saver_save (saver);
205    gimv_image_saver_unref (saver);
206 
207    return retval;
208 }
209 
210 
211 #if defined (HAVE_GDK_PIXBUF)
212 static void
free_rgb_buffer(guchar * pixels,gpointer data)213 free_rgb_buffer (guchar *pixels, gpointer data)
214 {
215    g_free(pixels);
216 }
217 #endif /* HAVE_GDK_PIXBUF */
218 
219 
220 GimvImage *
gimv_image_create_from_data(guchar * data,gint width,gint height,gboolean alpha)221 gimv_image_create_from_data (guchar *data, gint width, gint height, gboolean alpha)
222 {
223    GimvImage *image;
224 
225    image = gimv_image_new ();
226 
227 #if defined (HAVE_GDK_PIXBUF)
228    {
229       gint bytes = 3;
230 
231       if (alpha)
232          bytes = 4;
233 
234       image->image = gdk_pixbuf_new_from_data (data,
235                                                GDK_COLORSPACE_RGB, alpha, 8,
236                                                width, height, bytes * width,
237                                                free_rgb_buffer, NULL);
238    }
239 #elif defined (HAVE_GDK_IMLIB)
240    image->image = gdk_imlib_create_image_from_data (data, NULL, width, height);
241    g_free (data);
242 #endif /* HAVE_GDK_PIXBUF */
243 
244    if (!image->image) {
245       gimv_image_unref (image);
246       image = NULL;
247    }
248 
249    return image;
250 }
251 
252 
253 GimvImage *
gimv_image_create_from_drawable(GdkDrawable * drawable,gint x,gint y,gint width,gint height)254 gimv_image_create_from_drawable (GdkDrawable *drawable, gint x, gint y,
255                                  gint width, gint height)
256 {
257    GimvImage *image;
258 
259    image = gimv_image_new ();
260 
261 #if defined (HAVE_GDK_PIXBUF)
262    {
263       GdkColormap *cmap = gdk_colormap_get_system ();
264       image->image = gdk_pixbuf_get_from_drawable (NULL, drawable, cmap,
265                                                    x , y, 0, 0,
266                                                    width, height);
267    }
268 #elif defined (HAVE_GDK_IMLIB)
269    image->image = gdk_imlib_create_image_from_drawable (drawable, NULL,
270                                                         x, y,
271                                                         width, height);
272 #endif /* HAVE_GDK_PIXBUF */
273 
274    if (!image->image) {
275       gimv_image_unref (image);
276       image = NULL;
277    }
278 
279    return image;
280 }
281 
282 
283 void
gimv_image_add_comment(GimvImage * image,const gchar * key,const gchar * val)284 gimv_image_add_comment (GimvImage *image,
285                         const gchar *key,
286                         const gchar *val)
287 {
288    gchar *orig_key, *old_value;
289    gboolean success;
290 
291    g_return_if_fail (image);
292    g_return_if_fail (key && *key);
293    g_return_if_fail (val);
294 
295    if (!image->comments)
296       image->comments = g_hash_table_new (g_str_hash, g_str_equal);
297 
298    success = g_hash_table_lookup_extended (image->comments, key,
299                                            (gpointer) &orig_key,
300                                            (gpointer) &old_value);
301    if (success) {
302       g_hash_table_remove (image->comments, key);
303       g_free (orig_key);
304       g_free (old_value);
305    }
306 
307    g_hash_table_insert (image->comments, g_strdup (key), g_strdup (val));
308 }
309 
310 
311 GimvImage *
gimv_image_rotate_90(GimvImage * image,gboolean counter_clockwise)312 gimv_image_rotate_90 (GimvImage *image,
313                       gboolean counter_clockwise)
314 {
315    GimvRawImage *src_rawimage, *dest_rawimage;
316 
317    g_return_val_if_fail (image, NULL);
318    g_return_val_if_fail (image->image, NULL);
319 
320    src_rawimage = (GimvRawImage *) image->image;
321 
322 #if defined (HAVE_GDK_PIXBUF)
323    dest_rawimage = pixbuf_copy_rotate_90 (src_rawimage, counter_clockwise);
324    gdk_pixbuf_unref (src_rawimage);
325 #elif defined (HAVE_GDK_IMLIB)
326    if (counter_clockwise) {
327       gdk_imlib_flip_image_horizontal (src_rawimage);
328       gdk_imlib_rotate_image (src_rawimage, 1);
329    } else {
330       gdk_imlib_flip_image_vertical (src_rawimage);
331       gdk_imlib_rotate_image (src_rawimage, 1);
332    }
333    dest_rawimage = src_rawimage;
334 #endif /* HAVE_GDK_PIXBUF */
335 
336    image->image = dest_rawimage;
337 
338    if (counter_clockwise)
339       image->angle += GIMV_IMAGE_ROTATE_90;
340    else
341       image->angle += GIMV_IMAGE_ROTATE_270;
342 
343    image->angle %= 4;
344 
345    if (image->angle < 0)
346       image->angle += 4;
347 
348    return image;
349 }
350 
351 
352 GimvImage *
gimv_image_rotate_180(GimvImage * image)353 gimv_image_rotate_180 (GimvImage *image)
354 {
355    GimvRawImage *src_rawimage, *dest_rawimage;
356 
357    g_return_val_if_fail (image, NULL);
358    g_return_val_if_fail (image->image, NULL);
359 
360    src_rawimage = (GimvRawImage *) image->image;
361 
362 #if defined (HAVE_GDK_PIXBUF)
363    dest_rawimage = pixbuf_copy_mirror (src_rawimage, TRUE, TRUE);
364    gdk_pixbuf_unref (src_rawimage);
365 #elif defined (HAVE_GDK_IMLIB)
366    gdk_imlib_flip_image_vertical (src_rawimage);
367    gdk_imlib_flip_image_horizontal (src_rawimage);
368    dest_rawimage = src_rawimage;
369 #endif /* HAVE_GDK_PIXBUF */
370 
371    image->image = dest_rawimage;
372 
373    image->angle += GIMV_IMAGE_ROTATE_180;
374    image->angle %= 4;
375    if (image->angle < 0)
376       image->angle += 4;
377 
378    return image;
379 }
380 
381 
382 GimvImage *
gimv_image_rotate(GimvImage * image,GimvImageAngle abs_angle)383 gimv_image_rotate (GimvImage *image, GimvImageAngle abs_angle)
384 {
385    gint rotate, angle;
386 
387    g_return_val_if_fail (image, NULL);
388 
389    if (image->angle < 0 || image->angle > 3) {
390       image->angle %= 4;
391       if (image->angle < 0)
392          image->angle += 4;
393    }
394 
395    if (abs_angle < 0 || abs_angle > 3) {
396       angle = abs_angle % 4;
397       if (angle < 0)
398          angle += 4;
399    } else {
400       angle = abs_angle;
401    }
402 
403    if (image->angle == (GimvImageAngle) angle)
404       return image;
405 
406    rotate = angle - image->angle;
407    if (rotate < 0)
408       rotate += 4;
409 
410    switch (rotate) {
411    case GIMV_IMAGE_ROTATE_90:
412       gimv_image_rotate_90 (image, TRUE);
413       break;
414    case GIMV_IMAGE_ROTATE_180:
415       gimv_image_rotate_180 (image);
416       break;
417    case GIMV_IMAGE_ROTATE_270:
418       gimv_image_rotate_90 (image, FALSE);
419       break;
420    default:
421       break;
422    }
423 
424    return image;
425 }
426 
427 
428 void
gimv_image_get_pixmap_and_mask(GimvImage * image,GdkPixmap ** pixmap_return,GdkBitmap ** mask_return)429 gimv_image_get_pixmap_and_mask (GimvImage  *image,
430                                 GdkPixmap **pixmap_return,
431                                 GdkBitmap **mask_return)
432 {
433    GimvRawImage *rawimage;
434 
435    g_return_if_fail (image);
436    g_return_if_fail (image->image);
437    g_return_if_fail (pixmap_return);
438    g_return_if_fail (mask_return);
439 
440    rawimage = (GimvRawImage *) image->image;
441 
442 #if defined (HAVE_GDK_PIXBUF)
443    gdk_pixbuf_render_pixmap_and_mask (rawimage, pixmap_return, mask_return, 64);
444 #elif defined (HAVE_GDK_IMLIB)
445    *pixmap_return = gdk_imlib_move_image (rawimage);
446    *mask_return = gdk_imlib_move_mask (rawimage);
447 
448    /* FIXME */
449    if (!*pixmap_return) {
450       gdk_imlib_render (image->image,
451                         gimv_image_width (image), gimv_image_height (image));
452       *pixmap_return = gdk_imlib_move_image (rawimage);
453       *mask_return = gdk_imlib_move_mask (rawimage);
454    }
455 #endif /* HAVE_GDK_PIXBUF */
456 }
457 
458 
459 void
gimv_image_free_pixmap_and_mask(GdkPixmap * pixmap,GdkBitmap * mask)460 gimv_image_free_pixmap_and_mask (GdkPixmap *pixmap,
461                                  GdkBitmap *mask)
462 {
463 #if defined (HAVE_GDK_PIXBUF)
464    if (pixmap) gdk_pixmap_unref (pixmap);
465    if (mask) gdk_bitmap_unref (mask);
466 #elif defined (HAVE_GDK_IMLIB)
467    gdk_imlib_free_pixmap (pixmap);
468    gdk_imlib_free_bitmap (mask);
469 #endif /* HAVE_GDK_PIXBUF */
470 }
471 
472 
473 gboolean
gimv_image_is_scalable(GimvImage * image)474 gimv_image_is_scalable (GimvImage *image)
475 {
476    g_return_val_if_fail (image, FALSE);
477 
478    return image->flags & GIMV_IMAGE_VECTOR_FLAGS;
479 }
480 
481 
482 GimvImage *
gimv_image_scale(GimvImage * image,gint width,gint height)483 gimv_image_scale (GimvImage *image,
484                   gint width, gint height)
485 {
486    GimvImage *dest_image;
487    GimvRawImage *src_rawimage, *dest_rawimage;
488 
489    g_return_val_if_fail (image, NULL);
490    g_return_val_if_fail (image->image, NULL);
491 
492    /* Check me!! */
493    if (conf.fast_scale_down
494        && width <= gimv_image_width (image)
495        && height <= gimv_image_height (image))
496    {
497       return gimv_image_scale_down (image, width, height);
498    }
499 
500    src_rawimage = (GimvRawImage *) image->image;
501 
502    /*
503    if (gimv_image_is_scalable (image)) {
504    } else {
505    }
506    */
507 
508 #if defined (HAVE_GDK_PIXBUF)
509    dest_rawimage = gdk_pixbuf_scale_simple (src_rawimage, width, height,
510                                             conf.interpolation);
511 #elif defined (HAVE_GDK_IMLIB)
512    dest_rawimage = gdk_imlib_clone_scaled_image (src_rawimage, width, height);
513 #endif /* HAVE_GDK_PIXBUF */
514 
515    dest_image = gimv_image_new ();
516    dest_image->image = dest_rawimage;
517 
518    return dest_image;
519 }
520 
521 
522 /*
523  *  fetched from of libgnomeui-2.2.0.1
524  *  (libgnomeui/gnome-thumbnail-pixbuf-utils.c) and adapt to GImageView
525  *
526  *  Copyright (C) 2002 Red Hat, Inc.
527  *  Author: Alexander Larsson <alexl@redhat.com>
528  */
529 GimvImage *
gimv_image_scale_down(GimvImage * image,int dest_width,int dest_height)530 gimv_image_scale_down (GimvImage *image,
531                        int dest_width,
532                        int dest_height)
533 {
534    int source_width, source_height;
535    int s_x1, s_y1, s_x2, s_y2;
536    int s_xfrac, s_yfrac;
537    int dx, dx_frac, dy, dy_frac;
538    div_t ddx, ddy;
539    int x, y;
540    int r, g, b, a;
541    int n_pixels;
542    gboolean has_alpha;
543    guchar *dest, *dest_pixels, *src, *xsrc, *src_pixels;
544    GimvImage *dest_image;
545    int pixel_stride;
546    int source_rowstride, dest_rowstride;
547 
548    if (dest_width <= 0 || dest_height <= 0) {
549       return NULL;
550    }
551 
552    source_width  = gimv_image_width (image);
553    source_height = gimv_image_height (image);
554 
555    g_assert (source_width >= dest_width);
556    g_assert (source_height >= dest_height);
557 
558    ddx = div (source_width, dest_width);
559    dx = ddx.quot;
560    dx_frac = ddx.rem;
561 
562    ddy = div (source_height, dest_height);
563    dy = ddy.quot;
564    dy_frac = ddy.rem;
565 
566    has_alpha = gimv_image_has_alpha (image);
567    pixel_stride = has_alpha ? 4 : 3;
568    source_rowstride = source_width * pixel_stride;
569    src_pixels = gimv_image_get_pixels (image);
570 
571    dest_rowstride = dest_width * pixel_stride;
572    dest_pixels = g_malloc0 (sizeof (guchar) * dest_rowstride * dest_height);
573    dest = dest_pixels;
574 
575    s_y1 = 0;
576    s_yfrac = -dest_height / 2;
577    while (s_y1 < source_height) {
578       s_y2 = s_y1 + dy;
579       s_yfrac += dy_frac;
580       if (s_yfrac > 0) {
581          s_y2++;
582          s_yfrac -= dest_height;
583       }
584 
585       s_x1 = 0;
586       s_xfrac = -dest_width / 2;
587       while (s_x1 < source_width) {
588          s_x2 = s_x1 + dx;
589          s_xfrac += dx_frac;
590          if (s_xfrac > 0) {
591             s_x2++;
592             s_xfrac -= dest_width;
593          }
594 
595          /* Average block of [x1,x2[ x [y1,y2[ and store in dest */
596          r = g = b = a = 0;
597          n_pixels = 0;
598 
599          src = src_pixels + s_y1 * source_rowstride + s_x1 * pixel_stride;
600          for (y = s_y1; y < s_y2; y++) {
601             xsrc = src;
602             if (has_alpha) {
603                for (x = 0; x < s_x2-s_x1; x++) {
604                   n_pixels++;
605 
606                   r += xsrc[3] * xsrc[0];
607                   g += xsrc[3] * xsrc[1];
608                   b += xsrc[3] * xsrc[2];
609                   a += xsrc[3];
610                   xsrc += 4;
611                }
612             } else {
613                for (x = 0; x < s_x2-s_x1; x++) {
614                   n_pixels++;
615                   r += *xsrc++;
616                   g += *xsrc++;
617                   b += *xsrc++;
618                }
619             }
620             src += source_rowstride;
621          }
622 
623          if (has_alpha) {
624             if (a != 0) {
625                *dest++ = r / a;
626                *dest++ = g / a;
627                *dest++ = b / a;
628                *dest++ = a / n_pixels;
629             } else {
630                *dest++ = 0;
631                *dest++ = 0;
632                *dest++ = 0;
633                *dest++ = 0;
634             }
635          } else {
636             *dest++ = r / n_pixels;
637             *dest++ = g / n_pixels;
638             *dest++ = b / n_pixels;
639          }
640 
641          s_x1 = s_x2;
642       }
643       s_y1 = s_y2;
644       dest += dest_rowstride - dest_width * pixel_stride;
645    }
646 
647    dest_image = gimv_image_create_from_data (dest_pixels,
648                                              dest_width,
649                                              dest_height,
650                                              has_alpha);
651 
652 	return dest_image;
653 }
654 
655 
656 void
gimv_image_scale_get_pixmap(GimvImage * image,gint width,gint height,GdkPixmap ** pixmap_return,GdkBitmap ** mask_return)657 gimv_image_scale_get_pixmap (GimvImage *image,
658                              gint width, gint height,
659                              GdkPixmap **pixmap_return,
660                              GdkBitmap **mask_return)
661 {
662    g_return_if_fail (image);
663    g_return_if_fail (image->image);
664    g_return_if_fail (pixmap_return);
665    g_return_if_fail (mask_return);
666 
667 #if defined (HAVE_GDK_PIXBUF)
668    {
669       GimvImage *dest_image;
670       dest_image = gimv_image_scale (image, width, height);
671       gimv_image_get_pixmap_and_mask (dest_image, pixmap_return, mask_return);
672       gimv_image_unref (dest_image);
673    }
674 #elif defined (HAVE_GDK_IMLIB)
675    gdk_imlib_render (image->image, width, height);
676    gimv_image_get_pixmap_and_mask (image, pixmap_return, mask_return);
677 #endif
678 }
679 
680 
681 void
gimv_image_get_size(GimvImage * image,gint * width,gint * height)682 gimv_image_get_size (GimvImage *image, gint *width, gint *height)
683 {
684    GimvRawImage *rawimage;
685 
686    g_return_if_fail (width && height);
687    *width = *height = -1;
688 
689    g_return_if_fail (image);
690    g_return_if_fail (image->image);
691 
692    rawimage = (GimvRawImage *) image->image;
693 
694 #if defined (HAVE_GDK_PIXBUF)
695    *width  = gdk_pixbuf_get_width  (rawimage);
696    *height = gdk_pixbuf_get_height (rawimage);
697 #elif defined (HAVE_GDK_IMLIB)
698    *width  = rawimage->rgb_width;
699    *height = rawimage->rgb_height;
700 #endif /* HAVE_GDK_PIXBUF */
701 }
702 
703 
704 gint
gimv_image_width(GimvImage * image)705 gimv_image_width (GimvImage *image)
706 {
707    GimvRawImage *rawimage;
708 
709    g_return_val_if_fail (image, -1);
710    g_return_val_if_fail (image->image, -1);
711 
712    rawimage = (GimvRawImage *) image->image;
713 
714 #if defined (HAVE_GDK_PIXBUF)
715    return gdk_pixbuf_get_width  (rawimage);
716 #elif defined (HAVE_GDK_IMLIB)
717    return rawimage->rgb_width;
718 #endif /* HAVE_GDK_PIXBUF */
719 }
720 
721 
722 gint
gimv_image_height(GimvImage * image)723 gimv_image_height (GimvImage *image)
724 {
725    GimvRawImage *rawimage;
726 
727    g_return_val_if_fail (image, -1);
728    g_return_val_if_fail (image->image, -1);
729 
730    rawimage = (GimvRawImage *) image->image;
731 
732 #if defined (HAVE_GDK_PIXBUF)
733    return gdk_pixbuf_get_height (rawimage);
734 #elif defined (HAVE_GDK_IMLIB)
735    return rawimage->rgb_height;
736 #endif /* HAVE_GDK_PIXBUF */
737 }
738 
739 
740 gint
gimv_image_depth(GimvImage * image)741 gimv_image_depth (GimvImage *image)
742 {
743    GimvRawImage *rawimage;
744 
745    g_return_val_if_fail (image, -1);
746    g_return_val_if_fail (image->image, -1);
747 
748    rawimage = (GimvRawImage *) image->image;
749 
750 #if defined (HAVE_GDK_PIXBUF)
751    return gdk_pixbuf_get_bits_per_sample (rawimage);
752 #elif defined (HAVE_GDK_IMLIB)
753    return 8;
754 #endif /* HAVE_GDK_PIXBUF */
755 }
756 
757 
758 gboolean
gimv_image_has_alpha(GimvImage * image)759 gimv_image_has_alpha (GimvImage *image)
760 {
761    GimvRawImage *rawimage;
762 
763    g_return_val_if_fail (image, FALSE);
764    g_return_val_if_fail (image->image, FALSE);
765 
766    rawimage = (GimvRawImage *) image->image;
767 
768 #if defined (HAVE_GDK_PIXBUF)
769    return gdk_pixbuf_get_has_alpha (rawimage);
770 #elif defined (HAVE_GDK_IMLIB)
771    return FALSE;
772 #endif /* HAVE_GDK_PIXBUF */
773 }
774 
775 
776 gboolean
gimv_image_can_alpha(GimvImage * image)777 gimv_image_can_alpha (GimvImage *image)
778 {
779 #if defined (HAVE_GDK_PIXBUF)
780    return TRUE;
781 #elif defined (HAVE_GDK_IMLIB)
782    return FALSE;
783 #endif /* HAVE_GDK_PIXBUF */
784 }
785 
786 
787 gint
gimv_image_rowstride(GimvImage * image)788 gimv_image_rowstride (GimvImage *image)
789 {
790    GimvRawImage *rawimage;
791 
792    g_return_val_if_fail (image, -1);
793    g_return_val_if_fail (image->image, -1);
794 
795    rawimage = (GimvRawImage *) image->image;
796 
797 #if defined (HAVE_GDK_PIXBUF)
798    return gdk_pixbuf_get_rowstride (rawimage);
799 #elif defined (HAVE_GDK_IMLIB)
800    if (!rawimage)
801       return 0;
802    else
803       return rawimage->rgb_width * 3;
804 #endif /* HAVE_GDK_PIXBUF */
805 }
806 
807 
808 guchar *
gimv_image_get_pixels(GimvImage * image)809 gimv_image_get_pixels (GimvImage *image)
810 {
811    GimvRawImage *rawimage;
812 
813    g_return_val_if_fail (image, NULL);
814    g_return_val_if_fail (image->image, NULL);
815 
816    rawimage = (GimvRawImage *) image->image;
817 
818 #if defined (HAVE_GDK_PIXBUF)
819    return gdk_pixbuf_get_pixels (rawimage);
820 #elif defined (HAVE_GDK_IMLIB)
821    if (!rawimage)
822       return NULL;
823    else
824       return rawimage->rgb_data;
825 #endif /* HAVE_GDK_PIXBUF */
826 }
827 
828 
829 const gchar *
gimv_image_get_comment(GimvImage * image,const gchar * key)830 gimv_image_get_comment (GimvImage *image, const gchar *key)
831 {
832    g_return_val_if_fail (image, NULL);
833 
834    if (!image->comments) return NULL;
835 
836    return g_hash_table_lookup (image->comments, key);
837 }
838 
839 
840 GimvImage  *
gimv_image_ref(GimvImage * image)841 gimv_image_ref (GimvImage *image)
842 {
843    gtk_object_ref (GTK_OBJECT (image));
844    return image;
845 }
846 
847 
848 void
gimv_image_unref(GimvImage * image)849 gimv_image_unref (GimvImage *image)
850 {
851    gtk_object_unref (GTK_OBJECT (image));
852 }
853 
854 
855 static void
free_comment(gpointer key,gpointer value,gpointer data)856 free_comment (gpointer key, gpointer value, gpointer data)
857 {
858    g_free (key);
859    g_free (value);
860 }
861 
862 
863 void
gimv_image_free_comments(GimvImage * image)864 gimv_image_free_comments (GimvImage *image)
865 {
866    g_return_if_fail (image);
867 
868    if (!image->comments) return;
869 
870    g_hash_table_foreach (image->comments,
871                          (GHFunc) free_comment,
872                          image);
873    g_hash_table_destroy (image->comments);
874    image->comments = NULL;
875 }
876 
877 
878 /*
879  *  gimv_image_detect_type_by_ext:
880  *     @ Detect image format by filename extension.
881  *
882  *  str    : Image file name.
883  *  Return : Image type by string.
884  */
885 const gchar *
gimv_image_detect_type_by_ext(const gchar * str)886 gimv_image_detect_type_by_ext (const gchar *str)
887 {
888    gchar *ext = fileutil_get_extention (str);
889    return gimv_mime_types_get_type_from_ext (ext);
890 }
891 
892 
893 
894 /****************************************************************************
895  *  FIXME!!
896  ****************************************************************************/
897 static void
rgb_to_hsv(gint * r,gint * g,gint * b)898 rgb_to_hsv (gint *r,
899             gint *g,
900             gint *b)
901 {
902    gint red, green, blue;
903    gfloat h, s, v;
904    gint min, max;
905    gint delta;
906 
907    h = 0.0;
908 
909    red = *r;
910    green = *g;
911    blue = *b;
912 
913    if (red > green) {
914       if (red > blue)
915          max = red;
916       else
917          max = blue;
918 
919       if (green < blue)
920          min = green;
921       else
922          min = blue;
923    } else {
924       if (green > blue)
925          max = green;
926       else
927          max = blue;
928 
929       if (red < blue)
930          min = red;
931       else
932          min = blue;
933    }
934 
935    v = max;
936 
937    if (max != 0)
938       s = ((max - min) * 255) / (gfloat) max;
939    else
940       s = 0;
941 
942    if (s == 0) {
943       h = 0;
944    } else {
945       delta = max - min;
946       if (red == max)
947          h = (green - blue) / (gfloat) delta;
948       else if (green == max)
949          h = 2 + (blue - red) / (gfloat) delta;
950       else if (blue == max)
951          h = 4 + (red - green) / (gfloat) delta;
952       h *= 42.5;
953 
954       if (h < 0)
955          h += 255;
956       if (h > 255)
957          h -= 255;
958    }
959 
960    *r = h;
961    *g = s;
962    *b = v;
963 }
964 
965 
966 static void
hsv_to_rgb(gint * h,gint * s,gint * v)967 hsv_to_rgb (gint *h,
968             gint *s,
969             gint *v)
970 {
971    gfloat hue, saturation, value;
972    gfloat f, p, q, t;
973 
974    if (*s == 0) {
975       *h = *v;
976       *s = *v;
977       *v = *v;
978    } else {
979       hue = *h * 6.0 / 255.0;
980       saturation = *s / 255.0;
981       value = *v / 255.0;
982 
983       f = hue - (gint) hue;
984       p = value * (1.0 - saturation);
985       q = value * (1.0 - (saturation * f));
986       t = value * (1.0 - (saturation * (1.0 - f)));
987 
988       switch ((gint) hue) {
989       case 0:
990          *h = value * 255;
991          *s = t * 255;
992          *v = p * 255;
993          break;
994       case 1:
995          *h = q * 255;
996          *s = value * 255;
997          *v = p * 255;
998          break;
999       case 2:
1000          *h = p * 255;
1001          *s = value * 255;
1002          *v = t * 255;
1003          break;
1004       case 3:
1005          *h = p * 255;
1006          *s = q * 255;
1007          *v = value * 255;
1008          break;
1009       case 4:
1010          *h = t * 255;
1011          *s = p * 255;
1012          *v = value * 255;
1013          break;
1014       case 5:
1015          *h = value * 255;
1016          *s = p * 255;
1017          *v = q * 255;
1018          break;
1019       }
1020    }
1021 }
1022 
1023 
1024 static void
rgb_to_hls(gint * r,gint * g,gint * b)1025 rgb_to_hls (gint *r,
1026             gint *g,
1027             gint *b)
1028 {
1029    gint red, green, blue;
1030    gfloat h, l, s;
1031    gint min, max;
1032    gint delta;
1033 
1034    red = *r;
1035    green = *g;
1036    blue = *b;
1037 
1038    if (red > green) {
1039       if (red > blue)
1040          max = red;
1041       else
1042          max = blue;
1043 
1044       if (green < blue)
1045          min = green;
1046       else
1047          min = blue;
1048    } else {
1049       if (green > blue)
1050          max = green;
1051       else
1052          max = blue;
1053 
1054       if (red < blue)
1055          min = red;
1056       else
1057          min = blue;
1058    }
1059 
1060    l = (max + min) / 2.0;
1061 
1062    if (max == min) {
1063       s = 0.0;
1064       h = 0.0;
1065    } else {
1066       delta = (max - min);
1067 
1068       if (l < 128)
1069          s = 255 * (gfloat) delta / (gfloat) (max + min);
1070       else
1071          s = 255 * (gfloat) delta / (gfloat) (511 - max - min);
1072 
1073       if (red == max)
1074          h = (green - blue) / (gfloat) delta;
1075       else if (green == max)
1076          h = 2 + (blue - red) / (gfloat) delta;
1077       else
1078          h = 4 + (red - green) / (gfloat) delta;
1079 
1080       h = h * 42.5;
1081 
1082       if (h < 0)
1083          h += 255;
1084       if (h > 255)
1085          h -= 255;
1086    }
1087 
1088    *r = h;
1089    *g = l;
1090    *b = s;
1091 }
1092 
1093 static gint
hls_value(gfloat n1,gfloat n2,gfloat hue)1094 hls_value (gfloat n1,
1095            gfloat n2,
1096            gfloat hue)
1097 {
1098    gfloat value;
1099 
1100    if (hue > 255)
1101       hue -= 255;
1102    else if (hue < 0)
1103       hue += 255;
1104    if (hue < 42.5)
1105       value = n1 + (n2 - n1) * (hue / 42.5);
1106    else if (hue < 127.5)
1107       value = n2;
1108    else if (hue < 170)
1109       value = n1 + (n2 - n1) * ((170 - hue) / 42.5);
1110    else
1111       value = n1;
1112 
1113    return (gint) (value * 255);
1114 }
1115 
1116 
1117 static void
hls_to_rgb(gint * h,gint * l,gint * s)1118 hls_to_rgb (gint *h,
1119             gint *l,
1120             gint *s)
1121 {
1122    gfloat hue, lightness, saturation;
1123    gfloat m1, m2;
1124 
1125    hue = *h;
1126    lightness = *l;
1127    saturation = *s;
1128 
1129    if (saturation == 0) {
1130       /*  achromatic case  */
1131       *h = lightness;
1132       *l = lightness;
1133       *s = lightness;
1134    } else {
1135       if (lightness < 128)
1136          m2 = (lightness * (255 + saturation)) / 65025.0;
1137       else
1138          m2 = (lightness + saturation - (lightness * saturation)/255.0) / 255.0;
1139 
1140       m1 = (lightness / 127.5) - m2;
1141 
1142       /*  chromatic case  */
1143       *h = hls_value (m1, m2, hue + 85);
1144       *l = hls_value (m1, m2, hue);
1145       *s = hls_value (m1, m2, hue - 85);
1146    }
1147 }
1148 
1149 
1150 static void
pixel_apply_layer_mode(guchar * src1,guchar * src2,guchar * dest,gint b1,gint b2,gboolean ha1,gboolean ha2,GimvImageLayerMode mode)1151 pixel_apply_layer_mode(guchar *src1,
1152                        guchar *src2,
1153                        guchar *dest,
1154                        gint b1,
1155                        gint b2,
1156                        gboolean ha1,
1157                        gboolean ha2,
1158                        GimvImageLayerMode mode)
1159 {
1160    static gint b, alpha, t, t2, red1, green1, blue1, red2, green2, blue2;
1161 
1162    alpha = (ha1 || ha2) ? MAX(b1, b2) - 1 : b1;
1163    switch (mode) {
1164    case GIMV_IMAGE_DISSOLVE_MODE:
1165       for (b = 0; b < alpha; b++)
1166          dest[b] = src2[b];
1167       /*  dissolve if random value is > opacity  */
1168       t = (rand() & 0xFF);
1169       dest[alpha] = (t > src2[alpha]) ? 0 : src2[alpha];
1170       break;
1171 
1172    case GIMV_IMAGE_MULTIPLY_MODE:
1173       for (b = 0; b < alpha; b++)
1174          dest[b] = (src1[b] * src2[b]) / 255;
1175       if (ha1 && ha2)
1176          dest[alpha] = MIN(src1[alpha], src2[alpha]);
1177       else if (ha2)
1178          dest[alpha] = src2[alpha];
1179       break;
1180 
1181    case GIMV_IMAGE_SCREEN_MODE:
1182       for (b = 0; b < alpha; b++)
1183          dest[b] = 255 - ((255 - src1[b]) * (255 - src2[b])) / 255;
1184       if (ha1 && ha2)
1185          dest[alpha] = MIN(src1[alpha], src2[alpha]);
1186       else if (ha2)
1187          dest[alpha] = src2[alpha];
1188       break;
1189 
1190    case GIMV_IMAGE_OVERLAY_MODE:
1191       for (b = 0; b < alpha; b++) {
1192          /* screen */
1193          t = 255 - ((255 - src1[b]) * (255 - src2[b])) / 255;
1194          /* mult */
1195          t2 = (src1[b] * src2[b]) / 255;
1196          dest[b] = (t * src1[b] + t2 * (255 - src1[b])) / 255;
1197       }
1198       if (ha1 && ha2)
1199          dest[alpha] = MIN(src1[alpha], src2[alpha]);
1200       else if (ha2)
1201          dest[alpha] = src2[alpha];
1202       break;
1203 
1204    case GIMV_IMAGE_DIFFERENCE_MODE:
1205       for (b = 0; b < alpha; b++) {
1206          t = src1[b] - src2[b];
1207          dest[b] = (t < 0) ? -t : t;
1208       }
1209       if (ha1 && ha2)
1210          dest[alpha] = MIN(src1[alpha], src2[alpha]);
1211       else if (ha2)
1212          dest[alpha] = src2[alpha];
1213       break;
1214 
1215    case GIMV_IMAGE_ADDITION_MODE:
1216       for (b = 0; b < alpha; b++) {
1217          t = src1[b] + src2[b];
1218          dest[b] = (t > 255) ? 255 : t;
1219       }
1220       if (ha1 && ha2)
1221          dest[alpha] = MIN(src1[alpha], src2[alpha]);
1222       else if (ha2)
1223          dest[alpha] = src2[alpha];
1224       break;
1225 
1226    case GIMV_IMAGE_SUBTRACT_MODE:
1227       for (b = 0; b < alpha; b++) {
1228          t = (gint)src1[b] - (gint)src2[b];
1229          dest[b] = (t < 0) ? 0 : t;
1230       }
1231       if (ha1 && ha2)
1232          dest[alpha] = MIN(src1[alpha], src2[alpha]);
1233       else if (ha2)
1234          dest[alpha] = src2[alpha];
1235       break;
1236 
1237    case GIMV_IMAGE_DARKEN_ONLY_MODE:
1238       for (b = 0; b < alpha; b++) {
1239          t = src1[b];
1240          t2 = src2[b];
1241          dest[b] = (t < t2) ? t : t2;
1242       }
1243       if (ha1 && ha2)
1244          dest[alpha] = MIN(src1[alpha], src2[alpha]);
1245       else if (ha2)
1246          dest[alpha] = src2[alpha];
1247       break;
1248 
1249    case GIMV_IMAGE_LIGHTEN_ONLY_MODE:
1250       for (b = 0; b < alpha; b++) {
1251          t = src1[b];
1252          t2 = src2[b];
1253          dest[b] = (t < t2) ? t2 : t;
1254       }
1255       if (ha1 && ha2)
1256          dest[alpha] = MIN(src1[alpha], src2[alpha]);
1257       else if (ha2)
1258          dest[alpha] = src2[alpha];
1259       break;
1260 
1261    case GIMV_IMAGE_HUE_MODE:
1262    case GIMV_IMAGE_SATURATION_MODE:
1263    case GIMV_IMAGE_VALUE_MODE:
1264       red1 = src1[0]; green1 = src1[1]; blue1 = src1[2];
1265       red2 = src2[0]; green2 = src2[1]; blue2 = src2[2];
1266       rgb_to_hsv (&red1, &green1, &blue1);
1267       rgb_to_hsv (&red2, &green2, &blue2);
1268       switch (mode) {
1269       case GIMV_IMAGE_HUE_MODE:
1270          red1 = red2;
1271          break;
1272       case GIMV_IMAGE_SATURATION_MODE:
1273          green1 = green2;
1274          break;
1275       case GIMV_IMAGE_VALUE_MODE:
1276          blue1 = blue2;
1277          break;
1278       default:
1279          break;
1280       }
1281       hsv_to_rgb (&red1, &green1, &blue1);
1282       dest[0] = red1; dest[1] = green1; dest[2] = blue1;
1283       if (ha1 && ha2)
1284          dest[3] = MIN(src1[3], src2[3]);
1285       else if (ha2)
1286          dest[3] = src2[3];
1287       break;
1288 
1289    case GIMV_IMAGE_COLOR_MODE:
1290       red1 = src1[0]; green1 = src1[1]; blue1 = src1[2];
1291       red2 = src2[0]; green2 = src2[1]; blue2 = src2[2];
1292       rgb_to_hls (&red1, &green1, &blue1);
1293       rgb_to_hls (&red2, &green2, &blue2);
1294       red1 = red2;
1295       blue1 = blue2;
1296       hls_to_rgb (&red1, &green1, &blue1);
1297       dest[0] = red1; dest[1] = green1; dest[2] = blue1;
1298       if (ha1 && ha2)
1299          dest[3] = MIN(src1[3], src2[3]);
1300       else if (ha2)
1301          dest[3] = src2[3];
1302       break;
1303 
1304    case GIMV_IMAGE_NORMAL_MODE:
1305    default:
1306       for (b = 0; b < b2; b++) dest[b] = src2[b];
1307       break;
1308    }
1309 }
1310 
1311 static gint bgcolor_red   = 255;
1312 static gint bgcolor_green = 255;
1313 static gint bgcolor_blue  = 255;
1314 
1315 gboolean
gimv_image_add_layer(guchar * buffer,gint width,gint left,gint components,gint pass,GimvImageLayerMode mode,guchar * rgbbuffer)1316 gimv_image_add_layer (guchar *buffer,
1317                       gint width,
1318                       gint left,
1319                       gint components,
1320                       gint pass,
1321                       GimvImageLayerMode mode,
1322                       guchar *rgbbuffer)
1323 {
1324    gint i, j, k;
1325    static gint alpha, cur_red, cur_green, cur_blue;
1326    static guchar src1[4], src2[4], dest[4];
1327 
1328    if (pass <= 0) {
1329       cur_red   = bgcolor_red;
1330       cur_green = bgcolor_green;
1331       cur_blue  = bgcolor_blue;
1332    }
1333 
1334    for (i = 0, j = 0, k = 0; i < width; i++) {
1335       if (pass > 0) {
1336          cur_red   = rgbbuffer[k];
1337          cur_green = rgbbuffer[k + 1];
1338          cur_blue  = rgbbuffer[k + 2];
1339       }
1340 
1341       switch (components) {
1342       case 1:
1343          rgbbuffer[k++] = buffer[j];
1344          rgbbuffer[k++] = buffer[j];
1345          rgbbuffer[k++] = buffer[j++];
1346          break;
1347 
1348       case 2:
1349          if (pass > 0 && mode > 0) {
1350             src1[0] = cur_red;
1351             src1[1] = cur_green;
1352             src1[2] = cur_blue;
1353             src1[3] = 255;
1354             src2[0] = buffer[j];
1355             src2[1] = buffer[j];
1356             src2[2] = buffer[j];
1357             src2[3] = buffer[j + 1];
1358             pixel_apply_layer_mode(src1, src2, dest, 4, 4, TRUE, TRUE, mode);
1359             alpha = dest[3];
1360             rgbbuffer[k++] = dest[0] * alpha / 255 + cur_red   * (255 - alpha) / 255;
1361             rgbbuffer[k++] = dest[1] * alpha / 255 + cur_green * (255 - alpha) / 255;
1362             rgbbuffer[k++] = dest[2] * alpha / 255 + cur_blue  * (255 - alpha) / 255;
1363          } else {
1364             alpha = buffer[j + 1];
1365             rgbbuffer[k++] = buffer[j] * alpha / 255 + cur_red   * (255 - alpha) / 255;
1366             rgbbuffer[k++] = buffer[j] * alpha / 255 + cur_green * (255 - alpha) / 255;
1367             rgbbuffer[k++] = buffer[j] * alpha / 255 + cur_blue  * (255 - alpha) / 255;
1368          }
1369          j += 2;
1370          break;
1371 
1372       case 3:
1373          rgbbuffer[k++] = buffer[j++];
1374          rgbbuffer[k++] = buffer[j++];
1375          rgbbuffer[k++] = buffer[j++];
1376          break;
1377 
1378       case 4:
1379          if (pass > 0 && mode > 0) {
1380             src1[0] = cur_red;
1381             src1[1] = cur_green;
1382             src1[2] = cur_blue;
1383             src1[3] = 255;
1384             src2[0] = buffer[j];
1385             src2[1] = buffer[j + 1];
1386             src2[2] = buffer[j + 2];
1387             src2[3] = buffer[j + 3];
1388             pixel_apply_layer_mode(src1, src2, &buffer[j], 4, 4, TRUE, TRUE, mode);
1389          }
1390          alpha = buffer[j + 3];
1391          rgbbuffer[k++] = buffer[j++] * alpha / 255 + cur_red   * (255 - alpha) / 255;
1392          rgbbuffer[k++] = buffer[j++] * alpha / 255 + cur_green * (255 - alpha) / 255;
1393          rgbbuffer[k++] = buffer[j++] * alpha / 255 + cur_blue  * (255 - alpha) / 255;
1394          j++;
1395          break;
1396 
1397       default:
1398          break;
1399       }
1400    }
1401 
1402    return FALSE;
1403 }
1404 
1405 
1406 GimvImage *
gimv_image_rgba2rgb(GimvImage * image,gint bg_red,gint bg_green,gint bg_blue,gboolean ignore_alpha)1407 gimv_image_rgba2rgb (GimvImage *image,
1408                      gint       bg_red,
1409                      gint       bg_green,
1410                      gint       bg_blue,
1411                      gboolean   ignore_alpha)
1412 {
1413    GimvImage *dest_image = NULL;
1414    gint width, height, i, j;
1415    guchar *src, *dest;
1416 
1417    /* set bg color */
1418    if (bg_red >= 0 && bg_red < 256)
1419       bgcolor_red = bg_red;
1420    if (bg_green >= 0 && bg_green < 256)
1421       bgcolor_green = bg_green;
1422    if (bg_blue >= 0 && bg_blue < 256)
1423       bgcolor_blue = bg_blue;
1424 
1425 #ifdef HAVE_GDK_IMLIB
1426    goto ERROR;
1427 #endif /* HAVE_GDK_IMLIB */
1428 
1429    if (!gimv_image_has_alpha (image)) goto ERROR;
1430 
1431    width  = gimv_image_width  (image);
1432    height = gimv_image_height (image);
1433    src = gimv_image_get_pixels (image);
1434 
1435    dest = g_malloc (width * height * 3 * sizeof (guchar));
1436 
1437    for (i = 0; i < height; i++) {
1438       if (ignore_alpha) {
1439          for (j = 0; j < width; j++) {
1440             gint pos, src_pos;
1441             src_pos  = (j + i * width) * 4;
1442             pos = (j + i * width) * 3;
1443             dest [pos]     = src [src_pos];
1444             dest [pos + 1] = src [src_pos + 1];
1445             dest [pos + 2] = src [src_pos + 2];
1446          }
1447       } else {
1448         gimv_image_add_layer (src + (width * i * 4),
1449                                width, 0, 4,
1450                                0, GIMV_IMAGE_NORMAL_MODE,
1451                                dest + (width * i * 3));
1452       }
1453    }
1454 
1455    dest_image = gimv_image_create_from_data (dest, width, height, FALSE);
1456 
1457 ERROR:
1458    /* reset bg color to default value */
1459    bgcolor_red   = 255;
1460    bgcolor_green = 255;
1461    bgcolor_blue  = 255;
1462 
1463    return dest_image;
1464 }
1465