libgimpthumb/gimpthumb-utils.[ch] libgimpthumb/gimpthumbnail.[ch] added

2004-10-23  Sven Neumann  <sven@gimp.org>

	* libgimpthumb/gimpthumb-utils.[ch]
	* libgimpthumb/gimpthumbnail.[ch]
	* libgimpthumb/gimpthumb.def: added missing API, mainly for deleting
	thumbnails.

	* app/core/gimpimagefile.[ch]: when saving a thumbnail, delete a
	failure thumbnail if one exists. Unless the thumbnail was created
	explicitely, remove all other thumbnails for this image.

	* app/actions/documents-commands.c: changed accordingly.

	* app/file/file-open.c: only save a thumbnail if there isn't a
	valid thumbnail already.

	* app/widgets/gimpthumbbox.c: before attempting to create a new
	thumbnail, check if there's an uptodate failure thumbnail.
This commit is contained in:
Sven Neumann 2004-10-23 15:30:39 +00:00 committed by Sven Neumann
parent dab05392af
commit ea273aadb9
14 changed files with 389 additions and 61 deletions

View file

@ -1,3 +1,22 @@
2004-10-23 Sven Neumann <sven@gimp.org>
* libgimpthumb/gimpthumb-utils.[ch]
* libgimpthumb/gimpthumbnail.[ch]
* libgimpthumb/gimpthumb.def: added missing API, mainly for deleting
thumbnails.
* app/core/gimpimagefile.[ch]: when saving a thumbnail, delete a
failure thumbnail if one exists. Unless the thumbnail was created
explicitely, remove all other thumbnails for this image.
* app/actions/documents-commands.c: changed accordingly.
* app/file/file-open.c: only save a thumbnail if there isn't a
valid thumbnail already.
* app/widgets/gimpthumbbox.c: before attempting to create a new
thumbnail, check if there's an uptodate failure thumbnail.
2004-10-23 Michael Natterer <mitch@gimp.org>
* app/dialogs/Makefile.am

View file

@ -180,16 +180,10 @@ documents_recreate_preview_cmd_callback (GtkAction *action,
if (imagefile && gimp_container_have (container, GIMP_OBJECT (imagefile)))
{
const gchar *uri = gimp_object_get_name (GIMP_OBJECT (imagefile));
gint size = imagefile->gimp->config->thumbnail_size;
if (!size)
return;
if (uri)
gimp_thumbs_delete_for_uri (uri);
gimp_imagefile_create_thumbnail (imagefile, context, NULL, size);
gimp_imagefile_create_thumbnail (imagefile,
context, NULL,
imagefile->gimp->config->thumbnail_size,
FALSE);
}
}

View file

