Mercurial > geeqie
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 |