Krolyxon
Commit 7b91e10

Branches

Refs →

nsxiv7b91e10

Added thumbnail zooming...

- Key mappings +/- are now general commands
- Use JPG as thumbnail cache file format instead of PNG
- Fixes issue #161
Author
Bert Münnich
Date
2014-09-28 00:26 +0200
Committer
Bert Münnich · 2014-09-28 00:28 +0200
Parent
b2dbd2f
Commit
7b91e10f225797cef26ce7094bf2ac6b94901b33

+100 −63

7 files changed

  1. M README.md +2 −2
  2. M commands.c +14 −12
  3. M commands.lst +1 −1
  4. M config.def.h +6 −6
  5. M sxiv.1 +6 −6
  6. M thumbs.c +68 −36
  7. M thumbs.h +3 −0
M README.md View
@@ -101,6 +101,8 @@ of small previews is displayed, making it easy to choose an image to open.
101101 r Reload image
102102 D Remove image from file list and go to next image
103103 Ctrl-h,j,k,l Scroll one window width/height left/down/up/right
104+ + Zoom in
105+ - Zoom out
104106 m Mark/unmark current image
105107 M Reverse all image marks
106108 Ctrl-m Remove all image marks
@@ -123,8 +125,6 @@ of small previews is displayed, making it easy to choose an image to open.
123125 h,j,k,l Scroll image 1/5 of window width/height or [count] pixels
124126 left/down/up/right (also with arrow keys)
125127 H,J,K,L Scroll to left/bottom/top/right image edge
126− + Zoom in
127− - Zoom out
128128 = Set zoom level to 100%, or [count]%
129129 w Set zoom level to 100%, but fit large images into window
130130 W Fit image to window
M commands.c View
@@ -193,6 +193,20 @@ bool cg_scroll_screen(arg_t a)
193193 return tns_scroll(&tns, dir, true);
194194 }
195195
196+bool cg_zoom(arg_t a)
197+{
198+ long d = (long) a;
199+
200+ if (mode == MODE_THUMB)
201+ return tns_zoom(&tns, d);
202+ else if (d > 0)
203+ return img_zoom_in(&img);
204+ else if (d < 0)
205+ return img_zoom_out(&img);
206+ else
207+ return false;
208+}
209+
196210 bool cg_toggle_image_mark(arg_t a)
197211 {
198212 files[fileidx].marked = !files[fileidx].marked;
@@ -386,18 +400,6 @@ bool ci_drag(arg_t a)
386400 return true;
387401 }
388402
389−bool ci_zoom(arg_t a)
390−{
391− long scale = (long) a;
392−
393− if (scale > 0)
394− return img_zoom_in(&img);
395− else if (scale < 0)
396− return img_zoom_out(&img);
397− else
398− return false;
399−}
400−
401403 bool ci_set_zoom(arg_t a)
402404 {
403405 return img_zoom(&img, (prefix ? prefix : (long) a) / 100.0);
M commands.lst View
@@ -8,6 +8,7 @@ G_CMD(remove_image)
88 G_CMD(first)
99 G_CMD(n_or_last)
1010 G_CMD(scroll_screen)
11+G_CMD(zoom)
1112 G_CMD(toggle_image_mark)
1213 G_CMD(reverse_marks)
1314 G_CMD(unmark_all)
@@ -20,7 +21,6 @@ I_CMD(toggle_animation)
2021 I_CMD(scroll)
2122 I_CMD(scroll_to_edge)
2223 I_CMD(drag)
23−I_CMD(zoom)
2424 I_CMD(set_zoom)
2525 I_CMD(fit_to_win)
2626 I_CMD(rotate)
M config.def.h View
@@ -79,6 +79,10 @@ static const keymap_t keys[] = {
7979 { ControlMask, XK_Up, g_scroll_screen, (arg_t) DIR_UP },
8080 { ControlMask, XK_l, g_scroll_screen, (arg_t) DIR_RIGHT },
8181 { ControlMask, XK_Right, g_scroll_screen, (arg_t) DIR_RIGHT },
82+ { 0, XK_plus, g_zoom, (arg_t) +1 },
83+ { 0, XK_KP_Add, g_zoom, (arg_t) +1 },
84+ { 0, XK_minus, g_zoom, (arg_t) -1 },
85+ { 0, XK_KP_Subtract, g_zoom, (arg_t) -1 },
8286 { 0, XK_m, g_toggle_image_mark, (arg_t) None },
8387 { 0, XK_M, g_reverse_marks, (arg_t) None },
8488 { ControlMask, XK_m, g_unmark_all, (arg_t) None },
@@ -119,10 +123,6 @@ static const keymap_t keys[] = {
119123 { 0, XK_J, i_scroll_to_edge, (arg_t) DIR_DOWN },
120124 { 0, XK_K, i_scroll_to_edge, (arg_t) DIR_UP },
121125 { 0, XK_L, i_scroll_to_edge, (arg_t) DIR_RIGHT },
122− { 0, XK_plus, i_zoom, (arg_t) +1 },
123− { 0, XK_KP_Add, i_zoom, (arg_t) +1 },
124− { 0, XK_minus, i_zoom, (arg_t) -1 },
125− { 0, XK_KP_Subtract, i_zoom, (arg_t) -1 },
126126 { 0, XK_equal, i_set_zoom, (arg_t) 100 },
127127 { 0, XK_w, i_fit_to_win, (arg_t) SCALE_DOWN },
128128 { 0, XK_W, i_fit_to_win, (arg_t) SCALE_FIT },
@@ -153,8 +153,8 @@ static const button_t buttons[] = {
153153 { ShiftMask, 5, i_scroll, (arg_t) DIR_RIGHT },
154154 { 0, 6, i_scroll, (arg_t) DIR_LEFT },
155155 { 0, 7, i_scroll, (arg_t) DIR_RIGHT },
156− { ControlMask, 4, i_zoom, (arg_t) +1 },
157− { ControlMask, 5, i_zoom, (arg_t) -1 },
156+ { ControlMask, 4, g_zoom, (arg_t) +1 },
157+ { ControlMask, 5, g_zoom, (arg_t) -1 },
158158 };
159159
160160 #endif
M sxiv.1 View
@@ -140,6 +140,12 @@ Scroll up one screen height.
140140 .BR Ctrl-l ", " Ctrl-Right
141141 Scroll right one screen width.
142142 .TP
143+.BR +
144+Zoom in.
145+.TP
146+.B \-
147+Zoom out.
148+.TP
143149 .B m
144150 Mark/unmark the current image.
145151 .TP
@@ -251,12 +257,6 @@ Scroll to top image edge.
251257 Scroll to right image edge.
252258 .SS Zooming
253259 .TP
254−.BR +
255−Zoom in.
256−.TP
257−.B \-
258−Zoom out.
259−.TP
260260 .B =
261261 Set zoom level to 100%, or
262262 .IR count %.
M thumbs.c View
@@ -17,7 +17,6 @@
1717 */
1818
1919 #define _POSIX_C_SOURCE 200112L
20−#define _THUMBS_CONFIG
2120
2221 #include <stdio.h>
2322 #include <stdlib.h>
@@ -37,7 +36,7 @@ void exif_auto_orientate(const fileinfo_t*);
3736 #endif
3837
3938 static char *cache_dir;
40−static const int thumb_dim = THUMB_SIZE + 10;
39+static const int thumb_size[] = { 32, 64, 96, 128, 160 };
4140
4241 char* tns_cache_filepath(const char *filepath)
4342 {
@@ -51,7 +50,7 @@ char* tns_cache_filepath(const char *filepath)
5150 /* don't cache images inside the cache directory! */
5251 len = strlen(cache_dir) + strlen(filepath) + 6;
5352 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);
5554 }
5655 return cfile;
5756 }
@@ -79,21 +78,19 @@ Imlib_Image tns_cache_load(const char *filepath, bool *outdated)
7978 return im;
8079 }
8180
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)
8382 {
8483 char *cfile, *dirend;
8584 struct stat cstats, fstats;
8685 struct utimbuf times;
8786 Imlib_Load_Error err = 0;
8887
89− if (t == NULL || t->im == NULL)
88+ if (im == NULL || filepath == NULL)
9089 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)
9491 return;
9592
96− if ((cfile = tns_cache_filepath(file->path)) != NULL) {
93+ if ((cfile = tns_cache_filepath(filepath)) != NULL) {
9794 if (force || stat(cfile, &cstats) < 0 ||
9895 cstats.st_mtime != fstats.st_mtime)
9996 {
@@ -103,8 +100,8 @@ void tns_cache_write(thumb_t *t, const fileinfo_t *file, bool force)
103100 *dirend = '/';
104101 }
105102 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");
108105 imlib_save_image_with_error_return(cfile, &err);
109106 }
110107 if (err == 0) {
@@ -173,6 +170,7 @@ void tns_init(tns_t *tns, const fileinfo_t *files, int cnt, int *sel, win_t *win
173170 tns->loadnext = tns->first = tns->end = tns->r_first = tns->r_end = 0;
174171 tns->sel = sel;
175172 tns->win = win;
173+ tns->zl = 1;
176174 tns->dirty = false;
177175
178176 if ((homedir = getenv("XDG_CACHE_HOME")) == NULL || homedir[0] == '\0') {
@@ -211,11 +209,34 @@ void tns_free(tns_t *tns)
211209 cache_dir = NULL;
212210 }
213211
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+
214235 bool tns_load(tns_t *tns, int n, bool force)
215236 {
216237 int w, h;
217238 bool cache_hit = false;
218− float z, zw, zh;
239+ float zw, zh;
219240 thumb_t *t;
220241 Imlib_Image im = NULL;
221242 const fileinfo_t *file;
@@ -301,31 +322,20 @@ bool tns_load(tns_t *tns, int n, bool force)
301322 return false;
302323 }
303324 }
304− imlib_context_set_image(im);
305− imlib_context_set_anti_alias(1);
306325
326+ if (!cache_hit) {
307327 #if HAVE_LIBEXIF
308− if (!cache_hit)
328+ imlib_context_set_image(im);
309329 exif_auto_orientate(file);
310330 #endif
331+ im = tns_scale_down(im, thumb_size[ARRLEN(thumb_size)-1]);
332+ tns_cache_write(im, file->path, true);
333+ }
311334
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();
329339
330340 tns->dirty = true;
331341 return true;
@@ -382,6 +392,7 @@ void tns_render(tns_t *tns)
382392 thumb_t *t;
383393 win_t *win;
384394 int i, cnt, r, x, y;
395+ int thumb_dim;
385396
386397 if (tns == NULL || tns->thumbs == NULL || tns->win == NULL)
387398 return;
@@ -392,6 +403,7 @@ void tns_render(tns_t *tns)
392403 win_clear(win);
393404 imlib_context_set_drawable(win->buf.pm);
394405
406+ thumb_dim = thumb_size[tns->zl] + 10;
395407 tns->cols = MAX(1, win->w / thumb_dim);
396408 tns->rows = MAX(1, win->h / thumb_dim);
397409
@@ -422,8 +434,8 @@ void tns_render(tns_t *tns)
422434 for (i = tns->first; i < tns->end; i++) {
423435 t = &tns->thumbs[i];
424436 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;
427439 imlib_context_set_image(t->im);
428440 imlib_render_image_on_drawable_at_size(t->x, t->y, t->w, t->h);
429441 if (tns->files[i].marked)
@@ -550,6 +562,26 @@ bool tns_scroll(tns_t *tns, direction_t dir, bool screen)
550562 return tns->first != old;
551563 }
552564
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+
553585 int tns_translate(tns_t *tns, int x, int y)
554586 {
555587 int n;
@@ -559,8 +591,8 @@ int tns_translate(tns_t *tns, int x, int y)
559591 if (x < tns->x || y < tns->y)
560592 return -1;
561593
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);
564596 if (n >= tns->cnt)
565597 n = -1;
566598
M thumbs.h View
@@ -47,6 +47,7 @@ typedef struct {
4747 int y;
4848 int cols;
4949 int rows;
50+ int zl;
5051
5152 bool dirty;
5253 } tns_t;
@@ -66,6 +67,8 @@ void tns_highlight(tns_t*, int, bool);
6667 bool tns_move_selection(tns_t*, direction_t, int);
6768 bool tns_scroll(tns_t*, direction_t, bool);
6869
70+bool tns_zoom(tns_t*, int);
71+
6972 int tns_translate(tns_t*, int, int);
7073
7174 #endif /* THUMBS_H */