@ -72,6 +72,7 @@ static GdkPixbuf * gimp_imagefile_load_thumb (GimpImagefile *imagefile,
static gboolean gimp_imagefile_save_thumb (GimpImagefile *imagefile,
GimpImage *gimage,
gint size,
gboolean replace,
GError **error);
static gchar * gimp_imagefile_get_description (GimpViewable *viewable,
@ -230,7 +231,8 @@ void
gimp_imagefile_create_thumbnail (GimpImagefile *imagefile,
GimpContext *context,
GimpProgress *progress,
gint size)
gint size,
gboolean replace)
{
GimpThumbnail *thumbnail;
@ -276,7 +278,7 @@ gimp_imagefile_create_thumbnail (GimpImagefile *imagefile,
NULL);
success = gimp_imagefile_save_thumb (imagefile,
gimage, size, &error);
gimage, size, replace, &error);
g_object_unref (gimage);
}
@ -285,11 +287,12 @@ gimp_imagefile_create_thumbnail (GimpImagefile *imagefile,
success = gimp_thumbnail_save_failure (thumbnail,
"The GIMP " GIMP_VERSION,
&error);
gimp_imagefile_update (imagefile);
}
g_object_unref (imagefile);
if (!success)
if (! success)
{
g_message (error->message);
g_error_free (error);
@ -300,13 +303,14 @@ gimp_imagefile_create_thumbnail (GimpImagefile *imagefile,
/* The weak version doesn't ref the imagefile but deals gracefully
* with an imagefile that is destroyed while the thumbnail is
* created. Thia allows to use this function w/o the need to block
* the user interface (making it insensitive).
* the user interface.
*/
void
gimp_imagefile_create_thumbnail_weak (GimpImagefile *imagefile,
GimpContext *context,
GimpProgress *progress,
gint size)
gint size,
gboolean replace)
{
GimpImagefile *local;
const gchar *uri;
@ -327,7 +331,7 @@ gimp_imagefile_create_thumbnail_weak (GimpImagefile *imagefile,
g_object_add_weak_pointer (G_OBJECT (imagefile), (gpointer) &imagefile);
gimp_imagefile_create_thumbnail (local, context, progress, size);
gimp_imagefile_create_thumbnail (local, context, progress, size, replace);
if (imagefile)
{
@ -346,28 +350,54 @@ gimp_imagefile_create_thumbnail_weak (GimpImagefile *imagefile,
g_object_unref (local);
}
gboolean
gimp_imagefile_check_thumbnail (GimpImagefile *imagefile)
{
gint size;
g_return_val_if_fail (GIMP_IS_IMAGEFILE (imagefile), FALSE);
size = imagefile->gimp->config->thumbnail_size;
if (size > 0)
{
GimpThumbState state;
state = gimp_thumbnail_check_thumb (imagefile->thumbnail, size);
return (state == GIMP_THUMB_STATE_OK);
}
return TRUE;
}
gboolean
gimp_imagefile_save_thumbnail (GimpImagefile *imagefile,
GimpImage *gimage)
{
gboolean success;
GError *error = NULL;
gint size;
gboolean success = TRUE;
GError *error = NULL;
g_return_val_if_fail (GIMP_IS_IMAGEFILE (imagefile), FALSE);
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
/* peek the thumbnail to make sure that mtime and filesize are set */
gimp_thumbnail_peek_image (imagefile->thumbnail);
size = imagefile->gimp->config->thumbnail_size;
success = gimp_imagefile_save_thumb (imagefile,
gimage,
gimage->gimp->config->thumbnail_size,
&error);
if (! success)
if (size > 0)
{
g_message (error->message);
g_error_free (error);
/* peek the thumbnail to make sure that mtime and filesize are set */
gimp_thumbnail_peek_image (imagefile->thumbnail);
success = gimp_imagefile_save_thumb (imagefile,
gimage, size, FALSE,
&error);
if (! success)
{
g_message (error->message);
g_error_free (error);
}
}
return success;
@ -684,6 +714,7 @@ static gboolean
gimp_imagefile_save_thumb (GimpImagefile *imagefile,
GimpImage *gimage,
gint size,
gboolean replace,
GError **error)
{
GimpThumbnail *thumbnail = imagefile->thumbnail;
@ -750,7 +781,14 @@ gimp_imagefile_save_thumb (GimpImagefile *imagefile,
g_object_unref (pixbuf);
if (success)
gimp_imagefile_update (imagefile);
{
if (replace)
gimp_thumbnail_delete_others (thumbnail, size);
else
gimp_thumbnail_delete_failure (thumbnail);
gimp_imagefile_update (imagefile);
}
return success;
}

View file

@ -68,11 +68,14 @@ void gimp_imagefile_update (GimpImagefile *imagefile);
void gimp_imagefile_create_thumbnail (GimpImagefile *imagefile,
GimpContext *context,
GimpProgress *progress,
gint thumb_size);
gint size,
gboolean replace);
void gimp_imagefile_create_thumbnail_weak (GimpImagefile *imagefile,
GimpContext *context,
GimpProgress *progress,
gint size);
gint size,
gboolean replace);
gboolean gimp_imagefile_check_thumbnail (GimpImagefile *imagefile);
gboolean gimp_imagefile_save_thumbnail (GimpImagefile *imagefile,
GimpImage *gimage);
const gchar * gimp_imagefile_get_desc_string (GimpImagefile *imagefile);

View file

@ -247,7 +247,11 @@ file_open_with_proc_and_display (Gimp *gimp,
*/
if (strcmp (uri, gimp_image_get_uri (gimage)) == 0)
{
gimp_imagefile_save_thumbnail (imagefile, gimage);
/* no need to save a thumbnail if there's a good one already */
if (! gimp_imagefile_check_thumbnail (imagefile))
{
gimp_imagefile_save_thumbnail (imagefile, gimage);
}
}
gimp_recent_list_add_uri (uri, mime_type);

View file

@ -677,24 +677,26 @@ gimp_thumb_box_create_thumbnail (GimpThumbBox *box,
if (filename && g_file_test (filename, G_FILE_TEST_IS_REGULAR))
{
gchar *basename = file_utils_uri_to_utf8_basename (uri);
GimpThumbnail *thumb = box->imagefile->thumbnail;
gchar *basename;
basename = file_utils_uri_to_utf8_basename (uri);
gtk_label_set_text (GTK_LABEL (box->filename), basename);
g_free (basename);
if (force)
gimp_thumbs_delete_for_uri (uri);
gimp_object_set_name (GIMP_OBJECT (box->imagefile), uri);
if (force ||
gimp_thumbnail_peek_thumb (box->imagefile->thumbnail, size)
< GIMP_THUMB_STATE_FAILED)
(gimp_thumbnail_peek_thumb (thumb, size) < GIMP_THUMB_STATE_FAILED &&
! gimp_thumbnail_has_failed (thumb)))
{
Gimp *gimp = box->imagefile->gimp;
gimp_imagefile_create_thumbnail (box->imagefile,
gimp_get_user_context (box->imagefile->gimp),
gimp_get_user_context (gimp),
GIMP_PROGRESS (box),
size);
size,
!force);
}
}
@ -715,6 +717,7 @@ gimp_thumb_box_auto_thumbnail (GimpThumbBox *box)
case GIMP_THUMB_STATE_NOT_FOUND:
case GIMP_THUMB_STATE_OLD:
if (thumb->image_filesize < gimp->config->thumbnail_filesize_limit &&
! gimp_thumbnail_has_failed (thumb) &&
file_utils_find_proc_by_extension (gimp->load_procs, uri))
{
if (thumb->image_filesize > 0)
@ -740,7 +743,8 @@ gimp_thumb_box_auto_thumbnail (GimpThumbBox *box)
gimp_imagefile_create_thumbnail_weak (box->imagefile,
gimp_get_user_context (gimp),
GIMP_PROGRESS (box),
gimp->config->thumbnail_size);
gimp->config->thumbnail_size,
TRUE);
}
break;

View file

@ -1,3 +1,8 @@
2004-10-23 Sven Neumann <sven@gimp.org>
* libgimpthumb/libgimpthumb-sections.txt
* libgimpthumb/tmpl/gimpthumbnail.sgml: updated.
2004-10-14 Sven Neumann <sven@gimp.org>
* libgimpwidgets/libgimpwidgets-sections.txt: added

View file

@ -8,10 +8,15 @@ gimp_thumbnail_set_filename
gimp_thumbnail_set_from_thumb
gimp_thumbnail_peek_image
gimp_thumbnail_peek_thumb
gimp_thumbnail_check_thumb
gimp_thumbnail_load_thumb
gimp_thumbnail_save_thumb
gimp_thumbnail_save_failure
gimp_thumbnail_save_thumb_local
gimp_thumbnail_save_failure
gimp_thumbnail_delete_failure
gimp_thumbnail_delete_others
gimp_thumbnail_has_failed
<SUBSECTION Standard>
GimpThumbnailClass
GIMP_THUMBNAIL

View file

@ -129,6 +129,16 @@ using object properties.
@Returns:
<!-- ##### FUNCTION gimp_thumbnail_check_thumb ##### -->
<para>
</para>
@thumbnail:
@size:
@Returns:
<!-- ##### FUNCTION gimp_thumbnail_load_thumb ##### -->
<para>
@ -152,17 +162,6 @@ using object properties.
@Returns:
<!-- ##### FUNCTION gimp_thumbnail_save_failure ##### -->
<para>
</para>
@thumbnail:
@software:
@error:
@Returns:
<!-- ##### FUNCTION gimp_thumbnail_save_thumb_local ##### -->
<para>
@ -175,3 +174,40 @@ using object properties.
@Returns:
<!-- ##### FUNCTION gimp_thumbnail_save_failure ##### -->
<para>
</para>
@thumbnail:
@software:
@error:
@Returns:
<!-- ##### FUNCTION gimp_thumbnail_delete_failure ##### -->
<para>
</para>
@thumbnail:
<!-- ##### FUNCTION gimp_thumbnail_delete_others ##### -->
<para>
</para>
@thumbnail:
@size:
<!-- ##### FUNCTION gimp_thumbnail_has_failed ##### -->
<para>
</para>
@thumbnail:
@Returns:

View file

@ -548,6 +548,30 @@ gimp_thumbs_delete_for_uri_local (const gchar *uri)
}
}
void
_gimp_thumbs_delete_others (const gchar *uri,
GimpThumbSize size)
{
gint i;
g_return_if_fail (gimp_thumb_initialized);
g_return_if_fail (uri != NULL);
for (i = 0; i < thumb_num_sizes; i++)
{
if (thumb_sizes[i] != size)
{
gchar *filename = gimp_thumb_name_from_uri (uri, thumb_sizes[i]);
if (filename)
{
unlink (filename);
g_free (filename);
}
}
}
}
static void
gimp_thumb_exit (void)
{

View file

@ -57,6 +57,10 @@ gboolean gimp_thumb_ensure_thumb_dir_local (const gchar *dirname,
void gimp_thumbs_delete_for_uri_local (const gchar *uri);
/* for internal use only */
void _gimp_thumbs_delete_others (const gchar *uri,
GimpThumbSize size);
G_END_DECLS

View file

@ -11,7 +11,11 @@ EXPORTS
gimp_thumb_name_from_uri_local
gimp_thumb_size_get_type
gimp_thumb_state_get_type
gimp_thumbnail_check_thumb
gimp_thumbnail_delete_failure
gimp_thumbnail_delete_others
gimp_thumbnail_get_type
gimp_thumbnail_has_failed
gimp_thumbnail_load_thumb
gimp_thumbnail_new
gimp_thumbnail_peek_image

View file

@ -561,6 +561,10 @@ gimp_thumbnail_peek_image (GimpThumbnail *thumbnail)
* valid and uptodate for the image file asosciated with the
* @thumbnail.
*
* If you want to check the thumbnail, either attempt to load it using
* gimp_thumbnail_load_thumb(), or, if you don't need the resulting
* thumbnail pixbuf, use gimp_thumbnail_check_thumb().
*
* Return value: the thumbnail's #GimpThumbState after the update
**/
GimpThumbState
@ -582,6 +586,40 @@ gimp_thumbnail_peek_thumb (GimpThumbnail *thumbnail,
return thumbnail->thumb_state;
}
/**
* gimp_thumbnail_check_thumb:
* @thumbnail: a #GimpThumbnail object
* @size: the preferred size of the thumbnail image
*
* Checks if a thumbnail file for the @thumbnail exists, loads it and
* verifies it is valid and uptodate for the image file asosciated
* with the @thumbnail.
*
* Return value: the thumbnail's #GimpThumbState after the update
*
* Since: GIMP 2.2
**/
GimpThumbState
gimp_thumbnail_check_thumb (GimpThumbnail *thumbnail,
GimpThumbSize size)
{
GdkPixbuf *pixbuf;
g_return_val_if_fail (GIMP_IS_THUMBNAIL (thumbnail), FALSE);
GIMP_THUMB_DEBUG_CALL (thumbnail);
if (gimp_thumbnail_peek_thumb (thumbnail, size) == GIMP_THUMB_STATE_OK)
return GIMP_THUMB_STATE_OK;
pixbuf = gimp_thumbnail_load_thumb (thumbnail, size, NULL);
if (pixbuf)
g_object_unref (pixbuf);
return thumbnail->thumb_state;
}
static void
gimp_thumbnail_update_image (GimpThumbnail *thumbnail)
{
@ -657,6 +695,11 @@ gimp_thumbnail_update_image (GimpThumbnail *thumbnail)
"image-mtime", mtime,
"image-filesize", filesize,
NULL);
if (thumbnail->thumb_state == GIMP_THUMB_STATE_OK)
g_object_set (thumbnail,
"thumb-state", GIMP_THUMB_STATE_OLD,
NULL);
}
}
@ -706,8 +749,7 @@ gimp_thumbnail_update_thumb (GimpThumbnail *thumbnail,
if (filename)
state = (size > GIMP_THUMB_SIZE_FAIL ?
GIMP_THUMB_STATE_EXISTS :
GIMP_THUMB_STATE_FAILED);
GIMP_THUMB_STATE_EXISTS : GIMP_THUMB_STATE_FAILED);
thumbnail->thumb_size = size;
thumbnail->thumb_filesize = filesize;
@ -887,12 +929,23 @@ gimp_thumbnail_save (GimpThumbnail *thumbnail,
success = (chmod (filename, 0600) == 0);
if (success)
gimp_thumbnail_update_thumb (thumbnail, size);
else
if (! success)
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
"Could not set permissions of thumbnail for %s: %s",
thumbnail->image_uri, g_strerror (errno));
g_object_freeze_notify (G_OBJECT (thumbnail));
gimp_thumbnail_update_thumb (thumbnail, size);
if (success &&
thumbnail->thumb_state == GIMP_THUMB_STATE_EXISTS &&
strcmp (filename, thumbnail->thumb_filename) == 0)
{
thumbnail->thumb_state = GIMP_THUMB_STATE_OK;
}
g_object_thaw_notify (G_OBJECT (thumbnail));
}
unlink (tmpname);
@ -1264,3 +1317,128 @@ gimp_thumbnail_save_failure (GimpThumbnail *thumbnail,
return success;
}
/**
* gimp_thumbnail_delete_failure:
* @thumbnail: a #GimpThumbnail object
*
* Removes a failure thumbnail if one exists. This function should be
* used after a thumbnail has been successfully created.
*
* Since: GIMP 2.2
**/
void
gimp_thumbnail_delete_failure (GimpThumbnail *thumbnail)
{
gchar *filename;
g_return_if_fail (GIMP_IS_THUMBNAIL (thumbnail));
g_return_if_fail (thumbnail->image_uri != NULL);
GIMP_THUMB_DEBUG_CALL (thumbnail);
filename = gimp_thumb_name_from_uri (thumbnail->image_uri,
GIMP_THUMB_SIZE_FAIL);
if (filename)
{
unlink (filename);
g_free (filename);
}
}
/**
* gimp_thumbnail_delete_others:
* @thumbnail: a #GimpThumbnail object
* @size: the thumbnail size which should not be deleted
*
* Removes all other thumbnails from the global thumbnail
* repository. Only the thumbnail for @size is not deleted. This
* function should be used after a thumbnail has been successfully
* updated. See the spec for a more detailed description on when to
* delete thumbnails.
*
* Since: GIMP 2.2
**/
void
gimp_thumbnail_delete_others (GimpThumbnail *thumbnail,
GimpThumbSize size)
{
g_return_if_fail (GIMP_IS_THUMBNAIL (thumbnail));
g_return_if_fail (thumbnail->image_uri != NULL);
GIMP_THUMB_DEBUG_CALL (thumbnail);
_gimp_thumbs_delete_others (thumbnail->image_uri, size);
}
/**
* gimp_thumbnail_has_failed:
* @thumbnail: a #GimpThumbnail object
*
* Checks if a valid failure thumbnail for the given thumbnail exists
* in the global thumbnail repository. This may be the case even if
* gimp_thumbnail_peek_thumb() doesn't return %GIMP_THUMB_STATE_FAILED
* since there might be a real thumbnail and a failure thumbnail for
* the same image file.
*
* The application should not attempt to create the thumbnail if a
* valid failure thumbnail exists.
*
* Return value: %TRUE if a failure thumbnail exists or
*
* Since: GIMP 2.2
**/
gboolean
gimp_thumbnail_has_failed (GimpThumbnail *thumbnail)
{
GdkPixbuf *pixbuf;
const gchar *option;
gchar *filename;
gint64 image_mtime;
gint64 image_size;
gboolean failed = FALSE;
g_return_val_if_fail (GIMP_IS_THUMBNAIL (thumbnail), FALSE);
g_return_val_if_fail (thumbnail->image_uri != NULL, FALSE);
GIMP_THUMB_DEBUG_CALL (thumbnail);
filename = gimp_thumb_name_from_uri (thumbnail->image_uri,
GIMP_THUMB_SIZE_FAIL);
if (! filename)
return FALSE;
pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
g_free (filename);
if (! pixbuf)
return FALSE;
if (gimp_thumbnail_peek_image (thumbnail) < GIMP_THUMB_STATE_EXISTS)
goto finish;
/* URI and mtime from the thumbnail need to match our file */
option = gdk_pixbuf_get_option (pixbuf, TAG_THUMB_URI);
if (! option || strcmp (option, thumbnail->image_uri))
goto finish;
option = gdk_pixbuf_get_option (pixbuf, TAG_THUMB_MTIME);
if (!option || sscanf (option, "%" G_GINT64_FORMAT, &image_mtime) != 1)
goto finish;
option = gdk_pixbuf_get_option (pixbuf, TAG_THUMB_FILESIZE);
if (option && sscanf (option, "%" G_GINT64_FORMAT, &image_size) != 1)
goto finish;
/* TAG_THUMB_FILESIZE is optional but must match if present */
if (image_mtime == thumbnail->image_mtime &&
(option == NULL || image_size == thumbnail->image_filesize))
{
failed = TRUE;
}
finish:
g_object_unref (pixbuf);
return failed;
}

