comparison src/thumb.c @ 1:b3e0e515fabf

Initial revision
author gqview
date Mon, 03 Apr 2000 18:24:05 +0000
parents
children c0e337a01cb7
comparison
equal deleted inserted replaced
0:513c7c01b50c 1:b3e0e515fabf
1 /*
2 * GQview image viewer
3 * (C)1999 John Ellis
4 *
5 * Author: John Ellis
6 *
7 */
8
9 #include "gqview.h"
10 #include "icons/img_unknown.xpm" /* fixme! duplicate, included in image.c too */
11
12 #define THUMBNAIL_CACHE_DIR "/.gqview_thmb"
13
14 static guchar *load_xv_thumbnail(gchar *filename, gint *widthp, gint *heightp);
15 static void normalize_thumb(gint *width, gint *height);
16 static gint get_xv_thumbnail(gchar *thumb_filename, GdkPixmap **thumb_pixmap, GdkBitmap **thumb_mask);
17
18 /*
19 *-----------------------------------------------------------------------------
20 * thumbnail routines: creation, caching, and maintenance (public)
21 *-----------------------------------------------------------------------------
22 */
23
24 gint create_thumbnail(gchar *path, GdkPixmap **thumb_pixmap, GdkBitmap **thumb_mask)
25 {
26 gint width, height;
27 gint space;
28 GdkImlibImage *thumb = NULL;
29 GdkImlibImage *image = NULL;
30 gint cached = FALSE;
31
32 if (debug) printf("Gen thumbnail:%s\n",path);
33
34 /* if xvpics enabled, check for that first */
35 if (use_xvpics_thumbnails)
36 {
37 space = get_xv_thumbnail(path, thumb_pixmap, thumb_mask);
38 if (space != -1)
39 {
40 if (debug) printf("XV thumbnail found, loaded\n");
41 return space;
42 }
43 }
44
45 /* start load from cache */
46
47 if (enable_thumb_caching)
48 {
49 gchar *cache_path;
50 cache_path = g_strconcat(homedir(), THUMBNAIL_CACHE_DIR, path, ".png", NULL);
51
52 if (isfile(cache_path) && filetime(cache_path) >= filetime(path))
53 {
54 if (debug) printf("Found in cache:%s\n", path);
55 image = gdk_imlib_load_image(cache_path);
56 if (image && image->rgb_width != thumb_max_width && image->rgb_height != thumb_max_height)
57 {
58 if (debug) printf("Thumbnail size may have changed, reloading:%s\n", path);
59 unlink(cache_path);
60 gdk_imlib_destroy_image(image);
61 image = gdk_imlib_load_image(path);
62 }
63 else
64 {
65 cached = TRUE;
66 }
67 }
68 else
69 image = gdk_imlib_load_image(path);
70
71 }
72 else
73 image = gdk_imlib_load_image(path);
74
75 if (!image)
76 {
77 image = gdk_imlib_create_image_from_xpm_data((gchar **)img_unknown_xpm);
78 cached = TRUE; /* no need to save a thumbnail of the unknown pixmap */
79 }
80
81 if (image)
82 {
83 if (image->rgb_width > thumb_max_width || image->rgb_height > thumb_max_height)
84 {
85 if (((float)thumb_max_width / image->rgb_width) < ((float)thumb_max_height / image->rgb_height))
86 {
87 width = thumb_max_width;
88 height = (float)width / image->rgb_width * image->rgb_height;
89 if (height < 1) height = 1;
90 }
91 else
92 {
93 height = thumb_max_height;
94 width = (float)height / image->rgb_height * image->rgb_width;
95 if (width < 1) width = 1;
96 }
97 }
98 else
99 {
100 width = image->rgb_width;
101 height = image->rgb_height;
102 cached = TRUE; /* don't cache images smaller than thumbnail size */
103 }
104 if (*thumb_pixmap) gdk_imlib_free_pixmap(*thumb_pixmap);
105 *thumb_pixmap = NULL;
106 *thumb_mask = NULL;
107
108 /* start save cache */
109
110 if (enable_thumb_caching && !cached)
111 {
112 gchar *thumb_path;
113 gchar *base_dir;
114 gchar *thumb_dir;
115 gchar *image_dir;
116
117 /* attempt at speed-up? move this here */
118 thumb = gdk_imlib_clone_scaled_image(image, width, height);
119 gdk_imlib_destroy_image(image);
120 image = NULL;
121
122 base_dir = g_strconcat(homedir(), THUMBNAIL_CACHE_DIR, NULL);
123 if (!isdir(base_dir))
124 {
125 if (debug) printf("creating thumbnail dir:%s\n", base_dir);
126 if (mkdir(base_dir, 0755) < 0)
127 printf(_("create dir failed: %s\n"), base_dir);
128 }
129
130 image_dir = remove_level_from_path(path);
131 thumb_dir = g_strconcat(base_dir, image_dir, NULL);
132 g_free(image_dir);
133 if (!isdir(thumb_dir))
134 {
135 gchar *p = thumb_dir;
136 while (p[0] != '\0')
137 {
138 p++;
139 if (p[0] == '/' || p[0] == '\0')
140 {
141 gint end = TRUE;
142 if (p[0] != '\0')
143 {
144 p[0] = '\0';
145 end = FALSE;
146 }
147 if (!isdir(thumb_dir))
148 {
149 if (debug) printf("creating sub dir:%s\n",thumb_dir);
150 if (mkdir(thumb_dir, 0755) < 0)
151 printf(_("create dir failed: %s\n"), thumb_dir);
152 }
153 if (!end) p[0] = '/';
154 }
155 }
156 }
157 g_free(thumb_dir);
158
159 thumb_path = g_strconcat(base_dir, path, ".png", NULL);
160 if (debug) printf("Saving thumb: %s\n",thumb_path);
161
162 gdk_imlib_save_image(thumb, thumb_path, NULL);
163
164 g_free(base_dir);
165 g_free(thumb_path);
166 }
167 else
168 {
169 thumb = image;
170 }
171
172 /* end save cache */
173
174 gdk_imlib_render(thumb, width, height);
175 *thumb_pixmap = gdk_imlib_move_image(thumb);
176 *thumb_mask = gdk_imlib_move_mask(thumb);
177 if (*thumb_pixmap)
178 space = thumb_max_width - width;
179 gdk_imlib_destroy_image(thumb);
180 thumb = NULL;
181 }
182 else
183 {
184 space = -1;
185 }
186 return space;
187 }
188
189 gint maintain_thumbnail_dir(gchar *dir, gint recursive)
190 {
191 gchar *thumb_dir;
192 gint base_length;
193 gint still_have_a_file = FALSE;
194
195 if (debug) printf("maintainance check: %s\n", dir);
196
197 base_length = strlen(homedir()) + strlen(THUMBNAIL_CACHE_DIR);
198 thumb_dir = g_strconcat(homedir(), THUMBNAIL_CACHE_DIR, dir, NULL);
199
200 if (isdir(thumb_dir))
201 {
202 DIR *dp;
203 struct dirent *dirent;
204 struct stat ent_sbuf;
205
206 if((dp = opendir(thumb_dir))==NULL)
207 {
208 /* dir not found */
209 g_free(thumb_dir);
210 return FALSE;
211 }
212
213 while ((dirent = readdir(dp)) != NULL)
214 {
215 /* skips removed files */
216 if (dirent->d_ino > 0)
217 {
218 int l = 0;
219 gchar *path_buf;
220 if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
221 continue;
222 path_buf = g_strconcat(thumb_dir, "/", dirent->d_name, NULL);
223 if (strlen(path_buf) > 4) l = strlen(path_buf) - 4;
224
225 if (stat(path_buf,&ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode))
226 {
227 /* recurse dir then delete it */
228 gchar *rdir = g_strconcat(dir, "/", dirent->d_name, NULL);
229 if (recursive && !maintain_thumbnail_dir(rdir, TRUE))
230 {
231 if (debug) printf("Deleting thumb dir: %s\n",path_buf);
232 if ( (rmdir (path_buf) < 0) )
233 printf(_("Unable to delete dir: %s\n"), path_buf);
234 }
235 else
236 still_have_a_file = TRUE;
237 g_free(rdir);
238 }
239 else
240 {
241 gchar *fp = path_buf + l;
242 fp[0] = '\0';
243 if (strlen(path_buf) > base_length &&
244 !isfile(path_buf + base_length))
245 {
246 fp[0] = '.';
247 if (debug) printf("Deleting thumb: %s\n",path_buf);
248 if ( (unlink (path_buf) < 0) )
249 printf(_("failed to delete:%s\n"),path_buf);
250 }
251 else
252 still_have_a_file = TRUE;
253 }
254 g_free(path_buf);
255 }
256 }
257 closedir(dp);
258 }
259 g_free(thumb_dir);
260 return still_have_a_file;
261 }
262
263 /*
264 *-----------------------------------------------------------------------------
265 * xvpics thumbnail support, read-only (private)
266 *-----------------------------------------------------------------------------
267 */
268
269 /*
270 * xvpics code originally supplied by:
271 * "Diederen Damien" <D.Diederen@student.ulg.ac.be>
272 *
273 * Note: Code has been modified to fit the style of the other code, and to use
274 * a few more glib-isms.
275 */
276
277 #define XV_BUFFER 2048
278 static guchar *load_xv_thumbnail(gchar *filename, gint *widthp, gint *heightp)
279 {
280 FILE *file;
281 gchar buffer[XV_BUFFER];
282 guchar *data;
283 gint width, height, depth;
284
285 file = fopen(filename, "rt");
286 if(!file) return NULL;
287
288 fgets(buffer, XV_BUFFER, file);
289 if(strncmp(buffer, "P7 332", 6) != 0)
290 {
291 fclose(file);
292 return NULL;
293 }
294
295 while(fgets(buffer, XV_BUFFER, file) && buffer[0] == '#') /* do_nothing() */;
296
297 if(sscanf(buffer, "%d %d %d", &width, &height, &depth) != 3)
298 {
299 fclose(file);
300 return NULL;
301 }
302
303 data = g_new(guchar, width * height);
304 fread(data, 1, width * height, file);
305
306 fclose(file);
307 *widthp = width;
308 *heightp = height;
309 return data;
310 }
311 #undef XV_BUFFER
312
313 static void normalize_thumb(gint *width, gint *height)
314 {
315 if(*width > thumb_max_width || *height > thumb_max_height)
316 {
317 gfloat factor = MAX((gfloat) *width / thumb_max_width, (gfloat) *height / thumb_max_height);
318 *width = (gfloat) *width / factor;
319 *height = (gfloat) *height / factor;
320 }
321 }
322
323 static gint get_xv_thumbnail(gchar *thumb_filename, GdkPixmap **thumb_pixmap, GdkBitmap **thumb_mask)
324 {
325 gint width, height;
326 gchar *thumb_name;
327 gchar *tmp_string;
328 gchar *last_slash;
329 guchar *packed_data;
330
331 tmp_string = g_strdup(thumb_filename);
332 last_slash = strrchr(tmp_string, '/');
333 if(!last_slash) return -1;
334 *last_slash++ = '\0';
335
336 thumb_name = g_strconcat(tmp_string, "/.xvpics/", last_slash, NULL);
337 packed_data = load_xv_thumbnail(thumb_name, &width, &height);
338 g_free(tmp_string);
339 g_free(thumb_name);
340
341 if(packed_data)
342 {
343 guchar *rgb_data;
344 GdkImlibImage *image;
345 gint i;
346
347 rgb_data = g_new(guchar, width * height * 3);
348 for(i = 0; i < width * height; i++)
349 {
350 rgb_data[i * 3 + 0] = (packed_data[i] >> 5) * 36;
351 rgb_data[i * 3 + 1] = ((packed_data[i] & 28) >> 2) * 36;
352 rgb_data[i * 3 + 2] = (packed_data[i] & 3) * 85;
353 }
354
355 g_free(packed_data);
356 image = gdk_imlib_create_image_from_data(rgb_data, NULL, width, height);
357 g_free(rgb_data);
358 normalize_thumb(&width, &height);
359 gdk_imlib_render(image, width, height);
360
361 if(*thumb_pixmap) gdk_imlib_free_pixmap(*thumb_pixmap);
362
363 *thumb_pixmap = gdk_imlib_move_image(image);
364 *thumb_mask = gdk_imlib_move_mask(image);
365 gdk_imlib_destroy_image(image);
366 return thumb_max_width - width;
367 }
368
369 return -1;
370 }
371