A little comment about a compilation matter: -lungif parameter is not usually correct...
[fbv.git] / main.c
blob9f684d412a548971e34c7fbd6285e940b6294bd9
1 /*
2 fbv -- simple image viewer for the linux framebuffer
3 Copyright (C) 2000, 2001, 2003, 2004 Mateusz 'mteg' Golicz
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <stdio.h>
21 #include <sys/time.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <getopt.h>
25 #include <stdlib.h>
26 #include <termios.h>
27 #include <string.h>
28 #include <signal.h>
29 #include "config.h"
30 #include "fbv.h"
32 #define PAN_STEPPING 20
34 static int opt_clear = 1,
35 opt_alpha = 0,
36 opt_hide_cursor = 1,
37 opt_image_info = 1,
38 opt_stretch = 0,
39 opt_delay = 0,
40 opt_enlarge = 0,
41 opt_ignore_aspect = 0;
45 void setup_console(int t)
47 struct termios our_termios;
48 static struct termios old_termios;
50 if(t)
52 tcgetattr(0, &old_termios);
53 memcpy(&our_termios, &old_termios, sizeof(struct termios));
54 our_termios.c_lflag &= !(ECHO | ICANON);
55 tcsetattr(0, TCSANOW, &our_termios);
57 else
58 tcsetattr(0, TCSANOW, &old_termios);
62 static inline void do_rotate(struct image *i, int rot)
64 if(rot)
66 unsigned char *image, *alpha = NULL;
67 int t;
69 image = rotate(i->rgb, i->width, i->height, rot);
70 if(i->alpha)
71 alpha = alpha_rotate(i->alpha, i->width, i->height, rot);
72 if(i->do_free)
74 free(i->alpha);
75 free(i->rgb);
78 i->rgb = image;
79 i->alpha = alpha;
80 i->do_free = 1;
82 if(rot & 1)
84 t = i->width;
85 i->width = i->height;
86 i->height = t;
92 static inline void do_enlarge(struct image *i, int screen_width, int screen_height, int ignoreaspect)
94 if(((i->width > screen_width) || (i->height > screen_height)) && (!ignoreaspect))
95 return;
96 if((i->width < screen_width) || (i->height < screen_height))
98 int xsize = i->width, ysize = i->height;
99 unsigned char * image, * alpha = NULL;
101 if(ignoreaspect)
103 if(i->width < screen_width)
104 xsize = screen_width;
105 if(i->height < screen_height)
106 ysize = screen_height;
108 goto have_sizes;
111 if((i->height * screen_width / i->width) <= screen_height)
113 xsize = screen_width;
114 ysize = i->height * screen_width / i->width;
115 goto have_sizes;
118 if((i->width * screen_height / i->height) <= screen_width)
120 xsize = i->width * screen_height / i->height;
121 ysize = screen_height;
122 goto have_sizes;
124 return;
125 have_sizes:
126 image = simple_resize(i->rgb, i->width, i->height, xsize, ysize);
127 if(i->alpha)
128 alpha = alpha_resize(i->alpha, i->width, i->height, xsize, ysize);
130 if(i->do_free)
132 free(i->alpha);
133 free(i->rgb);
136 i->rgb = image;
137 i->alpha = alpha;
138 i->do_free = 1;
139 i->width = xsize;
140 i->height = ysize;
145 static inline void do_fit_to_screen(struct image *i, int screen_width, int screen_height, int ignoreaspect, int cal)
147 if((i->width > screen_width) || (i->height > screen_height))
149 unsigned char * new_image, * new_alpha = NULL;
150 int nx_size = i->width, ny_size = i->height;
152 if(ignoreaspect)
154 if(i->width > screen_width)
155 nx_size = screen_width;
156 if(i->height > screen_height)
157 ny_size = screen_height;
159 else
161 if((i->height * screen_width / i->width) <= screen_height)
163 nx_size = screen_width;
164 ny_size = i->height * screen_width / i->width;
166 else
168 nx_size = i->width * screen_height / i->height;
169 ny_size = screen_height;
173 if(cal)
174 new_image = color_average_resize(i->rgb, i->width, i->height, nx_size, ny_size);
175 else
176 new_image = simple_resize(i->rgb, i->width, i->height, nx_size, ny_size);
178 if(i->alpha)
179 new_alpha = alpha_resize(i->alpha, i->width, i->height, nx_size, ny_size);
181 if(i->do_free)
183 free(i->alpha);
184 free(i->rgb);
187 i->rgb = new_image;
188 i->alpha = new_alpha;
189 i->do_free = 1;
190 i->width = nx_size;
191 i->height = ny_size;
196 int show_image(char *filename)
198 int (*load)(char *, unsigned char *, unsigned char **, int, int);
200 unsigned char * image = NULL;
201 unsigned char * alpha = NULL;
203 int x_size, y_size, screen_width, screen_height;
204 int x_pan = 0, y_pan = 0, x_offs = 0, y_offs = 0, refresh = 1, c, ret = 1;
205 int delay = opt_delay, retransform = 1;
207 int transform_stretch = opt_stretch, transform_enlarge = opt_enlarge, transform_cal = (opt_stretch == 2),
208 transform_iaspect = opt_ignore_aspect, transform_rotation = 0;
210 struct image i;
211 memset(&i, 0, sizeof(struct image));
213 #ifdef FBV_SUPPORT_GIF
214 if(fh_gif_id(filename))
215 if(fh_gif_getsize(filename, &x_size, &y_size) == FH_ERROR_OK)
217 load = fh_gif_load;
218 goto identified;
220 #endif
222 #ifdef FBV_SUPPORT_PNG
223 if(fh_png_id(filename))
224 if(fh_png_getsize(filename, &x_size, &y_size) == FH_ERROR_OK)
226 load = fh_png_load;
227 goto identified;
229 #endif
231 #ifdef FBV_SUPPORT_JPEG
232 if(fh_jpeg_id(filename))
233 if(fh_jpeg_getsize(filename, &x_size, &y_size) == FH_ERROR_OK)
235 load = fh_jpeg_load;
236 goto identified;
238 #endif
240 #ifdef FBV_SUPPORT_BMP
241 if(fh_bmp_id(filename))
242 if(fh_bmp_getsize(filename, &x_size, &y_size) == FH_ERROR_OK)
244 load = fh_bmp_load;
245 goto identified;
247 #endif
248 fprintf(stderr, "%s: Unable to access file or file format unknown.\n", filename);
249 return(1);
251 identified:
253 if(!(image = (unsigned char*) malloc(x_size * y_size * 3)))
255 fprintf(stderr, "%s: Out of memory.\n", filename);
256 goto error_mem;
259 if(load(filename, image, &alpha, x_size, y_size) != FH_ERROR_OK)
261 fprintf(stderr, "%s: Image data is corrupt?\n", filename);
262 goto error_mem;
265 if(!opt_alpha)
267 free(alpha);
268 alpha = NULL;
273 getCurrentRes(&screen_width, &screen_height);
274 i.do_free = 0;
275 while(1)
277 if(retransform)
279 if(i.do_free)
281 free(i.rgb);
282 free(i.alpha);
284 i.width = x_size;
285 i.height = y_size;
286 i.rgb = image;
287 i.alpha = alpha;
288 i.do_free = 0;
291 if(transform_rotation)
292 do_rotate(&i, transform_rotation);
294 if(transform_stretch)
295 do_fit_to_screen(&i, screen_width, screen_height, transform_iaspect, transform_cal);
297 if(transform_enlarge)
298 do_enlarge(&i, screen_width, screen_height, transform_iaspect);
300 x_pan = y_pan = 0;
301 refresh = 1; retransform = 0;
302 if(opt_clear)
304 printf("\033[H\033[J");
305 fflush(stdout);
307 if(opt_image_info)
308 printf("fbv - The Framebuffer Viewer\n%s\n%d x %d\n", filename, x_size, y_size);
310 if(refresh)
312 if(i.width < screen_width)
313 x_offs = (screen_width - i.width) / 2;
314 else
315 x_offs = 0;
317 if(i.height < screen_height)
318 y_offs = (screen_height - i.height) / 2;
319 else
320 y_offs = 0;
322 fb_display(i.rgb, i.alpha, i.width, i.height, x_pan, y_pan, x_offs, y_offs);
323 refresh = 0;
325 if(delay)
327 struct timeval tv;
328 fd_set fds;
329 tv.tv_sec = delay / 10;
330 tv.tv_usec = (delay % 10) * 100000;
331 FD_ZERO(&fds);
332 FD_SET(0, &fds);
334 if(select(1, &fds, NULL, NULL, &tv) <= 0)
335 break;
336 delay = 0;
339 c = getchar();
340 switch(c)
342 case EOF:
343 case 'q':
344 ret = 0;
345 goto done;
346 case ' ': case 10: case 13:
347 goto done;
348 case '>': case '.':
349 goto done;
350 case '<': case ',':
351 ret = -1;
352 goto done;
353 case 'r':
354 refresh = 1;
355 break;
356 case 'a': case 'D':
357 if(x_pan == 0) break;
358 x_pan -= i.width / PAN_STEPPING;
359 if(x_pan < 0) x_pan = 0;
360 refresh = 1;
361 break;
362 case 'd': case 'C':
363 if(x_offs) break;
364 if(x_pan >= (i.width - screen_width)) break;
365 x_pan += i.width / PAN_STEPPING;
366 if(x_pan > (i.width - screen_width)) x_pan = i.width - screen_width;
367 refresh = 1;
368 break;
369 case 'w': case 'A':
370 if(y_pan == 0) break;
371 y_pan -= i.height / PAN_STEPPING;
372 if(y_pan < 0) y_pan = 0;
373 refresh = 1;
374 break;
375 case 'x': case 'B':
376 if(y_offs) break;
377 if(y_pan >= (i.height - screen_height)) break;
378 y_pan += i.height / PAN_STEPPING;
379 if(y_pan > (i.height - screen_height)) y_pan = i.height - screen_height;
380 refresh = 1;
381 break;
382 case 'f':
383 transform_stretch = !transform_stretch;
384 retransform = 1;
385 break;
386 case 'e':
387 transform_enlarge = !transform_enlarge;
388 retransform = 1;
389 break;
390 case 'k':
391 transform_cal = !transform_cal;
392 retransform = 1;
393 break;
394 case 'i':
395 transform_iaspect = !transform_iaspect;
396 retransform = 1;
397 break;
398 case 'p':
399 transform_cal = 0;
400 transform_iaspect = 0;
401 transform_enlarge = 0;
402 transform_stretch = 0;
403 retransform = 1;
404 break;
405 case 'n':
406 transform_rotation -= 1;
407 if(transform_rotation < 0)
408 transform_rotation += 4;
409 retransform = 1;
410 break;
411 case 'm':
412 transform_rotation += 1;
413 if(transform_rotation > 3)
414 transform_rotation -= 4;
415 retransform = 1;
416 break;
422 done:
423 if(opt_clear)
425 printf("\033[H\033[J");
426 fflush(stdout);
429 error_mem:
430 free(image);
431 free(alpha);
432 if(i.do_free)
434 free(i.rgb);
435 free(i.alpha);
437 return(ret);
441 void help(char *name)
443 printf("Usage: %s [options] image1 image2 image3 ...\n\n"
444 "Available options:\n"
445 " --help | -h : Show this help\n"
446 " --alpha | -a : Use the alpha channel (if applicable)\n"
447 " --dontclear | -c : Do not clear the screen before and after displaying the image\n"
448 " --donthide | -u : Do not hide the cursor before and after displaying the image\n"
449 " --noinfo | -i : Supress image information\n"
450 " --stretch | -f : Strech (using a simple resizing routine) the image to fit onto screen if necessary\n"
451 " --colorstretch| -k : Strech (using a 'color average' resizing routine) the image to fit onto screen if necessary\n"
452 " --enlarge | -e : Enlarge the image to fit the whole screen if necessary\n"
453 " --ignore-aspect| -r : Ignore the image aspect while resizing\n"
454 " --delay <d> | -s <delay> : Slideshow, 'delay' is the slideshow delay in tenths of seconds.\n\n"
455 "Keys:\n"
456 " r : Redraw the image\n"
457 " a, d, w, x : Pan the image\n"
458 " f : Toggle resizing on/off\n"
459 " k : Toggle resizing quality\n"
460 " e : Toggle enlarging on/off\n"
461 " i : Toggle respecting the image aspect on/off\n"
462 " n : Rotate the image 90 degrees left\n"
463 " m : Rotate the image 90 degrees right\n"
464 " p : Disable all transformations\n"
465 "Copyright (C) 2000 - 2004 Mateusz Golicz, Tomasz Sterna.\n", name);
468 void sighandler(int s)
470 if(opt_hide_cursor)
472 printf("\033[?25h");
473 fflush(stdout);
475 setup_console(0);
476 _exit(128 + s);
480 int main(int argc, char **argv)
482 static struct option long_options[] =
484 {"help", no_argument, 0, 'h'},
485 {"noclear", no_argument, 0, 'c'},
486 {"alpha", no_argument, 0, 'a'},
487 {"unhide", no_argument, 0, 'u'},
488 {"noinfo", no_argument, 0, 'i'},
489 {"stretch", no_argument, 0, 'f'},
490 {"colorstrech", no_argument, 0, 'k'},
491 {"delay", required_argument, 0, 's'},
492 {"enlarge", no_argument, 0, 'e'},
493 {"ignore-aspect", no_argument, 0, 'r'},
494 {0, 0, 0, 0}
496 int c, i;
498 if(argc < 2)
500 help(argv[0]);
501 fprintf(stderr, "Error: Required argument missing.\n");
502 return(1);
505 while((c = getopt_long_only(argc, argv, "hcauifks:er", long_options, NULL)) != EOF)
507 switch(c)
509 case 'a':
510 opt_alpha = 1;
511 break;
512 case 'c':
513 opt_clear = 0;
514 break;
515 case 's':
516 opt_delay = atoi(optarg);
517 break;
518 case 'u':
519 opt_hide_cursor = 0;
520 break;
521 case 'h':
522 help(argv[0]);
523 return(0);
524 case 'i':
525 opt_image_info = 0;
526 break;
527 case 'f':
528 opt_stretch = 1;
529 break;
530 case 'k':
531 opt_stretch = 2;
532 break;
533 case 'e':
534 opt_enlarge = 1;
535 break;
536 case 'r':
537 opt_ignore_aspect = 1;
538 break;
543 if(!argv[optind])
545 fprintf(stderr, "Required argument missing! Consult %s -h.\n", argv[0]);
546 return(1);
549 signal(SIGHUP, sighandler);
550 signal(SIGINT, sighandler);
551 signal(SIGQUIT, sighandler);
552 signal(SIGSEGV, sighandler);
553 signal(SIGTERM, sighandler);
554 signal(SIGABRT, sighandler);
556 if(opt_hide_cursor)
558 printf("\033[?25l");
559 fflush(stdout);
562 setup_console(1);
564 for(i = optind; argv[i]; )
566 int r = show_image(argv[i]);
568 if(!r) break;
570 i += r;
571 if(i < optind)
572 i = optind;
575 setup_console(0);
577 if(opt_hide_cursor)
579 printf("\033[?25h");
580 fflush(stdout);
582 return(0);