summaryrefslogtreecommitdiff
path: root/apps/x11pdf.c
diff options
context:
space:
mode:
authorTor Andersson <tor@ghostscript.com>2005-01-11 07:19:08 +0100
committerTor Andersson <tor@ghostscript.com>2005-01-11 07:19:08 +0100
commit4a6def1aebcb61599f9d975e92079aad5bb423c6 (patch)
tree65d7ae5520822cc10b79ef5d421672f5b7d6f435 /apps/x11pdf.c
parent15db9438f7a852643bb2b5e81e67de4eb805b173 (diff)
downloadmupdf-4a6def1aebcb61599f9d975e92079aad5bb423c6.tar.xz
rename apps directory and reorganize macpdf.app
Diffstat (limited to 'apps/x11pdf.c')
-rw-r--r--apps/x11pdf.c590
1 files changed, 590 insertions, 0 deletions
diff --git a/apps/x11pdf.c b/apps/x11pdf.c
new file mode 100644
index 00000000..e35f90a6
--- /dev/null
+++ b/apps/x11pdf.c
@@ -0,0 +1,590 @@
+#include <fitz.h>
+#include <mupdf.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/cursorfont.h>
+#include <X11/keysym.h>
+
+extern int ximage_init(Display *display, int screen, Visual *visual);
+extern int ximage_get_depth(void);
+extern Visual *ximage_get_visual(void);
+extern Colormap ximage_get_colormap(void);
+extern void ximage_blit(Drawable d, GC gc, int dstx, int dsty,
+ unsigned char *srcdata,
+ int srcx, int srcy, int srcw, int srch, int srcstride);
+
+static Display *xdpy;
+static int xscr;
+static Window xwin;
+static GC xgc;
+static XEvent xevt;
+static int mapped = 0;
+static Cursor xcarrow, xchand, xcwait;
+
+static char *doctitle = "<untitled>";
+
+static float zoom = 1.0;
+static int rotate = 0;
+static int pageno = 1;
+static int count = 0;
+
+static pdf_page *page = nil;
+static fz_obj *pageobj = nil;
+
+static int hist[256];
+static int histlen = 0;
+
+/* for 123G commands */
+static unsigned char pagebuf[256];
+static int pagebufidx = 0;
+
+static pdf_xref *xref;
+static pdf_pagetree *pages;
+static pdf_outline *outline;
+static fz_renderer *rast;
+static fz_pixmap *image;
+
+void usage()
+{
+ fprintf(stderr, "usage: x11pdf [-b] [-pzr page/zoom/rotate] [-u password] file.pdf\n");
+ fprintf(stderr,
+"\n"
+ );
+ exit(1);
+}
+
+/*
+ * X11 magic
+ */
+
+static void xopen(void)
+{
+ xdpy = XOpenDisplay(nil);
+ assert(xdpy != nil);
+
+ xscr = DefaultScreen(xdpy);
+
+ ximage_init(xdpy, xscr, DefaultVisual(xdpy, xscr));
+
+ xcarrow = XCreateFontCursor(xdpy, XC_left_ptr);
+ xchand = XCreateFontCursor(xdpy, XC_hand2);
+ xcwait = XCreateFontCursor(xdpy, XC_watch);
+
+ xwin = XCreateWindow(xdpy, DefaultRootWindow(xdpy),
+ 10, 10, 200, 100, 1,
+ ximage_get_depth(),
+ InputOutput,
+ ximage_get_visual(),
+ 0,
+ nil);
+
+ XSetWindowColormap(xdpy, xwin, ximage_get_colormap());
+ XSelectInput(xdpy, xwin,
+ StructureNotifyMask | ExposureMask | KeyPressMask |
+ PointerMotionMask | ButtonPressMask);
+
+ mapped = 0;
+
+ xgc = XCreateGC(xdpy, xwin, 0, nil);
+}
+
+static void xresize(void)
+{
+ XWindowChanges values;
+ int mask;
+
+ mask = CWWidth | CWHeight;
+ values.width = image->w;
+ values.height = image->h;
+ XConfigureWindow(xdpy, xwin, mask, &values);
+
+ if (!mapped)
+ {
+ XMapWindow(xdpy, xwin);
+ XFlush(xdpy);
+
+ while (1)
+ {
+ XNextEvent(xdpy, &xevt);
+ if (xevt.type == MapNotify)
+ break;
+ }
+
+ XSetForeground(xdpy, xgc, WhitePixel(xdpy, xscr));
+ XFillRectangle(xdpy, xwin, xgc, 0, 0, image->w, image->h);
+ XFlush(xdpy);
+
+ mapped = 1;
+ }
+}
+
+static void xblit(void)
+{
+ ximage_blit(xwin, xgc, 0, 0, image->samples, 0, 0,
+ image->w, image->h, image->w * image->n);
+}
+
+static void xtitle(char *s)
+{
+ XmbSetWMProperties(xdpy, xwin, s, s, 0, 0, 0, 0, 0);
+}
+
+static void showpage(void)
+{
+ fz_error *error;
+ fz_matrix ctm;
+ fz_rect bbox;
+ fz_obj *obj;
+ char s[256];
+
+ assert(pageno > 0 && pageno <= pdf_getpagecount(pages));
+
+ XDefineCursor(xdpy, xwin, xcwait);
+ XFlush(xdpy);
+
+ if (image)
+ fz_droppixmap(image);
+ image = nil;
+
+ obj = pdf_getpageobject(pages, pageno - 1);
+ if (obj == pageobj)
+ goto Lskipload;
+ pageobj = obj;
+
+ if (page)
+ pdf_droppage(page);
+
+ sprintf(s, "Loading page %d", pageno);
+ XSetForeground(xdpy, xgc, BlackPixel(xdpy, xscr));
+ XDrawString(xdpy, xwin, xgc, 10, 20, s, strlen(s));
+ XFlush(xdpy);
+
+ error = pdf_loadpage(&page, xref, pageobj);
+ if (error)
+ fz_abort(error);
+
+Lskipload:
+
+ sprintf(s, "Rendering...");
+ XSetForeground(xdpy, xgc, BlackPixel(xdpy, xscr));
+ XDrawString(xdpy, xwin, xgc, 10, 30, s, strlen(s));
+ XFlush(xdpy);
+
+ ctm = fz_identity();
+ ctm = fz_concat(ctm, fz_translate(0, -page->mediabox.max.y));
+ ctm = fz_concat(ctm, fz_scale(zoom, -zoom));
+ ctm = fz_concat(ctm, fz_rotate(rotate + page->rotate));
+
+ bbox = fz_transformaabb(ctm, page->mediabox);
+
+ error = fz_rendertree(&image, rast, page->tree, ctm, fz_roundrect(bbox), 1);
+ if (error)
+ fz_abort(error);
+
+ XDefineCursor(xdpy, xwin, xcarrow);
+ XFlush(xdpy);
+
+ {
+ char buf[512];
+ sprintf(buf, "%s - %d/%d", doctitle, pageno, count);
+ xtitle(buf);
+ }
+
+ xresize();
+ xblit();
+}
+
+static void pdfopen(char *filename, char *password)
+{
+ fz_error *error;
+ fz_obj *obj;
+
+ error = pdf_newxref(&xref);
+ if (error)
+ fz_abort(error);
+
+ error = pdf_loadxref(xref, filename);
+ if (error)
+ {
+ fz_warn(error->msg);
+ printf("trying to repair...\n");
+ error = pdf_repairxref(xref, filename);
+ if (error)
+ fz_abort(error);
+ }
+
+ error = pdf_decryptxref(xref);
+ if (error)
+ fz_abort(error);
+
+ if (xref->crypt)
+ {
+ error = pdf_setpassword(xref->crypt, password);
+ if (error) fz_abort(error);
+ }
+
+ obj = fz_dictgets(xref->trailer, "Root");
+ if (!obj)
+ fz_abort(fz_throw("syntaxerror: missing Root object"));
+ error = pdf_loadindirect(&xref->root, xref, obj);
+ if (error) fz_abort(error);
+
+ obj = fz_dictgets(xref->trailer, "Info");
+ if (obj)
+ {
+ error = pdf_loadindirect(&xref->info, xref, obj);
+ if (error) fz_abort(error);
+ }
+
+ error = pdf_loadnametrees(xref);
+ if (error) fz_abort(error);
+
+ error = pdf_loadoutline(&outline, xref);
+ if (error) fz_abort(error);
+
+ doctitle = filename;
+ if (xref->info)
+ {
+ obj = fz_dictgets(xref->info, "Title");
+ if (obj)
+ {
+ error = pdf_toutf8(&doctitle, obj);
+ if (error) fz_abort(error);
+ }
+ }
+
+ if (outline)
+ pdf_debugoutline(outline, 0);
+
+ error = pdf_loadpagetree(&pages, xref);
+ if (error) fz_abort(error);
+
+ count = pdf_getpagecount(pages);
+
+ error = fz_newrenderer(&rast, pdf_devicergb, 0, 1024 * 512);
+ if (error) fz_abort(error);
+
+ image = nil;
+}
+
+static void dumptext()
+{
+ fz_error *error;
+ pdf_textline *line;
+
+ printf("----");
+
+ error = pdf_loadtextfromtree(&line, page->tree);
+ if (error)
+ fz_abort(error);
+
+ pdf_debugtextline(line);
+
+ pdf_droptextline(line);
+}
+
+static void gotouri(fz_obj *uri)
+{
+ char cmd[2048];
+ char buf[2048];
+
+ printf("goto uri: ");
+ fz_debugobj(uri);
+ printf("\n");
+
+ memcpy(buf, fz_tostrbuf(uri), fz_tostrlen(uri));
+ buf[fz_tostrlen(uri)] = 0;
+
+ if (getenv("BROWSER"))
+ sprintf(cmd, "$BROWSER %s &", buf);
+ else
+#ifdef WIN32
+ sprintf(cmd, "start %s", buf);
+#else
+ sprintf(cmd, "open %s", buf);
+#endif
+ system(cmd);
+}
+
+static void gotopage(fz_obj *obj)
+{
+ int oid = fz_tonum(obj);
+ int gen = fz_togen(obj);
+ int i;
+
+ printf("goto page: %d %d R\n", oid, gen);
+
+ for (i = 0; i < count; i++)
+ {
+ if (fz_tonum(pages->pref[i]) == oid)
+ {
+ if (histlen + 1 == 256)
+ {
+ memmove(hist, hist + 1, sizeof(int) * 255);
+ histlen --;
+ }
+ hist[histlen++] = pageno;
+ pageno = i + 1;
+ showpage();
+ return;
+ }
+ }
+}
+
+static void drawlinks(void)
+{
+ pdf_link *link;
+ fz_matrix ctm;
+ fz_point a, b, c, d;
+ fz_rect r;
+
+ ctm = fz_identity();
+ ctm = fz_concat(ctm, fz_translate(0, -page->mediabox.max.y));
+ ctm = fz_concat(ctm, fz_scale(zoom, -zoom));
+ ctm = fz_concat(ctm, fz_rotate(rotate + page->rotate));
+ ctm = fz_concat(ctm, fz_translate(-image->x, -image->y));
+
+ for (link = page->links; link; link = link->next)
+ {
+ r = link->rect;
+
+ a.x = r.min.x; a.y = r.min.y;
+ b.x = r.min.x; b.y = r.max.y;
+ c.x = r.max.x; c.y = r.max.y;
+ d.x = r.max.x; d.y = r.min.y;
+
+ a = fz_transformpoint(ctm, a);
+ b = fz_transformpoint(ctm, b);
+ c = fz_transformpoint(ctm, c);
+ d = fz_transformpoint(ctm, d);
+
+ XDrawLine(xdpy, xwin, xgc, a.x, a.y, b.x, b.y);
+ XDrawLine(xdpy, xwin, xgc, b.x, b.y, c.x, c.y);
+ XDrawLine(xdpy, xwin, xgc, c.x, c.y, d.x, d.y);
+ XDrawLine(xdpy, xwin, xgc, d.x, d.y, a.x, a.y);
+ }
+
+ XFlush(xdpy);
+}
+
+static void handlekey(int c)
+{
+ int oldpage = pageno;
+ float oldzoom = zoom;
+ int oldrotate = rotate;
+
+ if (c >= '0' && c <= '9')
+ pagebuf[pagebufidx++] = c;
+ else
+ if (c != 'g' && c != 'G')
+ pagebufidx = 0;
+
+ switch (c)
+ {
+ case 'd': fz_debugglyphcache(rast->cache); break;
+ case 'a': rotate -= 5; break;
+ case 's': rotate += 5; break;
+ case 'x': dumptext(); break;
+ case 'o': drawlinks(); break;
+
+ case '\b':
+ case 'b':
+ pageno--;
+ if (pageno < 1)
+ pageno = 1;
+ break;
+ case 'B':
+ pageno -= 10;
+ if (pageno < 1)
+ pageno = 1;
+ break;
+ case ' ':
+ case 'f':
+ pageno++;
+ if (pageno > count)
+ pageno = count;
+ break;
+ case 'F':
+ pageno += 10;
+ if (pageno > count)
+ pageno = count;
+ break;
+ case 'm':
+ if (histlen + 1 == 256)
+ {
+ memmove(hist, hist + 1, sizeof(int) * 255);
+ histlen --;
+ }
+ hist[histlen++] = pageno;
+ break;
+ case 't':
+ case 'T':
+ if (histlen > 0)
+ pageno = hist[--histlen];
+ break;
+ case '-':
+ zoom -= 0.1;
+ if (zoom < 0.1)
+ zoom = 0.1;
+ break;
+ case '+':
+ zoom += 0.1;
+ if (zoom > 3.0)
+ zoom = 3.0;
+ break;
+ case '<':
+ rotate -= 90;
+ break;
+ case '>':
+ rotate += 90;
+ break;
+ case 'q':
+ exit(0);
+ case 'g':
+ case 'G':
+ if (pagebufidx > 0)
+ {
+ pagebuf[pagebufidx] = '\0';
+ pageno = atoi(pagebuf);
+ pagebufidx = 0;
+ if (pageno < 1)
+ pageno = 1;
+ if (pageno > count)
+ pageno = count;
+ }
+ else
+ {
+ if (c == 'G')
+ {
+ pageno = count;
+ }
+ }
+ break;
+ }
+
+ if (pageno != oldpage || zoom != oldzoom || rotate != oldrotate)
+ showpage();
+}
+
+static void handlemouse(float x, int y, int btn)
+{
+ pdf_link *link;
+ fz_matrix ctm;
+ fz_point p;
+
+ p.x = x + image->x;
+ p.y = y + image->y;
+
+ ctm = fz_identity();
+ ctm = fz_concat(ctm, fz_translate(0, -page->mediabox.max.y));
+ ctm = fz_concat(ctm, fz_scale(zoom, -zoom));
+ ctm = fz_concat(ctm, fz_rotate(rotate + page->rotate));
+ ctm = fz_invertmatrix(ctm);
+
+ p = fz_transformpoint(ctm, p);
+
+ for (link = page->links; link; link = link->next)
+ {
+ if (p.x >= link->rect.min.x && p.x <= link->rect.max.x)
+ if (p.y >= link->rect.min.y && p.y <= link->rect.max.y)
+ break;
+ }
+
+ if (link)
+ {
+ XDefineCursor(xdpy, xwin, xchand);
+ if (btn)
+ {
+ if (fz_isstring(link->dest))
+ gotouri(link->dest);
+ if (fz_isindirect(link->dest))
+ gotopage(link->dest);
+ }
+ }
+ else
+ {
+ XDefineCursor(xdpy, xwin, xcarrow);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ char *filename;
+ int c;
+
+ int benchmark = 0;
+ char *password = "";
+
+ while ((c = getopt(argc, argv, "bz:r:p:u:")) != -1)
+ {
+ switch (c)
+ {
+ case 'b': ++benchmark; break;
+ case 'u': password = optarg; break;
+ case 'p': pageno = atoi(optarg); break;
+ case 'z': zoom = atof(optarg); break;
+ case 'r': rotate = atoi(optarg); break;
+ default: usage();
+ }
+ }
+
+ if (argc - optind == 0)
+ usage();
+
+ fz_cpudetect();
+ fz_accelerate();
+
+ filename = argv[optind++];
+
+ xopen();
+ pdfopen(filename, password);
+ showpage();
+
+ if (benchmark)
+ {
+ while (pageno < count)
+ {
+ pageno ++;
+ showpage();
+ }
+ return 0;
+ }
+
+ while (1)
+ {
+ int len;
+ unsigned char buf[128];
+ KeySym keysym;
+
+ XNextEvent(xdpy, &xevt);
+ switch (xevt.type)
+ {
+ case Expose:
+ if (xevt.xexpose.count == 0)
+ xblit();
+ break;
+
+ case KeyPress:
+ len = XLookupString(&xevt.xkey, buf, sizeof buf, &keysym, 0);
+ if (len)
+ handlekey(buf[0]);
+ break;
+
+ case MotionNotify:
+ handlemouse(xevt.xbutton.x, xevt.xbutton.y, 0);
+ break;
+
+ case ButtonPress:
+ handlemouse(xevt.xbutton.x, xevt.xbutton.y, 1);
+ break;
+ }
+ }
+
+ pdf_closexref(xref);
+
+ return 0;
+}
+