2 * fbpdf - a small framebuffer pdf viewer using mupdf
4 * Copyright (C) 2009-2014 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))
22 #define CTRLKEY(x) ((x) - 96)
23 #define ISMARK(x) (isalpha(x) || (x) == '\'' || (x) == '`')
26 #define PDFCOLS (1 << 11)
27 #define PDFROWS (1 << 12)
30 static struct doc
*doc
;
31 static fbval_t pbuf
[PDFROWS
* PDFCOLS
]; /* current page */
32 static int prows
, pcols
; /* the dimensions of current page */
34 static struct termios termios
;
35 static char filename
[256];
36 static int mark
[128]; /* mark page number */
37 static int mark_head
[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 */
47 static void draw(void)
50 for (i
= head
; i
< MIN(head
+ fb_rows(), PDFROWS
); i
++)
51 fb_set(i
- head
, 0, pbuf
+ i
* PDFCOLS
+ left
, fb_cols());
54 static int showpage(int p
, int h
)
56 if (p
< 1 || p
> doc_pages(doc
))
58 memset(pbuf
, 0x00, sizeof(pbuf
));
61 doc_draw(doc
, p
, zoom
, rotate
, pbuf
, &prows
, &pcols
);
68 static void zoom_page(int z
)
71 zoom
= MIN(MAXZOOM
, MAX(1, z
));
72 showpage(num
, MIN(PDFROWS
- fb_rows(), head
* zoom
/ _zoom
));
75 static void setmark(int c
)
79 mark_head
[c
] = head
/ zoom
;
83 static void jmpmark(int c
, int offset
)
87 if (ISMARK(c
) && mark
[c
]) {
89 int dst_head
= offset
? mark_head
[c
] * zoom
: 0;
91 showpage(dst
, dst_head
);
95 static int readkey(void)
98 if (read(0, &b
, 1) <= 0)
103 static int getcount(int def
)
105 int result
= count
? count
: def
;
110 static void printinfo(void)
113 printf("FBPDF: file:%s page:%d(%d) zoom:%d%% \x1b[K\r",
114 filename
, num
, doc_pages(doc
), zoom
* 10);
118 static void term_setup(void)
120 struct termios newtermios
;
121 tcgetattr(0, &termios
);
122 newtermios
= termios
;
123 newtermios
.c_lflag
&= ~ICANON
;
124 newtermios
.c_lflag
&= ~ECHO
;
125 tcsetattr(0, TCSAFLUSH
, &newtermios
);
126 printf("\x1b[?25l"); /* hide the cursor */
127 printf("\x1b[2J"); /* clear the screen */
131 static void term_cleanup(void)
133 tcsetattr(0, 0, &termios
);
134 printf("\x1b[?25h\n"); /* show the cursor */
137 static void sigcont(int sig
)
142 static int reload(void)
145 doc
= doc_open(filename
);
146 if (!doc
|| !doc_pages(doc
)) {
147 fprintf(stderr
, "\nfbpdf: cannot open <%s>\n", filename
);
154 static int rightmost(int cont
)
158 for (i
= 0; i
< prows
; i
++) {
160 while (j
> ret
&& pbuf
[i
* PDFCOLS
+ j
] == FB_VAL(0, 0, 0))
162 while (cont
&& j
> ret
&&
163 pbuf
[i
* PDFCOLS
+ j
] == FB_VAL(255, 255, 255))
171 static int leftmost(int cont
)
175 for (i
= 0; i
< prows
; i
++) {
177 while (j
< ret
&& pbuf
[i
* PDFCOLS
+ j
] == FB_VAL(0, 0, 0))
179 while (cont
&& j
< ret
&&
180 pbuf
[i
* PDFCOLS
+ j
] == FB_VAL(255, 255, 255))
188 static void mainloop(void)
190 int step
= fb_rows() / PAGESTEPS
;
191 int hstep
= fb_cols() / PAGESTEPS
;
194 signal(SIGCONT
, sigcont
);
196 while ((c
= readkey()) != -1) {
199 if (c
== 'e' && reload())
204 showpage(num
+ getcount(1), 0);
208 showpage(num
- getcount(1), 0);
212 showpage(getcount(doc_pages(doc
) - numdiff
) + numdiff
, 0);
215 numdiff
= num
- getcount(num
);
217 showpage(num
+ numdiff
, 0);
220 numdiff
= num
- getcount(num
);
223 zoom_page(getcount(zoom_def
));
226 zoom_def
= getcount(zoom
);
229 zoom_page(zoom
* fb_cols() / pcols
);
232 if (leftmost(1) < rightmost(1))
233 zoom_page(zoom
* (fb_cols() - hstep
) /
234 (rightmost(1) - leftmost(1)));
237 zoom_page(zoom
* fb_rows() / prows
);
240 rotate
= getcount(0);
254 jmpmark(readkey(), c
== '`');
261 count
= count
* 10 + c
- '0';
265 head
+= step
* getcount(1);
268 head
-= step
* getcount(1);
271 left
+= hstep
* getcount(1);
274 left
-= hstep
* getcount(1);
280 head
= MAX(0, prows
- fb_rows());
283 head
= (prows
- fb_rows()) / 2;
286 left
= (PDFCOLS
- fb_cols()) / 2;
290 head
+= fb_rows() * getcount(1) - step
;
294 head
-= fb_rows() * getcount(1) - step
;
300 left
= rightmost(0) - fb_cols();
303 left
= leftmost(1) - hstep
/ 2;
306 left
= rightmost(1) + hstep
/ 2 - fb_cols();
311 /* no need to redraw */
314 head
= MAX(0, MIN(PDFROWS
- fb_rows(), head
));
315 left
= MAX(0, MIN(PDFCOLS
- fb_cols(), left
));
322 "usage: fbpdf [-r rotation] [-z zoom x10] [-p page] filename\n";
324 int main(int argc
, char *argv
[])
331 strcpy(filename
, argv
[argc
- 1]);
332 doc
= doc_open(filename
);
333 if (!doc
|| !doc_pages(doc
)) {
334 fprintf(stderr
, "fbpdf: cannot open <%s>\n", filename
);
337 for (i
= 1; i
< argc
&& argv
[i
][0] == '-'; i
++) {
338 switch (argv
[i
][1]) {
340 rotate
= atoi(argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
]);
343 zoom
= atoi(argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
]);
346 num
= atoi(argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
]);
353 left
= (PDFCOLS
- fb_cols()) / 2;
354 if (FBM_BPP(fb_mode()) != sizeof(fbval_t
))
355 fprintf(stderr
, "fbpdf: fbval_t doesn't match fb depth\n");