1
/* LIBGIMP - The GIMP Library
2
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
4
* Thumbnail handling according to the Thumbnail Managing Standard.
5
* http://triq.net/~pearl/thumbnail-spec/
7
* Copyright (C) 2001-2003 Sven Neumann <sven@gimp.org>
8
* Michael Natterer <mitch@gimp.org>
10
* This library is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU Lesser General Public
12
* License as published by the Free Software Foundation; either
13
* version 2 of the License, or (at your option) any later version.
15
* This library is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
* Lesser General Public License for more details.
20
* You should have received a copy of the GNU Lesser General Public
21
* License along with this library; if not, write to the
22
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23
* Boston, MA 02111-1307, USA.
30
#include <sys/types.h>
36
#include <glib-object.h>
39
#include "libgimpbase/gimpwin32-io.h"
42
#include "libgimpmath/gimpmath.h"
44
#include "gimpthumb-error.h"
45
#include "gimpthumb-types.h"
46
#include "gimpthumb-utils.h"
48
#include "libgimp/libgimp-intl.h"
51
static gint gimp_thumb_size (GimpThumbSize size);
52
static gchar * gimp_thumb_png_lookup (const gchar *name,
55
static const gchar * gimp_thumb_png_name (const gchar *uri);
56
static void gimp_thumb_exit (void);
60
static gboolean gimp_thumb_initialized = FALSE;
61
static gint thumb_num_sizes = 0;
62
static gint *thumb_sizes = NULL;
63
static const gchar **thumb_sizenames = NULL;
64
static gchar *thumb_dir = NULL;
65
static gchar **thumb_subdirs = NULL;
66
static gchar *thumb_fail_subdir = NULL;
71
* @creator: an ASCII string that identifies the thumbnail creator
72
* @thumb_basedir: an absolute path or %NULL to use the default
74
* This function initializes the thumbnail system. It must be called
75
* before any other functions from libgimpthumb are used. You may call
76
* it more than once if you want to change the @thumb_basedir but if
77
* you do that, you should make sure that no thread is still using the
78
* library. Apart from this function, libgimpthumb is multi-thread
81
* The @creator string must be 7bit ASCII and should contain the name
82
* of the software that creates the thumbnails. It is used to handle
83
* thumbnail creation failures. See the spec for more details.
85
* Usually you will pass %NULL for @thumb_basedir. Thumbnails will
86
* then be stored in the user's personal thumbnail directory as
87
* defined in the spec. If you wish to use libgimpthumb to store
88
* application-specific thumbnails, you can specify a different base
91
* Return value: %TRUE if the library was successfully initialized.
94
gimp_thumb_init (const gchar *creator,
95
const gchar *thumb_basedir)
97
GEnumClass *enum_class;
98
GEnumValue *enum_value;
101
g_return_val_if_fail (creator != NULL, FALSE);
102
g_return_val_if_fail (thumb_basedir == NULL ||
103
g_path_is_absolute (thumb_basedir), FALSE);
105
if (gimp_thumb_initialized)
110
thumb_dir = g_strdup (thumb_basedir);
114
const gchar *home_dir = g_get_home_dir ();
116
if (home_dir && g_file_test (home_dir, G_FILE_TEST_IS_DIR))
118
thumb_dir = g_build_filename (home_dir, ".thumbnails", NULL);
123
g_filename_to_utf8 (g_get_tmp_dir (), -1, NULL, NULL, NULL);
125
g_message (_("Cannot determine a valid home directory.\n"
126
"Thumbnails will be stored in the folder for "
127
"temporary files (%s) instead."), name);
130
thumb_dir = g_build_filename (g_get_tmp_dir (), ".thumbnails", NULL);
134
enum_class = g_type_class_ref (GIMP_TYPE_THUMB_SIZE);
136
thumb_num_sizes = enum_class->n_values;
137
thumb_sizes = g_new (gint, thumb_num_sizes);
138
thumb_sizenames = g_new (const gchar *, thumb_num_sizes);
139
thumb_subdirs = g_new (gchar *, thumb_num_sizes);
141
for (i = 0, enum_value = enum_class->values;
142
i < enum_class->n_values;
145
thumb_sizes[i] = enum_value->value;
146
thumb_sizenames[i] = enum_value->value_nick;
147
thumb_subdirs[i] = g_build_filename (thumb_dir,
148
enum_value->value_nick, NULL);
151
thumb_fail_subdir = thumb_subdirs[0];
152
thumb_subdirs[0] = g_build_filename (thumb_fail_subdir, creator, NULL);
154
g_type_class_unref (enum_class);
156
gimp_thumb_initialized = TRUE;
158
return gimp_thumb_initialized;
162
* gimp_thumb_get_thumb_dir:
163
* @size: a GimpThumbSize
165
* Retrieve the name of the thumbnail folder for a specific size. The
166
* returned pointer will become invalid if gimp_thumb_init() is used
167
* again. It must not be changed or freed.
169
* Return value: the thumbnail directory in the encoding of the filesystem
172
gimp_thumb_get_thumb_dir (GimpThumbSize size)
174
g_return_val_if_fail (gimp_thumb_initialized, NULL);
176
size = gimp_thumb_size (size);
178
return thumb_subdirs[size];
182
* gimp_thumb_get_thumb_dir_local:
184
* @size: a GimpThumbSize
186
* Retrieve the name of the local thumbnail folder for a specific
187
* size. Unlike gimp_thumb_get_thumb_dir() the returned string is not
188
* constant and should be free'd when it is not any longer needed.
190
* Return value: the thumbnail directory in the encoding of the filesystem
195
gimp_thumb_get_thumb_dir_local (const gchar *dirname,
198
g_return_val_if_fail (gimp_thumb_initialized, NULL);
199
g_return_val_if_fail (dirname != NULL, NULL);
200
g_return_val_if_fail (size > GIMP_THUMB_SIZE_FAIL, NULL);
202
size = gimp_thumb_size (size);
204
return g_build_filename (dirname, thumb_sizenames[size], NULL);
208
* gimp_thumb_ensure_thumb_dir:
209
* @size: a GimpThumbSize
210
* @error: return location for possible errors
212
* This function checks if the directory that is required to store
213
* thumbnails for a particular @size exist and attempts to create it
216
* You shouldn't have to call this function directly since
217
* gimp_thumbnail_save_thumb() and gimp_thumbnail_save_failure() will
220
* Return value: %TRUE is the directory exists, %FALSE if it could not
224
gimp_thumb_ensure_thumb_dir (GimpThumbSize size,
227
g_return_val_if_fail (gimp_thumb_initialized, FALSE);
228
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
230
size = gimp_thumb_size (size);
232
if (g_file_test (thumb_subdirs[size], G_FILE_TEST_IS_DIR))
235
if (g_file_test (thumb_dir, G_FILE_TEST_IS_DIR) ||
236
(mkdir (thumb_dir, S_IRUSR | S_IWUSR | S_IXUSR) == 0))
239
mkdir (thumb_fail_subdir, S_IRUSR | S_IWUSR | S_IXUSR);
241
mkdir (thumb_subdirs[size], S_IRUSR | S_IWUSR | S_IXUSR);
244
if (g_file_test (thumb_subdirs[size], G_FILE_TEST_IS_DIR))
248
GIMP_THUMB_ERROR, GIMP_THUMB_ERROR_MKDIR,
249
_("Failed to create thumbnail folder '%s'."),
250
thumb_subdirs[size]);
256
* gimp_thumb_ensure_thumb_dir_local:
258
* @size: a GimpThumbSize
259
* @error: return location for possible errors
261
* This function checks if the directory that is required to store
262
* local thumbnails for a particular @size exist and attempts to
263
* create it if necessary.
265
* You shouldn't have to call this function directly since
266
* gimp_thumbnail_save_thumb_local() will do this for you.
268
* Return value: %TRUE is the directory exists, %FALSE if it could not
274
gimp_thumb_ensure_thumb_dir_local (const gchar *dirname,
281
g_return_val_if_fail (gimp_thumb_initialized, FALSE);
282
g_return_val_if_fail (dirname != NULL, FALSE);
283
g_return_val_if_fail (g_path_is_absolute (dirname), FALSE);
284
g_return_val_if_fail (size > GIMP_THUMB_SIZE_FAIL, FALSE);
285
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
287
size = gimp_thumb_size (size);
289
subdir = g_build_filename (dirname,
290
".thumblocal", thumb_sizenames[size],
293
if (g_file_test (subdir, G_FILE_TEST_IS_DIR))
299
basedir = g_build_filename (dirname, ".thumblocal", NULL);
301
if (g_file_test (basedir, G_FILE_TEST_IS_DIR) ||
302
(mkdir (thumb_dir, S_IRUSR | S_IWUSR | S_IXUSR) == 0))
304
mkdir (subdir, S_IRUSR | S_IWUSR | S_IXUSR);
309
if (g_file_test (subdir, G_FILE_TEST_IS_DIR))
316
GIMP_THUMB_ERROR, GIMP_THUMB_ERROR_MKDIR,
317
_("Failed to create thumbnail folder '%s'."),
325
* gimp_thumb_name_from_uri:
326
* @uri: an escaped URI
327
* @size: a #GimpThumbSize
329
* Creates the name of the thumbnail file of the specified @size that
330
* belongs to an image file located at the given @uri.
332
* Return value: a newly allocated filename in the encoding of the
333
* filesystem or %NULL if @uri points to the user's
334
* thumbnail repository.
337
gimp_thumb_name_from_uri (const gchar *uri,
340
g_return_val_if_fail (gimp_thumb_initialized, NULL);
341
g_return_val_if_fail (uri != NULL, NULL);
343
if (strstr (uri, thumb_dir))
346
size = gimp_thumb_size (size);
348
return g_build_filename (thumb_subdirs[size],
349
gimp_thumb_png_name (uri),
354
* gimp_thumb_name_from_uri_local:
355
* @uri: an escaped URI
356
* @size: a #GimpThumbSize
358
* Creates the name of a local thumbnail file of the specified @size
359
* that belongs to an image file located at the given @uri. Local
360
* thumbnails have been introduced with version 0.7 of the spec.
362
* Return value: a newly allocated filename in the encoding of the
363
* filesystem or %NULL if @uri is a remote file or
364
* points to the user's thumbnail repository.
369
gimp_thumb_name_from_uri_local (const gchar *uri,
373
gchar *result = NULL;
375
g_return_val_if_fail (gimp_thumb_initialized, NULL);
376
g_return_val_if_fail (uri != NULL, NULL);
377
g_return_val_if_fail (size > GIMP_THUMB_SIZE_FAIL, NULL);
379
if (strstr (uri, thumb_dir))
382
filename = _gimp_thumb_filename_from_uri (uri);
386
const gchar *baseuri = strrchr (uri, '/');
388
if (baseuri && baseuri[0] && baseuri[1])
390
gchar *dirname = g_path_get_dirname (filename);
391
gint i = gimp_thumb_size (size);
393
result = g_build_filename (dirname,
394
".thumblocal", thumb_sizenames[i],
395
gimp_thumb_png_name (uri),
408
* gimp_thumb_find_thumb:
409
* @uri: an escaped URI
410
* @size: pointer to a #GimpThumbSize
412
* This function attempts to locate a thumbnail for the given
413
* @uri. First it tries the size that is stored at @size. If no
414
* thumbnail of that size is found, it will look for a larger
415
* thumbnail, then falling back to a smaller size.
417
* If the user's thumbnail repository doesn't provide a thumbnail but
418
* a local thumbnail repository exists for the folder the image is
419
* located in, the same search is done among the local thumbnails (if
422
* If a thumbnail is found, it's size is written to the variable
423
* pointer to by @size and the file location is returned.
425
* Return value: a newly allocated string in the encoding of the
426
* filesystem or %NULL if no thumbnail for @uri was found
429
gimp_thumb_find_thumb (const gchar *uri,
434
g_return_val_if_fail (gimp_thumb_initialized, NULL);
435
g_return_val_if_fail (uri != NULL, NULL);
436
g_return_val_if_fail (size != NULL, NULL);
437
g_return_val_if_fail (*size > GIMP_THUMB_SIZE_FAIL, NULL);
439
result = gimp_thumb_png_lookup (gimp_thumb_png_name (uri), NULL, size);
443
gchar *filename = _gimp_thumb_filename_from_uri (uri);
447
const gchar *baseuri = strrchr (uri, '/');
449
if (baseuri && baseuri[0] && baseuri[1])
451
gchar *dirname = g_path_get_dirname (filename);
453
result = gimp_thumb_png_lookup (gimp_thumb_png_name (baseuri + 1),
467
* gimp_thumb_file_test:
468
* @filename: a filename in the encoding of the filesystem
469
* @mtime: return location for modification time
470
* @size: return location for file size
471
* @err_no: return location for system "errno"
473
* This is a convenience and portability wrapper around stat(). It
474
* checks if the given @filename exists and returns modification time
475
* and file size in 64bit integer values.
477
* Return value: The type of the file, or #GIMP_THUMB_FILE_TYPE_NONE if
478
* the file doesn't exist.
481
gimp_thumb_file_test (const gchar *filename,
488
g_return_val_if_fail (filename != NULL, FALSE);
490
if (stat (filename, &s) == 0)
492
if (mtime) *mtime = s.st_mtime;
493
if (size) *size = s.st_size;
494
if (err_no) *err_no = 0;
496
if (S_ISREG (s.st_mode))
498
return GIMP_THUMB_FILE_TYPE_REGULAR;
500
else if (S_ISDIR (s.st_mode))
502
return GIMP_THUMB_FILE_TYPE_FOLDER;
505
return GIMP_THUMB_FILE_TYPE_SPECIAL;
508
if (mtime) *mtime = 0;
510
if (err_no) *err_no = errno;
512
return GIMP_THUMB_FILE_TYPE_NONE;
516
* gimp_thumbs_delete_for_uri:
517
* @uri: an escaped URI
519
* Deletes all thumbnails for the image file specified by @uri from the
520
* user's thumbnail repository.
525
gimp_thumbs_delete_for_uri (const gchar *uri)
529
g_return_if_fail (gimp_thumb_initialized);
530
g_return_if_fail (uri != NULL);
532
for (i = 0; i < thumb_num_sizes; i++)
534
gchar *filename = gimp_thumb_name_from_uri (uri, thumb_sizes[i]);
545
* gimp_thumbs_delete_for_uri_local:
546
* @uri: an escaped URI
548
* Deletes all thumbnails for the image file specified by @uri from
549
* the local thumbnail repository.
554
gimp_thumbs_delete_for_uri_local (const gchar *uri)
558
g_return_if_fail (gimp_thumb_initialized);
559
g_return_if_fail (uri != NULL);
561
for (i = 0; i < thumb_num_sizes; i++)
563
gchar *filename = gimp_thumb_name_from_uri_local (uri, thumb_sizes[i]);
574
_gimp_thumbs_delete_others (const gchar *uri,
579
g_return_if_fail (gimp_thumb_initialized);
580
g_return_if_fail (uri != NULL);
582
size = gimp_thumb_size (size);
584
for (i = 0; i < thumb_num_sizes; i++)
591
filename = gimp_thumb_name_from_uri (uri, thumb_sizes[i]);
601
_gimp_thumb_filename_from_uri (const gchar *uri)
606
g_return_val_if_fail (uri != NULL, NULL);
608
filename = g_filename_from_uri (uri, &hostname, NULL);
615
/* we have a file: URI with a hostname */
618
/* on Win32, create a valid UNC path and use it as the filename */
619
gchar *tmp = g_build_filename ("//", hostname, filename, NULL);
624
/* otherwise return NULL, caller should use URI then */
636
gimp_thumb_exit (void)
641
g_free (thumb_sizes);
642
g_free (thumb_sizenames);
643
for (i = 0; i < thumb_num_sizes; i++)
644
g_free (thumb_subdirs[i]);
645
g_free (thumb_subdirs);
646
g_free (thumb_fail_subdir);
650
thumb_sizenames = NULL;
652
thumb_subdirs = NULL;
653
thumb_fail_subdir = NULL;
654
gimp_thumb_initialized = FALSE;
658
gimp_thumb_size (GimpThumbSize size)
662
if (size > GIMP_THUMB_SIZE_FAIL)
665
i < thumb_num_sizes && thumb_sizes[i] < size;
669
if (i == thumb_num_sizes)
677
gimp_thumb_png_lookup (const gchar *name,
678
const gchar *basedir,
681
gchar *thumb_name = NULL;
682
gchar **subdirs = NULL;
687
gchar *dir = g_build_filename (basedir, ".thumblocal", NULL);
689
if (g_file_test (basedir, G_FILE_TEST_IS_DIR))
693
subdirs = g_new (gchar *, thumb_num_sizes);
695
subdirs[0] = NULL; /* GIMP_THUMB_SIZE_FAIL */
697
for (i = 1; i < thumb_num_sizes; i++)
698
subdirs[i] = g_build_filename (dir, thumb_sizenames[i], NULL);
705
subdirs = thumb_subdirs;
711
i = n = gimp_thumb_size (*size);
713
for (; i < thumb_num_sizes; i++)
718
thumb_name = g_build_filename (subdirs[i], name, NULL);
720
if (gimp_thumb_file_test (thumb_name,
722
NULL) == GIMP_THUMB_FILE_TYPE_REGULAR)
724
*size = thumb_sizes[i];
731
for (i = n - 1; i >= 0; i--)
736
thumb_name = g_build_filename (subdirs[i], name, NULL);
738
if (gimp_thumb_file_test (thumb_name,
740
NULL) == GIMP_THUMB_FILE_TYPE_REGULAR)
742
*size = thumb_sizes[i];
754
for (i = 0; i < thumb_num_sizes; i++)
763
gimp_thumb_png_name (const gchar *uri)
765
static gchar name[40];
770
gimp_md5_get_digest (uri, -1, digest);
772
for (i = 0; i < 16; i++)
774
n = (digest[i] >> 4) & 0xF;
775
name[i * 2] = (n > 9) ? 'a' + n - 10 : '0' + n;
778
name[i * 2 + 1] = (n > 9) ? 'a' + n - 10 : '0' + n;
781
strncpy (name + 32, ".png", 5);
783
return (const gchar *) name;