3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
23 #include "glibcompat.h"
28 #define PURPLE_IMAGE_GET_PRIVATE(obj) \
29 (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_IMAGE, PurpleImagePrivate))
36 const gchar
*extension
;
39 gchar
*friendly_filename
;
50 static GParamSpec
*properties
[PROP_LAST
];
52 /******************************************************************************
54 ******************************************************************************/
56 _purple_image_set_path(PurpleImage
*image
, const gchar
*path
) {
57 PurpleImagePrivate
*priv
= PURPLE_IMAGE_GET_PRIVATE(image
);
61 priv
->path
= g_strdup(path
);
65 _purple_image_set_contents(PurpleImage
*image
, GBytes
*bytes
) {
66 PurpleImagePrivate
*priv
= PURPLE_IMAGE_GET_PRIVATE(image
);
69 g_bytes_unref(priv
->contents
);
71 priv
->contents
= (bytes
) ? g_bytes_ref(bytes
) : NULL
;
74 /******************************************************************************
76 ******************************************************************************/
77 G_DEFINE_TYPE_WITH_PRIVATE(PurpleImage
, purple_image
, G_TYPE_OBJECT
);
80 purple_image_init(PurpleImage
*image
) {
84 purple_image_finalize(GObject
*obj
) {
85 PurpleImagePrivate
*priv
= PURPLE_IMAGE_GET_PRIVATE(obj
);
88 g_bytes_unref(priv
->contents
);
91 g_free(priv
->gen_filename
);
92 g_free(priv
->friendly_filename
);
94 G_OBJECT_CLASS(purple_image_parent_class
)->finalize(obj
);
98 purple_image_set_property(GObject
*obj
, guint param_id
,
99 const GValue
*value
, GParamSpec
*pspec
)
101 PurpleImage
*image
= PURPLE_IMAGE(obj
);
105 _purple_image_set_path(image
, g_value_get_string(value
));
108 _purple_image_set_contents(image
, g_value_get_boxed(value
));
111 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
117 purple_image_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
120 PurpleImage
*image
= PURPLE_IMAGE(obj
);
124 g_value_set_string(value
, purple_image_get_path(image
));
127 g_value_set_boxed(value
, purple_image_get_contents(image
));
130 g_value_set_uint64(value
, purple_image_get_data_size(image
));
133 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
139 purple_image_class_init(PurpleImageClass
*klass
) {
140 GObjectClass
*gobj_class
= G_OBJECT_CLASS(klass
);
142 gobj_class
->finalize
= purple_image_finalize
;
143 gobj_class
->get_property
= purple_image_get_property
;
144 gobj_class
->set_property
= purple_image_set_property
;
146 properties
[PROP_PATH
] = g_param_spec_string(
149 "The filepath for the image if one was provided",
151 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
| G_PARAM_STATIC_STRINGS
154 properties
[PROP_CONTENTS
] = g_param_spec_boxed(
157 "The contents of the image stored in a GBytes",
159 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
| G_PARAM_STATIC_STRINGS
162 properties
[PROP_SIZE
] = g_param_spec_uint64(
165 "The size of the image in bytes",
169 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
172 g_object_class_install_properties(gobj_class
, PROP_LAST
, properties
);
175 /******************************************************************************
177 ******************************************************************************/
179 purple_image_new_from_bytes(GBytes
*bytes
) {
188 purple_image_new_from_file(const gchar
*path
, GError
**error
) {
189 PurpleImage
*image
= NULL
;
190 GBytes
*bytes
= NULL
;
191 gchar
*contents
= NULL
;
194 if(!g_file_get_contents(path
, &contents
, &length
, error
)) {
198 bytes
= g_bytes_new_take(contents
, length
);
200 image
= g_object_new(
207 g_bytes_unref(bytes
);
213 purple_image_new_from_data(const guint8
*data
, gsize length
) {
215 GBytes
*bytes
= NULL
;
217 bytes
= g_bytes_new(data
, length
);
219 image
= purple_image_new_from_bytes(bytes
);
221 g_bytes_unref(bytes
);
227 purple_image_new_take_data(guint8
*data
, gsize length
) {
229 GBytes
*bytes
= NULL
;
231 bytes
= g_bytes_new_take(data
, length
);
233 image
= purple_image_new_from_bytes(bytes
);
235 g_bytes_unref(bytes
);
241 purple_image_save(PurpleImage
*image
, const gchar
*path
) {
242 PurpleImagePrivate
*priv
= PURPLE_IMAGE_GET_PRIVATE(image
);
247 g_return_val_if_fail(priv
!= NULL
, FALSE
);
248 g_return_val_if_fail(path
!= NULL
, FALSE
);
249 g_return_val_if_fail(path
[0] != '\0', FALSE
);
251 data
= purple_image_get_data(image
);
252 len
= purple_image_get_data_size(image
);
254 g_return_val_if_fail(data
!= NULL
, FALSE
);
255 g_return_val_if_fail(len
> 0, FALSE
);
257 succ
= purple_util_write_data_to_file_absolute(path
, data
, len
);
258 if (succ
&& priv
->path
== NULL
)
259 priv
->path
= g_strdup(path
);
265 purple_image_get_contents(const PurpleImage
*image
) {
266 PurpleImagePrivate
*priv
= NULL
;
268 g_return_val_if_fail(PURPLE_IS_IMAGE(image
), NULL
);
270 priv
= PURPLE_IMAGE_GET_PRIVATE(image
);
273 return g_bytes_ref(priv
->contents
);
279 purple_image_get_path(PurpleImage
*image
) {
280 PurpleImagePrivate
*priv
= PURPLE_IMAGE_GET_PRIVATE(image
);
282 g_return_val_if_fail(priv
!= NULL
, NULL
);
284 return priv
->path
? priv
->path
: purple_image_generate_filename(image
);
288 purple_image_get_data_size(PurpleImage
*image
) {
289 PurpleImagePrivate
*priv
;
291 g_return_val_if_fail(PURPLE_IS_IMAGE(image
), 0);
293 priv
= PURPLE_IMAGE_GET_PRIVATE(image
);
296 return g_bytes_get_size(priv
->contents
);
302 purple_image_get_data(PurpleImage
*image
) {
303 PurpleImagePrivate
*priv
= NULL
;
305 g_return_val_if_fail(PURPLE_IS_IMAGE(image
), NULL
);
307 priv
= PURPLE_IMAGE_GET_PRIVATE(image
);
310 return g_bytes_get_data(priv
->contents
, NULL
);
316 purple_image_get_extension(PurpleImage
*image
) {
317 PurpleImagePrivate
*priv
= PURPLE_IMAGE_GET_PRIVATE(image
);
320 g_return_val_if_fail(priv
!= NULL
, NULL
);
323 return priv
->extension
;
325 if (purple_image_get_data_size(image
) < 4)
328 data
= purple_image_get_data(image
);
329 g_assert(data
!= NULL
);
331 if (memcmp(data
, "GIF8", 4) == 0)
332 return priv
->extension
= "gif";
333 if (memcmp(data
, "\xff\xd8\xff", 3) == 0) /* 4th may be e0 through ef */
334 return priv
->extension
= "jpg";
335 if (memcmp(data
, "\x89PNG", 4) == 0)
336 return priv
->extension
= "png";
337 if (memcmp(data
, "MM", 2) == 0)
338 return priv
->extension
= "tif";
339 if (memcmp(data
, "II", 2) == 0)
340 return priv
->extension
= "tif";
341 if (memcmp(data
, "BM", 2) == 0)
342 return priv
->extension
= "bmp";
343 if (memcmp(data
, "\x00\x00\x01\x00", 4) == 0)
344 return priv
->extension
= "ico";
350 purple_image_get_mimetype(PurpleImage
*image
) {
351 PurpleImagePrivate
*priv
= PURPLE_IMAGE_GET_PRIVATE(image
);
352 const gchar
*ext
= purple_image_get_extension(image
);
354 g_return_val_if_fail(priv
!= NULL
, NULL
);
359 g_return_val_if_fail(ext
!= NULL
, NULL
);
361 if (g_strcmp0(ext
, "gif") == 0)
362 return priv
->mime
= "image/gif";
363 if (g_strcmp0(ext
, "jpg") == 0)
364 return priv
->mime
= "image/jpeg";
365 if (g_strcmp0(ext
, "png") == 0)
366 return priv
->mime
= "image/png";
367 if (g_strcmp0(ext
, "tif") == 0)
368 return priv
->mime
= "image/tiff";
369 if (g_strcmp0(ext
, "bmp") == 0)
370 return priv
->mime
= "image/bmp";
371 if (g_strcmp0(ext
, "ico") == 0)
372 return priv
->mime
= "image/vnd.microsoft.icon";
378 purple_image_generate_filename(PurpleImage
*image
) {
379 PurpleImagePrivate
*priv
= NULL
;
382 const gchar
*ext
= NULL
;
385 g_return_val_if_fail(PURPLE_IS_IMAGE(image
), NULL
);
387 priv
= PURPLE_IMAGE_GET_PRIVATE(image
);
389 if (priv
->gen_filename
)
390 return priv
->gen_filename
;
392 /* grab the image's data and size of that data */
393 data
= purple_image_get_data(image
);
394 len
= purple_image_get_data_size(image
);
396 /* create a checksum of it and use it as the start of our filename */
397 checksum
= g_compute_checksum_for_data(G_CHECKSUM_SHA1
, data
, len
);
399 /* if the image has a known format, set the extension appropriately */
400 ext
= purple_image_get_extension(image
);
402 priv
->gen_filename
= g_strdup_printf("%s.%s", checksum
, ext
);
405 priv
->gen_filename
= checksum
;
408 return priv
->gen_filename
;
412 purple_image_set_friendly_filename(PurpleImage
*image
, const gchar
*filename
) {
413 PurpleImagePrivate
*priv
= PURPLE_IMAGE_GET_PRIVATE(image
);
415 const gchar
*escaped
;
417 g_return_if_fail(priv
!= NULL
);
419 newname
= g_path_get_basename(filename
);
420 escaped
= purple_escape_filename(newname
);
424 if (g_strcmp0(escaped
, "") == 0 || g_strcmp0(escaped
, ".") == 0 ||
425 g_strcmp0(escaped
, G_DIR_SEPARATOR_S
) == 0 ||
426 g_strcmp0(escaped
, "/") == 0 || g_strcmp0(escaped
, "\\") == 0)
431 g_free(priv
->friendly_filename
);
432 priv
->friendly_filename
= g_strdup(escaped
);
436 purple_image_get_friendly_filename(PurpleImage
*image
) {
437 PurpleImagePrivate
*priv
= NULL
;
439 g_return_val_if_fail(PURPLE_IS_IMAGE(image
), NULL
);
441 priv
= PURPLE_IMAGE_GET_PRIVATE(image
);
443 if(priv
->friendly_filename
) {
444 return priv
->friendly_filename
;
447 return purple_image_generate_filename(image
);