summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ghostscript.com>2005-04-01 12:49:29 +0200
committerTor Andersson <tor@ghostscript.com>2005-04-01 12:49:29 +0200
commitfb2db10b9760e7692ef16b4cf70bfae188b836af (patch)
tree3a41e061d7d7eead6b85ff4cb33b2264eacdbbb3
parent71147425af91535ba76b4a49f8527cb3b0fc1a21 (diff)
downloadmupdf-fb2db10b9760e7692ef16b4cf70bfae188b836af.tar.xz
new keybindings. copy text to clipboard.
-rw-r--r--TODO5
-rw-r--r--apps/pdfrip.c39
-rw-r--r--apps/windows/win_main.c422
-rw-r--r--include/mupdf/page.h3
-rw-r--r--mupdf/pdf_page.c14
-rw-r--r--mupdf/pdf_unicode.c4
6 files changed, 332 insertions, 155 deletions
diff --git a/TODO b/TODO
index 715c209c..c7a67117 100644
--- a/TODO
+++ b/TODO
@@ -1,8 +1,3 @@
-be smarter about where i put deps on font and rendering in mupdf files
-so that the linker can chuck them if they arent used
-
----
-
immediate plan:
* design gui for editor
diff --git a/apps/pdfrip.c b/apps/pdfrip.c
index b160ea65..d25e84b3 100644
--- a/apps/pdfrip.c
+++ b/apps/pdfrip.c
@@ -7,6 +7,7 @@ char *namefmt = nil;
fz_renderer *gc;
int nbands = 1;
int verbose = 0;
+int textonly = 0;
void usage()
{
@@ -14,8 +15,9 @@ void usage()
"usage: pdfrip [options] file.pdf pageranges\n"
" -b -\trender page in N bands (default 1)\n"
" -d -\tpassword for decryption\n"
+" -g \tshow display tree -- debug\n"
" -o -\toutput filename format (default out-%%03d.ppm)\n"
-" -t \tshow display tree\n"
+" -t \tprint text on stdout instead of rendering\n"
" -v \tverbose\n"
" -z -\tzoom factor (default 1.0 = 72 dpi)\n"
);
@@ -72,6 +74,22 @@ void showpage(pdf_xref *xref, fz_obj *pageobj, int pagenum)
ctm = fz_concat(fz_translate(0, -page->mediabox.max.y),
fz_scale(zoom, -zoom));
+ if (textonly)
+ {
+ pdf_textline *line;
+
+ error = pdf_loadtextfromtree(&line, page->tree, ctm);
+ if (error)
+ fz_abort(error);
+ pdf_debugtextline(line);
+ pdf_droptextline(line);
+ pdf_droppage(page);
+
+ printf("\n\f\n");
+
+ return;
+ }
+
bbox = fz_roundrect(page->mediabox);
bbox.min.x = bbox.min.x * zoom;
bbox.min.y = bbox.min.y * zoom;
@@ -123,6 +141,8 @@ void showpage(pdf_xref *xref, fz_obj *pageobj, int pagenum)
fz_droppixmap(pix);
close(fd);
+
+ pdf_droppage(page);
}
int main(int argc, char **argv)
@@ -138,11 +158,12 @@ int main(int argc, char **argv)
fz_cpudetect();
fz_accelerate();
- while ((c = getopt(argc, argv, "Vtvz:d:o:b:")) != -1)
+ while ((c = getopt(argc, argv, "Vgtvz:d:o:b:")) != -1)
{
switch (c)
{
- case 't': ++showtree; break;
+ case 'g': ++showtree; break;
+ case 't': ++textonly; break;
case 'v': ++verbose; break;
case 'd': password = optarg; break;
case 'z': zoom = atof(optarg); break;
@@ -209,7 +230,16 @@ int main(int argc, char **argv)
pdf_debugpagetree(pages);
if (optind == argc)
+ {
printf("%d pages\n", pdf_getpagecount(pages));
+ return 0;
+ }
+
+ if (textonly)
+ {
+ puts("Content-Type: text/plain; charset=UTF-8");
+ puts("");
+ }
error = fz_newrenderer(&gc, pdf_devicergb, 0, 1024 * 512);
if (error)
@@ -250,6 +280,9 @@ int main(int argc, char **argv)
fz_droprenderer(gc);
+ pdf_dropstore(xref->store);
+ xref->store = nil;
+
pdf_closexref(xref);
return 0;
diff --git a/apps/windows/win_main.c b/apps/windows/win_main.c
index 4fb97ed3..353ed4cc 100644
--- a/apps/windows/win_main.c
+++ b/apps/windows/win_main.c
@@ -21,9 +21,11 @@ static LRESULT CALLBACK windproc(HWND, UINT, WPARAM, LPARAM);
static int winwidth = 0;
static int winheight = 0;
-static int isdown = 0;
+static int ispanning = 0;
static int oldx = 0, oldy = 0;
-
+static int iscopying = 0;
+static RECT copyrect;
+static int firstx = 0, firsty = 0;
static int bmpstride = 0;
static char *bmpdata = NULL;
@@ -225,22 +227,27 @@ void help()
{
char msg[1024];
sprintf(msg,
- "GhostPDF v%0.2f -- %s\n\n"
- " h\t-- display this help\n"
- " <\t-- rotate left\n"
- " >\t-- rotate right\n"
- " +\t-- zoom in\n"
- " -\t-- zoom out\n"
- " w\t-- shrinkwrap window\n"
- " b\t-- go back one page\n"
- " B\t-- go back ten pages\n"
- " f\t-- go forward one page\n"
- " F\t-- go forward ten pages\n"
- " G\t-- go to last page\n"
- " m\t-- mark page\n"
- " t\t-- pop back to last marked page\n"
- " 123g\t-- go to page 123\n",
- PDF_VERSION / 100.0, PDF_COPYRIGHT);
+"GhostPDF v%0.2f -- %s\n\n"
+" l <\t\t-- rotate left\n"
+" r >\t\t-- rotate right\n"
+" u up\t\t-- scroll up\n"
+" d down\t\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"
+ , PDF_VERSION / 100.0, PDF_COPYRIGHT);
MessageBoxA(hwnd, msg, "GhostPDF: Usage", MB_ICONINFORMATION);
}
@@ -344,6 +351,33 @@ void winconvertimage()
}
}
+void invertcopyrect()
+{
+ int x0 = copyrect.left - panx;
+ int x1 = copyrect.right - panx;
+ int y0 = copyrect.top - pany;
+ int y1 = copyrect.bottom - pany;
+ int x, y;
+
+ x0 = CLAMP(x0, 0, image->w - 1);
+ x1 = CLAMP(x1, 0, image->w - 1);
+ y0 = CLAMP(y0, 0, image->h - 1);
+ y1 = CLAMP(y1, 0, image->h - 1);
+
+ unsigned char *p;
+ for (y = y0; y < y1; y++)
+ {
+ p = bmpdata + y * bmpstride + x0 * 3;
+ for (x = x0; x < x1; x++)
+ {
+ p[0] = 255 - p[0];
+ p[1] = 255 - p[1];
+ p[2] = 255 - p[2];
+ p += 3;
+ }
+ }
+}
+
void winblit()
{
int x0 = panx;
@@ -354,6 +388,8 @@ void winblit()
if (bmpdata)
{
+ if (iscopying)
+ invertcopyrect();
dibinf->bmiHeader.biWidth = image->w;
dibinf->bmiHeader.biHeight = -image->h;
dibinf->bmiHeader.biSizeImage = image->h * bmpstride;
@@ -370,21 +406,23 @@ void winblit()
dibinf, /* pInfo */
DIB_RGB_COLORS /* color use flag */
);
+ if (iscopying)
+ invertcopyrect();
}
-
+ /* Grey background */
r.top = 0; r.bottom = winheight;
r.left = 0; r.right = x0;
FillRect(hdc, &r, bgbrush);
r.left = x1; r.right = winwidth;
FillRect(hdc, &r, bgbrush);
-
r.left = 0; r.right = winwidth;
r.top = 0; r.bottom = y0;
FillRect(hdc, &r, bgbrush);
r.top = y1; r.bottom = winheight;
FillRect(hdc, &r, bgbrush);
+ /* Drop shadow */
r.left = x0 + 2;
r.right = x1 + 2;
r.top = y1;
@@ -425,6 +463,16 @@ void dragndrop()
* Event handling
*/
+fz_matrix makectm(void)
+{
+ fz_matrix ctm;
+ 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));
+ return ctm;
+}
+
void constrainpan(int *panx, int *pany)
{
int newx = *panx;
@@ -447,15 +495,72 @@ void constrainpan(int *panx, int *pany)
*pany = newy;
}
-void dumptext()
+void handlecopy()
{
+#define BUFLEN 4096
+ HGLOBAL handle;
+ unsigned short *ucsbuf;
fz_error *error;
- pdf_textline *line;
- error = pdf_loadtextfromtree(&line, page->tree);
+ pdf_textline *line, *ln;
+ int x, y, c;
+ int i, p;
+
+ int x0 = image->x + copyrect.left - panx;
+ int x1 = image->x + copyrect.right - panx;
+ int y0 = image->y + copyrect.top - pany;
+ int y1 = image->y + copyrect.bottom - pany;
+
+ if (!OpenClipboard(hwnd))
+ return;
+ EmptyClipboard();
+
+ handle = GlobalAlloc(GMEM_MOVEABLE, BUFLEN * sizeof(unsigned short));
+ if (!handle)
+ {
+ CloseClipboard();
+ return;
+ }
+
+ ucsbuf = GlobalLock(handle);
+
+ error = pdf_loadtextfromtree(&line, page->tree, makectm());
if (error)
fz_abort(error);
- pdf_debugtextline(line);
+
+ 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 < BUFLEN - 1)
+ ucsbuf[p++] = c;
+ }
+
+ if (y >= y0 && y <= y1)
+ {
+ if (p < BUFLEN - 1)
+ ucsbuf[p++] = '\r';
+ if (p < BUFLEN - 1)
+ ucsbuf[p++] = '\n';
+ }
+ }
+
+ ucsbuf[p] = 0;
+
pdf_droptextline(line);
+
+ GlobalUnlock(handle);
+
+ SetClipboardData(CF_UNICODETEXT, handle);
+
+ CloseClipboard();
}
void gotouri(fz_obj *uri)
@@ -495,6 +600,11 @@ void handlekey(int c)
int oldpage = pageno;
float oldzoom = zoom;
int oldrotate = rotate;
+ int panto = 0; /* 0 = top, 1 = bottom, 2 = leave alone */
+
+ /*
+ * Save numbers typed for later
+ */
if (c >= '0' && c <= '9')
pagebuf[pagebufidx++] = c;
@@ -504,85 +614,40 @@ void handlekey(int c)
switch (c)
{
+
+ /*
+ * Help and quit
+ */
+
case VK_F1:
case 'h':
+ case '?':
help();
break;
- 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 VK_LEFT:
- case '\b':
- case 'b':
- pageno--;
- if (pageno < 1)
- pageno = 1;
- break;
- case 'B':
- pageno -= 10;
- if (pageno < 1)
- pageno = 1;
- break;
-
- case VK_PRIOR:
- pany += image->h;
- case VK_UP:
- pany += image->h / 10;
- constrainpan(&panx, &pany);
- winrepaint();
+ case VK_ESCAPE:
+ case 'q':
+ exit(0);
break;
- case VK_NEXT:
- pany -= image->h;
- case VK_DOWN:
- pany -= image->h / 10;
- constrainpan(&panx, &pany);
- winrepaint();
- break;
+ /*
+ * Zoom and rotate
+ */
- case VK_RIGHT:
- 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];
+ case '+': case '=':
+ zoom += 0.1;
+ if (zoom > 3.0)
+ zoom = 3.0;
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 '<':
+ case 'l': case '<':
rotate -= 90;
break;
- case '>':
+ case 'r': case '>':
rotate += 90;
break;
@@ -592,11 +657,41 @@ void handlekey(int c)
winresize(image->w, image->h);
break;
- case VK_ESCAPE:
- case 'q':
- exit(0);
+ /*
+ * Pan view, but dont change page
+ */
+
+ case 'd': case VK_DOWN:
+ pany -= image->h / 10;
+ constrainpan(&panx, &pany);
+ winrepaint();
+ break;
+
+ case 'u': case VK_UP:
+ pany += image->h / 10;
+ constrainpan(&panx, &pany);
+ winrepaint();
+ break;
+
+ case ',':
+ panx += image->w / 10;
+ constrainpan(&panx, &pany);
+ winrepaint();
+ break;
+
+ case '.':
+ panx -= image->w / 10;
+ constrainpan(&panx, &pany);
+ winrepaint();
+ break;
+
+ /*
+ * Page navigation
+ */
+
case 'g':
- case 'G':
+ case '\n':
+ case '\r':
if (pagebufidx > 0)
{
pagebuf[pagebufidx] = '\0';
@@ -607,18 +702,76 @@ void handlekey(int c)
if (pageno > count)
pageno = count;
}
- else
+ break;
+
+ case 'G':
+ pageno = count;
+ break;
+
+ case 'm':
+ if (histlen + 1 == 256)
{
- if (c == 'G')
- {
- pageno = count;
- }
+ memmove(hist, hist + 1, sizeof(int) * 255);
+ histlen --;
}
+ hist[histlen++] = pageno;
+ break;
+
+ case 't':
+ if (histlen > 0)
+ pageno = hist[--histlen];
+ break;
+
+ /*
+ * Back and forth ...
+ */
+
+ case VK_LEFT:
+ panto = 2;
+ pageno--;
+ if (pageno < 1)
+ pageno = 1;
+ break;
+
+ case VK_PRIOR: case '\b': case 'b':
+ panto = 1;
+ pageno--;
+ if (pageno < 1)
+ pageno = 1;
+ break;
+
+ case VK_RIGHT:
+ panto = 2;
+ case VK_NEXT: case ' ': case 'f': case 'n':
+ pageno++;
+ if (pageno > count)
+ pageno = count;
+ break;
+
+ case 'B':
+ pageno -= 10;
+ if (pageno < 1)
+ pageno = 1;
+ break;
+
+ case 'F': case 'N':
+ pageno += 10;
+ if (pageno > count)
+ pageno = count;
break;
}
if (pageno != oldpage || zoom != oldzoom || rotate != oldrotate)
+ {
+ switch (panto)
+ {
+ case 0: pany = 0; break;
+ case 1: pany = -2000; break;
+ case 2: break;
+ }
showpage();
+ constrainpan(&panx, &pany);
+ }
}
void handlemouse(int x, int y, int btn, int state)
@@ -630,10 +783,7 @@ void handlemouse(int x, int y, int btn, int state)
p.x = x - panx + image->x;
p.y = y - pany + 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 = makectm();
ctm = fz_invertmatrix(ctm);
p = fz_transformpoint(ctm, p);
@@ -664,15 +814,38 @@ void handlemouse(int x, int y, int btn, int state)
if (state == 1)
{
- isdown = 1;
SetCapture(hwnd);
+ if (btn == 1 && !iscopying)
+ ispanning = 1;
+ if (btn == 3 && !ispanning)
+ {
+ iscopying = 1;
+ firstx = x;
+ firsty = y;
+ copyrect.left = x;
+ copyrect.right = x;
+ copyrect.top = y;
+ copyrect.bottom = y;
+ }
}
+
else if (state == -1)
{
- isdown = 0;
ReleaseCapture();
+ if (iscopying)
+ {
+ copyrect.left = MIN(firstx, x);
+ copyrect.right = MAX(firstx, x);
+ copyrect.top = MIN(firsty, y);
+ copyrect.bottom = MAX(firsty, y);
+ handlecopy();
+ winrepaint();
+ }
+ ispanning = 0;
+ iscopying = 0;
}
- else if (isdown)
+
+ else if (ispanning)
{
int newx = panx + x - oldx;
int newy = pany + y - oldy;
@@ -687,6 +860,15 @@ void handlemouse(int x, int y, int btn, int state)
}
}
+ else if (iscopying)
+ {
+ copyrect.left = MIN(firstx, x);
+ copyrect.right = MAX(firstx, x);
+ copyrect.top = MIN(firsty, y);
+ copyrect.bottom = MAX(firsty, y);
+ winrepaint();
+ }
+
oldx = x;
oldy = y;
}
@@ -781,34 +963,15 @@ windproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
/* Mouse wheel */
case WM_MOUSEWHEEL:
- if ((signed short)HIWORD(wParam) > 0) {
- // wheel-up
- handlekey('+');
- }
- else {
- // wheel-down
- handlekey('-');
- }
+ if ((signed short)HIWORD(wParam) > 0)
+ handlekey('u');
+ else
+ handlekey('d');
return 0;
/* Keyboard events */
- /* Only deal with key-down */
- case WM_KEYUP:
- return 0;
- case WM_SYSKEYUP:
- return 0;
-
- case WM_SYSCHAR:
- //printf("WM_SYSCHAR: %d '%c'\n", wParam, wParam);
- return 0;
-
- case WM_SYSKEYDOWN:
- //printf("WM_SYSKEYDOWN: %d '%c'\n", wParam, wParam);
- return 0;
-
case WM_KEYDOWN:
- //printf("WM_KEYDOWN: %d '%c'\n", wParam, wParam);
/* only handle special keys */
switch (wParam)
{
@@ -828,7 +991,6 @@ windproc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
/* unicode encoded chars, including escape, backspace etc... */
case WM_CHAR:
- //printf("WM_CHAR: %d '%c'\n", wParam, wParam);
handlekey(wParam);
handlemouse(oldx, oldy, 0, 0); /* update cursor */
return 0;
@@ -1005,7 +1167,7 @@ int main(int argc, char **argv)
associateme(argv[0]);
- while ((c = getopt(argc, argv, "hbz:r:p:u:")) != -1)
+ while ((c = getopt(argc, argv, "bz:r:p:u:")) != -1)
{
switch (c)
{
@@ -1014,7 +1176,6 @@ int main(int argc, char **argv)
case 'p': pageno = atoi(optarg); break;
case 'z': zoom = atof(optarg); break;
case 'r': rotate = atoi(optarg); break;
- case 'h': help(); break;
default: help(); exit(1); break;
}
}
@@ -1054,6 +1215,9 @@ int main(int argc, char **argv)
DispatchMessage(&msg);
}
+ pdf_dropstore(xref->store);
+ xref->store = nil;
+
pdf_closexref(xref);
return 0;
diff --git a/include/mupdf/page.h b/include/mupdf/page.h
index 648fe54d..bf14dca2 100644
--- a/include/mupdf/page.h
+++ b/include/mupdf/page.h
@@ -21,7 +21,6 @@ struct pdf_page_s
int rotate;
fz_obj *resources;
fz_tree *tree;
- pdf_textline *text;
pdf_comment *comments;
pdf_link *links;
};
@@ -50,7 +49,7 @@ fz_error *pdf_loadpage(pdf_page **pagep, pdf_xref *xref, fz_obj *ref);
void pdf_droppage(pdf_page *page);
/* unicode.c */
-fz_error *pdf_loadtextfromtree(pdf_textline **linep, fz_tree *tree);
+fz_error *pdf_loadtextfromtree(pdf_textline **linep, fz_tree *tree, fz_matrix ctm);
void pdf_debugtextline(pdf_textline *line);
fz_error *pdf_newtextline(pdf_textline **linep);
void pdf_droptextline(pdf_textline *line);
diff --git a/mupdf/pdf_page.c b/mupdf/pdf_page.c
index 994657e3..9597a9d8 100644
--- a/mupdf/pdf_page.c
+++ b/mupdf/pdf_page.c
@@ -245,18 +245,6 @@ pdf_loadpage(pdf_page **pagep, pdf_xref *xref, fz_obj *dict)
page->comments = comments;
page->links = links;
- page->text = nil;
-
- /*
- * Extract unicode text lines
- */
-
- error = pdf_loadtextfromtree(&page->text, page->tree);
- if (error)
- {
- pdf_droppage(page);
- return error;
- }
pdf_logpage("} %p\n", page);
@@ -273,8 +261,6 @@ pdf_droppage(pdf_page *page)
*/
if (page->links)
pdf_droplink(page->links);
- if (page->text)
- pdf_droptextline(page->text);
fz_dropobj(page->resources);
fz_droptree(page->tree);
fz_free(page);
diff --git a/mupdf/pdf_unicode.c b/mupdf/pdf_unicode.c
index ccfd3f30..d9103cd2 100644
--- a/mupdf/pdf_unicode.c
+++ b/mupdf/pdf_unicode.c
@@ -233,7 +233,7 @@ extracttext(pdf_textline **line, fz_node *node, fz_matrix ctm)
}
fz_error *
-pdf_loadtextfromtree(pdf_textline **outp, fz_tree *tree)
+pdf_loadtextfromtree(pdf_textline **outp, fz_tree *tree, fz_matrix ctm)
{
pdf_textline *root;
pdf_textline *line;
@@ -248,7 +248,7 @@ pdf_loadtextfromtree(pdf_textline **outp, fz_tree *tree)
line = root;
- error = extracttext(&line, tree->root, fz_identity());
+ error = extracttext(&line, tree->root, ctm);
if (error)
{
pdf_droptextline(root);