exit when document has no pages
[fbpdf.git] / fbpdf.c
blobc8227484ba461e46245ac3e537740d70f1d02531
1 /*
2 * fbpdf - A small framebuffer pdf viewer using poppler
4 * Copyright (C) 2009 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.
11 #include <ctype.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <pty.h>
17 #include <cairo/cairo.h>
18 #include <glib/poppler.h>
19 #include "draw.h"
21 #define PAGESTEPS 8
22 #define CTRLKEY(x) ((x) - 96)
23 #define MAXWIDTH 2
24 #define MAXHEIGHT 3
26 static PopplerDocument *doc;
27 static PopplerPage *page;
28 static int num;
29 static cairo_t *cairo;
30 static cairo_surface_t *surface;
31 static char filename[PATH_MAX];
32 static int zoom = 15;
33 static int head;
34 static int left;
35 static int count;
37 static void draw()
39 unsigned char *img = cairo_image_surface_get_data(surface);
40 fbval_t slice[1 << 14];
41 int i, j;
42 int h = MIN(fb_rows(), cairo_image_surface_get_height(surface));
43 int w = MIN(fb_cols(), cairo_image_surface_get_width(surface));
44 int cols = cairo_image_surface_get_width(surface);
45 for (i = head; i < h + head; i++) {
46 for (j = left; j < w + left; j++) {
47 unsigned char *p = img + (i * cols + j) * 4;
48 slice[j - left] = fb_color(*p, *(p + 1), *(p + 2));
50 fb_set(i - head, 0, slice, w);
54 static int load_document(void)
56 char abspath[PATH_MAX];
57 char uri[PATH_MAX + 16];
58 realpath(filename, abspath);
59 snprintf(uri, sizeof(uri), "file://%s", abspath);
60 doc = poppler_document_new_from_file(uri, NULL, NULL);
61 return !doc;
64 static void cleanup_page(void)
66 if (cairo)
67 cairo_destroy(cairo);
68 if (surface)
69 cairo_surface_destroy(surface);
70 if (page)
71 g_object_unref(G_OBJECT(page));
74 static void showpage(int p)
76 if (p < 0 || p >= poppler_document_get_n_pages(doc))
77 return;
78 cleanup_page();
79 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
80 fb_cols() * MAXWIDTH, fb_rows() * MAXHEIGHT);
81 cairo = cairo_create(surface);
82 cairo_scale(cairo, (float) zoom / 10, (float) zoom / 10);
83 cairo_set_source_rgb(cairo, 1.0, 1.0, 1.0);
84 cairo_paint(cairo);
85 num = p;
86 page = poppler_document_get_page(doc, p);
87 poppler_page_render(page, cairo);
88 head = 0;
89 draw();
92 static int readkey(void)
94 unsigned char b;
95 if (read(STDIN_FILENO, &b, 1) <= 0)
96 return -1;
97 return b;
100 static int getcount(int def)
102 int result = count ? count : def;
103 count = 0;
104 return result;
107 static void printinfo(void)
109 printf("\x1b[H");
110 printf("FBPDF: file:%s page:%d(%d) zoom:%d%% \x1b[K",
111 filename, num + 1, poppler_document_get_n_pages(doc), zoom * 10);
112 fflush(stdout);
115 static void mainloop()
117 int step = fb_rows() / PAGESTEPS;
118 int hstep = fb_cols() / PAGESTEPS;
119 struct termios oldtermios, termios;
120 int c;
121 tcgetattr(STDIN_FILENO, &termios);
122 oldtermios = termios;
123 cfmakeraw(&termios);
124 tcsetattr(STDIN_FILENO, TCSAFLUSH, &termios);
125 showpage(0);
126 while ((c = readkey()) != -1) {
127 int maxhead = cairo_image_surface_get_height(surface) - fb_rows();
128 int maxleft = cairo_image_surface_get_width(surface) - fb_cols();
129 switch (c) {
130 case CTRLKEY('f'):
131 case 'J':
132 showpage(num + getcount(1));
133 break;
134 case CTRLKEY('b'):
135 case 'K':
136 showpage(num - getcount(1));
137 break;
138 case 'G':
139 showpage(getcount(poppler_document_get_n_pages(doc)) - 1);
140 break;
141 case 'z':
142 zoom = getcount(15);
143 showpage(num);
144 break;
145 case 'i':
146 printinfo();
147 break;
148 case 'q':
149 tcsetattr(STDIN_FILENO, 0, &oldtermios);
150 return;
151 case 27:
152 count = 0;
153 break;
154 default:
155 if (isdigit(c))
156 count = count * 10 + c - '0';
158 switch (c) {
159 case 'j':
160 head += step * getcount(1);
161 break;
162 case 'k':
163 head -= step * getcount(1);
164 break;
165 case 'l':
166 left += hstep * getcount(1);
167 break;
168 case 'h':
169 left -= hstep * getcount(1);
170 break;
171 case 'H':
172 head = 0;
173 break;
174 case 'L':
175 head = maxhead;
176 break;
177 case 'M':
178 head = maxhead / 2;
179 break;
180 case ' ':
181 head += fb_rows() * getcount(1) - step;
182 break;
183 case '\b':
184 head -= fb_rows() * getcount(1) - step;
185 break;
186 case CTRLKEY('l'):
187 break;
188 default:
189 /* no need to redraw */
190 continue;
192 head = MAX(0, MIN(maxhead, head));
193 left = MAX(0, MIN(maxleft, left));
194 draw();
198 int main(int argc, char* argv[])
200 char *hide = "\x1b[?25l";
201 char *show = "\x1b[?25h";
202 char *clear = "\x1b[2J";
203 if (argc < 2) {
204 printf("usage: fbpdf filename\n");
205 return 1;
207 g_type_init();
208 strcpy(filename, argv[1]);
209 if (load_document()) {
210 printf("cannot open file\n");
211 return 1;
213 if (poppler_document_get_n_pages(doc)) {
214 write(STDIN_FILENO, hide, strlen(hide));
215 write(STDOUT_FILENO, clear, strlen(clear));
216 printinfo();
217 fb_init();
218 mainloop();
219 cleanup_page();
220 fb_free();
221 write(STDIN_FILENO, show, strlen(show));
222 printf("\n");
223 } else {
224 printf("zero pages!\n");
225 return 1;
227 if (doc)
228 g_object_unref(G_OBJECT(doc));
229 return 0;