fix the order of rendered colors
[fbpdf.git] / fbpdf.c
blob26f2bc5189f8f37dba1bd580ad1f745a41389a97
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 <signal.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <pty.h>
18 #include <cairo/cairo.h>
19 #include <glib/poppler.h>
20 #include "draw.h"
22 #define PAGESTEPS 8
23 #define CTRLKEY(x) ((x) - 96)
24 #define MAXWIDTH 2
25 #define MAXHEIGHT 3
27 static PopplerDocument *doc;
28 static PopplerPage *page;
29 static int num;
30 static cairo_t *cairo;
31 static cairo_surface_t *surface;
32 static struct termios termios;
33 static char filename[PATH_MAX];
34 static int zoom = 15;
35 static int head;
36 static int left;
37 static int count;
39 static void draw()
41 unsigned char *img = cairo_image_surface_get_data(surface);
42 fbval_t slice[1 << 14];
43 int i, j;
44 int h = MIN(fb_rows(), cairo_image_surface_get_height(surface));
45 int w = MIN(fb_cols(), cairo_image_surface_get_width(surface));
46 int cols = cairo_image_surface_get_width(surface);
47 for (i = head; i < h + head; i++) {
48 for (j = left; j < w + left; j++) {
49 unsigned char *p = img + (i * cols + j) * 4;
50 slice[j - left] = fb_color(*(p + 2), *(p + 1), *p);
52 fb_set(i - head, 0, slice, w);
56 static int load_document(void)
58 char abspath[PATH_MAX];
59 char uri[PATH_MAX + 16];
60 realpath(filename, abspath);
61 snprintf(uri, sizeof(uri), "file://%s", abspath);
62 doc = poppler_document_new_from_file(uri, NULL, NULL);
63 return !doc;
66 static void cleanup_page(void)
68 if (cairo)
69 cairo_destroy(cairo);
70 if (surface)
71 cairo_surface_destroy(surface);
72 if (page)
73 g_object_unref(G_OBJECT(page));
76 static void showpage(int p)
78 if (p < 0 || p >= poppler_document_get_n_pages(doc))
79 return;
80 cleanup_page();
81 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
82 fb_cols() * MAXWIDTH, fb_rows() * MAXHEIGHT);
83 cairo = cairo_create(surface);
84 cairo_scale(cairo, (float) zoom / 10, (float) zoom / 10);
85 cairo_set_source_rgb(cairo, 1.0, 1.0, 1.0);
86 cairo_paint(cairo);
87 num = p;
88 page = poppler_document_get_page(doc, p);
89 poppler_page_render(page, cairo);
90 head = 0;
91 draw();
94 static int readkey(void)
96 unsigned char b;
97 if (read(STDIN_FILENO, &b, 1) <= 0)
98 return -1;
99 return b;
102 static int getcount(int def)
104 int result = count ? count : def;
105 count = 0;
106 return result;
109 static void printinfo(void)
111 printf("\x1b[H");
112 printf("FBPDF: file:%s page:%d(%d) zoom:%d%% \x1b[K",
113 filename, num + 1, poppler_document_get_n_pages(doc), zoom * 10);
114 fflush(stdout);
117 static void term_setup(void)
119 struct termios newtermios;
120 tcgetattr(STDIN_FILENO, &termios);
121 newtermios = termios;
122 newtermios.c_lflag &= ~ICANON;
123 newtermios.c_lflag &= ~ECHO;
124 tcsetattr(STDIN_FILENO, TCSAFLUSH, &newtermios);
127 static void term_cleanup(void)
129 tcsetattr(STDIN_FILENO, 0, &termios);
132 static void sigcont(int sig)
134 term_setup();
137 static void mainloop()
139 int step = fb_rows() / PAGESTEPS;
140 int hstep = fb_cols() / PAGESTEPS;
141 int c;
142 term_setup();
143 signal(SIGCONT, sigcont);
144 showpage(0);
145 while ((c = readkey()) != -1) {
146 int maxhead = cairo_image_surface_get_height(surface) - fb_rows();
147 int maxleft = cairo_image_surface_get_width(surface) - fb_cols();
148 switch (c) {
149 case CTRLKEY('f'):
150 case 'J':
151 showpage(num + getcount(1));
152 break;
153 case CTRLKEY('b'):
154 case 'K':
155 showpage(num - getcount(1));
156 break;
157 case 'G':
158 showpage(getcount(poppler_document_get_n_pages(doc)) - 1);
159 break;
160 case 'z':
161 zoom = getcount(15);
162 showpage(num);
163 break;
164 case 'i':
165 printinfo();
166 break;
167 case 'q':
168 term_cleanup();
169 return;
170 case 27:
171 count = 0;
172 break;
173 default:
174 if (isdigit(c))
175 count = count * 10 + c - '0';
177 switch (c) {
178 case 'j':
179 head += step * getcount(1);
180 break;
181 case 'k':
182 head -= step * getcount(1);
183 break;
184 case 'l':
185 left += hstep * getcount(1);
186 break;
187 case 'h':
188 left -= hstep * getcount(1);
189 break;
190 case 'H':
191 head = 0;
192 break;
193 case 'L':
194 head = maxhead;
195 break;
196 case 'M':
197 head = maxhead / 2;
198 break;
199 case ' ':
200 case CTRL('d'):
201 head += fb_rows() * getcount(1) - step;
202 break;
203 case 127:
204 case CTRL('u'):
205 head -= fb_rows() * getcount(1) - step;
206 break;
207 case CTRLKEY('l'):
208 break;
209 default:
210 /* no need to redraw */
211 continue;
213 head = MAX(0, MIN(maxhead, head));
214 left = MAX(0, MIN(maxleft, left));
215 draw();
219 int main(int argc, char* argv[])
221 char *hide = "\x1b[?25l";
222 char *show = "\x1b[?25h";
223 char *clear = "\x1b[2J";
224 if (argc < 2) {
225 printf("usage: fbpdf filename\n");
226 return 1;
228 g_type_init();
229 strcpy(filename, argv[1]);
230 if (load_document()) {
231 printf("cannot open file\n");
232 return 1;
234 if (poppler_document_get_n_pages(doc)) {
235 write(STDIN_FILENO, hide, strlen(hide));
236 write(STDOUT_FILENO, clear, strlen(clear));
237 printinfo();
238 fb_init();
239 mainloop();
240 cleanup_page();
241 fb_free();
242 write(STDIN_FILENO, show, strlen(show));
243 printf("\n");
244 } else {
245 printf("zero pages!\n");
246 return 1;
248 if (doc)
249 g_object_unref(G_OBJECT(doc));
250 return 0;