⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 thumb_standard.c

📁 Gqview,Linux下基于GTK+库写成的轻量级而能丰富的图像浏览程序。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * GQview * (C) 2005 John Ellis * * Author: John Ellis * * This software is released under the GNU General Public License (GNU GPL). * Please read the included file COPYING for more information. * This software comes with no warranty of any kind, use at your own risk! */#include "gqview.h"#include "thumb_standard.h"#include "cache.h"	/* for cache_ensure_dir_exists */#include "image-load.h"#include "md5-util.h"#include "pixbuf_util.h"#include "ui_fileops.h"/* * This thumbnail caching implementation attempts to conform * to the Thumbnail Managing Standard proposed on freedesktop.org * The standard is documented here: *   http://triq.net/~jens/thumbnail-spec/index.html *  (why isn't it actually hosted on freedesktop.org?) * * This code attempts to conform to version 0.7.0 of the standard. * * Notes: *   > Validation of the thumb's embedded uri is a simple strcmp between our *     version of the escaped uri and the thumb's escaped uri. But not all uri *     escape functions escape the same set of chars, comparing the unescaped *     versions may be more accurate. *   > Only Thumb::URI and Thumb::MTime are stored in a thumb at this time. *     Storing the Size, Width, Height should probably be implemented. */#define THUMB_SIZE_NORMAL 128#define THUMB_SIZE_LARGE  256#define THUMB_MARKER_URI    "tEXt::Thumb::URI"#define THUMB_MARKER_MTIME  "tEXt::Thumb::MTime"#define THUMB_MARKER_SIZE   "tEXt::Thumb::Size"#define THUMB_MARKER_WIDTH  "tEXt::Thumb::Image::Width"#define THUMB_MARKER_HEIGHT "tEXt::Thumb::Image::Height"#define THUMB_MARKER_APP    "tEXt::Software"#define THUMB_PERMS_FOLDER 0700#define THUMB_PERMS_THUMB  0600/* *----------------------------------------------------------------------------- * thumbnail loader *----------------------------------------------------------------------------- */static void thumb_loader_std_error_cb(ImageLoader *il, gpointer data);static gint thumb_loader_std_setup(ThumbLoaderStd *tl, const gchar *path);ThumbLoaderStd *thumb_loader_std_new(gint width, gint height){	ThumbLoaderStd *tl;	tl = g_new0(ThumbLoaderStd, 1);	tl->standard_loader = TRUE;	tl->requested_width = width;	tl->requested_height = height;	tl->pixbuf = NULL;	tl->il = NULL;	tl->source_path = NULL;	tl->cache_enable = enable_thumb_caching;	tl->cache_local = FALSE;	tl->cache_retry = FALSE;	return tl;}void thumb_loader_std_set_callbacks(ThumbLoaderStd *tl,				    ThumbLoaderStdFunc func_done,				    ThumbLoaderStdFunc func_error,				    ThumbLoaderStdFunc func_progress,				    gpointer data){	if (!tl) return;	tl->func_done = func_done;	tl->func_error = func_error;	tl->func_progress = func_progress;	tl->data = data;}static void thumb_loader_std_reset(ThumbLoaderStd *tl){	if (tl->pixbuf) g_object_unref(tl->pixbuf);	tl->pixbuf = NULL;	image_loader_free(tl->il);	tl->il = NULL;	g_free(tl->source_path);	tl->source_path = NULL;	g_free(tl->thumb_path);	tl->thumb_path = NULL;	g_free(tl->thumb_uri);	tl->thumb_uri = NULL;	tl->local_uri = NULL;	tl->thumb_path_local = FALSE;	tl->cache_hit = FALSE;	tl->source_mtime = 0;	tl->source_size = 0;	tl->source_mode = 0;	tl->progress = 0.0;}static gchar *thumb_std_cache_path(const gchar *path, const gchar *uri, gint local,				   const gchar *cache_subfolder){	gchar *result = NULL;	gchar *cache_base;	gchar *md5_text;	guchar digest[16];	if (!path || !uri || !cache_subfolder) return NULL;	if (local)		{		gchar *base;		base = remove_level_from_path(path);		cache_base = g_strconcat(base, "/", THUMB_FOLDER, "/", cache_subfolder, NULL);		g_free(base);		}	else		{		cache_base = g_strconcat(homedir(), "/", THUMB_FOLDER, "/", cache_subfolder, NULL);		}	md5_get_digest(uri, strlen(uri), digest);	md5_text = md5_digest_to_text(digest);	if (cache_base && md5_text)		{		result = g_strconcat(cache_base, "/", md5_text, THUMB_NAME_EXTENSION, NULL);		}	g_free(cache_base);	g_free(md5_text);	return result;}static gchar *thumb_loader_std_cache_path(ThumbLoaderStd *tl, gint local, GdkPixbuf *pixbuf, gint fail){#if 0	gchar *result = NULL;	gchar *cache_base;#endif	const gchar *folder_size;#if 0	const gchar *uri;	gchar *md5_text;	guchar digest[16];#endif	gint w, h;	if (!tl->source_path || !tl->thumb_uri) return NULL;	if (pixbuf)		{		w = gdk_pixbuf_get_width(pixbuf);		h = gdk_pixbuf_get_height(pixbuf);		}	else		{		w = tl->requested_width;		h = tl->requested_height;		}	if (fail)		{		folder_size = THUMB_FOLDER_FAIL;		}	else if (w > THUMB_SIZE_NORMAL || h > THUMB_SIZE_NORMAL)		{		folder_size = THUMB_FOLDER_LARGE;		}	else		{		folder_size = THUMB_FOLDER_NORMAL;		}	return thumb_std_cache_path(tl->source_path,				    (local) ?  tl->local_uri : tl->thumb_uri,				    local, folder_size);#if 0	if (local)		{		gchar *base;		base = remove_level_from_path(tl->source_path);		cache_base = g_strconcat(base, "/", THUMB_FOLDER, "/", folder_size, NULL);		g_free(base);		}	else		{		cache_base = g_strconcat(homedir(), "/", THUMB_FOLDER, "/", folder_size, NULL);		}	uri = (local) ? tl->local_uri : tl->thumb_uri;	md5_get_digest(uri, strlen(uri), digest);	md5_text = md5_digest_to_text(digest);	if (cache_base && md5_text)		{		result = g_strconcat(cache_base, "/", md5_text, THUMB_NAME_EXTENSION, NULL);		}	g_free(cache_base);	g_free(md5_text);	return result;#endif}static gint thumb_loader_std_fail_check(ThumbLoaderStd *tl){	gchar *fail_path;	gint result = FALSE;	fail_path = thumb_loader_std_cache_path(tl, FALSE, NULL, TRUE);	if (isfile(fail_path))		{		GdkPixbuf *pixbuf;		if (tl->cache_retry)			{			pixbuf = NULL;			}		else			{			gchar *pathl;			pathl = path_from_utf8(fail_path);			pixbuf = gdk_pixbuf_new_from_file(pathl, NULL);			g_free(pathl);			}		if (pixbuf)			{			const gchar *mtime_str;			mtime_str = gdk_pixbuf_get_option(pixbuf, THUMB_MARKER_MTIME);			if (mtime_str && strtol(mtime_str, NULL, 10) == tl->source_mtime)				{				result = TRUE;				if (debug)					{					printf("thumb fail valid: %s\n", tl->source_path);					printf("           thumb: %s\n", fail_path);					}				}			g_object_unref(G_OBJECT(pixbuf));			}		if (!result) unlink_file(fail_path);		}	g_free(fail_path);	return result;}static gint thumb_loader_std_validate(ThumbLoaderStd *tl, GdkPixbuf *pixbuf){	const gchar *valid_uri;	const gchar *uri;	const gchar *mtime_str;	time_t mtime;	gint w, h;	if (!pixbuf) return FALSE;	w = gdk_pixbuf_get_width(pixbuf);	h = gdk_pixbuf_get_height(pixbuf);	if (w != THUMB_SIZE_NORMAL && w != THUMB_SIZE_LARGE &&	    h != THUMB_SIZE_NORMAL && h != THUMB_SIZE_LARGE) return FALSE;	valid_uri = (tl->thumb_path_local) ? tl->local_uri : tl->thumb_uri;	uri = gdk_pixbuf_get_option(pixbuf, THUMB_MARKER_URI);	mtime_str = gdk_pixbuf_get_option(pixbuf, THUMB_MARKER_MTIME);	if (!mtime_str || !uri || !valid_uri) return FALSE;	if (strcmp(uri, valid_uri) != 0) return FALSE;	mtime = strtol(mtime_str, NULL, 10);	if (tl->source_mtime != mtime) return FALSE;	return TRUE;}static void thumb_loader_std_save(ThumbLoaderStd *tl, GdkPixbuf *pixbuf){	gchar *base_path;	gchar *tmp_path;	gint fail;	if (!tl->cache_enable || tl->cache_hit) return;	if (tl->thumb_path) return;	if (!pixbuf)		{		/* local failures are not stored */		if (tl->cache_local) return;		pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);		fail = TRUE;		}	else		{		g_object_ref(G_OBJECT(pixbuf));		fail = FALSE;		}	tl->thumb_path = thumb_loader_std_cache_path(tl, tl->cache_local, pixbuf, fail);	if (!tl->thumb_path)		{		g_object_unref(G_OBJECT(pixbuf));		return;		}	tl->thumb_path_local = tl->cache_local;	/* create thumbnail dir if needed */	base_path = remove_level_from_path(tl->thumb_path);	if (tl->cache_local)		{		if (!isdir(base_path))			{			struct stat st;			gchar *source_base;			source_base = remove_level_from_path(tl->source_path);			if (stat_utf8(source_base, &st))				{				cache_ensure_dir_exists(base_path, st.st_mode);				}			g_free(source_base);			}		}	else		{		cache_ensure_dir_exists(base_path, THUMB_PERMS_FOLDER);		}	g_free(base_path);	if (debug)		{		printf("thumb saving: %s\n", tl->source_path);		printf("       saved: %s\n", tl->thumb_path);		}	/* save thumb, using a temp file then renaming into place */	tmp_path = unique_filename(tl->thumb_path, ".tmp", "_", 2);	if (tmp_path)		{		const gchar *mark_uri;		gchar *mark_app;		gchar *mark_mtime;		gchar *pathl;		gint success;		mark_uri = (tl->cache_local) ? tl->local_uri :tl->thumb_uri;		mark_app = g_strdup_printf("GQview %s", VERSION);		mark_mtime = g_strdup_printf("%lu", tl->source_mtime);		pathl = path_from_utf8(tmp_path);		success = gdk_pixbuf_save(pixbuf, pathl, "png", NULL,					  THUMB_MARKER_URI, mark_uri,					  THUMB_MARKER_MTIME, mark_mtime,					  THUMB_MARKER_APP, mark_app,					  NULL);		if (success)			{			chmod(pathl, (tl->cache_local) ? tl->source_mode : THUMB_PERMS_THUMB);			success = rename_file(tmp_path, tl->thumb_path);			}		g_free(pathl);		g_free(mark_mtime);		g_free(mark_app);		g_free(tmp_path);		if (!success && debug)			{			printf("thumb save failed: %s\n", tl->source_path);			printf("            thumb: %s\n", tl->thumb_path);			}		}	g_object_unref(G_OBJECT(pixbuf));}static gint thumb_loader_std_scale_aspect(gint req_w, gint req_h, gint old_w, gint old_h,					  gint *new_w, gint *new_h){	if (((gdouble)req_w / old_w) < ((gdouble)req_h / old_h))		{		*new_w = req_w;		*new_h = (gdouble)*new_w / old_w * old_h;		if (*new_h < 1) *new_h = 1;		}	else		{		*new_h = req_h;		*new_w = (gdouble)*new_h / old_h * old_w;		if (*new_w < 1) *new_w = 1;		}	return (*new_w != old_w || *new_h != old_h);}static GdkPixbuf *thumb_loader_std_finish(ThumbLoaderStd *tl, GdkPixbuf *pixbuf, gint shrunk){	GdkPixbuf *pixbuf_thumb = NULL;	GdkPixbuf *result;	gint sw, sh;	sw = gdk_pixbuf_get_width(pixbuf);	sh = gdk_pixbuf_get_height(pixbuf);	if (tl->cache_enable)		{		if (!tl->cache_hit)			{			gint cache_w, cache_h;			if (tl->requested_width > THUMB_SIZE_NORMAL || tl->requested_height > THUMB_SIZE_NORMAL)				{				cache_w = cache_h = THUMB_SIZE_LARGE;				}			else				{				cache_w = cache_h = THUMB_SIZE_NORMAL;				}			if (sw > cache_w || sh > cache_h || shrunk)				{				gint thumb_w, thumb_h;				if (thumb_loader_std_scale_aspect(cache_w, cache_h, sw, sh,								  &thumb_w, &thumb_h))					{					pixbuf_thumb = gdk_pixbuf_scale_simple(pixbuf, thumb_w, thumb_h,									       (GdkInterpType)thumbnail_quality);					}				else					{					pixbuf_thumb = pixbuf;					g_object_ref(G_OBJECT(pixbuf_thumb));					}				thumb_loader_std_save(tl, pixbuf_thumb);				}			}		else if (tl->cache_hit &&			 tl->cache_local && !tl->thumb_path_local)			{			/* A local cache save was requested, but a valid thumb is in $HOME,			 * so specifically save as a local thumbnail.			 */			g_free(tl->thumb_path);			tl->thumb_path = NULL;			tl->cache_hit = FALSE;			if (debug) printf("thumb copied: %s\n", tl->source_path);			thumb_loader_std_save(tl, pixbuf);			}		}	if (sw <= tl->requested_width && sh <= tl->requested_height)		{		result = pixbuf;		g_object_ref(result);		}	else		{		gint thumb_w, thumb_h;		if (pixbuf_thumb)			{			pixbuf = pixbuf_thumb;			sw = gdk_pixbuf_get_width(pixbuf);			sh = gdk_pixbuf_get_height(pixbuf);			}		if (thumb_loader_std_scale_aspect(tl->requested_width, tl->requested_height, sw, sh,						  &thumb_w, &thumb_h))			{			result = gdk_pixbuf_scale_simple(pixbuf, thumb_w, thumb_h,							 (GdkInterpType)thumbnail_quality);			}		else			{			result = pixbuf;			g_object_ref(result);			}		}	if (pixbuf_thumb) g_object_unref(pixbuf_thumb);	return result;}static gint thumb_loader_std_next_source(ThumbLoaderStd *tl, gint remove_broken){	image_loader_free(tl->il);	tl->il = NULL;	if (tl->thumb_path)		{		if (!tl->thumb_path_local && remove_broken)			{			if (debug) printf("thumb broken, unlinking: %s\n", tl->thumb_path);			unlink_file(tl->thumb_path);			}		g_free(tl->thumb_path);		tl->thumb_path = NULL;		if (!tl->thumb_path_local)			{			tl->thumb_path = thumb_loader_std_cache_path(tl, TRUE, NULL, FALSE);			if (isfile(tl->thumb_path) && thumb_loader_std_setup(tl, tl->thumb_path))				{				tl->thumb_path_local = TRUE;				return TRUE;				}			g_free(tl->thumb_path);			tl->thumb_path = NULL;			}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -