| |
1 /* |
| |
2 * Purple - Internet Messaging Library |
| |
3 * Copyright (C) Pidgin Developers <devel@pidgin.im> |
| |
4 * |
| |
5 * Purple is the legal property of its developers, whose names are too numerous |
| |
6 * to list here. Please refer to the COPYRIGHT file distributed with this |
| |
7 * source distribution. |
| |
8 * |
| |
9 * This program is free software; you can redistribute it and/or modify |
| |
10 * it under the terms of the GNU General Public License as published by |
| |
11 * the Free Software Foundation; either version 2 of the License, or |
| |
12 * (at your option) any later version. |
| |
13 * |
| |
14 * This program is distributed in the hope that it will be useful, |
| |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |
17 * GNU General Public License for more details. |
| |
18 * |
| |
19 * You should have received a copy of the GNU General Public License |
| |
20 * along with this program; if not, see <https://www.gnu.org/licenses/>. |
| |
21 */ |
| |
22 |
| |
23 #include "libpurple/purplegdkpixbuf.h" |
| |
24 |
| |
25 #include "debug.h" |
| |
26 |
| |
27 void purple_gdk_pixbuf_make_round(GdkPixbuf *pixbuf) { |
| |
28 gint width, height, rowstride; |
| |
29 guchar *pixels; |
| |
30 |
| |
31 if (!gdk_pixbuf_get_has_alpha(pixbuf)) { |
| |
32 return; |
| |
33 } |
| |
34 |
| |
35 width = gdk_pixbuf_get_width(pixbuf); |
| |
36 height = gdk_pixbuf_get_height(pixbuf); |
| |
37 rowstride = gdk_pixbuf_get_rowstride(pixbuf); |
| |
38 pixels = gdk_pixbuf_get_pixels(pixbuf); |
| |
39 |
| |
40 if (width < 6 || height < 6) { |
| |
41 return; |
| |
42 } |
| |
43 |
| |
44 /* The following code will convert the alpha of the pixel data in all |
| |
45 * corners to look something like the following diagram. |
| |
46 * |
| |
47 * 00 80 c0 FF FF c0 80 00 |
| |
48 * 80 FF FF FF FF FF FF 80 |
| |
49 * c0 FF FF FF FF FF FF c0 |
| |
50 * FF FF FF FF FF FF FF FF |
| |
51 * FF FF FF FF FF FF FF FF |
| |
52 * c0 FF FF FF FF FF FF c0 |
| |
53 * 80 FF FF FF FF FF FF 80 |
| |
54 * 00 80 c0 FF FF c0 80 00 |
| |
55 */ |
| |
56 |
| |
57 /* Top left */ |
| |
58 pixels[3] = 0; |
| |
59 pixels[7] = 0x80; |
| |
60 pixels[11] = 0xC0; |
| |
61 pixels[rowstride + 3] = 0x80; |
| |
62 pixels[rowstride * 2 + 3] = 0xC0; |
| |
63 |
| |
64 /* Top right */ |
| |
65 pixels[width * 4 - 1] = 0; |
| |
66 pixels[width * 4 - 5] = 0x80; |
| |
67 pixels[width * 4 - 9] = 0xC0; |
| |
68 pixels[rowstride + (width * 4) - 1] = 0x80; |
| |
69 pixels[(2 * rowstride) + (width * 4) - 1] = 0xC0; |
| |
70 |
| |
71 /* Bottom left */ |
| |
72 pixels[(height - 1) * rowstride + 3] = 0; |
| |
73 pixels[(height - 1) * rowstride + 7] = 0x80; |
| |
74 pixels[(height - 1) * rowstride + 11] = 0xC0; |
| |
75 pixels[(height - 2) * rowstride + 3] = 0x80; |
| |
76 pixels[(height - 3) * rowstride + 3] = 0xC0; |
| |
77 |
| |
78 /* Bottom right */ |
| |
79 pixels[height * rowstride - 1] = 0; |
| |
80 pixels[(height - 1) * rowstride - 1] = 0x80; |
| |
81 pixels[(height - 2) * rowstride - 1] = 0xC0; |
| |
82 pixels[height * rowstride - 5] = 0x80; |
| |
83 pixels[height * rowstride - 9] = 0xC0; |
| |
84 } |
| |
85 |
| |
86 gboolean |
| |
87 purple_gdk_pixbuf_is_opaque(GdkPixbuf *pixbuf) { |
| |
88 gint height, rowstride, i; |
| |
89 guchar *pixels; |
| |
90 guchar *row; |
| |
91 |
| |
92 if (!gdk_pixbuf_get_has_alpha(pixbuf)) { |
| |
93 return TRUE; |
| |
94 } |
| |
95 |
| |
96 height = gdk_pixbuf_get_height (pixbuf); |
| |
97 rowstride = gdk_pixbuf_get_rowstride (pixbuf); |
| |
98 pixels = gdk_pixbuf_get_pixels (pixbuf); |
| |
99 |
| |
100 /* check the top row */ |
| |
101 row = pixels; |
| |
102 for (i = 3; i < rowstride; i+=4) { |
| |
103 if (row[i] < 0xfe) { |
| |
104 return FALSE; |
| |
105 } |
| |
106 } |
| |
107 |
| |
108 /* check the left and right sides */ |
| |
109 for (i = 1; i < height - 1; i++) { |
| |
110 row = pixels + (i * rowstride); |
| |
111 if (row[3] < 0xfe || row[rowstride - 1] < 0xfe) { |
| |
112 return FALSE; |
| |
113 } |
| |
114 } |
| |
115 |
| |
116 /* check the bottom */ |
| |
117 row = pixels + ((height - 1) * rowstride); |
| |
118 for (i = 3; i < rowstride; i += 4) { |
| |
119 if (row[i] < 0xfe) { |
| |
120 return FALSE; |
| |
121 } |
| |
122 } |
| |
123 |
| |
124 return TRUE; |
| |
125 } |
| |
126 |
| |
127 static GObject *purple_gdk_pixbuf_from_data_helper(const guchar *buf, gsize count, gboolean animated) |
| |
128 { |
| |
129 GObject *pixbuf; |
| |
130 GdkPixbufLoader *loader; |
| |
131 GError *error = NULL; |
| |
132 |
| |
133 loader = gdk_pixbuf_loader_new(); |
| |
134 |
| |
135 if (!gdk_pixbuf_loader_write(loader, buf, count, &error) || error) { |
| |
136 purple_debug_warning("gtkutils", "gdk_pixbuf_loader_write() " |
| |
137 "failed with size=%" G_GSIZE_FORMAT ": %s\n", count, |
| |
138 error ? error->message : "(no error message)"); |
| |
139 if (error) |
| |
140 g_error_free(error); |
| |
141 g_object_unref(G_OBJECT(loader)); |
| |
142 return NULL; |
| |
143 } |
| |
144 |
| |
145 if (!gdk_pixbuf_loader_close(loader, &error) || error) { |
| |
146 purple_debug_warning("gtkutils", "gdk_pixbuf_loader_close() " |
| |
147 "failed for image of size %" G_GSIZE_FORMAT ": %s\n", count, |
| |
148 error ? error->message : "(no error message)"); |
| |
149 if (error) |
| |
150 g_error_free(error); |
| |
151 g_object_unref(G_OBJECT(loader)); |
| |
152 return NULL; |
| |
153 } |
| |
154 |
| |
155 if (animated) |
| |
156 pixbuf = G_OBJECT(gdk_pixbuf_loader_get_animation(loader)); |
| |
157 else |
| |
158 pixbuf = G_OBJECT(gdk_pixbuf_loader_get_pixbuf(loader)); |
| |
159 if (!pixbuf) { |
| |
160 purple_debug_warning("gtkutils", "%s() returned NULL for image " |
| |
161 "of size %" G_GSIZE_FORMAT "\n", |
| |
162 animated ? "gdk_pixbuf_loader_get_animation" |
| |
163 : "gdk_pixbuf_loader_get_pixbuf", count); |
| |
164 g_object_unref(G_OBJECT(loader)); |
| |
165 return NULL; |
| |
166 } |
| |
167 |
| |
168 g_object_ref(pixbuf); |
| |
169 g_object_unref(G_OBJECT(loader)); |
| |
170 |
| |
171 return pixbuf; |
| |
172 } |
| |
173 |
| |
174 GdkPixbuf *purple_gdk_pixbuf_from_data(const guchar *buf, gsize count) |
| |
175 { |
| |
176 return GDK_PIXBUF(purple_gdk_pixbuf_from_data_helper(buf, count, FALSE)); |
| |
177 } |
| |
178 |
| |
179 GdkPixbuf * |
| |
180 purple_gdk_pixbuf_from_image(PurpleImage *image) |
| |
181 { |
| |
182 return purple_gdk_pixbuf_from_data(purple_image_get_data(image), |
| |
183 purple_image_get_data_size(image)); |
| |
184 } |
| |
185 |
| |
186 GdkPixbuf *purple_gdk_pixbuf_new_from_file(const gchar *filename) |
| |
187 { |
| |
188 GdkPixbuf *pixbuf; |
| |
189 GError *error = NULL; |
| |
190 |
| |
191 g_return_val_if_fail(filename != NULL, NULL); |
| |
192 g_return_val_if_fail(filename[0] != '\0', NULL); |
| |
193 |
| |
194 pixbuf = gdk_pixbuf_new_from_file(filename, &error); |
| |
195 if (!pixbuf || error) { |
| |
196 purple_debug_warning("gtkutils", "gdk_pixbuf_new_from_file() " |
| |
197 "returned %s for file %s: %s\n", |
| |
198 pixbuf ? "something" : "nothing", |
| |
199 filename, |
| |
200 error ? error->message : "(no error message)"); |
| |
201 if (error) |
| |
202 g_error_free(error); |
| |
203 if (pixbuf) |
| |
204 g_object_unref(G_OBJECT(pixbuf)); |
| |
205 return NULL; |
| |
206 } |
| |
207 |
| |
208 return pixbuf; |
| |
209 } |
| |
210 |
| |
211 GdkPixbuf *purple_gdk_pixbuf_new_from_file_at_size(const char *filename, int width, int height) |
| |
212 { |
| |
213 GdkPixbuf *pixbuf; |
| |
214 GError *error = NULL; |
| |
215 |
| |
216 g_return_val_if_fail(filename != NULL, NULL); |
| |
217 g_return_val_if_fail(filename[0] != '\0', NULL); |
| |
218 |
| |
219 pixbuf = gdk_pixbuf_new_from_file_at_size(filename, |
| |
220 width, height, &error); |
| |
221 if (!pixbuf || error) { |
| |
222 purple_debug_warning("gtkutils", "gdk_pixbuf_new_from_file_at_size() " |
| |
223 "returned %s for file %s: %s\n", |
| |
224 pixbuf ? "something" : "nothing", |
| |
225 filename, |
| |
226 error ? error->message : "(no error message)"); |
| |
227 if (error) |
| |
228 g_error_free(error); |
| |
229 if (pixbuf) |
| |
230 g_object_unref(G_OBJECT(pixbuf)); |
| |
231 return NULL; |
| |
232 } |
| |
233 |
| |
234 return pixbuf; |
| |
235 } |