1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * GThumb
5 *
6 * Copyright (C) 2001-2009 The Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23 #include <math.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #define GDK_PIXBUF_ENABLE_BACKEND 1
28 #include <gdk-pixbuf/gdk-pixbuf.h>
29 #include "cairo-utils.h"
30 #include "pixbuf-utils.h"
31 #include "gimp-op.h"
32
33
34 GdkPixbuf *
_gdk_pixbuf_new_from_cairo_context(cairo_t * cr)35 _gdk_pixbuf_new_from_cairo_context (cairo_t *cr)
36 {
37 return _gdk_pixbuf_new_from_cairo_surface (cairo_get_target (cr));
38 }
39
40
41 /* Started from from http://www.gtkforums.com/about5204.html
42 * Author: tadeboro */
43 GdkPixbuf *
_gdk_pixbuf_new_from_cairo_surface(cairo_surface_t * surface)44 _gdk_pixbuf_new_from_cairo_surface (cairo_surface_t *surface)
45 {
46 int width;
47 int height;
48 int s_stride;
49 unsigned char *s_pixels;
50 GdkPixbuf *pixbuf;
51 int p_stride;
52 guchar *p_pixels;
53 int p_n_channels;
54
55 if (surface == NULL)
56 return NULL;
57
58 if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
59 return NULL;
60
61 width = cairo_image_surface_get_width (surface);
62 height = cairo_image_surface_get_height (surface);
63 s_stride = cairo_image_surface_get_stride (surface);
64 s_pixels = _cairo_image_surface_flush_and_get_data (surface);
65
66 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, _cairo_image_surface_get_has_alpha (surface), 8, width, height);
67 p_stride = gdk_pixbuf_get_rowstride (pixbuf);
68 p_pixels = gdk_pixbuf_get_pixels (pixbuf);
69 p_n_channels = gdk_pixbuf_get_n_channels (pixbuf);
70
71 while (height--) {
72 guchar *s_iter = s_pixels;
73 guchar *p_iter = p_pixels;
74 int i, temp;
75
76 for (i = 0; i < width; i++) {
77 gdouble alpha_factor = (gdouble) 0xff / s_iter[CAIRO_ALPHA];
78
79 p_iter[0] = CLAMP_PIXEL (alpha_factor * s_iter[CAIRO_RED]);
80 p_iter[1] = CLAMP_PIXEL (alpha_factor * s_iter[CAIRO_GREEN]);
81 p_iter[2] = CLAMP_PIXEL (alpha_factor * s_iter[CAIRO_BLUE]);
82 if (p_n_channels == 4)
83 p_iter[3] = s_iter[CAIRO_ALPHA];
84
85 s_iter += 4;
86 p_iter += p_n_channels;
87 }
88
89 s_pixels += s_stride;
90 p_pixels += p_stride;
91 }
92
93 /* copy the known metadata from the surface to the pixbuf */
94
95 {
96 cairo_surface_metadata_t *metadata;
97
98 metadata = _cairo_image_surface_get_metadata (surface);
99 if ((metadata->thumbnail.image_width > 0) && (metadata->thumbnail.image_height > 0)) {
100 char *value;
101
102 value = g_strdup_printf ("%d", metadata->thumbnail.image_width);
103 gdk_pixbuf_set_option (pixbuf, "tEXt::Thumb::Image::Width", value);
104 g_free (value);
105
106 value = g_strdup_printf ("%d", metadata->thumbnail.image_height);
107 gdk_pixbuf_set_option (pixbuf, "tEXt::Thumb::Image::Height", value);
108 g_free (value);
109 }
110 }
111
112 return pixbuf;
113 }
114
115
116 /* The gdk_pixbuf scaling routines do not handle large-ratio downscaling
117 very well. Memory usage explodes and the application may freeze or crash.
118 For scale-down ratios in excess of 100, do the scale in two steps.
119 It is faster and safer that way. See bug 80925 for background info. */
120 GdkPixbuf*
_gdk_pixbuf_scale_simple_safe(const GdkPixbuf * src,int dest_width,int dest_height,GdkInterpType interp_type)121 _gdk_pixbuf_scale_simple_safe (const GdkPixbuf *src,
122 int dest_width,
123 int dest_height,
124 GdkInterpType interp_type)
125 {
126 GdkPixbuf* temp_pixbuf1;
127 GdkPixbuf* temp_pixbuf2;
128 int x_ratio, y_ratio;
129 int temp_width = dest_width, temp_height = dest_height;
130
131 g_assert (dest_width >= 1);
132 g_assert (dest_height >= 1);
133
134 x_ratio = gdk_pixbuf_get_width (src) / dest_width;
135 y_ratio = gdk_pixbuf_get_height (src) / dest_height;
136
137 if (x_ratio > 100)
138 /* Scale down to 10x the requested size first. */
139 temp_width = 10 * dest_width;
140
141 if (y_ratio > 100)
142 /* Scale down to 10x the requested size first. */
143 temp_height = 10 * dest_height;
144
145 if ( (temp_width != dest_width) || (temp_height != dest_height)) {
146 temp_pixbuf1 = gdk_pixbuf_scale_simple (src, temp_width, temp_height, interp_type);
147 temp_pixbuf2 = gdk_pixbuf_scale_simple (temp_pixbuf1, dest_width, dest_height, interp_type);
148 g_object_unref (temp_pixbuf1);
149 } else
150 temp_pixbuf2 = gdk_pixbuf_scale_simple (src, dest_width, dest_height, interp_type);
151
152 return temp_pixbuf2;
153 }
154
155
156 /*
157 * Returns a transformed image.
158 */
159 GdkPixbuf *
_gdk_pixbuf_transform(GdkPixbuf * src,GthTransform transform)160 _gdk_pixbuf_transform (GdkPixbuf *src,
161 GthTransform transform)
162 {
163 GdkPixbuf *temp = NULL, *dest = NULL;
164
165 if (src == NULL)
166 return NULL;
167
168 switch (transform) {
169 case GTH_TRANSFORM_NONE:
170 dest = src;
171 g_object_ref (dest);
172 break;
173 case GTH_TRANSFORM_FLIP_H:
174 dest = gdk_pixbuf_flip (src, TRUE);
175 break;
176 case GTH_TRANSFORM_ROTATE_180:
177 dest = gdk_pixbuf_rotate_simple (src, GDK_PIXBUF_ROTATE_UPSIDEDOWN);
178 break;
179 case GTH_TRANSFORM_FLIP_V:
180 dest = gdk_pixbuf_flip (src, FALSE);
181 break;
182 case GTH_TRANSFORM_TRANSPOSE:
183 temp = gdk_pixbuf_rotate_simple (src, GDK_PIXBUF_ROTATE_CLOCKWISE);
184 dest = gdk_pixbuf_flip (temp, TRUE);
185 g_object_unref (temp);
186 break;
187 case GTH_TRANSFORM_ROTATE_90:
188 dest = gdk_pixbuf_rotate_simple (src, GDK_PIXBUF_ROTATE_CLOCKWISE);
189 break;
190 case GTH_TRANSFORM_TRANSVERSE:
191 temp = gdk_pixbuf_rotate_simple (src, GDK_PIXBUF_ROTATE_CLOCKWISE);
192 dest = gdk_pixbuf_flip (temp, FALSE);
193 g_object_unref (temp);
194 break;
195 case GTH_TRANSFORM_ROTATE_270:
196 dest = gdk_pixbuf_rotate_simple (src, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE);
197 break;
198 default:
199 dest = src;
200 g_object_ref (dest);
201 break;
202 }
203
204 return dest;
205 }
206
207
208 char *
_gdk_pixbuf_get_type_from_mime_type(const char * mime_type)209 _gdk_pixbuf_get_type_from_mime_type (const char *mime_type)
210 {
211 if (mime_type == NULL)
212 return NULL;
213
214 if (g_str_has_prefix (mime_type, "image/x-"))
215 return g_strdup (mime_type + strlen ("image/x-"));
216 else if (g_str_has_prefix (mime_type, "image/"))
217 return g_strdup (mime_type + strlen ("image/"));
218 else
219 return g_strdup (mime_type);
220 }
221
222
223 gboolean
_gdk_pixbuf_mime_type_is_readable(const char * mime_type)224 _gdk_pixbuf_mime_type_is_readable (const char *mime_type)
225 {
226 GSList *formats;
227 GSList *scan;
228 gboolean result;
229
230 if (mime_type == NULL)
231 return FALSE;
232
233 result = FALSE;
234 formats = gdk_pixbuf_get_formats ();
235 for (scan = formats; ! result && scan; scan = scan->next) {
236 GdkPixbufFormat *format = scan->data;
237 char **mime_types;
238 int i;
239
240 if (gdk_pixbuf_format_is_disabled (format))
241 continue;
242
243 mime_types = gdk_pixbuf_format_get_mime_types (format);
244 for (i = 0; mime_types[i] != NULL; i++) {
245 if (strcmp (mime_type, mime_types[i]) == 0) {
246 result = TRUE;
247 break;
248 }
249 }
250 }
251
252 g_slist_free (formats);
253
254 return result;
255 }
256