1 /*****************************************************************************
2 * This file is part of gfxprim library. *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
19 * Copyright (C) 2009-2013 Cyril Hrubis <metan@ucw.cz> *
21 *****************************************************************************/
25 SPIV -- Simple yet Powerful Image Viewer.
36 #include <input/GP_InputDriverLinux.h>
38 #include "image_cache.h"
39 #include "image_list.h"
40 #include "image_actions.h"
41 #include "spiv_help.h"
42 #include "cpu_timer.h"
44 static GP_Pixel black_pixel
;
45 static GP_Pixel white_pixel
;
46 static GP_Pixel gray_pixel
;
48 static GP_Backend
*backend
= NULL
;
50 /* image loader thread */
51 static int abort_flag
= 0;
52 static int show_progress
= 0;
56 * Resize image to fit current size of the window.
61 * Use zoom set in zoom float and zoom offsets.
66 * Fixed zoom but spiv tries to change
67 * the window size to fit the image size
72 * Do not upscale images but downscale them
73 * if they are too big.
78 struct loader_params
{
79 /* current image path */
81 /* current resize ratio */
84 /* show loader progress */
86 long show_progress_once
:2;
87 /* show image info in topleft corner */
89 /* use nearest neighbour resampling first */
91 /* use dithering when blitting to display */
93 /* use low pass before resampling */
95 /* image orientation 0, 90, 180, 270 */
97 /* resampling method */
98 int resampling_method
;
100 /* offset in pixels */
101 unsigned int zoom_x_offset
;
102 unsigned int zoom_y_offset
;
105 enum zoom_type zoom_type
;
108 /* caches for loaded images */
109 struct image_cache
*img_resized_cache
;
110 struct image_cache
*img_orig_cache
;
112 /* image list structure */
113 struct image_list
*img_list
;
116 static int image_loader_callback(GP_ProgressCallback
*self
)
118 static GP_Size size
= 0;
119 GP_Context
*c
= backend
->context
;
129 snprintf(buf
, sizeof(buf
), "%s ... %-3.1f%%",
130 (const char*)self
->priv
, self
->percentage
);
132 int align
= GP_ALIGN_CENTER
|GP_VALIGN_ABOVE
;
134 size
= GP_TextWidth(NULL
, buf
);
136 int start
= c
->w
/2 - size
/2 - 10;
137 int end
= c
->w
/2 + size
/2 + 10;
138 int middle
= start
+ (end
- start
) * self
->percentage
/ 100;
139 int top
= c
->h
- GP_TextHeight(NULL
) - 11;
141 GP_FillRectXYXY(c
, start
, c
->h
- 1, middle
, top
, gray_pixel
);
142 GP_FillRectXYXY(c
, middle
, c
->h
- 1, end
, top
, black_pixel
);
144 GP_Text(c
, NULL
, c
->w
/2, c
->h
- 5, align
,
145 white_pixel
, black_pixel
, buf
);
147 GP_BackendUpdateRect(backend
, start
, c
->h
- 1, end
, top
);
152 static GP_Context
*load_image(struct loader_params
*params
, int elevate
);
155 * Ask backend to resize window may not be implemented or authorized. If
156 * backend (window) is resized we will get SYS_RESIZE event, see the main event
159 static void resize_backend(struct loader_params
*params
,
160 float ratio
, int shift_flag
)
162 GP_Context
*img
= load_image(params
, 1);
165 ratio
= 1.00 / ratio
;
167 unsigned int w
= img
->w
* ratio
+ 0.5;
168 unsigned int h
= img
->h
* ratio
+ 0.5;
170 GP_BackendResize(backend
, w
, h
);
174 static float calc_img_size(struct loader_params
*params
,
175 uint32_t img_w
, uint32_t img_h
,
176 uint32_t src_w
, uint32_t src_h
)
181 switch (params
->zoom_type
) {
182 case ZOOM_FIT_DOWNSCALE
:
183 if (img_w
<= src_w
&& img_h
<= src_h
)
186 w_rat
= 1.00 * src_w
/ img_w
;
187 h_rat
= 1.00 * src_h
/ img_h
;
188 return GP_MIN(w_rat
, h_rat
);
192 resize_backend(params
, params
->zoom
, 0);
199 static const char *img_name(const char *img_path
)
201 int i
, len
= strlen(img_path
);
203 for (i
= len
- 1; i
> 0; i
--) {
204 if (img_path
[i
] == '/')
205 return &img_path
[i
+1];
211 static void set_caption(const char *path
, float rat
)
215 snprintf(buf
, sizeof(buf
), "Spiv ~ %s 1:%3.3f", img_name(path
), rat
);
217 GP_BackendSetCaption(backend
, buf
);
223 static GP_Context
*load_image(struct loader_params
*params
, int elevate
)
225 struct cpu_timer timer
;
226 GP_Context
*img
, *context
= backend
->context
;
228 GP_ProgressCallback callback
= {.callback
= image_loader_callback
,
229 .priv
= "Loading image"};
231 img
= image_cache_get(params
->img_orig_cache
, params
->img_path
, 0, 0, elevate
);
233 /* Image not cached, load it */
235 fprintf(stderr
, "Loading '%s'\n", params
->img_path
);
237 cpu_timer_start(&timer
, "Loading");
238 if ((img
= GP_LoadImage(params
->img_path
, &callback
)) == NULL
) {
240 if (errno
== ECANCELED
)
243 GP_Fill(context
, black_pixel
);
244 GP_Print(context
, NULL
, context
->w
/2, context
->h
/2 - 10,
245 GP_ALIGN_CENTER
|GP_VALIGN_CENTER
, white_pixel
, black_pixel
,
246 "'%s'", params
->img_path
);
247 GP_Print(context
, NULL
, context
->w
/2, context
->h
/2 + 10,
248 GP_ALIGN_CENTER
|GP_VALIGN_CENTER
, white_pixel
, black_pixel
,
249 "Failed to load image :( (%s)", strerror(errno
));
250 GP_BackendFlip(backend
);
255 // if (img->pixel_type != GP_PIXEL_RGB888) {
257 // tmp = GP_ContextConvertAlloc(img, GP_PIXEL_RGB888);
258 // GP_ContextFree(img);
262 image_cache_put(params
->img_orig_cache
, img
, params
->img_path
, 0, 0);
264 cpu_timer_stop(&timer
);
271 * Fill context with chessboard-like pattern.
273 static void pattern_fill(GP_Context
*ctx
, unsigned int x0
, unsigned int y0
, unsigned int w
, unsigned int h
)
277 GP_Pixel g1
= GP_RGBToContextPixel(0x64, 0x64, 0x64, ctx
);
278 GP_Pixel g2
= GP_RGBToContextPixel(0x80, 0x80, 0x80, ctx
);
280 unsigned int wm
= w
/10 < 10 ? 10 : w
/10;
281 unsigned int hm
= h
/10 < 10 ? 10 : h
/10;
282 unsigned int wt
= w
/20 < 5 ? 5 : w
/20;
283 unsigned int ht
= h
/20 < 5 ? 5 : h
/20;
285 for (y
= 0; y
< h
; y
++) {
286 for (x
= 0; x
< w
; x
++) {
289 if ((x
% wm
< wt
) ^ (y
% hm
< ht
))
294 GP_PutPixel(ctx
, x0
+ x
, y0
+ y
, pix
);
302 static void update_display(struct loader_params
*params
, GP_Context
*img
)
304 GP_Context
*context
= backend
->context
;
305 struct cpu_timer timer
;
306 GP_ProgressCallback callback
= {.callback
= image_loader_callback
};
308 switch (params
->rotate
) {
312 callback
.priv
= "Rotating image (90)";
313 img
= GP_FilterRotate90Alloc(img
, &callback
);
316 callback
.priv
= "Rotating image (180)";
317 img
= GP_FilterRotate180Alloc(img
, &callback
);
320 callback
.priv
= "Rotating image (270)";
321 img
= GP_FilterRotate270Alloc(img
, &callback
);
331 switch (params
->zoom_type
) {
332 case ZOOM_FIT_DOWNSCALE
:
334 cx
= (context
->w
- img
->w
)/2;
335 cy
= (context
->h
- img
->h
)/2;
339 cx
= params
->zoom_x_offset
;
340 cy
= params
->zoom_y_offset
;
344 GP_Context sub_display
;
346 cpu_timer_start(&timer
, "Blitting");
348 if (params
->use_dithering
) {
349 callback
.priv
= "Dithering";
350 GP_SubContext(context
, &sub_display
, cx
, cy
, img
->w
, img
->h
);
351 GP_FilterFloydSteinberg_RGB888(img
, &sub_display
, NULL
);
352 // GP_FilterHilbertPeano_RGB888(img, &sub_display, NULL);
354 if (GP_PixelHasFlags(img
->pixel_type
, GP_PIXEL_HAS_ALPHA
))
355 pattern_fill(context
, cx
, cy
, img
->w
, img
->h
);
357 GP_Blit_Clipped(img
, 0, 0, img
->w
, img
->h
, context
, cx
, cy
);
360 cpu_timer_stop(&timer
);
365 /* clean up the rest of the display */
366 GP_FillRectXYWH(context
, 0, 0, cx
, context
->h
, black_pixel
);
367 GP_FillRectXYWH(context
, 0, 0, context
->w
, cy
, black_pixel
);
369 int w
= context
->w
- img
->w
- cx
;
372 GP_FillRectXYWH(context
, img
->w
+ cx
, 0, w
, context
->h
, black_pixel
);
374 int h
= context
->h
- img
->h
- cy
;
377 GP_FillRectXYWH(context
, 0, img
->h
+ cy
, context
->w
, h
, black_pixel
);
379 set_caption(params
->img_path
, params
->rat
);
381 if (!params
->show_info
) {
382 GP_BackendFlip(backend
);
386 GP_Size th
= GP_TextHeight(NULL
);
388 GP_Print(context
, NULL
, 11, 11, GP_ALIGN_RIGHT
|GP_VALIGN_BOTTOM
,
389 black_pixel
, white_pixel
, "%ux%u", img
->w
, img
->h
);
391 GP_Print(context
, NULL
, 10, 10, GP_ALIGN_RIGHT
|GP_VALIGN_BOTTOM
,
392 white_pixel
, black_pixel
, "%ux%u", img
->w
, img
->h
);
394 GP_Print(context
, NULL
, 11, 13 + th
, GP_ALIGN_RIGHT
|GP_VALIGN_BOTTOM
,
395 black_pixel
, white_pixel
, "1:%3.3f", params
->rat
);
397 GP_Print(context
, NULL
, 10, 12 + th
, GP_ALIGN_RIGHT
|GP_VALIGN_BOTTOM
,
398 white_pixel
, black_pixel
, "1:%3.3f", params
->rat
);
400 GP_Print(context
, NULL
, 11, 15 + 2 * th
, GP_ALIGN_RIGHT
|GP_VALIGN_BOTTOM
,
401 black_pixel
, white_pixel
, "%s", img_name(params
->img_path
));
403 GP_Print(context
, NULL
, 10, 14 + 2 * th
, GP_ALIGN_RIGHT
|GP_VALIGN_BOTTOM
,
404 white_pixel
, black_pixel
, "%s", img_name(params
->img_path
));
406 GP_Print(context
, NULL
, 11, 17 + 3 * th
, GP_ALIGN_RIGHT
|GP_VALIGN_BOTTOM
,
407 black_pixel
, white_pixel
, "%s%s",
408 params
->use_low_pass
&& params
->rat
< 1 ? "Gaussian LP + " : "",
409 GP_InterpolationTypeName(params
->resampling_method
));
411 GP_Print(context
, NULL
, 10, 16 + 3 * th
, GP_ALIGN_RIGHT
|GP_VALIGN_BOTTOM
,
412 white_pixel
, black_pixel
, "%s%s",
413 params
->use_low_pass
&& params
->rat
< 1 ? "Gaussian LP + " : "",
414 GP_InterpolationTypeName(params
->resampling_method
));
416 unsigned int count
= image_list_count(params
->img_list
);
417 unsigned int pos
= image_list_pos(params
->img_list
) + 1;
419 GP_Print(context
, NULL
, 11, 19 + 4 * th
, GP_ALIGN_RIGHT
|GP_VALIGN_BOTTOM
,
420 black_pixel
, white_pixel
, "%u of %u", pos
, count
);
422 GP_Print(context
, NULL
, 10, 18 + 4 * th
, GP_ALIGN_RIGHT
|GP_VALIGN_BOTTOM
,
423 white_pixel
, black_pixel
, "%u of %u", pos
, count
);
425 unsigned int dir_count
= image_list_dir_count(params
->img_list
);
426 unsigned int dir_pos
= image_list_dir_pos(params
->img_list
) + 1;
428 if (dir_count
> 1 && dir_count
!= count
) {
429 GP_Print(context
, NULL
, 11, 21 + 5 * th
, GP_ALIGN_RIGHT
|GP_VALIGN_BOTTOM
,
430 black_pixel
, white_pixel
, "%u of %u in directory", dir_pos
, dir_count
);
432 GP_Print(context
, NULL
, 10, 20 + 5 * th
, GP_ALIGN_RIGHT
|GP_VALIGN_BOTTOM
,
433 white_pixel
, black_pixel
, "%u of %u in directory", dir_pos
, dir_count
);
436 GP_BackendFlip(backend
);
439 GP_Context
*load_resized_image(struct loader_params
*params
, GP_Size w
, GP_Size h
)
441 long cookie
= (w
& 0xffff) | (h
& 0xffff)<<16;
442 GP_Context
*img
, *res
= NULL
;
443 struct cpu_timer timer
;
444 GP_ProgressCallback callback
= {.callback
= image_loader_callback
};
446 int key
= (params
->resampling_method
<<1) | !!(params
->use_low_pass
);
448 /* Try to get resized cached image */
449 img
= image_cache_get(params
->img_resized_cache
, params
->img_path
, cookie
, key
, 1);
454 /* Otherwise load image and resize it */
455 if ((img
= load_image(params
, 1)) == NULL
)
458 if (params
->show_nn_first
) {
459 /* Do simple interpolation and blit the result */
460 GP_Context
*nn
= GP_FilterResizeNNAlloc(img
, w
, h
, NULL
);
462 update_display(params
, nn
);
467 /* Do low pass filter */
468 if (params
->use_low_pass
&& params
->rat
< 1) {
469 cpu_timer_start(&timer
, "Blur");
470 callback
.priv
= "Blurring Image";
472 res
= GP_FilterGaussianBlurAlloc(img
, 0.3/params
->rat
,
473 0.3/params
->rat
, &callback
);
480 cpu_timer_stop(&timer
);
483 // img->gamma = GP_GammaAcquire(img->pixel_type, 0.45);
485 cpu_timer_start(&timer
, "Resampling");
486 callback
.priv
= "Resampling Image";
487 GP_Context
*i1
= GP_FilterResize(img
, NULL
, params
->resampling_method
, w
, h
, &callback
);
488 // img->gamma = NULL;
489 // GP_Context *i2 = GP_FilterResize(img, NULL, params->resampling_method, w, h, &callback);
490 // img = GP_FilterDifferenceAlloc(i2, i1, NULL);
491 // img = GP_FilterInvert(img, NULL, NULL);
493 // if (params->resampling_method == GP_INTERP_CUBIC_INT)
494 // GP_FilterEdgeSharpening(img, img, 0.2, NULL);
495 cpu_timer_stop(&timer
);
498 if (params->rat > 1.5) {
499 cpu_timer_start(&timer, "Sharpening");
500 callback.priv = "Sharpening";
501 GP_FilterEdgeSharpening(i1, i1, 0.1, &callback);
502 cpu_timer_stop(&timer);
506 /* Free low passed context if needed */
512 image_cache_put(params
->img_resized_cache
, img
, params
->img_path
, cookie
, key
);
517 static void *image_loader(void *ptr
)
519 struct loader_params
*params
= ptr
;
520 struct cpu_timer sum_timer
;
521 GP_Context
*img
, *context
= backend
->context
;
523 cpu_timer_start(&sum_timer
, "sum");
525 show_progress
= params
->show_progress
|| params
->show_progress_once
;
526 params
->show_progress_once
= 0;
528 /* Figure out rotation */
531 switch (params
->rotate
) {
545 if ((img
= load_image(params
, 0)) == NULL
)
548 params
->rat
= calc_img_size(params
, img
->w
, img
->h
, w
, h
);
550 /* Special case => no need to resize */
551 if (params
->rat
== 1.0)
557 img
= load_resized_image(params
, w
* params
->rat
+ 0.5, h
* params
->rat
+ 0.5);
562 image_cache_print(params
->img_resized_cache
);
563 image_cache_print(params
->img_orig_cache
);
566 update_display(params
, img
);
567 cpu_timer_stop(&sum_timer
);
572 static pthread_t loader_thread
= (pthread_t
)0;
574 static void stop_loader(void)
578 pthread_join(loader_thread
, NULL
);
579 loader_thread
= (pthread_t
)0;
584 static void show_image(struct loader_params
*params
, const char *path
)
589 params
->img_path
= path
;
591 /* stop previous loader thread */
594 ret
= pthread_create(&loader_thread
, NULL
, image_loader
, (void*)params
);
597 fprintf(stderr
, "Failed to start thread: %s\n", strerror(ret
));
598 GP_BackendExit(backend
);
603 static void set_zoom_offset(struct loader_params
*params
, int dx
, int dy
)
605 params
->zoom_x_offset
+= dx
;
606 params
->zoom_y_offset
+= dy
;
607 show_image(params
, NULL
);
610 static void zoom_mul(struct loader_params
*params
, float mul
)
613 show_image(params
, NULL
);
616 static void sighandler(int signo
)
619 GP_BackendExit(backend
);
621 fprintf(stderr
, "Got signal %i\n", signo
);
626 static void init_backend(const char *backend_opts
)
628 backend
= GP_BackendInit(backend_opts
, "Spiv", stderr
);
630 if (backend
== NULL
) {
631 fprintf(stderr
, "Failed to initalize backend '%s'\n", backend_opts
);
637 static void init_caches(struct loader_params
*params
)
639 size_t size
= image_cache_get_ram_size();
640 unsigned int resized_size
= (1024 * size
)/10;
641 unsigned int orig_size
= (1024 * size
)/50;
643 if (resized_size
> 100 * 1024 * 1024)
644 resized_size
= 100 * 1024 * 1024;
646 if (orig_size
> 40 * 1024 * 1024)
647 orig_size
= 40 * 1024 * 1024;
649 GP_DEBUG(1, "Cache sizes original = %u, resized = %u",
650 orig_size
, resized_size
);
652 params
->img_resized_cache
= image_cache_create(resized_size
);
653 params
->img_orig_cache
= image_cache_create(orig_size
);
655 // params->img_resized_cache = NULL;
656 // params->img_orig_cache = NULL;
659 static uint32_t timer_callback(GP_Timer
*self
)
661 struct loader_params
*params
= self
->priv
;
663 show_image(params
, image_list_move(params
->img_list
, 1));
668 int main(int argc
, char *argv
[])
670 GP_Context
*context
= NULL
;
671 const char *backend_opts
= "X11";
675 GP_PixelType emul_type
= GP_PIXEL_UNKNOWN
;
677 struct loader_params params
= {
681 .show_progress_once
= 0,
686 .resampling_method
= GP_INTERP_LINEAR_LF_INT
,
688 .zoom_type
= ZOOM_FIT_DOWNSCALE
,
691 .img_resized_cache
= NULL
,
692 .img_orig_cache
= NULL
,
695 GP_TIMER_DECLARE(timer
, 0, 0, "Slideshow", timer_callback
, ¶ms
);
697 while ((opt
= getopt(argc
, argv
, "b:ce:fhIPs:r:z:0:1:2:3:4:5:6:7:8:9:")) != -1) {
700 params
.show_info
= 1;
703 params
.show_progress
= 1;
706 params
.use_dithering
= 1;
709 sleep_ms
= atoi(optarg
);
712 params
.resampling_method
= GP_INTERP_CUBIC_INT
;
713 /* Cubic resampling needs low pass */
714 params
.use_low_pass
= 1;
715 /* Cubic resampling is slow, show nn first */
716 params
.show_nn_first
= 1;
719 emul_type
= GP_PixelTypeByName(optarg
);
721 if (emul_type
== GP_PIXEL_UNKNOWN
) {
722 fprintf(stderr
, "Invalid pixel type '%s'\n", optarg
);
727 if (!strcmp(optarg
, "90"))
729 else if (!strcmp(optarg
, "180"))
731 else if (!strcmp(optarg
, "270"))
734 backend_opts
= optarg
;
743 params
.zoom_type
= ZOOM_FIXED
;
746 params
.zoom_type
= ZOOM_FIXED_WIN
;
751 image_action_set(opt
- '0', optarg
);
754 fprintf(stderr
, "Invalid paramter '%c'\n", opt
);
760 if (optind
>= argc
) {
761 fprintf(stderr
, "Requires path to at least one image\n\n");
766 signal(SIGINT
, sighandler
);
767 signal(SIGSEGV
, sighandler
);
768 signal(SIGBUS
, sighandler
);
769 signal(SIGABRT
, sighandler
);
771 init_caches(¶ms
);
773 init_backend(backend_opts
);
775 if (emul_type
!= GP_PIXEL_UNKNOWN
)
776 backend
= GP_BackendVirtualInit(backend
, emul_type
, GP_BACKEND_CALL_EXIT
);
778 context
= backend
->context
;
780 black_pixel
= GP_ColorToContextPixel(GP_COL_BLACK
, context
);
781 white_pixel
= GP_ColorToContextPixel(GP_COL_WHITE
, context
);
782 gray_pixel
= GP_RGBToContextPixel(0x33, 0x33, 0x33, context
);
784 GP_Fill(context
, black_pixel
);
785 GP_BackendFlip(backend
);
787 struct image_list
*list
= image_list_create((const char**)argv
+ optind
);
788 params
.img_list
= list
;
790 params
.show_progress_once
= 1;
791 show_image(¶ms
, image_list_img_path(list
));
794 timer
.period
= sleep_ms
;
795 GP_BackendAddTimer(backend
, &timer
);
799 GP_BackendWait(backend
);
803 while (GP_BackendGetEvent(backend
, &ev
)) {
805 shift_flag
= GP_EventGetKey(&ev
, GP_KEY_LEFT_SHIFT
) ||
806 GP_EventGetKey(&ev
, GP_KEY_RIGHT_SHIFT
);
811 case GP_EV_REL_WHEEL
:
819 if (GP_EventGetKey(&ev
, GP_BTN_LEFT
))
820 set_zoom_offset(¶ms
,
827 if (ev
.code
!= GP_EV_KEY_DOWN
)
830 switch (ev
.val
.key
.key
) {
833 show_image(¶ms
, NULL
);
836 if (GP_BackendIsX11(backend
))
837 GP_BackendX11RequestFullscreen(backend
, 2);
840 params
.show_info
= !params
.show_info
;
842 params
.show_progress_once
= 1;
843 show_image(¶ms
, NULL
);
846 params
.show_progress
= !params
.show_progress
;
850 if (params
.rotate
> 270)
853 params
.show_progress_once
= 1;
854 show_image(¶ms
, NULL
);
856 case GP_KEY_RIGHT_BRACE
:
857 params
.resampling_method
++;
859 if (params
.resampling_method
> GP_INTERP_MAX
)
860 params
.resampling_method
= 0;
862 if (params
.resampling_method
== GP_INTERP_LINEAR_LF_INT
) {
863 params
.use_low_pass
= 0;
864 params
.show_nn_first
= 0;
866 params
.use_low_pass
= 1;
867 params
.show_nn_first
= 1;
870 params
.show_progress_once
= 1;
871 show_image(¶ms
, image_list_img_path(list
));
873 case GP_KEY_LEFT_BRACE
:
874 if (params
.resampling_method
== 0)
875 params
.resampling_method
= GP_INTERP_MAX
;
877 params
.resampling_method
--;
879 if (params
.resampling_method
== GP_INTERP_LINEAR_LF_INT
) {
880 params
.use_low_pass
= 0;
881 params
.show_nn_first
= 0;
883 params
.use_low_pass
= 1;
884 params
.show_nn_first
= 1;
887 params
.show_progress_once
= 1;
888 show_image(¶ms
, image_list_img_path(list
));
891 params
.use_low_pass
= !params
.use_low_pass
;
893 params
.show_progress_once
= 1;
894 show_image(¶ms
, image_list_img_path(list
));
897 image_cache_drop(params
.img_resized_cache
);
898 image_cache_drop(params
.img_orig_cache
);
903 image_cache_drop(params
.img_resized_cache
);
904 image_cache_drop(params
.img_orig_cache
);
905 GP_BackendExit(backend
);
909 params
.show_progress_once
= 1;
910 show_image(¶ms
, image_list_dir_move(list
, -1));
912 case GP_KEY_PAGE_DOWN
:
913 params
.show_progress_once
= 1;
914 show_image(¶ms
, image_list_dir_move(list
, 1));
917 params
.show_progress_once
= 1;
918 show_image(¶ms
, image_list_first(list
));
921 params
.show_progress_once
= 1;
922 show_image(¶ms
, image_list_last(list
));
926 set_zoom_offset(¶ms
, 1, 0);
928 set_zoom_offset(¶ms
, 10, 0);
933 set_zoom_offset(¶ms
, -1, 0);
935 set_zoom_offset(¶ms
, -10, 0);
939 set_zoom_offset(¶ms
, 0, -1);
941 set_zoom_offset(¶ms
, 0, -10);
945 set_zoom_offset(¶ms
, 0, 1);
947 set_zoom_offset(¶ms
, 0, 10);
951 params
.show_progress_once
= 1;
953 show_image(¶ms
, image_list_move(list
, 10));
955 show_image(¶ms
, image_list_move(list
, 1));
958 case GP_KEY_BACKSPACE
:
959 params
.show_progress_once
= 1;
961 show_image(¶ms
, image_list_move(list
, -10));
963 show_image(¶ms
, image_list_move(list
, -1));
966 resize_backend(¶ms
, 1, shift_flag
);
969 resize_backend(¶ms
, 2, shift_flag
);
972 resize_backend(¶ms
, 3, shift_flag
);
975 resize_backend(¶ms
, 4, shift_flag
);
978 resize_backend(¶ms
, 5, shift_flag
);
981 resize_backend(¶ms
, 6, shift_flag
);
984 resize_backend(¶ms
, 7, shift_flag
);
987 resize_backend(¶ms
, 8, shift_flag
);
990 resize_backend(¶ms
, 9, shift_flag
);
994 params
.show_progress_once
= 1;
995 zoom_mul(¶ms
, 1.5);
997 case GP_KEY_KP_MINUS
:
999 params
.show_progress_once
= 1;
1000 zoom_mul(¶ms
, 1/1.5);
1002 case GP_KEY_F1
... GP_KEY_F10
:
1003 image_action_run(ev
.val
.key
.key
- GP_KEY_F1
,
1004 image_list_img_path(list
));
1010 case GP_EV_SYS_RESIZE
:
1011 /* stop loader thread before resizing backend buffer */
1013 GP_BackendResizeAck(backend
);
1014 GP_Fill(backend
->context
, 0);
1015 params
.show_progress_once
= 1;
1016 show_image(¶ms
, NULL
);
1018 case GP_EV_SYS_QUIT
:
1019 GP_BackendExit(backend
);
1028 GP_BackendExit(backend
);