use mupdf instead of poppler
[fbpdf.git] / fbpdf.c
blobe304e26d3347900e9c82a07d93ed72492b995ee0
1 /*
2 * fbpdf - a small framebuffer pdf viewer using mupdf
4 * Copyright (C) 2009-2010 Ali Gholami Rudi
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License, as published by the
8 * Free Software Foundation.
9 */
10 #include <ctype.h>
11 #include <signal.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <pty.h>
17 #include "fitz.h"
18 #include "mupdf.h"
19 #include "draw.h"
21 #define PAGESTEPS 8
22 #define CTRLKEY(x) ((x) - 96)
23 #define MAXWIDTH 2
24 #define MAXHEIGHT 3
25 #define PDFCOLS (1 << 11)
26 #define PDFROWS (1 << 12)
28 static fbval_t pbuf[PDFROWS * PDFCOLS];
30 static int num = 1;
31 static struct termios termios;
32 static char filename[256];
33 static int zoom = 15;
34 static int head;
35 static int left;
36 static int count;
38 static fz_glyphcache *glyphcache;
39 static pdf_xref *xref;
40 static int pagecount;
42 static void draw(void)
44 int i;
45 for (i = head; i < MIN(head + fb_rows(), PDFROWS); i++)
46 fb_set(i - head, 0, pbuf + i * PDFCOLS + left, fb_cols());
49 static int showpage(int p)
51 fz_matrix ctm;
52 fz_bbox bbox;
53 fz_pixmap *pix;
54 fz_device *dev;
55 fz_obj *pageobj;
56 fz_displaylist *list;
57 pdf_page *page;
58 int x, y, w, h;
59 if (p < 1 || p > pagecount)
60 return 0;
62 memset(pbuf, 0x00, sizeof(pbuf));
64 pageobj = pdf_getpageobject(xref, p);
65 if (pdf_loadpage(&page, xref, pageobj))
66 return 1;
67 list = fz_newdisplaylist();
68 dev = fz_newlistdevice(list);
69 if (pdf_runpage(xref, page, dev, fz_identity))
70 return 1;
71 fz_freedevice(dev);
73 ctm = fz_translate(0, -page->mediabox.y1);
74 ctm = fz_concat(ctm, fz_scale((float) zoom / 10, (float) -zoom / 10));
75 bbox = fz_roundrect(fz_transformrect(ctm, page->mediabox));
76 w = bbox.x1 - bbox.x0;
77 h = bbox.y1 - bbox.y0;
79 pix = fz_newpixmapwithrect(fz_devicergb, bbox);
80 fz_clearpixmap(pix, 0xff);
82 dev = fz_newdrawdevice(glyphcache, pix);
83 fz_executedisplaylist(list, dev, ctm);
84 fz_freedevice(dev);
86 for (y = 0; y < MIN(pix->h, PDFROWS); y++) {
87 for (x = 0; x < MIN(pix->w, PDFCOLS); x++) {
88 unsigned char *s = pix->samples + y * pix->w * 4 + x * 4;
89 pbuf[y * PDFCOLS + x] = fb_color(s[0], s[1], s[2]);
93 fz_droppixmap(pix);
94 fz_freedisplaylist(list);
95 pdf_freepage(page);
96 pdf_agestore(xref->store, 3);
97 num = p;
98 head = 0;
99 draw();
100 return 0;
103 static int readkey(void)
105 unsigned char b;
106 if (read(STDIN_FILENO, &b, 1) <= 0)
107 return -1;
108 return b;
111 static int getcount(int def)
113 int result = count ? count : def;
114 count = 0;
115 return result;
118 static void printinfo(void)
120 printf("\x1b[H");
121 printf("FBPDF: file:%s page:%d(%d) zoom:%d%% \x1b[K",
122 filename, num, pagecount, zoom * 10);
123 fflush(stdout);
126 static void term_setup(void)
128 struct termios newtermios;
129 tcgetattr(STDIN_FILENO, &termios);
130 newtermios = termios;
131 newtermios.c_lflag &= ~ICANON;
132 newtermios.c_lflag &= ~ECHO;
133 tcsetattr(STDIN_FILENO, TCSAFLUSH, &newtermios);
136 static void term_cleanup(void)
138 tcsetattr(STDIN_FILENO, 0, &termios);
141 static void sigcont(int sig)
143 term_setup();
146 static void mainloop()
148 int step = fb_rows() / PAGESTEPS;
149 int hstep = fb_cols() / PAGESTEPS;
150 int c;
151 term_setup();
152 signal(SIGCONT, sigcont);
153 showpage(1);
154 while ((c = readkey()) != -1) {
155 int maxhead = PDFROWS - fb_rows();
156 int maxleft = PDFCOLS - fb_cols();
157 switch (c) {
158 case CTRLKEY('f'):
159 case 'J':
160 showpage(num + getcount(1));
161 break;
162 case CTRLKEY('b'):
163 case 'K':
164 showpage(num - getcount(1));
165 break;
166 case 'G':
167 showpage(getcount(pagecount));
168 break;
169 case 'z':
170 zoom = getcount(15);
171 showpage(num);
172 break;
173 case 'i':
174 printinfo();
175 break;
176 case 'q':
177 term_cleanup();
178 return;
179 case 27:
180 count = 0;
181 break;
182 default:
183 if (isdigit(c))
184 count = count * 10 + c - '0';
186 switch (c) {
187 case 'j':
188 head += step * getcount(1);
189 break;
190 case 'k':
191 head -= step * getcount(1);
192 break;
193 case 'l':
194 left += hstep * getcount(1);
195 break;
196 case 'h':
197 left -= hstep * getcount(1);
198 break;
199 case 'H':
200 head = 0;
201 break;
202 case 'L':
203 head = maxhead;
204 break;
205 case 'M':
206 head = maxhead / 2;
207 break;
208 case ' ':
209 case CTRL('d'):
210 head += fb_rows() * getcount(1) - step;
211 break;
212 case 127:
213 case CTRL('u'):
214 head -= fb_rows() * getcount(1) - step;
215 break;
216 case CTRLKEY('l'):
217 break;
218 default:
219 /* no need to redraw */
220 continue;
222 head = MAX(0, MIN(maxhead, head));
223 left = MAX(0, MIN(maxleft, left));
224 draw();
228 int main(int argc, char *argv[])
230 char *hide = "\x1b[?25l";
231 char *show = "\x1b[?25h";
232 char *clear = "\x1b[2J";
233 if (argc < 2) {
234 printf("usage: fbpdf filename\n");
235 return 1;
237 strcpy(filename, argv[1]);
238 fz_accelerate();
239 glyphcache = fz_newglyphcache();
240 if (pdf_openxref(&xref, filename, NULL)) {
241 printf("cannot open file\n");
242 return 1;
244 if (pdf_loadpagetree(xref))
245 return 1;
246 pagecount = pdf_getpagecount(xref);
248 write(STDIN_FILENO, hide, strlen(hide));
249 write(STDOUT_FILENO, clear, strlen(clear));
250 printinfo();
251 fb_init();
252 mainloop();
253 fb_free();
254 write(STDIN_FILENO, show, strlen(show));
255 printf("\n");
257 pdf_freexref(xref);
258 fz_freeglyphcache(glyphcache);
259 return 0;