diff options
Diffstat (limited to 'apps/windows/pdfapp.c')
-rw-r--r-- | apps/windows/pdfapp.c | 641 |
1 files changed, 641 insertions, 0 deletions
diff --git a/apps/windows/pdfapp.c b/apps/windows/pdfapp.c new file mode 100644 index 00000000..d771fc9c --- /dev/null +++ b/apps/windows/pdfapp.c @@ -0,0 +1,641 @@ +#include <fitz.h>
+#include <mupdf.h>
+#include "pdfapp.h"
+
+void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage);
+
+void pdfapp_warn(pdfapp_t *app, const char *fmt, ...)
+{
+ char buf[1024];
+ va_list ap;
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+ winwarn(app, buf);
+}
+
+void pdfapp_error(pdfapp_t *app, fz_error *error)
+{
+ winerror(app, error->msg);
+}
+
+char *pdfapp_usage(pdfapp_t *app)
+{
+ return
+ " l <\t\t-- rotate left\n"
+ " r >\t\t-- rotate right\n"
+ " u up\t\t-- scroll up\n"
+ " d down\t-- scroll down\n"
+ " = +\t\t-- zoom in\n"
+ " -\t\t-- zoom out\n"
+ " w\t\t-- shrinkwrap\n"
+ "\n"
+ " n pgdn space\t-- next page\n"
+ " b pgup back\t-- previous page\n"
+ " right\t\t-- next page\n"
+ " left\t\t-- previous page\n"
+ " N F\t\t-- next 10\n"
+ " B\t\t-- back 10\n"
+ " m\t\t-- mark page for snap back\n"
+ " t\t\t-- pop back to last mark\n"
+ " 123g\t\t-- go to page\n"
+ "\n"
+ " left drag to pan, right drag to copy text\n";
+}
+
+void pdfapp_init(pdfapp_t *app)
+{
+ fz_error *error;
+
+ memset(app, 0, sizeof(pdfapp_t));
+
+ error = fz_newrenderer(&app->rast, pdf_devicergb, 0, 1024 * 512);
+ if (error)
+ pdfapp_error(app, error);
+
+ app->scrw = 640;
+ app->scrh = 480;
+}
+
+void pdfapp_open(pdfapp_t *app, char *filename)
+{
+ fz_error *error;
+ fz_obj *obj;
+ char *password = "";
+
+ /*
+ * Open PDF and load xref table
+ */
+
+ app->filename = filename;
+
+ error = pdf_newxref(&app->xref);
+ if (error)
+ pdfapp_error(app, error);
+
+ error = pdf_loadxref(app->xref, filename);
+ if (error)
+ {
+ if (!strncmp(error->msg, "ioerror", 7))
+ pdfapp_error(app, error);
+ pdfapp_warn(app,
+ "There was a problem with file \"%s\".\n"
+ "It may be corrupted, or generated by broken software.\n\n"
+ "%s\n\nTrying to continue anyway...",
+ filename, error->msg);
+ error = pdf_repairxref(app->xref, filename);
+ if (error)
+ pdfapp_error(app, error);
+ }
+
+ /*
+ * Handle encrypted PDF files
+ */
+
+ error = pdf_decryptxref(app->xref);
+ if (error)
+ pdfapp_error(app, error);
+
+ if (app->xref->crypt)
+ {
+ error = pdf_setpassword(app->xref->crypt, password);
+ while (error)
+ {
+ fz_droperror(error);
+ password = winpassword(app, filename);
+ if (!password)
+ exit(1);
+ error = pdf_setpassword(app->xref->crypt, password);
+ if (error)
+ pdfapp_warn(app, "Invalid password.");
+ }
+ }
+
+ /*
+ * Load page tree
+ */
+
+ error = pdf_loadpagetree(&app->pages, app->xref);
+ if (error)
+ pdfapp_error(app, error);
+
+ /*
+ * Load meta information
+ * TODO: move this into mupdf library
+ */
+
+ obj = fz_dictgets(app->xref->trailer, "Root");
+ if (!obj)
+ pdfapp_error(app, fz_throw("syntaxerror: missing Root object"));
+
+ error = pdf_loadindirect(&app->xref->root, app->xref, obj);
+ if (error)
+ pdfapp_error(app, error);
+
+ obj = fz_dictgets(app->xref->trailer, "Info");
+ if (obj)
+ {
+ error = pdf_loadindirect(&app->xref->info, app->xref, obj);
+ if (error)
+ pdfapp_error(app, error);
+ }
+
+ error = pdf_loadnametrees(app->xref);
+ if (error)
+ pdfapp_error(app, error);
+
+ error = pdf_loadoutline(&app->outline, app->xref);
+ if (error)
+ pdfapp_error(app, error);
+
+ app->doctitle = filename;
+ if (strrchr(app->doctitle, '\\'))
+ app->doctitle = strrchr(app->doctitle, '\\') + 1;
+ if (strrchr(app->doctitle, '/'))
+ app->doctitle = strrchr(app->doctitle, '/') + 1;
+ if (app->xref->info)
+ {
+ obj = fz_dictgets(app->xref->info, "Title");
+ if (obj)
+ {
+ error = pdf_toutf8(&app->doctitle, obj);
+ if (error)
+ pdfapp_error(app, error);
+ }
+ }
+
+ /*
+ * Start at first page
+ */
+
+ app->shrinkwrap = 1;
+ app->pageno = 1;
+ app->zoom = 1.0;
+ app->rotate = 0;
+ app->panx = 0;
+ app->pany = 0;
+
+ pdfapp_showpage(app, 1, 1);
+}
+
+void pdfapp_close(pdfapp_t *app)
+{
+ if (app->pages)
+ pdf_droppagetree(app->pages);
+ app->pages = nil;
+
+ if (app->page)
+ pdf_droppage(app->page);
+ app->page = nil;
+
+ if (app->image)
+ fz_droppixmap(app->image);
+ app->image = nil;
+
+ if (app->outline)
+ pdf_dropoutline(app->outline);
+ app->outline = nil;
+
+ if (app->xref->store)
+ pdf_dropstore(app->xref->store);
+ app->xref->store = nil;
+
+ pdf_closexref(app->xref);
+ app->xref = nil;
+}
+
+fz_matrix pdfapp_viewctm(pdfapp_t *app)
+{
+ fz_matrix ctm;
+ ctm = fz_identity();
+ ctm = fz_concat(ctm, fz_translate(0, -app->page->mediabox.y1));
+ ctm = fz_concat(ctm, fz_scale(app->zoom, -app->zoom));
+ ctm = fz_concat(ctm, fz_rotate(app->rotate + app->page->rotate));
+ return ctm;
+}
+
+void pdfapp_panview(pdfapp_t *app, int newx, int newy)
+{
+ if (newx > 0)
+ newx = 0;
+ if (newy > 0)
+ newy = 0;
+
+ if (newx + app->image->w < app->winw)
+ newx = app->winw - app->image->w;
+ if (newy + app->image->h < app->winh)
+ newy = app->winh - app->image->h;
+
+ if (app->winw >= app->image->w)
+ newx = (app->winw - app->image->w) / 2;
+ if (app->winh >= app->image->h)
+ newy = (app->winh - app->image->h) / 2;
+
+ if (newx != app->panx || newy != app->pany)
+ winrepaint(app);
+
+ app->panx = newx;
+ app->pany = newy;
+}
+
+void pdfapp_showpage(pdfapp_t *app, int loadpage, int drawpage)
+{
+ char buf[256];
+ fz_error *error;
+ fz_matrix ctm;
+ fz_rect bbox;
+ fz_obj *obj;
+
+ if (loadpage)
+ {
+ wincursor(app, WAIT);
+
+ if (app->page)
+ pdf_droppage(app->page);
+ app->page = nil;
+
+ obj = pdf_getpageobject(app->pages, app->pageno - 1);
+
+ error = pdf_loadpage(&app->page, app->xref, obj);
+ if (error)
+ pdfapp_error(app, error);
+
+ sprintf(buf, "%s - %d/%d", app->doctitle,
+ app->pageno, pdf_getpagecount(app->pages));
+ wintitle(app, buf);
+ }
+
+ if (drawpage)
+ {
+ wincursor(app, WAIT);
+
+ if (app->image)
+ fz_droppixmap(app->image);
+ app->image = nil;
+
+ ctm = pdfapp_viewctm(app);
+ bbox = fz_transformaabb(ctm, app->page->mediabox);
+
+ error = fz_rendertree(&app->image, app->rast, app->page->tree,
+ ctm, fz_roundrect(bbox), 1);
+ if (error)
+ pdfapp_error(app, error);
+
+ winconvert(app, app->image);
+ }
+
+ pdfapp_panview(app, app->panx, app->pany);
+
+ if (app->shrinkwrap)
+ {
+ int w = app->image->w;
+ int h = app->image->h;
+ if (app->winw == w)
+ app->panx = 0;
+ if (app->winh == h)
+ app->pany = 0;
+ if (w > app->scrw * 95 / 100)
+ w = app->scrw * 95 / 100;
+ if (h > app->scrh * 95 / 100)
+ h = app->scrh * 95 / 100;
+ if (w != app->winw || h != app->winh)
+ winresize(app, w, h);
+ }
+
+ winrepaint(app);
+}
+
+
+void pdfapp_gotouri(pdfapp_t *app, fz_obj *uri)
+{
+ char buf[2048];
+ memcpy(buf, fz_tostrbuf(uri), fz_tostrlen(uri));
+ buf[fz_tostrlen(uri)] = 0;
+ winopenuri(app, buf);
+}
+
+void pdfapp_gotopage(pdfapp_t *app, fz_obj *obj)
+{
+ int oid = fz_tonum(obj);
+ int i;
+
+ for (i = 0; i < pdf_getpagecount(app->pages); i++)
+ {
+ if (fz_tonum(app->pages->pref[i]) == oid)
+ {
+ if (app->histlen + 1 == 256)
+ {
+ memmove(app->hist, app->hist + 1, sizeof(int) * 255);
+ app->histlen --;
+ }
+ app->hist[app->histlen++] = app->pageno;
+ app->pageno = i + 1;
+ pdfapp_showpage(app, 1, 1);
+ return;
+ }
+ }
+}
+
+void pdfapp_onresize(pdfapp_t *app, int w, int h)
+{
+ app->winw = w;
+ app->winh = h;
+ pdfapp_panview(app, app->panx, app->pany);
+ winrepaint(app);
+}
+
+void pdfapp_onkey(pdfapp_t *app, int c)
+{
+ int oldpage = app->pageno;
+ int panto = 0; /* 0 = top, 1 = bottom, 2 = leave alone */
+
+ /*
+ * Save numbers typed for later
+ */
+
+ if (c >= '0' && c <= '9')
+ app->number[app->numberlen++] = c;
+ else
+ if (c != 'g' && c != 'G')
+ app->numberlen = 0;
+
+ switch (c)
+ {
+
+ /*
+ * Zoom and rotate
+ */
+
+ case '+': case '=':
+ app->zoom += 0.1;
+ if (app->zoom > 3.0)
+ app->zoom = 3.0;
+ pdfapp_showpage(app, 0, 1);
+ break;
+ case '-':
+ app->zoom -= 0.1;
+ if (app->zoom < 0.1)
+ app->zoom = 0.1;
+ pdfapp_showpage(app, 0, 1);
+ break;
+ case 'l': case '<':
+ app->rotate -= 90;
+ pdfapp_showpage(app, 0, 1);
+ break;
+ case 'r': case '>':
+ app->rotate += 90;
+ pdfapp_showpage(app, 0, 1);
+ break;
+
+ /*
+ * Pan view, but dont need to repaint image
+ */
+
+ case 'w':
+ app->shrinkwrap = 1;
+ app->panx = app->pany = 0;
+ pdfapp_showpage(app, 0, 0);
+ break;
+
+ case 'd':
+ app->pany -= app->image->h / 10;
+ pdfapp_showpage(app, 0, 0);
+ break;
+
+ case 'u':
+ app->pany += app->image->h / 10;
+ pdfapp_showpage(app, 0, 0);
+ break;
+
+ case ',':
+ app->panx += app->image->w / 10;
+ pdfapp_showpage(app, 0, 0);
+ break;
+
+ case '.':
+ app->panx -= app->image->w / 10;
+ pdfapp_showpage(app, 0, 0);
+ break;
+
+ /*
+ * Page navigation
+ */
+
+ case 'g':
+ case '\n':
+ case '\r':
+ if (app->numberlen > 0)
+ {
+ app->number[app->numberlen] = '\0';
+ app->pageno = atoi(app->number);
+ app->numberlen = 0;
+ }
+ break;
+
+ case 'G':
+ app->pageno = pdf_getpagecount(app->pages);
+ break;
+
+ case 'm':
+ if (app->histlen + 1 == 256)
+ {
+ memmove(app->hist, app->hist + 1, sizeof(int) * 255);
+ app->histlen --;
+ }
+ app->hist[app->histlen++] = app->pageno;
+ break;
+
+ case 't':
+ if (app->histlen > 0)
+ app->pageno = app->hist[--app->histlen];
+ break;
+
+ /*
+ * Back and forth ...
+ */
+
+ case 'p':
+ panto = 2;
+ app->pageno--;
+ break;
+
+ case 'b': case '\b':
+ panto = 1;
+ app->pageno--;
+ break;
+
+ case 'n':
+ panto = 2;
+ case 'f': case ' ':
+ app->pageno++;
+ break;
+
+ case 'B':
+ app->pageno -= 10;
+ break;
+
+ case 'F':
+ app->pageno += 10;
+ break;
+ }
+
+ if (app->pageno < 1)
+ app->pageno = 1;
+ if (app->pageno > pdf_getpagecount(app->pages))
+ app->pageno = pdf_getpagecount(app->pages);
+
+ if (app->pageno != oldpage)
+ {
+ switch (panto)
+ {
+ case 0: app->pany = 0; break;
+ case 1: app->pany = -2000; break;
+ case 2: break;
+ }
+ pdfapp_showpage(app, 1, 1);
+ }
+}
+
+void pdfapp_onmouse(pdfapp_t *app, int x, int y, int btn, int state)
+{
+ pdf_link *link;
+ fz_matrix ctm;
+ fz_point p;
+
+ p.x = x - app->panx + app->image->x;
+ p.y = y - app->pany + app->image->y;
+
+ ctm = pdfapp_viewctm(app);
+ ctm = fz_invertmatrix(ctm);
+
+ p = fz_transformpoint(ctm, p);
+
+ for (link = app->page->links; link; link = link->next)
+ {
+ if (p.x >= link->rect.x0 && p.x <= link->rect.x1)
+ if (p.y >= link->rect.y0 && p.y <= link->rect.y1)
+ break;
+ }
+
+ if (link)
+ {
+ wincursor(app, HAND);
+ if (btn == 1 && state == 1)
+ {
+ if (fz_isstring(link->dest))
+ pdfapp_gotouri(app, link->dest);
+ if (fz_isindirect(link->dest))
+ pdfapp_gotopage(app, link->dest);
+ return;
+ }
+ }
+ else
+ {
+ wincursor(app, ARROW);
+ }
+
+ if (state == 1)
+ {
+ if (btn == 1 && !app->iscopying)
+ {
+ app->ispanning = 1;
+ app->selx = x;
+ app->sely = y;
+ }
+ if (btn == 3 && !app->ispanning)
+ {
+ app->iscopying = 1;
+ app->selx = x;
+ app->sely = y;
+ app->selr.x0 = x;
+ app->selr.x1 = x;
+ app->selr.y0 = y;
+ app->selr.y1 = y;
+ }
+ }
+
+ else if (state == -1)
+ {
+ if (app->iscopying)
+ {
+ app->iscopying = 0;
+ app->selr.x0 = MIN(app->selx, x);
+ app->selr.x1 = MAX(app->selx, x);
+ app->selr.y0 = MIN(app->sely, y);
+ app->selr.y1 = MAX(app->sely, y);
+ winrepaint(app);
+ if (app->selr.x0 < app->selr.x1 && app->selr.y0 < app->selr.y1)
+ windocopy(app);
+ }
+ if (app->ispanning)
+ app->ispanning = 0;
+ }
+
+ else if (app->ispanning)
+ {
+ int newx = app->panx + x - app->selx;
+ int newy = app->pany + y - app->sely;
+ pdfapp_panview(app, newx, newy);
+ app->selx = x;
+ app->sely = y;
+ }
+
+ else if (app->iscopying)
+ {
+ app->selr.x0 = MIN(app->selx, x);
+ app->selr.x1 = MAX(app->selx, x);
+ app->selr.y0 = MIN(app->sely, y);
+ app->selr.y1 = MAX(app->sely, y);
+ winrepaint(app);
+ }
+
+}
+
+void pdfapp_oncopy(pdfapp_t *app, unsigned short *ucsbuf, int ucslen)
+{
+ fz_error *error;
+ pdf_textline *line, *ln;
+ int x, y, c;
+ int i, p;
+
+ int x0 = app->image->x + app->selr.x0 - app->panx;
+ int x1 = app->image->x + app->selr.x1 - app->panx;
+ int y0 = app->image->y + app->selr.y0 - app->pany;
+ int y1 = app->image->y + app->selr.y1 - app->pany;
+
+ error = pdf_loadtextfromtree(&line, app->page->tree, pdfapp_viewctm(app));
+ if (error)
+ pdfapp_error(app, error);
+
+ p = 0;
+ for (ln = line; ln; ln = ln->next)
+ {
+ y = y0 - 1;
+ for (i = 0; i < ln->len; i++)
+ {
+ x = ln->text[i].x;
+ y = ln->text[i].y;
+ c = ln->text[i].c;
+ if (c < 32)
+ c = '?';
+ if (x >= x0 && x <= x1 && y >= y0 && y <= y1)
+ if (p < ucslen - 1)
+ ucsbuf[p++] = c;
+ }
+
+ if (y >= y0 && y <= y1)
+ {
+ if (p < ucslen - 1)
+ ucsbuf[p++] = '\r';
+#ifdef WIN32
+ if (p < ucslen - 1)
+ ucsbuf[p++] = '\n';
+#endif
+ }
+ }
+
+ ucsbuf[p] = 0;
+
+ pdf_droptextline(line);
+}
+
|