可以参考下列网站:
http://jens.triq.net/thumbnail-spec/
http://gezeiten.org/post/2009/10/Using-Tumbler-in-Client-Applications
http://live.gnome.org/ThumbnailerSpec
http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
在~/.thumbnails/下会生成对应的缩略图,浏览器通过调用这里面的缩略图实现预览。
比如要预览图片: file:///home/jens/photos/me.png
会先生成预览文件: /home/jens/.thumbnails/normal/c6ee772d9e49320e97ec29a7eb5b1697.png
这里的“c6ee772d9e49320e97ec29a7eb5b1697“ 就是源图片URI的16进制表示。
当文件显示的时候,Thunar会去搜索$HOME/.thumbnails/中文件夹,查看是否有对应的缩略图,如果有的话,就将其作为文件的图标显示出来。
上面一系列的都实际是图标的显示过程,那么,怎么从图片或者文档中获得缩略图写到$HOME/.thumbnails/中去呢?
具体的方式,我也不太了解。
但是,通过查找发现,对于一般的PNG,PDF的文件可以通过convert和evince-thumbnailer来生成,这些都是各种外部程序附带的功能。那么,Thunar本身似乎不太可能也对每种文件类型都去写一个生成缩略图的类。最有可能的是将大部分的文件类型和转换命令关联起来,具体的转换工作交给外部程序去作。
于是乎,在SOURCE中发现下面的文件:
./docs/ThumbnailersCacheFormat.txt
下面是原话:
The Thumbnailers Cache Format
=============================
Date: 2006-08-08
Author: Benedikt Meurer
Revision: $Rev: 22685 $
Motivation
----------
In order to avoid a dependency of libthunar-vfs-1.so on GConf and in order to
stay flexible wrt thumbnailers w/o adding more overhead to libthunar-vfs-1.so
(and thereby to all applications using the library), the available thumbnailers
for the ThunarVfsThumbFactory are determined by a separate utility program,
named thunar-vfs-update-thumbnailers-cache-1, which is installed to the
$(libexecdir).
This program generates a thumbnailers.cache file in the users home directory,
in $XDG_CACHE_HOME/Thunar/ (usually ~/.cache/Thunar/), which is a binary file
that lists all mime types for a thumbnailer is available. For each thumbnailer
the command required to run it is specified, where the command can contain
various special parameters that are substituted when the command is run.
This thumbnailers.cache is generated initially when the thumbnail factory is
loaded and no cache file is present, and afterwards the utility is run every
5 minutes to check if new thumbnailers are available (or existing thumbnailers
have been removed).
Special Thumbnailer Parameters
------------------------------
The following special parameters are supported in thumbnailer commands and
will be substituted when ThunarVfsThumbFactory runs the command:
%u The URL of the input file for which to create a thumbnail.
%i The absolute path to the input file.
%o The absolute path to the output file where to save the generated
thumbnail to (as PNG image).
%s The desired size of the thumbnail in pixel (usually 128 or 256).
%% Will be substituted with a single '%'.
The thunar-vfs-update-thumbnailers-cache-1 Utility
--------------------------------------------------
When compiled with support for GConf, the utility will first query all available
thumbnailers that have been registered with GConf. Otherwise, the utility checks
for several well-known thumbnailers (i.e. evince-thumbnailer, ...) and adds them
if the programs were found on the system.
Afterwards the available gdk-pixbuf formats will be queried and for each of the
returned mime types, the thunar-vfs-pixbuf-thumbnailer-1 will be registered. If
any such mime type was already registered by a thumbnailer queried from the
GConf database, the pixbuf thumbnailer will overwrite the previously registered
one.
The last step is to add all internal thumbnails (again overwriting previously
registered thumbnailers).
The thumbnailers.cache File Format
----------------------------------
The thumbnailers.cache file is a binary file, that maps mime types to thumbnai-
ler commands. The file format is designed to be mmap()ed into processes using
the thumbnailers.cache. All numbers are 32bit integers in big endian. All
strings are zero-terminated ASCII strings.
The current version of the file format is 1.0. Newer versions will either be
backward compatible with the current format or use a new file name.
The file starts with a header that contains the file format version, the number
of mime types stored in the file and the offset of the thumbnailers table:
Bits Meaning
---- -------
32 FORMAT MAJOR VERSION (currently 1)
32 FORMAT MINOR VERSION (currently 0)
32 NUMER OF MIME TYPES (and thereby NUMBER OF THUMBNAILERS)
32 OFFSET OF THE THUMBNAILERS TABLE
Next comes the table of mime types, where each entry contains the length of the
mime type in bytes (excluding the trailing zero) and the offset (relative to the
cache file start) where the name of the mime type is stored. The mime types are
sorted by strlen() and strcmp(), which means that binary search can be used to
find a mime type, trying the length first (so string comparisons are reduced to
a minimum to make the search cache-friendly) and performing a string comparison
when the lengths are equal (see thunar_vfs_thumb_factory_cache_lookup() for an
example implementation of the search).
Bits Meaning
---- -------
32 LENGTH OF MIME TYPE STRING
32 OFFSET OF MIME TYPE STRING
Once you successfully detected a mime type, you can use the index of the mime
type in the table above to locate the thumbnailer command for this mime type.
Therefore determine the OFFSET OF THE THUMBNAILERS TABLE (at offset 12 in the
cache) and look at that offset plus the index * 4 for the offset of the thumb-
nailer command string.
Bits Meaning
---- -------
32 OFFSET OF THUMBNAILER STRING
Afterwards substitute the special parameters as mentioned in "Special Thumbnai-
ler Parameters" above.
对应在代码./thunar-vfs/thunar-vfs-thumb.c中有:
/* 参考./thunar-vfs/thunar-vfs-mime-cache.c */ #define CACHE_READ32(cache, offset) (GUINT32_FROM_BE (*((guint32 *) ((cache) + (offset))))) static gboolean thunar_vfs_thumb_factory_cache_lookup (ThunarVfsThumbFactory *factory, const gchar *mime_type, gint mime_type_len, gchar **script_return) { const gchar *cache; gint max; gint mid; gint min; gint n; _thunar_vfs_return_val_if_fail (THUNAR_VFS_IS_THUMB_FACTORY (factory), FALSE); _thunar_vfs_return_val_if_fail (mime_type_len > 0, FALSE); _thunar_vfs_return_val_if_fail (mime_type != NULL, FALSE); /* acquire the cache lock */ g_mutex_lock (factory->cache_lock); /* 从thumbnailers.cach中获得传入文件类型对应的通用转换命令 */ /* binary search on the mime types */ for (cache = factory->cache, max = ((gint) CACHE_READ32 (cache, 8)) - 1, min = 0; max >= min; ) { mid = (min + max) / 2; /* compare the string length */ n = (gint) (CACHE_READ32 (cache, 16 + 8 * mid)) - mime_type_len; if (G_UNLIKELY (n == 0)) { /* compare the strings themselves */ n = strcmp (cache + CACHE_READ32 (cache, 16 + 8 * mid + 4), mime_type); } /* where to search next */ if (n < 0) min = mid + 1; else if (n > 0) max = mid - 1; else { /* check if we should return the script */ if (G_UNLIKELY (script_return != NULL)) *script_return = g_strdup (cache + CACHE_READ32 (cache + CACHE_READ32 (cache, 12) + mid * 4, 0)); /* we found it */ break; } } /* release the cache lock */ g_mutex_unlock (factory->cache_lock); return (max >= min); }
/* 分析得到的通用转换命令,确定文件路径和大小 */ static gchar* thumbnailer_script_expand (const gchar *script, const gchar *ipath, const gchar *opath, gint size) { const gchar *p; GString *s; gchar *quoted; gchar *uri; s = g_string_new (NULL); for (p = script; *p != '\0'; ++p) { if (G_LIKELY (*p != '%')) { g_string_append_c (s, *p); continue; } switch (*++p) { case 'u': uri = g_filename_to_uri (ipath, NULL, NULL); if (G_LIKELY (uri != NULL)) { quoted = g_shell_quote (uri); g_string_append (s, quoted); g_free (quoted); g_free (uri); } break; case 'i': quoted = g_shell_quote (ipath); g_string_append (s, quoted); g_free (quoted); break; case 's': g_string_append_printf (s, "%d", size); break; case '%': g_string_append_c (s, '%'); break; case '\0': --p; break; default: break; } } return g_string_free (s, FALSE); }
/** * thunar_vfs_thumb_factory_generate_thumbnail: * @factory : a #ThunarVfsThumbFactory. * @info : the #ThunarVfsInfo of the file for which a thumbnail * should be generated. * * Tries to generate a thumbnail for the file referred to by @info in * @factory. * * The caller is responsible to free the returned #GdkPixbuf using * g_object_unref() when no longer needed. * * The usage of this method is thread-safe. * * Return value: the thumbnail for the @uri or %NULL. **/ GdkPixbuf* thunar_vfs_thumb_factory_generate_thumbnail (ThunarVfsThumbFactory *factory, const ThunarVfsInfo *info) { ... /* otherwise check if we have a thumbnailer script in the cache */ if (pixbuf == NULL && thunar_vfs_thumb_factory_cache_lookup (factory, name, name_len, &script)) { /* create a temporary file for the thumbnailer */ fd = g_file_open_tmp (".thunar-vfs-thumbnail.XXXXXX", &tmp_path, NULL); if (G_LIKELY (fd >= 0)) { /* determine the command for the script */ command = thumbnailer_script_expand (script, path, tmp_path, size); /* 执行转换,在$HOME/.thumbnail/下生成缩略图 */ /* run the thumbnailer script and load the generated file */ if (g_spawn_command_line_sync (command, NULL, NULL, &status, NULL) && WIFEXITED (status) && WEXITSTATUS (status) == 0) { pixbuf = gdk_pixbuf_new_from_file (tmp_path, NULL); } /* unlink the temporary file */ g_unlink (tmp_path); /* cleanup */ g_free (tmp_path); g_free (command); close (fd); } /* cleanup */ g_free (script); } /* check if we need to scale the image */ if (pixbuf != NULL && (gdk_pixbuf_get_width (pixbuf) > size || gdk_pixbuf_get_height (pixbuf) > size)) { scaled = exo_gdk_pixbuf_scale_ratio (pixbuf, size); g_object_unref (G_OBJECT (pixbuf)); pixbuf = scaled; } done: /* cleanup */ g_free (path); return pixbuf; }