| @@ -17,7 +17,6 @@ |
| 17 | 17 | | */ |
| 18 | 18 | | |
| 19 | 19 | | #define _POSIX_C_SOURCE 200112L |
| 20 | | − | #define _THUMBS_CONFIG |
| 21 | 20 | | |
| 22 | 21 | | #include <stdio.h> |
| 23 | 22 | | #include <stdlib.h> |
| @@ -37,7 +36,7 @@ void exif_auto_orientate(const fileinfo_t*); |
| 37 | 36 | | #endif |
| 38 | 37 | | |
| 39 | 38 | | static char *cache_dir; |
| 40 | | − | static const int thumb_dim = THUMB_SIZE + 10; |
| 39 | + | static const int thumb_size[] = { 32, 64, 96, 128, 160 }; |
| 41 | 40 | | |
| 42 | 41 | | char* tns_cache_filepath(const char *filepath) |
| 43 | 42 | | { |
| @@ -51,7 +50,7 @@ char* tns_cache_filepath(const char *filepath) |
| 51 | 50 | | /* don't cache images inside the cache directory! */ |
| 52 | 51 | | len = strlen(cache_dir) + strlen(filepath) + 6; |
| 53 | 52 | | cfile = (char*) s_malloc(len); |
| 54 | | − | snprintf(cfile, len, "%s/%s.png", cache_dir, filepath + 1); |
| 53 | + | snprintf(cfile, len, "%s/%s.jpg", cache_dir, filepath + 1); |
| 55 | 54 | | } |
| 56 | 55 | | return cfile; |
| 57 | 56 | | } |
| @@ -79,21 +78,19 @@ Imlib_Image tns_cache_load(const char *filepath, bool *outdated) |
| 79 | 78 | | return im; |
| 80 | 79 | | } |
| 81 | 80 | | |
| 82 | | − | void tns_cache_write(thumb_t *t, const fileinfo_t *file, bool force) |
| 81 | + | void tns_cache_write(Imlib_Image im, const char *filepath, bool force) |
| 83 | 82 | | { |
| 84 | 83 | | char *cfile, *dirend; |
| 85 | 84 | | struct stat cstats, fstats; |
| 86 | 85 | | struct utimbuf times; |
| 87 | 86 | | Imlib_Load_Error err = 0; |
| 88 | 87 | | |
| 89 | | − | if (t == NULL || t->im == NULL) |
| 88 | + | if (im == NULL || filepath == NULL) |
| 90 | 89 | | return; |
| 91 | | − | if (file == NULL || file->name == NULL || file->path == NULL) |
| 92 | | − | return; |
| 93 | | − | if (stat(file->path, &fstats) < 0) |
| 90 | + | if (stat(filepath, &fstats) < 0) |
| 94 | 91 | | return; |
| 95 | 92 | | |
| 96 | | − | if ((cfile = tns_cache_filepath(file->path)) != NULL) { |
| 93 | + | if ((cfile = tns_cache_filepath(filepath)) != NULL) { |
| 97 | 94 | | if (force || stat(cfile, &cstats) < 0 || |
| 98 | 95 | | cstats.st_mtime != fstats.st_mtime) |
| 99 | 96 | | { |
| @@ -103,8 +100,8 @@ void tns_cache_write(thumb_t *t, const fileinfo_t *file, bool force) |
| 103 | 100 | | *dirend = '/'; |
| 104 | 101 | | } |
| 105 | 102 | | if (err == 0) { |
| 106 | | − | imlib_context_set_image(t->im); |
| 107 | | − | imlib_image_set_format("png"); |
| 103 | + | imlib_context_set_image(im); |
| 104 | + | imlib_image_set_format("jpg"); |
| 108 | 105 | | imlib_save_image_with_error_return(cfile, &err); |
| 109 | 106 | | } |
| 110 | 107 | | if (err == 0) { |
| @@ -173,6 +170,7 @@ void tns_init(tns_t *tns, const fileinfo_t *files, int cnt, int *sel, win_t *win |
| 173 | 170 | | tns->loadnext = tns->first = tns->end = tns->r_first = tns->r_end = 0; |
| 174 | 171 | | tns->sel = sel; |
| 175 | 172 | | tns->win = win; |
| 173 | + | tns->zl = 1; |
| 176 | 174 | | tns->dirty = false; |
| 177 | 175 | | |
| 178 | 176 | | if ((homedir = getenv("XDG_CACHE_HOME")) == NULL || homedir[0] == '\0') { |
| @@ -211,11 +209,34 @@ void tns_free(tns_t *tns) |
| 211 | 209 | | cache_dir = NULL; |
| 212 | 210 | | } |
| 213 | 211 | | |
| 212 | + | Imlib_Image tns_scale_down(Imlib_Image im, int dim) |
| 213 | + | { |
| 214 | + | int w, h; |
| 215 | + | float z, zw, zh; |
| 216 | + | |
| 217 | + | imlib_context_set_image(im); |
| 218 | + | w = imlib_image_get_width(); |
| 219 | + | h = imlib_image_get_height(); |
| 220 | + | zw = (float) dim / (float) w; |
| 221 | + | zh = (float) dim / (float) h; |
| 222 | + | z = MIN(zw, zh); |
| 223 | + | z = MIN(z, 1.0); |
| 224 | + | |
| 225 | + | if (z < 1.0) { |
| 226 | + | imlib_context_set_anti_alias(1); |
| 227 | + | im = imlib_create_cropped_scaled_image(0, 0, w, h, z * w, z * h); |
| 228 | + | if (im == NULL) |
| 229 | + | die("could not allocate memory"); |
| 230 | + | imlib_free_image_and_decache(); |
| 231 | + | } |
| 232 | + | return im; |
| 233 | + | } |
| 234 | + | |
| 214 | 235 | | bool tns_load(tns_t *tns, int n, bool force) |
| 215 | 236 | | { |
| 216 | 237 | | int w, h; |
| 217 | 238 | | bool cache_hit = false; |
| 218 | | − | float z, zw, zh; |
| 239 | + | float zw, zh; |
| 219 | 240 | | thumb_t *t; |
| 220 | 241 | | Imlib_Image im = NULL; |
| 221 | 242 | | const fileinfo_t *file; |
| @@ -301,31 +322,20 @@ bool tns_load(tns_t *tns, int n, bool force) |
| 301 | 322 | | return false; |
| 302 | 323 | | } |
| 303 | 324 | | } |
| 304 | | − | imlib_context_set_image(im); |
| 305 | | − | imlib_context_set_anti_alias(1); |
| 306 | 325 | | |
| 326 | + | if (!cache_hit) { |
| 307 | 327 | | #if HAVE_LIBEXIF |
| 308 | | − | if (!cache_hit) |
| 328 | + | imlib_context_set_image(im); |
| 309 | 329 | | exif_auto_orientate(file); |
| 310 | 330 | | #endif |
| 331 | + | im = tns_scale_down(im, thumb_size[ARRLEN(thumb_size)-1]); |
| 332 | + | tns_cache_write(im, file->path, true); |
| 333 | + | } |
| 311 | 334 | | |
| 312 | | − | w = imlib_image_get_width(); |
| 313 | | − | h = imlib_image_get_height(); |
| 314 | | − | zw = (float) THUMB_SIZE / (float) w; |
| 315 | | − | zh = (float) THUMB_SIZE / (float) h; |
| 316 | | − | z = MIN(zw, zh); |
| 317 | | − | z = MIN(z, 1.0); |
| 318 | | − | t->w = z * w; |
| 319 | | − | t->h = z * h; |
| 320 | | − | |
| 321 | | − | t->im = imlib_create_cropped_scaled_image(0, 0, w, h, t->w, t->h); |
| 322 | | − | if (t->im == NULL) |
| 323 | | − | die("could not allocate memory"); |
| 324 | | − | |
| 325 | | − | imlib_free_image_and_decache(); |
| 326 | | − | |
| 327 | | − | if (!cache_hit) |
| 328 | | − | tns_cache_write(t, file, true); |
| 335 | + | t->im = tns_scale_down(im, thumb_size[tns->zl]); |
| 336 | + | imlib_context_set_image(t->im); |
| 337 | + | t->w = imlib_image_get_width(); |
| 338 | + | t->h = imlib_image_get_height(); |
| 329 | 339 | | |
| 330 | 340 | | tns->dirty = true; |
| 331 | 341 | | return true; |
| @@ -382,6 +392,7 @@ void tns_render(tns_t *tns) |
| 382 | 392 | | thumb_t *t; |
| 383 | 393 | | win_t *win; |
| 384 | 394 | | int i, cnt, r, x, y; |
| 395 | + | int thumb_dim; |
| 385 | 396 | | |
| 386 | 397 | | if (tns == NULL || tns->thumbs == NULL || tns->win == NULL) |
| 387 | 398 | | return; |
| @@ -392,6 +403,7 @@ void tns_render(tns_t *tns) |
| 392 | 403 | | win_clear(win); |
| 393 | 404 | | imlib_context_set_drawable(win->buf.pm); |
| 394 | 405 | | |
| 406 | + | thumb_dim = thumb_size[tns->zl] + 10; |
| 395 | 407 | | tns->cols = MAX(1, win->w / thumb_dim); |
| 396 | 408 | | tns->rows = MAX(1, win->h / thumb_dim); |
| 397 | 409 | | |
| @@ -422,8 +434,8 @@ void tns_render(tns_t *tns) |
| 422 | 434 | | for (i = tns->first; i < tns->end; i++) { |
| 423 | 435 | | t = &tns->thumbs[i]; |
| 424 | 436 | | if (t->im != NULL) { |
| 425 | | − | t->x = x + (THUMB_SIZE - t->w) / 2; |
| 426 | | − | t->y = y + (THUMB_SIZE - t->h) / 2; |
| 437 | + | t->x = x + (thumb_size[tns->zl] - t->w) / 2; |
| 438 | + | t->y = y + (thumb_size[tns->zl] - t->h) / 2; |
| 427 | 439 | | imlib_context_set_image(t->im); |
| 428 | 440 | | imlib_render_image_on_drawable_at_size(t->x, t->y, t->w, t->h); |
| 429 | 441 | | if (tns->files[i].marked) |
| @@ -550,6 +562,26 @@ bool tns_scroll(tns_t *tns, direction_t dir, bool screen) |
| 550 | 562 | | return tns->first != old; |
| 551 | 563 | | } |
| 552 | 564 | | |
| 565 | + | bool tns_zoom(tns_t *tns, int d) |
| 566 | + | { |
| 567 | + | int i, oldzl; |
| 568 | + | |
| 569 | + | if (tns == NULL || tns->thumbs == NULL) |
| 570 | + | return false; |
| 571 | + | |
| 572 | + | oldzl = tns->zl; |
| 573 | + | tns->zl += -(d < 0) + (d > 0); |
| 574 | + | tns->zl = MAX(tns->zl, 0); |
| 575 | + | tns->zl = MIN(tns->zl, ARRLEN(thumb_size)-1); |
| 576 | + | |
| 577 | + | if (tns->zl != oldzl) { |
| 578 | + | for (i = 0; i < tns->cnt; i++) |
| 579 | + | tns_unload(tns, i); |
| 580 | + | tns->dirty = true; |
| 581 | + | } |
| 582 | + | return tns->zl != oldzl; |
| 583 | + | } |
| 584 | + | |
| 553 | 585 | | int tns_translate(tns_t *tns, int x, int y) |
| 554 | 586 | | { |
| 555 | 587 | | int n; |
| @@ -559,8 +591,8 @@ int tns_translate(tns_t *tns, int x, int y) |
| 559 | 591 | | if (x < tns->x || y < tns->y) |
| 560 | 592 | | return -1; |
| 561 | 593 | | |
| 562 | | − | n = tns->first + (y - tns->y) / thumb_dim * tns->cols + |
| 563 | | − | (x - tns->x) / thumb_dim; |
| 594 | + | n = tns->first + (y - tns->y) / (thumb_size[tns->zl] + 10) * tns->cols + |
| 595 | + | (x - tns->x) / (thumb_size[tns->zl] + 10); |
| 564 | 596 | | if (n >= tns->cnt) |
| 565 | 597 | | n = -1; |
| 566 | 598 | | |