stb_image: update to 64fa9a3d of stb.git
[fbvis.git] / fbvis.c
blobd683828c512121a102ef986710970903d8f0c850
1 /*
2 * fbvis - a framebuffer image viewer
4 * Copyright (C) 2013-2014 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 draw();
169 while ((c = readkey()) != -1) {
170 switch (c) {
171 case 'j':
172 head += step * getcount(1);
173 break;
174 case 'k':
175 head -= step * getcount(1);
176 break;
177 case 'l':
178 left += hstep * getcount(1);
179 break;
180 case 'h':
181 left -= hstep * getcount(1);
182 break;
183 case 'H':
184 head = 0;
185 break;
186 case 'L':
187 head = MAX(0, rows - fb_rows());
188 break;
189 case 'M':
190 head = MAX(0, (rows - fb_rows()) >> 1);
191 break;
192 case ' ':
193 case CTRLKEY('d'):
194 head += fb_rows() * getcount(1) - step;
195 break;
196 case 127:
197 case CTRLKEY('u'):
198 head -= fb_rows() * getcount(1) - step;
199 break;
200 case 'f':
201 zoom(ZOOM_FITHT);
202 break;
203 case 'w':
204 zoom(ZOOM_FITWID);
205 break;
206 case 'z':
207 zoom(ZOOM_ORIG);
208 break;
209 case 'r':
210 case CTRLKEY('l'):
211 break;
212 case CTRLKEY('f'):
213 case 'J':
214 case 'n':
215 if (nextfile(getcount(1)))
216 return;
217 break;
218 case CTRLKEY('b'):
219 case 'K':
220 case 'p':
221 if (nextfile(-getcount(1)))
222 return;
223 break;
224 case 'q':
225 return;
226 case 'i':
227 printinfo();
228 default:
229 if (c == 'd')
230 sleep(getcount(1));
231 if (isdigit(c))
232 count = count * 10 + c - '0';
233 if (c == 27)
234 count = 0;
235 /* no need to redraw */
236 continue;
238 head = REGION(0, MAX(0, rows - fb_rows()), head);
239 left = REGION(0, MAX(0, cols - fb_cols()), left);
240 draw();
244 int main(int argc, char *argv[])
246 if (argc < 2) {
247 printf("usage: %s file\n", argv[0]);
248 return 0;
250 files = argv + 1;
251 if (fb_init())
252 return 1;
253 if (nextfile(1)) {
254 fb_free();
255 return 1;
257 term_setup();
258 mainloop();
259 term_cleanup();
260 fb_free();
261 freebufs();
262 printf("\n");
263 return 0;