2 * fbpdf - a small framebuffer pdf viewer using mupdf
4 * Copyright (C) 2009-2016 Ali Gholami Rudi <ali at rudi dot ir>
6 * This program is released under the Modified BSD license.
18 #define MIN(a, b) ((a) < (b) ? (a) : (b))
19 #define MAX(a, b) ((a) > (b) ? (a) : (b))
24 #define CTRLKEY(x) ((x) - 96)
25 #define ISMARK(x) (isalpha(x) || (x) == '\'' || (x) == '`')
27 static struct doc
*doc
;
28 static fbval_t
*pbuf
; /* current page */
29 static int srows
, scols
; /* screen dimentions */
30 static int prows
, pcols
; /* current page dimensions */
31 static int prow
, pcol
; /* page position */
32 static int srow
, scol
; /* screen position */
34 static struct termios termios
;
35 static char filename
[256];
36 static int mark
[128]; /* mark page number */
37 static int mark_row
[128]; /* mark head position */
38 static int num
= 1; /* page number */
39 static int numdiff
; /* G command page number difference */
41 static int zoom_def
= 15; /* default zoom */
45 static void draw(void)
48 fbval_t
*rbuf
= malloc(scols
* sizeof(rbuf
[0]));
49 for (i
= srow
; i
< srow
+ srows
; i
++) {
50 int cbeg
= MAX(scol
, pcol
);
51 int cend
= MIN(scol
+ scols
, pcol
+ pcols
);
52 memset(rbuf
, 0, scols
* sizeof(rbuf
[0]));
53 if (i
>= prow
&& i
< prow
+ prows
&& cbeg
< cend
) {
54 memcpy(rbuf
+ cbeg
- scol
,
55 pbuf
+ (i
- prow
) * pcols
+ cbeg
- pcol
,
56 (cend
- cbeg
) * sizeof(rbuf
[0]));
58 fb_set(i
- srow
, 0, rbuf
, scols
);
63 static int loadpage(int p
)
65 if (p
< 1 || p
> doc_pages(doc
))
69 pbuf
= doc_draw(doc
, p
, zoom
, rotate
, &prows
, &pcols
);
76 static void zoom_page(int z
)
79 zoom
= MIN(MAXZOOM
, MAX(1, z
));
81 srow
= srow
* zoom
/ _zoom
;
84 static void setmark(int c
)
88 mark_row
[c
] = srow
/ zoom
;
92 static void jmpmark(int c
, int offset
)
96 if (ISMARK(c
) && mark
[c
]) {
98 int dst_row
= offset
? mark_row
[c
] * zoom
: 0;
101 srow
= offset
? dst_row
: prow
;
105 static int readkey(void)
108 if (read(0, &b
, 1) <= 0)
113 static int getcount(int def
)
115 int result
= count
? count
: def
;
120 static void printinfo(void)
123 printf("FBPDF: file:%s page:%d(%d) zoom:%d%% \x1b[K\r",
124 filename
, num
, doc_pages(doc
), zoom
* 10);
128 static void term_setup(void)
130 struct termios newtermios
;
131 tcgetattr(0, &termios
);
132 newtermios
= termios
;
133 newtermios
.c_lflag
&= ~ICANON
;
134 newtermios
.c_lflag
&= ~ECHO
;
135 tcsetattr(0, TCSAFLUSH
, &newtermios
);
136 printf("\x1b[?25l"); /* hide the cursor */
137 printf("\x1b[2J"); /* clear the screen */
141 static void term_cleanup(void)
143 tcsetattr(0, 0, &termios
);
144 printf("\x1b[?25h\n"); /* show the cursor */
147 static void sigcont(int sig
)
152 static int reload(void)
155 doc
= doc_open(filename
);
156 if (!doc
|| !doc_pages(doc
)) {
157 fprintf(stderr
, "\nfbpdf: cannot open <%s>\n", filename
);
165 static int rmargin(void)
169 for (i
= 0; i
< prows
; i
++) {
171 while (j
> ret
&& pbuf
[i
* pcols
+ j
] == FB_VAL(255, 255, 255))
179 static int lmargin(void)
183 for (i
= 0; i
< prows
; i
++) {
185 while (j
< ret
&& pbuf
[i
* pcols
+ j
] == FB_VAL(255, 255, 255))
193 static void mainloop(void)
195 int step
= srows
/ PAGESTEPS
;
196 int hstep
= scols
/ PAGESTEPS
;
199 signal(SIGCONT
, sigcont
);
204 while ((c
= readkey()) != -1) {
207 if (c
== 'e' && reload())
209 switch (c
) { /* commands that do not require redrawing */
211 numdiff
= num
- getcount(num
);
214 zoom_def
= getcount(zoom
);
230 count
= count
* 10 + c
- '0';
232 switch (c
) { /* commands that require redrawing */
235 if (!loadpage(num
+ getcount(1)))
240 if (!loadpage(num
- getcount(1)))
245 if (!loadpage(getcount(doc_pages(doc
) - numdiff
) + numdiff
))
249 numdiff
= num
- getcount(num
);
251 if (!loadpage(num
+ numdiff
))
255 zoom_page(getcount(zoom_def
));
258 zoom_page(pcols
? zoom
* scols
/ pcols
: zoom
);
261 if (lmargin() < rmargin())
262 zoom_page(zoom
* (scols
- hstep
) /
263 (rmargin() - lmargin()));
266 zoom_page(prows
? zoom
* srows
/ prows
: zoom
);
269 rotate
= getcount(0);
275 jmpmark(readkey(), c
== '`');
278 srow
+= step
* getcount(1);
281 srow
-= step
* getcount(1);
284 scol
+= hstep
* getcount(1);
287 scol
-= hstep
* getcount(1);
293 srow
= prow
+ prows
- srows
;
296 srow
= prow
+ prows
/ 2 - srows
/ 2;
303 srow
+= srows
* getcount(1) - step
;
307 srow
-= srows
* getcount(1) - step
;
313 scol
= pcol
+ pcols
- scols
;
316 scol
= pcol
+ lmargin() - hstep
/ 2;
319 scol
= pcol
+ rmargin() + hstep
/ 2 - scols
;
323 default: /* no need to redraw */
326 srow
= MAX(prow
- srows
+ MARGIN
, MIN(prow
+ prows
- MARGIN
, srow
));
327 scol
= MAX(pcol
- scols
+ MARGIN
, MIN(pcol
+ pcols
- MARGIN
, scol
));
334 "usage: fbpdf [-r rotation] [-z zoom x10] [-p page] filename\n";
336 int main(int argc
, char *argv
[])
343 strcpy(filename
, argv
[argc
- 1]);
344 doc
= doc_open(filename
);
345 if (!doc
|| !doc_pages(doc
)) {
346 fprintf(stderr
, "fbpdf: cannot open <%s>\n", filename
);
349 for (i
= 1; i
< argc
&& argv
[i
][0] == '-'; i
++) {
350 switch (argv
[i
][1]) {
352 rotate
= atoi(argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
]);
355 zoom
= atoi(argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
]);
358 num
= atoi(argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
]);
367 if (FBM_BPP(fb_mode()) != sizeof(fbval_t
))
368 fprintf(stderr
, "fbpdf: fbval_t doesn't match fb depth\n");