source: trunk/src/testing/app-3rd-party/sagepdf/sagepdf.cpp @ 4

Revision 4, 13.5 KB checked in by ajaworski, 13 years ago (diff)

Added modified SAGE sources

Line 
1/**************************************************************************
2    sagepdf - a PDF viewer for SAGE tiled displays.
3    Copyright (C) 2011  Christoph Willing
4   
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9   
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14   
15    You should have received a copy of the GNU General Public License along
16    with this program; if not, write to the Free Software Foundation, Inc.,
17    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18**************************************************************************/
19
20
21#include <unistd.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <cairo.h>
25#include <libgen.h>
26#include <string.h>
27#include <gtk/gtk.h>
28#include <gdk/gdkkeysyms.h>
29#include <glib/poppler.h>
30#include <math.h>
31
32#define SAGEPDF_DEF_SCALEFACTOR (4)
33
34int npages;
35int firstPage = 0;
36PopplerDocument *document;
37PopplerPage *page;
38double  width, height;
39cairo_t *cr, *sage_cr;
40cairo_surface_t *surface, *sage_surface;
41int scaleFactor;
42
43#ifndef NOSAGE
44// headers for SAGE
45#include "sail.h"
46#include "misc.h"
47sail sageInf; // sail object
48
49// for dxt compression
50#include "libdxt.h"
51
52using namespace std;
53bool useDXT = true;
54
55byte *sageBuffer = NULL;  // buffers for sage and dxt data
56byte *dxt = NULL;
57byte *rgba = NULL;
58
59float lastX = 0;
60float lastY = 0;
61float dist = 0;
62
63GdkWindow *local_window = NULL;
64#endif
65
66float local_startX = 0;
67float local_startY = 0;
68float local_dist = 0;
69bool button1_is_pressed = false;
70
71
72void
73show_page()
74{
75        /* Clear window */
76        cairo_rectangle(cr, 0, 0, width, height);
77        cairo_stroke_preserve(cr);
78        cairo_set_source_rgb(cr, 1, 1, 1);
79        cairo_fill(cr);
80
81
82        cairo_set_source_surface(cr, surface, 0, 0);
83        cairo_translate(cr, 0, 0);
84        cairo_scale(cr, 1, 1);
85        poppler_page_render(page, cr);
86
87        cairo_set_operator(cr, CAIRO_OPERATOR_DEST_OVER);
88        cairo_set_source_rgb(cr, 1, 1, 1);
89        cairo_paint(cr);
90
91
92#ifndef NOSAGE
93        if( useDXT )
94        {
95                int cairo_height, cairo_width, cairo_rowstride;
96                unsigned int numBytes, *src;
97                unsigned char *cairo_data, *dst;
98
99                sage_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width*scaleFactor, height*scaleFactor);
100                sage_cr = cairo_create(sage_surface);
101                cairo_save (sage_cr);
102                /* Flip */
103                cairo_translate(sage_cr, 0, height*scaleFactor);
104                cairo_scale(sage_cr, scaleFactor, -scaleFactor);
105                poppler_page_render (page, sage_cr);
106                cairo_restore (sage_cr);
107
108                cairo_set_operator(sage_cr, CAIRO_OPERATOR_DEST_OVER);
109                cairo_set_source_rgba(sage_cr, 1, 1, 1, 1);
110                cairo_paint(sage_cr);
111
112                /* We'd like to apply the sage_surface data directly to the
113                *  DXT compression engine but it is in the wrong colour space.
114                *  Therefore we extract it manually to the rgba buffer.
115                */
116                cairo_height = cairo_image_surface_get_height (sage_surface);
117                cairo_width = cairo_image_surface_get_width (sage_surface);
118                cairo_rowstride = cairo_image_surface_get_stride (sage_surface);
119                cairo_data = cairo_image_surface_get_data (sage_surface);
120                for (int y = 0; y < cairo_height; y++)
121                {
122                        src = (unsigned int *) (cairo_data + y * cairo_rowstride);
123                        dst = rgba + y * cairo_rowstride;
124                        for (int x = 0; x < cairo_width; x++)
125                        {
126                                dst[0] = (*src >> 16) & 0xff;
127                                dst[1] = (*src >> 8) & 0xff;
128                                dst[2] = (*src >> 0) & 0xff;
129                                dst[3] = (*src >> 24) & 0xff;
130                                dst += 4;
131                                src++;
132                        }
133                }
134
135                numBytes = CompressDXT(rgba, dxt, scaleFactor * width, scaleFactor * height, FORMAT_DXT1, 1);
136                sageBuffer = (byte*)sageInf.getBuffer();
137                memcpy(sageBuffer, dxt, scaleFactor * scaleFactor * width*height*4/8);
138                sageInf.swapBuffer();
139
140                cairo_destroy(sage_cr);
141        }
142        else
143        {
144                sage_surface = cairo_image_surface_create_for_data ((unsigned char*)sageInf.getBuffer(),
145                                             CAIRO_FORMAT_ARGB32, width * scaleFactor, height * scaleFactor,
146                                             cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width * scaleFactor));
147                sage_cr = cairo_create(sage_surface);
148
149                /* Clear SAGE window */
150                cairo_rectangle(sage_cr, 0, 0, width * scaleFactor, height * scaleFactor);
151                cairo_stroke_preserve(sage_cr);
152                cairo_set_source_rgb(sage_cr, 1, 1, 1);
153                cairo_fill(sage_cr);
154
155                cairo_set_source_surface(sage_cr, sage_surface, 0, 0);
156                cairo_scale(sage_cr, scaleFactor, scaleFactor);
157                poppler_page_render(page, sage_cr);
158                cairo_set_operator(sage_cr, CAIRO_OPERATOR_DEST_OVER);
159                cairo_set_source_rgb(sage_cr, 1, 1, 1);
160                cairo_paint(sage_cr);
161
162                sageInf.swapBuffer();
163                cairo_destroy(sage_cr);
164        }
165#endif
166
167}
168
169void
170show_absolute_page(int requested_page)
171{
172        if( requested_page < 0 )
173                requested_page = 0;
174        if( requested_page >= npages )
175                requested_page = npages - 1;
176
177        /* Don't render again if we're already at that page */
178        if( poppler_page_get_index(page) == requested_page )
179                return;
180
181        page = poppler_document_get_page(document, requested_page);
182        show_page();
183}
184
185void
186show_next_page(int next)
187{
188        show_absolute_page(poppler_page_get_index(page) + next);
189/*
190        int ncurrent = poppler_page_get_index(page) + next;
191        if( (ncurrent > -1) && (ncurrent < npages) )
192                page = poppler_document_get_page(document, ncurrent);
193        show_page();
194*/
195}
196
197gint
198check_sage_messages(gpointer data)
199{
200#ifndef NOSAGE
201        sageMessage msg;
202        if (sageInf.checkMsg(msg, false) > 0) {
203                char *data = (char*) msg.getData();
204
205                switch (msg.getCode()) {
206                        case APP_QUIT : {
207                                sageInf.shutdown();
208                                gtk_main_quit();
209                                break;
210
211                        case EVT_CLICK:
212                                // Click event x and y location normalized to size of window
213                                float clickX, clickY;
214
215                                // Click device Id, button Id, and is down flag
216                                int clickDeviceId, clickButtonId, clickIsDown, clickEvent;
217
218                                // Parse message
219                                sscanf(data,
220                                       "%d %f %f %d %d %d",
221                                       &clickDeviceId, &clickX, &clickY,
222                                       &clickButtonId, &clickIsDown, &clickEvent);
223                                //printf("Pointer click at %f,%f\n", clickX, clickY);
224
225                                // record the click position so we know how far we moved
226                                if (clickIsDown && clickEvent == EVT_PAN) {
227                                    lastX = clickX;
228                                    lastY = clickY;
229                                }
230
231                                if( clickIsDown )
232                                {
233                                        //printf("Pointer click by button %d\n", clickButtonId);
234
235                                        cr = gdk_cairo_create(local_window);
236                                        if( clickButtonId == 1 )
237                                                show_next_page(1);
238                                        else
239                                                show_next_page(-1);
240                                }
241
242                                break;
243
244                        case EVT_PAN:
245                                // Pan event properties
246                                int panDeviceId;
247
248                                // Pan event x and y location and change in x, y and z direction
249                                // normalized to size of window
250                                float startX, startY, panDX, panDY, panDZ;
251                                sscanf(data,
252                                        "%d %f %f %f %f %f",
253                                        &panDeviceId, &startX, &startY, &panDX, &panDY, &panDZ);
254
255                                // keep track of distance
256                                dist += panDX;
257
258                                // we started a new drag
259                                if (lastX != startX) {
260                                        lastX = startX;
261                                        dist = 0;
262                                }
263                                else if( fabs(dist) > 0.07 ) { // if we dragged more than a certain distance, change a page
264                                        cr = gdk_cairo_create(local_window);
265                                        if (dist > 0)
266                                                show_next_page(1);
267                                        else
268                                                show_next_page(-1);
269
270                                        // reset the counter
271                                        lastX = startX;
272                                        dist = 0;
273                                }
274                                break;
275
276                        }
277                }     
278        }
279#endif
280        return TRUE;
281}
282
283static gboolean
284on_motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer data)
285{
286        float local_lastX = event->x;
287        local_dist = local_lastX - local_startX;
288
289        if( button1_is_pressed )
290                if( fabs(local_dist / width) > 0.07 )
291                {
292                        cr = gdk_cairo_create(widget->window);
293                        local_startX = local_lastX;
294                        if( local_dist > 0 )
295                                show_next_page(1);
296                        else
297                                show_next_page(-1);
298                }
299
300        return true;
301}
302
303static gboolean
304on_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
305{
306        cr = gdk_cairo_create(widget->window);
307        button1_is_pressed = false;
308        switch(event->button)
309        {
310                case 1:
311                        button1_is_pressed = true;
312                        local_startX = event->x;
313                        show_next_page(1);
314                        break;
315                case 3:
316                        show_next_page(-1);
317                        break;
318                default:
319                        // printf("Unhandled button press: %d\n", event->button);
320                        return false;
321                        break;
322        }
323        return true;
324}
325
326static gboolean
327on_key_release_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
328{
329        cr = gdk_cairo_create(widget->window);
330        switch(event->keyval)
331        {
332                case GDK_Home:
333                        show_absolute_page(0);
334                        break;
335                case GDK_End:
336                        show_absolute_page(npages);
337                        break;
338                case GDK_Page_Up:
339                case GDK_Left:
340                        show_next_page(-1);
341                        break;
342                case GDK_Page_Down:
343                case GDK_Right:
344                        show_next_page(1);
345                        break;
346                case GDK_Escape:
347                        printf("Quit\n");
348                        gtk_main_quit();
349                        break;
350                default:
351                        // printf("XXXXXXXXXX Unhandled key: %d\n", event->keyval);
352                        return false;
353                        break;
354        }
355        return true;
356}
357
358static gboolean
359on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
360{
361        cr = gdk_cairo_create(widget->window);
362        show_page();
363
364        return FALSE;
365}
366
367
368int main(int argc, char *argv[])
369{
370        unsigned int window_width=-1, window_height=-1;  // sage window size
371        GtkWidget *window;
372
373        char *filename;
374        char pathbuf[PATH_MAX];
375        char uri[256];
376        char *dirc, *basec, *dname, *bname;
377        int     i=0;
378
379        gtk_init(&argc, &argv);
380        scaleFactor = SAGEPDF_DEF_SCALEFACTOR;
381#ifndef NOSAGE
382        sage::initUtil();
383#endif
384
385        // parse command line arguments
386        if( argc < 2 )
387        {
388#ifndef NOSAGE
389                sage::printLog("PDF> sagepdf filename [width] [height] [-show_original] [-page num] [-scale num]");
390#else
391                fprintf(stderr, "PDF> sagepdf filename [width] [height] [-show_original] [-page num] [-scale num]\n");
392#endif
393                exit(1);
394        }
395        for (int argNum=2; argNum<argc; argNum++)
396        {
397                if( strcmp(argv[argNum], "-page") == 0 )
398                {
399                        int p = atoi(argv[argNum+1]);
400                        if( p > 0 )
401                                firstPage = p - 1;
402                        if( p < 0 )
403                                firstPage = 0;
404                        argNum++;
405                }
406#ifndef NOSAGE
407                else if (strcmp(argv[argNum], "-show_original") == 0)
408                {
409                        useDXT = false;
410                }
411#endif
412                else if( strcmp(argv[argNum], "-scale") == 0 )
413                {
414                        scaleFactor = atoi(argv[argNum+1]);
415                        if( scaleFactor < 1 )
416                                scaleFactor = 1;
417                        argNum++;
418                }
419                else if(atoi(argv[argNum]) != 0 && atoi(argv[argNum+1]) != 0)
420                {
421                        window_width = atoi( argv[argNum] );
422                        window_height = atoi( argv[argNum+1] );
423                        argNum++;
424                }
425        }
426
427        /* Check that the filename is an absolute pathname */
428        filename = argv[1];
429        dirc = strdup(filename);
430        basec = strdup(filename);
431        dname = dirname(dirc);
432        bname = basename(basec);
433
434        if( dname[0] != '/' )
435        {
436                fprintf(stderr, "Need absolute path for PDF file\n");
437
438                /* We could try to construct a path -
439                 * assume the path givern is relative to here
440                 */
441                if( ! getcwd(pathbuf, PATH_MAX) )
442                        exit(1);
443                sprintf(pathbuf + strlen(pathbuf), "/\0");
444                strcat(pathbuf, filename);
445                fprintf(stderr, "Lets try %s\n", pathbuf);
446        }
447        else
448        {
449                sprintf(pathbuf, "%s\0", filename);
450        }
451        /* Can we read it ? */
452        if( access(pathbuf, R_OK ) )
453        {
454                fprintf(stderr, "Can't access %s - exiting now ...\n", filename);
455                exit(2);
456        }
457
458        sprintf(uri, "file://%s\0", pathbuf);
459        document = poppler_document_new_from_file(uri, NULL, NULL);
460        npages = poppler_document_get_n_pages(document);
461
462        if( npages <= firstPage )
463                firstPage = npages - 1;
464        page = poppler_document_get_page(document, firstPage);
465        poppler_page_get_size(page, &width, &height);
466        printf("Page %d has size %fx%f\n", firstPage, width, height);
467
468
469#ifndef NOSAGE
470        if (useDXT)
471        {
472                if ((int)width % 4 != 0 || (int)height % 4 != 0)
473                {
474                        fprintf(stderr, "\n**** Image cropped a few pixels to be a multiple of 4 for dxt");
475                        width -= (int)width % 4; width = (int)width * 1.0;
476                        height -= (int)height % 4; height = (int)height * 1.0;
477                }
478
479                // allocate buffers
480                rgba = (byte*) memalign(16, scaleFactor * scaleFactor * width*height*4);
481                dxt = (byte*) memalign(16, scaleFactor * scaleFactor * width*height*4/8);
482        }
483
484        // SAGE setup
485        sailConfig cfg;
486        cfg.init("sagepdf.conf");   // every app has a config file named "appName.conf"
487        std::cout << "SAIL configuration was initialized by sagepdf.conf" << std::endl;
488
489        cfg.setAppName("sagepdf");
490        cfg.rank = 0;
491        cfg.resX = width * scaleFactor;
492        cfg.resY = height * scaleFactor;
493        cfg.winWidth = width * scaleFactor;
494        cfg.winHeight = height * scaleFactor;
495
496        sageRect renderImageMap;
497        renderImageMap.left = 0.0;
498        renderImageMap.right = 1.0;
499        renderImageMap.bottom = 0.0;
500        renderImageMap.top = 1.0;
501
502        cfg.imageMap = renderImageMap;
503        if( useDXT )
504        {
505                cfg.pixFmt = PIXFMT_DXT;
506                cfg.rowOrd = BOTTOM_TO_TOP;
507        }
508        else
509        {
510                cfg.pixFmt = PIXFMT_8888_INV;
511                cfg.rowOrd = TOP_TO_BOTTOM;
512        }
513        cfg.master = TRUE;
514
515        sageInf.init(cfg);
516        std::cout << "sail initialized " << std::endl;
517#endif
518
519        //printf("Using page size %fx%f\n", width, height);
520        surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
521
522        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
523        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
524        gtk_window_set_default_size(GTK_WINDOW(window), width, height);
525        gtk_widget_set_app_paintable(window, TRUE);
526
527
528        g_signal_connect(window, "expose-event", G_CALLBACK (on_expose_event), NULL);
529        g_signal_connect(window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
530        g_signal_connect(window, "key_release_event", G_CALLBACK (on_key_release_event), NULL);
531        g_signal_connect(window, "button_press_event", G_CALLBACK (on_button_press_event), NULL);
532        g_signal_connect(window, "motion_notify_event", G_CALLBACK (on_motion_notify_event), NULL);
533        gtk_widget_set_events (window,  GDK_KEY_RELEASE |
534                                        GDK_BUTTON_PRESS_MASK |
535                                        GDK_BUTTON_MOTION_MASK |
536                                        GDK_POINTER_MOTION_HINT_MASK );
537
538        gtk_widget_show_all(window);
539#ifndef NOSAGE
540        local_window = window->window;
541#endif
542
543        g_timeout_add (200, check_sage_messages, NULL);
544
545        gtk_main();
546        sageInf.shutdown();
547        cairo_surface_destroy(surface);
548
549        return 0;
550}
551
Note: See TracBrowser for help on using the repository browser.