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