View file

@ -94,21 +94,31 @@ GimpThumbState gimp_thumbnail_peek_image (GimpThumbnail *thumbnail);
GimpThumbState gimp_thumbnail_peek_thumb (GimpThumbnail *thumbnail,
GimpThumbSize size);
GimpThumbState gimp_thumbnail_check_thumb (GimpThumbnail *thumbnail,
GimpThumbSize size);
GdkPixbuf * gimp_thumbnail_load_thumb (GimpThumbnail *thumbnail,
GimpThumbSize size,
GError **error);
gboolean gimp_thumbnail_save_thumb (GimpThumbnail *thumbnail,
GdkPixbuf *pixbuf,
const gchar *software,
GError **error);
gboolean gimp_thumbnail_save_failure (GimpThumbnail *thumbnail,
const gchar *software,
GError **error);
gboolean gimp_thumbnail_save_thumb_local (GimpThumbnail *thumbnail,
GdkPixbuf *pixbuf,
const gchar *software,
GError **error);
gboolean gimp_thumbnail_save_failure (GimpThumbnail *thumbnail,
const gchar *software,
GError **error);
void gimp_thumbnail_delete_failure (GimpThumbnail *thumbnail);
void gimp_thumbnail_delete_others (GimpThumbnail *thumbnail,
GimpThumbSize size);
gboolean gimp_thumbnail_has_failed (GimpThumbnail *thumbnail);
G_END_DECLS