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)
31 static fbval_t pbuf
[NBUFS
][PDFROWS
* PDFCOLS
]; /* rendered pages */
32 static int prows
[NBUFS
]; /* buf heights */
33 static int pcols
[NBUFS
]; /* buf widths */
34 static int ppage
[NBUFS
]; /* buf page number */
35 static struct doc
*doc
;
37 static struct termios termios
;
38 static char filename
[256];
39 static int mark
[128]; /* mark page number */
40 static int mark_head
[128]; /* mark head position */
41 static int num
= 1; /* page number */
42 static int numdiff
; /* G command page number difference */
44 static int zoom_def
= 15; /* default zoom */
50 static void draw(void)
53 int soff
= 0; /* screen position */
54 int poff
= head
; /* page position */
55 for (j
= 0; j
< NBUFS
&& ppage
[j
] && soff
< PDFROWS
; j
++) {
56 for (i
= poff
; soff
+ i
- poff
< fb_rows() && i
< prows
[j
]; i
++)
57 fb_set(soff
+ i
- poff
, 0, pbuf
[j
] + i
* PDFCOLS
+ left
, fb_cols());
58 soff
+= prows
[j
] - poff
;
61 /* blanking the rest of the screen */
62 for (; soff
< fb_rows(); soff
++)
63 fb_set(soff
, 0, pbuf
[0] + (prows
[0] - 1) * PDFCOLS
, fb_cols());
66 static int showpage(int p
, int h
)
70 if (p
< 1 || p
> doc_pages(doc
))
72 memset(ppage
, 0, sizeof(ppage
));
73 for (i
= 0; i
< NBUFS
&& p
+ i
<= doc_pages(doc
); i
++) {
77 memset(pbuf
[i
], 0x00, sizeof(pbuf
[i
]));
78 doc_draw(doc
, p
+ i
, zoom
, rotate
, pbuf
[i
], &prows
[i
], &pcols
[i
]);
79 /* leaving one blank row */
80 if (prows
[i
] < PDFROWS
)
83 if (rows
>= PDFROWS
|| rows
- prows
[0] >= fb_rows())
93 static void zoom_page(int z
)
96 zoom
= MIN(MAXZOOM
, MAX(1, z
));
97 showpage(num
, MIN(PDFROWS
- fb_rows(), head
* zoom
/ _zoom
));
100 static void setmark(int c
)
104 mark_head
[c
] = head
/ zoom
;
108 static void jmpmark(int c
, int offset
)
112 if (ISMARK(c
) && mark
[c
]) {
114 int dst_head
= offset
? mark_head
[c
] * zoom
: 0;
116 showpage(dst
, dst_head
);
120 static void scroll(int hdiff
)
123 if ((hdiff
< 0 && -hdiff
<= head
) || (hdiff
>= 0 && head
+ hdiff
< prows
[0])) {
128 pdiff
= (hdiff
+ head
) / prows
[0];
129 nhead
= (hdiff
+ head
) % prows
[0];
131 pdiff
= (hdiff
+ head
) / prows
[0] - 1;
132 nhead
= (prows
[0] * -pdiff
+ hdiff
+ head
) % prows
[0];
134 showpage(num
+ pdiff
, nhead
);
138 static int readkey(void)
141 if (read(0, &b
, 1) <= 0)
146 static int getcount(int def
)
148 int result
= count
? count
: def
;
153 static void printinfo(void)
156 printf("FBPDF: file:%s page:%d(%d) zoom:%d%% \x1b[K\r",
157 filename
, num
, doc_pages(doc
), zoom
* 10);
161 static void term_setup(void)
163 struct termios newtermios
;
164 tcgetattr(0, &termios
);
165 newtermios
= termios
;
166 newtermios
.c_lflag
&= ~ICANON
;
167 newtermios
.c_lflag
&= ~ECHO
;
168 tcsetattr(0, TCSAFLUSH
, &newtermios
);
169 printf("\x1b[?25l"); /* hide the cursor */
170 printf("\x1b[2J"); /* clear the screen */
174 static void term_cleanup(void)
176 tcsetattr(0, 0, &termios
);
177 printf("\x1b[?25h\n"); /* show the cursor */
180 static void sigcont(int sig
)
185 static int reload(void)
188 doc
= doc_open(filename
);
190 fprintf(stderr
, "\nfbpdf: cannot open <%s>\n", filename
);
197 static int rightmost(int cont
)
201 for (i
= 0; i
< prows
[0]; i
++) {
203 while (j
> ret
&& pbuf
[0][i
* PDFCOLS
+ j
] == FB_VAL(0, 0, 0))
205 while (cont
&& j
> ret
&&
206 pbuf
[0][i
* PDFCOLS
+ j
] == FB_VAL(255, 255, 255))
214 static int leftmost(int cont
)
218 for (i
= 0; i
< prows
[0]; i
++) {
220 while (j
< ret
&& pbuf
[0][i
* PDFCOLS
+ j
] == FB_VAL(0, 0, 0))
222 while (cont
&& j
< ret
&&
223 pbuf
[0][i
* PDFCOLS
+ j
] == FB_VAL(255, 255, 255))
231 static void mainloop(void)
233 int step
= fb_rows() / PAGESTEPS
;
234 int hstep
= fb_cols() / PAGESTEPS
;
238 signal(SIGCONT
, sigcont
);
240 while ((c
= readkey()) != -1) {
243 if (c
== 'e' && reload())
248 showpage(num
+ getcount(1), 0);
252 showpage(num
- getcount(1), 0);
256 showpage(getcount(doc_pages(doc
) - numdiff
) + numdiff
, 0);
259 numdiff
= num
- getcount(num
);
261 showpage(num
+ numdiff
, 0);
264 numdiff
= num
- getcount(num
);
267 zoom_page(getcount(zoom_def
));
270 zoom_def
= getcount(zoom
);
273 zoom_page(zoom
* fb_cols() / pcols
[0]);
276 if (leftmost(1) < rightmost(1))
277 zoom_page(zoom
* (fb_cols() - hstep
) /
278 (rightmost(1) - leftmost(1)));
281 zoom_page(zoom
* fb_rows() / prows
[0]);
284 rotate
= getcount(0);
298 jmpmark(readkey(), c
== '`');
305 count
= count
* 10 + c
- '0';
310 hdiff
= step
* getcount(1);
313 hdiff
= -step
* getcount(1);
316 left
+= hstep
* getcount(1);
319 left
-= hstep
* getcount(1);
325 hdiff
= prows
[0] - fb_rows() - head
;
328 hdiff
= prows
[0] / 2 - head
;
331 left
= (PDFCOLS
- fb_cols()) / 2;
335 hdiff
= fb_rows() * getcount(1) - step
;
339 hdiff
= -(fb_rows() * getcount(1) - step
);
345 left
= rightmost(0) - fb_cols();
348 left
= leftmost(1) - hstep
/ 2;
351 left
= rightmost(1) + hstep
/ 2 - fb_cols();
356 /* no need to redraw */
359 left
= MAX(0, MIN(PDFCOLS
- fb_cols(), left
));
366 "usage: fbpdf [-r rotation] [-z zoom x10] [-p page] filename\n";
368 int main(int argc
, char *argv
[])
375 strcpy(filename
, argv
[argc
- 1]);
376 doc
= doc_open(filename
);
378 fprintf(stderr
, "fbpdf: cannot open <%s>\n", filename
);
381 for (i
= 1; i
< argc
&& argv
[i
][0] == '-'; i
++) {
382 switch (argv
[i
][1]) {
384 rotate
= atoi(argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
]);
387 zoom
= atoi(argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
]);
390 num
= atoi(argv
[i
][2] ? argv
[i
] + 2 : argv
[++i
]);
397 left
= (PDFCOLS
- fb_cols()) / 2;
398 if (FBM_BPP(fb_mode()) != sizeof(fbval_t
))
399 fprintf(stderr
, "fbpdf: fbval_t doesn't match fb depth\n");