2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * Large (and important) sections of this file were adapted from
24 * ROX-Filer source code, Copyright (C) 2003, the ROX-Filer team,
25 * originally licensed under the GPL v2 or greater (as above).
40 #include <glib/gstdio.h>
42 #include "thumbnails.h"
43 #include "icons/icons.h"
47 #ifdef __CYGWIN_USE_BIG_TYPES__
48 #define ST_SIZE_FMT "%lld"
50 #define ST_SIZE_FMT "%ld"
53 /* FIXME -- on some systems this may need to me "lld", see ROX-Filer code */
54 #define ST_SIZE_FMT "%ld"
57 #undef MIN /* quit yer whining, gcc */
60 /* We need MAX macro and some system does not offer it */
61 #define MAX(a,b) (((a)>(b))?(a):(b))
64 #define HOME_DIR g_get_home_dir()
67 #define THUMB_DIR "\\THUMBNAILS\\" /* viking maps default viking\maps */
68 #define THUMB_SUB_DIR "normal\\"
70 #define THUMB_DIR "/.thumbnails/"
71 #define THUMB_SUB_DIR "normal/"
74 #define PIXMAP_THUMB_SIZE 128
76 static GdkPixbuf *save_thumbnail(const char *pathname, GdkPixbuf *full);
77 static GdkPixbuf *child_create_thumbnail(const gchar *path);
79 gboolean a_thumbnails_exists ( const gchar *filename )
81 GdkPixbuf *pixbuf = a_thumbnails_get(filename);
84 g_object_unref ( G_OBJECT ( pixbuf ) );
90 GdkPixbuf *a_thumbnails_get_default ()
92 return gdk_pixbuf_from_pixdata ( &thumbnails_pixbuf, FALSE, NULL );
95 /* filename must be absolute. you could have a function to make sure it exists and absolutize it */
97 void a_thumbnails_create(const gchar *filename)
99 GdkPixbuf *pixbuf = a_thumbnails_get(filename);
102 pixbuf = child_create_thumbnail(filename);
105 g_object_unref ( G_OBJECT ( pixbuf ) );
108 GdkPixbuf *a_thumbnails_scale_pixbuf(GdkPixbuf *src, int max_w, int max_h)
112 w = gdk_pixbuf_get_width(src);
113 h = gdk_pixbuf_get_height(src);
115 if (w <= max_w && h <= max_h)
117 g_object_ref ( G_OBJECT ( src ) );
122 float scale_x = ((float) w) / max_w;
123 float scale_y = ((float) h) / max_h;
124 float scale = MAX(scale_x, scale_y);
125 int dest_w = w / scale;
126 int dest_h = h / scale;
128 return gdk_pixbuf_scale_simple(src,
131 GDK_INTERP_BILINEAR);
135 static GdkPixbuf *child_create_thumbnail(const gchar *path)
137 GdkPixbuf *image, *tmpbuf;
139 image = gdk_pixbuf_new_from_file(path, NULL);
143 tmpbuf = gdk_pixbuf_apply_embedded_orientation(image);
144 g_object_unref(G_OBJECT(image));
149 GdkPixbuf *thumb = save_thumbnail(path, image);
150 g_object_unref ( G_OBJECT ( image ) );
157 static GdkPixbuf *save_thumbnail(const char *pathname, GdkPixbuf *full)
161 int original_width, original_height;
162 const gchar* orientation;
164 char *md5, *swidth, *sheight, *ssize, *smtime, *uri;
169 if (stat(pathname, &info) != 0)
172 thumb = a_thumbnails_scale_pixbuf(full, PIXMAP_THUMB_SIZE, PIXMAP_THUMB_SIZE);
174 orientation = gdk_pixbuf_get_option (full, "orientation");
176 original_width = gdk_pixbuf_get_width(full);
177 original_height = gdk_pixbuf_get_height(full);
180 swidth = g_strdup_printf("%d", original_width);
181 sheight = g_strdup_printf("%d", original_height);
182 ssize = g_strdup_printf(ST_SIZE_FMT, info.st_size);
183 smtime = g_strdup_printf("%ld", (long) info.st_mtime);
185 path = file_realpath_dup(pathname);
186 uri = g_strconcat("file://", path, NULL);
190 to = g_string_new(HOME_DIR);
191 g_string_append(to, THUMB_DIR);
192 g_string_append(to, THUMB_SUB_DIR);
193 if ( g_mkdir_with_parents(to->str, 0700) != 0 )
194 g_warning ("%s: Failed to mkdir %s", __FUNCTION__, to->str );
195 g_string_append(to, md5);
196 name_len = to->len + 4; /* Truncate to this length when renaming */
198 g_string_append_printf(to, ".png.Viking");
200 g_string_append_printf(to, ".png.Viking-%ld", (long) getpid());
205 // Thumb::URI must be in ISO-8859-1 encoding otherwise gdk_pixbuf_save() will fail
206 // - e.g. if characters such as 'ě' are encountered
207 // Also see http://en.wikipedia.org/wiki/ISO/IEC_8859-1
208 // ATM GLIB Manual doesn't specify in which version this function became available
209 // find out that it's fairly recent so may break builds without this test
210 #if GLIB_CHECK_VERSION(2,40,0)
211 char *thumb_uri = g_str_to_ascii ( uri, NULL );
213 char *thumb_uri = g_strdup ( uri );
215 old_mask = umask(0077);
216 GError *error = NULL;
217 gdk_pixbuf_save(thumb, to->str, "png", &error,
218 "tEXt::Thumb::Image::Width", swidth,
219 "tEXt::Thumb::Image::Height", sheight,
220 "tEXt::Thumb::Size", ssize,
221 "tEXt::Thumb::MTime", smtime,
222 "tEXt::Thumb::URI", thumb_uri,
223 "tEXt::Software", PROJECT,
224 "tEXt::Software::Orientation", orientation ? orientation : "0",
230 g_warning ( "%s::%s", __FUNCTION__, error->message );
231 g_error_free ( error );
232 g_object_unref ( G_OBJECT(thumb) );
233 thumb = NULL; /* return NULL */
236 /* We create the file ###.png.Viking-PID and rename it to avoid
237 * a race condition if two programs create the same thumb at
243 final = g_strndup(to->str, name_len);
244 if (rename(to->str, final))
246 g_warning("Failed to rename '%s' to '%s': %s",
247 to->str, final, g_strerror(errno));
248 g_object_unref ( G_OBJECT(thumb) );
249 thumb = NULL; /* return NULL */
255 g_string_free(to, TRUE);
266 GdkPixbuf *a_thumbnails_get(const gchar *pathname)
268 GdkPixbuf *thumb = NULL;
269 char *thumb_path, *md5, *uri, *path;
270 const char *ssize, *smtime;
273 path = file_realpath_dup(pathname);
274 uri = g_strconcat("file://", path, NULL);
278 thumb_path = g_strdup_printf("%s%s%s%s.png", HOME_DIR, THUMB_DIR, THUMB_SUB_DIR, md5);
282 thumb = gdk_pixbuf_new_from_file(thumb_path, NULL);
286 /* Note that these don't need freeing... */
287 ssize = gdk_pixbuf_get_option(thumb, "tEXt::Thumb::Size");
291 smtime = gdk_pixbuf_get_option(thumb, "tEXt::Thumb::MTime");
295 if (stat(path, &info) != 0)
298 if (info.st_mtime != atol(smtime) || info.st_size != atol(ssize))
304 g_object_unref ( G_OBJECT ( thumb ) );