fbvis: ignore directories
[fbvis.git] / fbvis.c
blob4f505843e70a4635ebef24ceb27b630d284c6f1d
1 /*
2 * fbvis - a framebuffer image viewer
4 * Copyright (C) 2013 Ali Gholami Rudi
6 * This file is released under the modified BSD license.
7 */
8 #include <ctype.h>
9 #include <signal.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <pty.h>
15 #include "draw.h"
16 #include "lodepng.h"
18 /* optimized version of fb_val() */
19 #define FB_VAL(r, g, b) fb_val(r, g, b)
21 #define PAGESTEPS 8
22 #define CTRLKEY(x) ((x) - 96)
23 #define MIN(a, b) ((a) < (b) ? (a) : (b))
24 #define MAX(a, b) ((a) > (b) ? (a) : (b))
25 #define REGION(a, b, x) (MIN(b, MAX(x, a)))
27 static unsigned char *obuf; /* original image */
28 static int ocols, orows; /* obuf dimensions */
29 static int ch; /* bytes per pixel */
30 static unsigned char *buf; /* zoomed image for framebuffer */
31 static int cols, rows; /* buf dimensions */
32 static int czoom; /* current zoom */
33 static int head, left; /* current viewing position */
34 static int count; /* command prefix */
35 static struct termios termios;
36 static char **files;
37 static int curfile = -1;
39 #define ZOOM_ORIG 0
40 #define ZOOM_FITHT 1
41 #define ZOOM_FITWID 2
43 static void zoom(int z)
45 int bpp = FBM_BPP(fb_mode());
46 int i, j;
47 int c = 100;
48 if (z == ZOOM_FITHT)
49 c = 100 * fb_rows() / orows;
50 if (z == ZOOM_FITWID)
51 c = 100 * fb_cols() / ocols;
52 czoom = z;
53 cols = ocols * c / 100;
54 rows = orows * c / 100;
55 buf = malloc(rows * cols * bpp);
56 for (i = 0; i < rows; i++) {
57 for (j = 0; j < cols; j++) {
58 unsigned char *src = obuf + (i * 100 / c * ocols +
59 j * 100 / c) * ch;
60 unsigned int *dst = (void *) buf + (i * cols + j) * bpp;
61 *dst = FB_VAL(src[0], src[1], src[2]);
66 static void draw(void)
68 int bpp = FBM_BPP(fb_mode());
69 int rs = head;
70 int re = rs + MIN(rows - rs, fb_rows());
71 int cs = left;
72 int ce = cs + MIN(cols - cs, fb_cols());
73 int fbr = (fb_rows() - (re - rs)) >> 1;
74 int fbc = (fb_cols() - (ce - cs)) >> 1;
75 int i;
76 for (i = rs; i < re; i++)
77 fb_set(fbr + i - rs, fbc, buf + (i * cols + cs) * bpp, ce - cs);
80 unsigned char *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp);
81 char *ppm_load(char *path, int *h, int *w);
83 static int loadfile(char *path)
85 FILE *fp = fopen(path, "r");
86 obuf = NULL;
87 if (!fp)
88 return 1;
89 fclose(fp);
90 ch = 4;
91 lodepng_decode32_file(&obuf, (void *) &ocols, (void *) &orows, path);
92 if (!obuf)
93 obuf = stbi_load(path, &ocols, &orows, &ch, 0);
94 if (!obuf) {
95 ch = 3;
96 obuf = (void *) ppm_load(path, &orows, &ocols);
98 return !obuf;
101 static void printinfo(void)
103 printf("\rFBVIS: file:%s\x1b[K\r", files[curfile]);
104 fflush(stdout);
107 static void freebufs(void)
109 free(buf);
110 free(obuf);
111 buf = NULL;
112 obuf = NULL;
115 static int nextfile(int dir)
117 freebufs();
118 head = 0;
119 while (1) {
120 curfile += dir;
121 if (curfile < 0 || !files[curfile])
122 return 1;
123 if (!loadfile(files[curfile]))
124 break;
125 else
126 printf("failed to load image <%s>\n", files[curfile]);
128 zoom(czoom);
129 printinfo();
130 return 0;
133 static int readkey(void)
135 unsigned char b;
136 if (read(0, &b, 1) <= 0)
137 return -1;
138 return b;
141 static int getcount(int def)
143 int result = count ? count : def;
144 count = 0;
145 return result;
148 static void term_setup(void)
150 struct termios newtermios;
151 tcgetattr(0, &termios);
152 newtermios = termios;
153 newtermios.c_lflag &= ~ICANON;
154 newtermios.c_lflag &= ~ECHO;
155 tcsetattr(0, TCSAFLUSH, &newtermios);
158 static void term_cleanup(void)
160 tcsetattr(0, 0, &termios);
163 static void mainloop(void)
165 int step = fb_rows() / PAGESTEPS;
166 int hstep = fb_cols() / PAGESTEPS;
167 int c;
168 term_setup();
169 draw();
170 while ((c = readkey()) != -1) {
171 switch (c) {
172 case 'j':
173 head += step * getcount(1);
174 break;
175 case 'k':
176 head -= step * getcount(1);
177 break;
178 case 'l':
179 left += hstep * getcount(1);
180 break;
181 case 'h':
182 left -= hstep * getcount(1);
183 break;
184 case 'H':
185 head = 0;
186 break;
187 case 'L':
188 head = MAX(0, rows - fb_rows());
189 break;
190 case 'M':
191 head = MAX(0, (rows - fb_rows()) >> 1);
192 break;
193 case ' ':
194 case CTRL('d'):
195 head += fb_rows() * getcount(1) - step;
196 break;
197 case 127:
198 case CTRL('u'):
199 head -= fb_rows() * getcount(1) - step;
200 break;
201 case 'f':
202 zoom(czoom == ZOOM_FITHT ? ZOOM_ORIG : ZOOM_FITHT);
203 break;
204 case 'w':
205 zoom(czoom == ZOOM_FITWID ? ZOOM_ORIG : ZOOM_FITWID);
206 break;
207 case 'r':
208 case CTRLKEY('l'):
209 break;
210 case CTRLKEY('f'):
211 case CTRLKEY('b'):
212 if (!nextfile(c == CTRLKEY('f') ? getcount(1) : -getcount(1)))
213 break;
214 case 'q':
215 term_cleanup();
216 return;
217 case 'i':
218 printinfo();
219 default:
220 if (c == 'd')
221 sleep(getcount(1));
222 if (isdigit(c))
223 count = count * 10 + c - '0';
224 if (c == 27)
225 count = 0;
226 /* no need to redraw */
227 continue;
229 head = REGION(0, MAX(0, rows - fb_rows()), head);
230 left = REGION(0, MAX(0, cols - fb_cols()), left);
231 draw();
235 int main(int argc, char *argv[])
237 if (argc < 2) {
238 printf("usage: %s file\n", argv[0]);
239 return 0;
241 files = argv + 1;
242 if (fb_init())
243 return 1;
244 if (nextfile(1)) {
245 fb_free();
246 return 1;
248 mainloop();
249 fb_free();
250 freebufs();
251 printf("\n");
252 return 0;