📄 fbi.c
字号:
/* * image viewer, for framebuffer devices * * (c) 1998-2002 Gerd Knorr <kraxel@bytesex.org> * */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <time.h>#include <fcntl.h>#include <errno.h>#include <termios.h>#include <getopt.h>#include <math.h>#include <setjmp.h>#include <signal.h>#include <ctype.h>#include <locale.h>#include <sys/time.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <linux/fb.h>#include <jpeglib.h>#ifdef HAVE_LIBEXIF# include <libexif/exif-data.h>#endif#ifdef HAVE_LIBLIRC# include "lirc/lirc_client.h"# include "lirc.h"#endif#include "loader.h"#include "dither.h"#include "fbtools.h"#include "fb-gui.h"#include "filter.h"#include "list.h"#include "jpeg/transupp.h" /* Support routines for jpegtran */#include "jpegtools.h"#define TRUE 1#define FALSE 0#define MAX(x,y) ((x)>(y)?(x):(y))#define MIN(x,y) ((x)<(y)?(x):(y))#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))#define KEY_EOF -1 /* ^D */#define KEY_ESC -2#define KEY_SPACE -3#define KEY_Q -4#define KEY_PGUP -5#define KEY_PGDN -6#define KEY_TIMEOUT -7#define KEY_TAGFILE -8#define KEY_PLUS -9#define KEY_MINUS -10#define KEY_VERBOSE -11#define KEY_ASCALE -12#define KEY_DESC -13/* with arg */#define KEY_GOTO -100#define KEY_SCALE -101/* edit */#define KEY_DELETE -200#define KEY_ROT_CW -201#define KEY_ROT_CCW -202#define DEFAULT_DEVICE "/dev/fb0"/* ---------------------------------------------------------------------- *//* lirc fd */int lirc = -1;/* variables for read_image */int32_t lut_red[256], lut_green[256], lut_blue[256];int dither = FALSE, pcd_res = 3, steps = 50;int textreading = 0, redraw = 0, statusline = 1;int new_image;int left, top;/* file list */struct flist { int nr; int tag; char *name; struct list_head list;};static LIST_HEAD(flist);static int fcount;static struct flist *fcurrent;/* framebuffer */char *fbdev = NULL;char *fbmode = NULL;int fd, switch_last, debug;unsigned short red[256], green[256], blue[256];struct fb_cmap cmap = { 0, 256, red, green, blue };static float fbgamma = 1;/* Command line options. */int autodown = 0;int autoup = 0;int comments = 0;struct option fbi_options[] = { {"version", no_argument, NULL, 'V'}, /* version */ {"help", no_argument, NULL, 'h'}, /* help */ {"device", required_argument, NULL, 'd'}, /* device */ {"mode", required_argument, NULL, 'm'}, /* video mode */ {"gamma", required_argument, NULL, 'g'}, /* set gamma */ {"quiet", no_argument, NULL, 'q'}, /* quiet */ {"verbose", no_argument, NULL, 'v'}, /* verbose */ {"scroll", required_argument, NULL, 's'}, /* set scrool */ {"timeout", required_argument, NULL, 't'}, /* timeout value */ {"once", no_argument, NULL, '1'}, /* loop only once */ {"resolution", required_argument, NULL, 'r'}, /* select resolution */ {"random", no_argument, NULL, 'u'}, /* randomize images */ {"font", required_argument, NULL, 'f'}, /* font */ {"autozoom", no_argument, NULL, 'a'}, {"edit", no_argument, NULL, 'e'}, /* enable editing */ {"list", required_argument, NULL, 'l'}, {"vt", required_argument, NULL, 'T'}, {"backup", no_argument, NULL, 'b'}, {"preserve", no_argument, NULL, 'p'}, /* long-only options */ {"autoup", no_argument, &autoup, 1 }, {"autodown", no_argument, &autodown, 1 }, {"comments", no_argument, &comments, 1 }, {0,0,0,0}};/* font handling */static char *fontname = NULL;/* ---------------------------------------------------------------------- */static voidversion(void){ fprintf(stderr, "fbi version " VERSION " (c) 1999-2003 Gerd Knorr; compiled on %s.\n", __DATE__ );}static voidusage(char *name){ char *h; if (NULL != (h = strrchr(name, '/'))) name = h+1; fprintf(stderr, "\n" "This program displays images using the Linux framebuffer device.\n" "Supported formats: PhotoCD, jpeg, ppm, gif, tiff, xwd, bmp, png.\n" "It tries to use ImageMagick's convert for unknown file formats.\n" "\n" " Usage: %s [ options ] file1 file2 ... fileN\n" "\n" " --help [-h] Print this text\n" " --version [-V] Show the fbi version number\n" " --device [-d] dev Framebuffer device [%s]\n" " --mode [-m] mode Video mode (must be listed in /etc/fb.modes)\n" " - Default is current mode.\n" " --gamma [-g] f Set gamma\n" " --scroll [-s] n Set scroll steps in pixels (default: 50)\n" " --quiet [-q] don't print anything at all\n" " --verbose [-v] show print filenames all the time\n" " --timeout [-t] n Load next image after N sec without any keypress\n" " --once [-1] Don't loop (for use with -t).\n" " --resolution [-r] n Select resolution [1..5] (PhotoCD)\n" " --random [-u] Show file1 .. fileN in a random order\n" " --font [-f] fn Use font fn (either console psf file or\n" " X11 font spec if a font server is available\n" " --autozoom [-a] Automagically pick useful zoom factor.\n" " --autoup Like the above, but upscale only.\n" " --autodown Like the above, but downscale only.\n" " --edit [-e] enable editing commands (see man page).\n" " --backup [-b] create backup files when editing.\n" " --preserve [-p] preserve timestamps when editing.\n" " --list [-l] file read list of images from file\n" " --comments display image comments\n" " --vt [-T] vt start on console #vt\n" "\n" "Large images can be scrolled using the cursor keys. Zoom in/out\n" "works with '+' and '-'. Use ESC or 'q' to quit. Space and PgDn\n" "show the next, PgUp shows the previous image. Jumping to a image\n" "works with <number>g. Return acts like Space but additionally\n" "prints the filename of the currently displayed image to stdout.\n" "\n", name, fbdev ? fbdev : "/dev/fb0");}/* ---------------------------------------------------------------------- */static int flist_add(char *filename){ struct flist *f; f = malloc(sizeof(*f)); memset(f,0,sizeof(*f)); f->name = strdup(filename); list_add_tail(&f->list,&flist); return 0;}static int flist_add_list(char *listfile){ char filename[256]; FILE *list; list = fopen(listfile,"r"); if (NULL == list) { fprintf(stderr,"open %s: %s\n",listfile,strerror(errno)); return -1; } while (NULL != fgets(filename,sizeof(filename)-1,list)) { size_t off = strcspn(filename,"\r\n"); if (off) filename[off] = 0; flist_add(filename); } fclose(list); return 0;}static int flist_del(struct flist *f){ list_del(&f->list); free(f->name); free(f); return 0;}static void flist_renumber(void){ struct list_head *item; struct flist *f; int i = 0; list_for_each(item,&flist) { f = list_entry(item, struct flist, list); f->nr = ++i; } fcount = i;}static int flist_islast(struct flist *f){ return (&flist == f->list.next) ? 1 : 0;}static int flist_isfirst(struct flist *f){ return (&flist == f->list.prev) ? 1 : 0;}static struct flist* flist_first(void){ return list_entry(flist.next, struct flist, list);}static struct flist* flist_next(struct flist *f, int eof, int loop){ if (flist_islast(f)) { if (eof) return NULL; if (loop) return flist_first(); return f; } return list_entry(f->list.next, struct flist, list);}static struct flist* flist_prev(struct flist *f){ if (flist_isfirst(f)) return f; return list_entry(f->list.prev, struct flist, list);}static struct flist* flist_goto(int dest){ struct list_head *item; struct flist *f; list_for_each(item,&flist) { f = list_entry(item, struct flist, list); if (f->nr == dest) return f; } return NULL;}static void flist_randomize(void){ struct flist *f; int count; srand((unsigned)time(NULL)); flist_renumber(); for (count = fcount; count > 0; count--) { f = flist_goto((rand() % count)+1); list_del(&f->list); list_add_tail(&f->list,&flist); flist_renumber(); }}static void flist_print_tagged(FILE *fp){ struct list_head *item; struct flist *f; list_for_each(item,&flist) { f = list_entry(item, struct flist, list); if (f->tag) fprintf(fp,"%s\n",f->name); }}/* ---------------------------------------------------------------------- */static void status(unsigned char *desc, char *info){ int chars, ilen; char *str; if (!statusline) return; chars = fb_var.xres / fb_font_width(); str = malloc(chars+1); if (info) { ilen = strlen(info); sprintf(str, "%-*.*s [ %s ] H - Help", chars-14-ilen, chars-14-ilen, desc, info); } else { sprintf(str, "%-*.*s | H - Help", chars-11, chars-11, desc); } fb_status_line(str); free(str);}static void show_error(unsigned char *msg){ fb_status_line(msg); sleep(2);}static void show_exif(struct flist *f){#ifdef HAVE_LIBEXIF static unsigned int tags[] = { 0x010f, // Manufacturer 0x0110, // Model 0x0112, // Orientation 0x0132, // Date and Time 0x01e3, // White Point 0x829a, // Exposure Time 0x829d, // FNumber 0x9206, // Subject Distance 0xa40c, // Subject Distance Range 0xa405, // Focal Length In 35mm Film 0x9209, // Flash }; ExifData *ed; ExifEntry *ee; unsigned int tag,l1,l2,len,count,i; const char *title[ARRAY_SIZE(tags)]; char *value[ARRAY_SIZE(tags)]; char *linebuffer[ARRAY_SIZE(tags)]; if (!visible) return; ed = exif_data_new_from_file(f->name); if (NULL == ed) { status("image has no EXIF data", NULL); return; } /* pass one -- get data + calc size */ l1 = 0; l2 = 0; for (tag = 0; tag < ARRAY_SIZE(tags); tag++) { ee = exif_content_get_entry (ed->ifd[EXIF_IFD_0], tags[tag]); if (NULL == ee) ee = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF], tags[tag]); if (NULL == ee) { title[tag] = NULL; value[tag] = NULL; continue; } title[tag] = exif_tag_get_title(tags[tag]); value[tag] = strdup(exif_entry_get_value(ee)); len = strlen(title[tag]); if (l1 < len) l1 = len; len = strlen(value[tag]); if (l2 < len) l2 = len; } /* pass two -- print stuff */ count = 0; for (tag = 0; tag < ARRAY_SIZE(tags); tag++) { if (NULL == title[tag]) continue; linebuffer[count] = malloc(l1+l2+8); sprintf(linebuffer[count],"%-*.*s : %-*.*s", l1, l1, title[tag], l2, l2, value[tag]); count++; } fb_text_box(24,16,linebuffer,count); /* pass three -- free data */ for (tag = 0; tag < ARRAY_SIZE(tags); tag++) if (NULL != value[tag]) free(value[tag]); exif_data_unref (ed); for (i = 0; i < count; i++) free(linebuffer[i]);#else status("compiled without EXIF support, sorry",NULL);#endif}static void show_help(void){ static char *help[] = { "keyboard commands", "~~~~~~~~~~~~~~~~~", " ESC, Q - quit", " pgdn, space - next image", " pgup - previous image", " +/- - zoom in/out", " A - autozoom image", " cursor keys - scroll image", "", " H - show this help text", " I - show EXIF info", " P - pause slideshow", " V - toggle statusline", "", "available if started with --edit switch,", "rotation works for jpeg images only:", " shift+D - delete image", " R - rotate clockwise", " L - rotate counter-clockwise", }; fb_text_box(24,16,help,ARRAY_SIZE(help));}/* ---------------------------------------------------------------------- */struct termios saved_attributes;int saved_fl;static voidtty_raw(void){ struct termios tattr; fcntl(0,F_GETFL,&saved_fl); tcgetattr (0, &saved_attributes); fcntl(0,F_SETFL,O_NONBLOCK); memcpy(&tattr,&saved_attributes,sizeof(struct termios)); tattr.c_lflag &= ~(ICANON|ECHO); tattr.c_cc[VMIN] = 1; tattr.c_cc[VTIME] = 0; tcsetattr (0, TCSAFLUSH, &tattr);}static voidtty_restore(void){ fcntl(0,F_SETFL,saved_fl); tcsetattr (0, TCSANOW, &saved_attributes);}/* testing: find key codes */static void debug_key(char *key){ char linebuffer[128]; int i,len; len = sprintf(linebuffer,"key: "); for (i = 0; key[i] != '\0'; i++) len += sprintf(linebuffer+len, "%s%c", key[i] < 0x20 ? "^" : "", key[i] < 0x20 ? key[i] + 0x40 : key[i]); status(linebuffer, NULL);}static voidconsole_switch(int is_busy){ switch (fb_switch_state) { case FB_REL_REQ: fb_switch_release(); case FB_INACTIVE: visible = 0; break; case FB_ACQ_REQ: fb_switch_acquire(); case FB_ACTIVE: visible = 1; redraw = 1; ioctl(fd,FBIOPAN_DISPLAY,&fb_var); fb_clear_screen(); if (is_busy) status("busy, please wait ...", NULL); break; default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -