📄 thumb_standard.c
字号:
if (thumb_loader_std_setup(tl, tl->source_path)) return TRUE; } thumb_loader_std_save(tl, NULL); return FALSE;}static void thumb_loader_std_done_cb(ImageLoader *il, gpointer data){ ThumbLoaderStd *tl = data; GdkPixbuf *pixbuf; if (debug) { printf("thumb image done: %s\n", tl->source_path); printf(" from: %s\n", tl->il->path); } pixbuf = image_loader_get_pixbuf(tl->il); if (!pixbuf) { if (debug) printf("...but no pixbuf\n"); thumb_loader_std_error_cb(il, data); return; } if (tl->thumb_path && !thumb_loader_std_validate(tl, pixbuf)) { if (thumb_loader_std_next_source(tl, TRUE)) return; if (tl->func_error) tl->func_error(tl, tl->data); return; } tl->cache_hit = (tl->thumb_path != NULL); tl->pixbuf = thumb_loader_std_finish(tl, pixbuf, il->shrunk); if (tl->func_done) tl->func_done(tl, tl->data);}static void thumb_loader_std_error_cb(ImageLoader *il, gpointer data){ ThumbLoaderStd *tl = data; /* if at least some of the image is available, go to done */ if (image_loader_get_pixbuf(tl->il) != NULL) { thumb_loader_std_done_cb(il, data); return; } if (debug) { printf("thumb image error: %s\n", tl->source_path); printf(" from: %s\n", tl->il->path); } if (thumb_loader_std_next_source(tl, TRUE)) return; if (tl->func_error) tl->func_error(tl, tl->data);}static void thumb_loader_std_progress_cb(ImageLoader *il, gdouble percent, gpointer data){ ThumbLoaderStd *tl = data; tl->progress = (gdouble)percent; if (tl->func_progress) tl->func_progress(tl, tl->data);}static gint thumb_loader_std_setup(ThumbLoaderStd *tl, const gchar *path){ tl->il = image_loader_new(path); if (thumbnail_fast) { /* this will speed up jpegs by up to 3x in some cases */ if (tl->requested_width <= THUMB_SIZE_NORMAL && tl->requested_height <= THUMB_SIZE_NORMAL) { image_loader_set_requested_size(tl->il, THUMB_SIZE_NORMAL, THUMB_SIZE_NORMAL); } else { image_loader_set_requested_size(tl->il, THUMB_SIZE_LARGE, THUMB_SIZE_LARGE); } } image_loader_set_error_func(tl->il, thumb_loader_std_error_cb, tl); if (tl->func_progress) { image_loader_set_percent_func(tl->il, thumb_loader_std_progress_cb, tl); } if (image_loader_start(tl->il, thumb_loader_std_done_cb, tl)) { return TRUE; } image_loader_free(tl->il); tl->il = NULL; return FALSE;}/* * Note: Currently local_cache only specifies where to save a _new_ thumb, if * a valid existing thumb is found anywhere the local thumb will not be created. */void thumb_loader_std_set_cache(ThumbLoaderStd *tl, gint enable_cache, gint local, gint retry_failed){ if (!tl) return; tl->cache_enable = enable_cache; tl->cache_local = local; tl->cache_retry = retry_failed;}gint thumb_loader_std_start(ThumbLoaderStd *tl, const gchar *path){ static gchar *thumb_cache = NULL; struct stat st; if (!tl || !path) return FALSE; thumb_loader_std_reset(tl); if (!stat_utf8(path, &st)) return FALSE; tl->source_path = g_strdup(path); tl->source_mtime = st.st_mtime; tl->source_size = st.st_size; tl->source_mode = st.st_mode; if (!thumb_cache) thumb_cache = g_strconcat(homedir(), "/", THUMB_FOLDER, NULL); if (strncmp(tl->source_path, thumb_cache, strlen(thumb_cache)) != 0) { gchar *pathl; pathl = path_from_utf8(path); tl->thumb_uri = g_filename_to_uri(pathl, NULL, NULL); tl->local_uri = filename_from_path(tl->thumb_uri); g_free(pathl); } if (tl->cache_enable) { gint found; tl->thumb_path = thumb_loader_std_cache_path(tl, FALSE, NULL, FALSE); tl->thumb_path_local = FALSE; found = isfile(tl->thumb_path); if (found && thumb_loader_std_setup(tl, tl->thumb_path)) return TRUE; if (thumb_loader_std_fail_check(tl)) return FALSE; return thumb_loader_std_next_source(tl, found); } if (!thumb_loader_std_setup(tl, tl->source_path)) { thumb_loader_std_save(tl, NULL); return FALSE; } return TRUE;}void thumb_loader_std_free(ThumbLoaderStd *tl){ if (!tl) return; thumb_loader_std_reset(tl); g_free(tl);}GdkPixbuf *thumb_loader_std_get_pixbuf(ThumbLoaderStd *tl, gint with_fallback){ GdkPixbuf *pixbuf; if (tl && tl->pixbuf) { pixbuf = tl->pixbuf; g_object_ref(pixbuf); } else if (with_fallback) { gint w, h; pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN); w = gdk_pixbuf_get_width(pixbuf); h = gdk_pixbuf_get_height(pixbuf); if (w > tl->requested_width || h > tl->requested_height) { gint nw, nh; if (thumb_loader_std_scale_aspect(tl->requested_width, tl->requested_height, w, h, &nw, &nh)) { GdkPixbuf *tmp; tmp = pixbuf; pixbuf = gdk_pixbuf_scale_simple(tmp, nw, nh, GDK_INTERP_TILES); g_object_unref(G_OBJECT(tmp)); } } } else { pixbuf = NULL; } return pixbuf;}typedef struct _ThumbValidate ThumbValidate;struct _ThumbValidate{ ThumbLoaderStd *tl; gchar *path; gint days; void (*func_valid)(const gchar *path, gint valid, gpointer data); gpointer data; gint idle_id;};static void thumb_loader_std_thumb_file_validate_free(ThumbValidate *tv){ thumb_loader_std_free(tv->tl); g_free(tv->path); g_free(tv);}void thumb_loader_std_thumb_file_validate_cancel(ThumbLoaderStd *tl){ ThumbValidate *tv; if (!tl) return; tv = tl->data; if (tv->idle_id != -1) g_source_remove(tv->idle_id); tv->idle_id = -1; thumb_loader_std_thumb_file_validate_free(tv);}static void thumb_loader_std_thumb_file_validate_finish(ThumbValidate *tv, gint valid){ if (tv->func_valid) tv->func_valid(tv->path, valid, tv->data); thumb_loader_std_thumb_file_validate_free(tv);}static void thumb_loader_std_thumb_file_validate_done_cb(ThumbLoaderStd *tl, gpointer data){ ThumbValidate *tv = data; GdkPixbuf *pixbuf; gint valid = FALSE; pixbuf = thumb_loader_std_get_pixbuf(tv->tl, FALSE); if (pixbuf) { const gchar *uri; const gchar *mtime_str; uri = gdk_pixbuf_get_option(pixbuf, THUMB_MARKER_URI); mtime_str = gdk_pixbuf_get_option(pixbuf, THUMB_MARKER_MTIME); if (uri && mtime_str) { if (strncmp(uri, "file:", strlen("file:")) == 0) { struct stat st; gchar *target; target = g_filename_from_uri(uri, NULL, NULL); if (stat(target, &st) == 0 && st.st_mtime == strtol(mtime_str, NULL, 10)) { valid = TRUE; } g_free(target); } else { struct stat st; if (debug) printf("thumb uri foreign, doing day check: %s\n", uri); if (stat_utf8(tv->path, &st)) { time_t now; now = time(NULL); if (st.st_atime >= now - (time_t)tv->days * 24 * 60 * 60) { valid = TRUE; } } } } g_object_unref(pixbuf); } thumb_loader_std_thumb_file_validate_finish(tv, valid);}static void thumb_loader_std_thumb_file_validate_error_cb(ThumbLoaderStd *tl, gpointer data){ ThumbValidate *tv = data; thumb_loader_std_thumb_file_validate_finish(tv, FALSE);}static gint thumb_loader_std_thumb_file_validate_idle_cb(gpointer data){ ThumbValidate *tv = data; tv->idle_id = -1; thumb_loader_std_thumb_file_validate_finish(tv, FALSE); return FALSE;}ThumbLoaderStd *thumb_loader_std_thumb_file_validate(const gchar *thumb_path, gint allowed_days, void (*func_valid)(const gchar *path, gint valid, gpointer data), gpointer data){ ThumbValidate *tv; tv = g_new0(ThumbValidate, 1); tv->tl = thumb_loader_std_new(THUMB_SIZE_LARGE, THUMB_SIZE_LARGE); thumb_loader_std_set_callbacks(tv->tl, thumb_loader_std_thumb_file_validate_done_cb, thumb_loader_std_thumb_file_validate_error_cb, NULL, tv); thumb_loader_std_reset(tv->tl); tv->path = g_strdup(thumb_path); tv->days = allowed_days; tv->func_valid = func_valid; tv->data = data; if (!thumb_loader_std_setup(tv->tl, thumb_path)) { tv->idle_id = g_idle_add(thumb_loader_std_thumb_file_validate_idle_cb, tv); } else { tv->idle_id = -1; } return tv->tl;}static void thumb_std_maint_remove_one(const gchar *source, const gchar *uri, gint local, const gchar *subfolder){ gchar *thumb_path; thumb_path = thumb_std_cache_path(source, (local) ? filename_from_path(uri) : uri, local, subfolder); if (isfile(thumb_path)) { if (debug) printf("thumb removing: %s\n", thumb_path); unlink_file(thumb_path); } g_free(thumb_path);}/* this also removes local thumbnails (the source is gone so it makes sense) */void thumb_std_maint_removed(const gchar *source){ gchar *uri; gchar *sourcel; sourcel = path_from_utf8(source); uri = g_filename_to_uri(sourcel, NULL, NULL); g_free(sourcel); /* all this to remove a thumbnail? */ thumb_std_maint_remove_one(source, uri, FALSE, THUMB_FOLDER_NORMAL); thumb_std_maint_remove_one(source, uri, FALSE, THUMB_FOLDER_LARGE); thumb_std_maint_remove_one(source, uri, FALSE, THUMB_FOLDER_FAIL); thumb_std_maint_remove_one(source, uri, TRUE, THUMB_FOLDER_NORMAL); thumb_std_maint_remove_one(source, uri, TRUE, THUMB_FOLDER_LARGE); g_free(uri);}typedef struct _TMaintMove TMaintMove;struct _TMaintMove{ gchar *source; gchar *dest; ThumbLoaderStd *tl; gchar *source_uri; gchar *thumb_path; gint pass;};static GList *thumb_std_maint_move_list = NULL;static GList *thumb_std_maint_move_tail = NULL;static void thumb_std_maint_move_step(TMaintMove *tm);static gint thumb_std_maint_move_idle(gpointer data);static void thumb_std_maint_move_validate_cb(const gchar *path, gint valid, gpointer data){ TMaintMove *tm = data; GdkPixbuf *pixbuf; pixbuf = thumb_loader_std_get_pixbuf(tm->tl, FALSE); if (pixbuf) { const gchar *uri; const gchar *mtime_str; uri = gdk_pixbuf_get_option(pixbuf, THUMB_MARKER_URI); mtime_str = gdk_pixbuf_get_option(pixbuf, THUMB_MARKER_MTIME); if (uri && mtime_str && strcmp(uri, tm->source_uri) == 0) { gchar *pathl; /* The validation utility abuses ThumbLoader, and we * abuse the utility just to load the thumbnail, * but the loader needs to look sane for the save to complete. */ tm->tl->cache_enable = TRUE; tm->tl->cache_hit = FALSE; tm->tl->cache_local = FALSE; g_free(tm->tl->source_path); tm->tl->source_path = g_strdup(tm->dest); tm->tl->source_mtime = strtol(mtime_str, NULL, 10); pathl = path_from_utf8(tm->tl->source_path); g_free(tm->tl->thumb_uri); tm->tl->thumb_uri = g_filename_to_uri(pathl, NULL, NULL); tm->tl->local_uri = filename_from_path(tm->tl->thumb_uri); g_free(pathl); g_free(tm->tl->thumb_path); tm->tl->thumb_path = NULL; tm->tl->thumb_path_local = FALSE; if (debug) printf("thumb move attempting save:\n"); thumb_loader_std_save(tm->tl, pixbuf); } if (debug) printf("thumb move unlink: %s\n", tm->thumb_path); unlink_file(tm->thumb_path); } thumb_std_maint_move_step(tm);}static void thumb_std_maint_move_step(TMaintMove *tm){ const gchar *folder; tm->pass++; if (tm->pass > 2) { g_free(tm->source); g_free(tm->dest); g_free(tm->source_uri); g_free(tm->thumb_path); g_free(tm); if (thumb_std_maint_move_list) { g_idle_add_full(G_PRIORITY_LOW, thumb_std_maint_move_idle, NULL, NULL); } return; } folder = (tm->pass == 1) ? THUMB_FOLDER_NORMAL : THUMB_FOLDER_LARGE; g_free(tm->thumb_path); tm->thumb_path = thumb_std_cache_path(tm->source, tm->source_uri, FALSE, folder); tm->tl = thumb_loader_std_thumb_file_validate(tm->thumb_path, 0, thumb_std_maint_move_validate_cb, tm);}static gint thumb_std_maint_move_idle(gpointer data){ TMaintMove *tm; gchar *pathl; if (!thumb_std_maint_move_list) return FALSE; tm = thumb_std_maint_move_list->data; thumb_std_maint_move_list = g_list_remove(thumb_std_maint_move_list, tm); if (!thumb_std_maint_move_list) thumb_std_maint_move_tail = NULL; pathl = path_from_utf8(tm->source); tm->source_uri = g_filename_to_uri(pathl, NULL, NULL); g_free(pathl); tm->pass = 0; thumb_std_maint_move_step(tm); return FALSE;}/* This will schedule a move of the thumbnail for source image to dest when idle. * We do this so that file renaming or moving speed is not sacrificed by * moving the thumbnails at the same time because: * * This cache design requires the tedious task of loading the png thumbnails and saving them. * * The thumbnails are processed when the app is idle. If the app * exits early well too bad - they can simply be regenerated from scratch. * * This does not manage local thumbnails (fixme ?) */void thumb_std_maint_moved(const gchar *source, const gchar *dest){ TMaintMove *tm; tm = g_new0(TMaintMove, 1); tm->source = g_strdup(source); tm->dest = g_strdup(dest); if (!thumb_std_maint_move_list) { g_idle_add_full(G_PRIORITY_LOW, thumb_std_maint_move_idle, NULL, NULL); } if (thumb_std_maint_move_tail) { g_list_append(thumb_std_maint_move_tail, tm); thumb_std_maint_move_tail = thumb_std_maint_move_tail->next; } else { thumb_std_maint_move_list = g_list_append(thumb_std_maint_move_list, tm); thumb_std_maint_move_tail = thumb_std_maint_move_list; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -