diff options
author | cinap_lenrek <cinap_lenrek@centraldogma> | 2011-09-15 20:59:31 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@centraldogma> | 2011-09-15 20:59:31 +0200 |
commit | d9657f82748a397eed451a4cfd0bbc6f19551488 (patch) | |
tree | 920beb374f6476d81df66188119254acc0db7197 /sys/src | |
parent | d02a0b77666d94bc97bbf0412b3cbefeff12c462 (diff) |
replaceing page with npage
Diffstat (limited to 'sys/src')
-rw-r--r-- | sys/src/cmd/page.c (renamed from sys/src/cmd/npage.c) | 36 | ||||
-rw-r--r-- | sys/src/cmd/page/cache.c | 187 | ||||
-rw-r--r-- | sys/src/cmd/page/filter.c | 107 | ||||
-rw-r--r-- | sys/src/cmd/page/gfx.c | 332 | ||||
-rw-r--r-- | sys/src/cmd/page/gs.c | 342 | ||||
-rw-r--r-- | sys/src/cmd/page/mkfile | 36 | ||||
-rw-r--r-- | sys/src/cmd/page/nrotate.c | 277 | ||||
-rw-r--r-- | sys/src/cmd/page/page.c | 238 | ||||
-rw-r--r-- | sys/src/cmd/page/page.h | 85 | ||||
-rw-r--r-- | sys/src/cmd/page/pdf.c | 153 | ||||
-rw-r--r-- | sys/src/cmd/page/pdfprolog.ps | 20 | ||||
-rw-r--r-- | sys/src/cmd/page/ps.c | 450 | ||||
-rw-r--r-- | sys/src/cmd/page/rotate.c | 500 | ||||
-rw-r--r-- | sys/src/cmd/page/util.c | 131 | ||||
-rw-r--r-- | sys/src/cmd/page/view.c | 1073 |
15 files changed, 36 insertions, 3931 deletions
diff --git a/sys/src/cmd/npage.c b/sys/src/cmd/page.c index 5bd1653c0..a0751a5eb 100644 --- a/sys/src/cmd/npage.c +++ b/sys/src/cmd/page.c @@ -873,6 +873,26 @@ translate(Page *p, Point d) } Page* +findpage(char *name) +{ + Page *p; + int n; + + n = strlen(name); + /* look in current document first */ + if(current && current->up){ + for(p = current->up->down; p; p = p->next) + if(cistrncmp(p->label, name, n) == 0) + return p; + } + /* look everywhere */ + for(p = root->down; p; p = nextpage(p)) + if(cistrncmp(p->label, name, n) == 0) + return p; + return nil; +} + +Page* pageat(int i) { Page *p; @@ -1006,6 +1026,7 @@ void main(int argc, char *argv[]) { enum { Eplumb = 4 }; + char jump[32]; Plumbmsg *pm; Point o; Mouse m; @@ -1061,6 +1082,7 @@ main(int argc, char *argv[]) for(; *argv; argv++) addpage(root, shortname(*argv), popenfile, strdup(*argv), -1); + jump[0] = 0; for(;;){ i=event(&e); switch(i){ @@ -1183,6 +1205,8 @@ main(int argc, char *argv[]) qunlock(current); if(prevpage(current)) pos.y = 0; + case '-': + case Kbs: case Kleft: showpage(prevpage(current)); break; @@ -1201,10 +1225,22 @@ main(int argc, char *argv[]) qunlock(current); if(nextpage(current)) pos.y = 0; + case '\n': + if(jump[0]){ + showpage(findpage(jump)); + jump[0] = 0; + break; + } case ' ': case Kright: showpage(nextpage(current)); break; + default: + i = strlen(jump); + if(i+1 < sizeof(jump)){ + jump[i] = e.kbdc; + jump[i+1] = 0; + } } break; case Eplumb: diff --git a/sys/src/cmd/page/cache.c b/sys/src/cmd/page/cache.c deleted file mode 100644 index 376a075ed..000000000 --- a/sys/src/cmd/page/cache.c +++ /dev/null @@ -1,187 +0,0 @@ -#include <u.h> -#include <libc.h> -#include <draw.h> -#include <cursor.h> -#include <event.h> -#include <bio.h> -#include <plumb.h> -#include <ctype.h> -#include <keyboard.h> -#include "page.h" - -typedef struct Cached Cached; -struct Cached -{ - Document *doc; - int page; - int angle; - Image *im; -}; - -static Cached cache[5]; - -static Image* -questionmark(void) -{ - static Image *im; - - if(im) - return im; - im = xallocimage(display, Rect(0,0,50,50), GREY1, 1, DBlack); - if(im == nil) - return nil; - string(im, ZP, display->white, ZP, display->defaultfont, "?"); - return im; -} - -void -cacheflush(void) -{ - int i; - Cached *c; - - for(i=0; i<nelem(cache); i++){ - c = &cache[i]; - if(c->im) - freeimage(c->im); - c->im = nil; - c->doc = nil; - } -} - -static Image* -_cachedpage(Document *doc, int angle, int page, char *ra) -{ - int i; - Cached *c, old; - Image *im, *tmp; - static int lastpage = -1; - - if((page < 0 || page >= doc->npage) && !doc->fwdonly) - return nil; - -Again: - for(i=0; i<nelem(cache); i++){ - c = &cache[i]; - if(c->doc == doc && c->angle == angle && c->page == page){ - if(chatty) fprint(2, "cache%s hit %d\n", ra, page); - goto Found; - } - if(c->doc == nil) - break; - } - - if(i >= nelem(cache)) - i = nelem(cache)-1; - c = &cache[i]; - if(c->im) - freeimage(c->im); - c->im = nil; - c->doc = nil; - c->page = -1; - - if(chatty) fprint(2, "cache%s load %d\n", ra, page); - im = doc->drawpage(doc, page); - if(im == nil){ - if(doc->fwdonly) /* end of file */ - wexits(0); - im = questionmark(); - if(im == nil){ - Flush: - if(i > 0){ - cacheflush(); - goto Again; - } - fprint(2, "out of memory: %r\n"); - wexits("memory"); - } - return im; - } - - if(im->r.min.x != 0 || im->r.min.y != 0){ - /* translate to 0,0 */ - tmp = xallocimage(display, Rect(0, 0, Dx(im->r), Dy(im->r)), im->chan, 0, DNofill); - if(tmp == nil){ - freeimage(im); - goto Flush; - } - drawop(tmp, tmp->r, im, nil, im->r.min, S); - freeimage(im); - im = tmp; - } - - switch(angle){ - case 90: - im = rot90(im); - break; - case 180: - rot180(im); - break; - case 270: - im = rot270(im); - break; - } - if(im == nil) - goto Flush; - - c->doc = doc; - c->page = page; - c->angle = angle; - c->im = im; - -Found: - if(chatty) fprint(2, "cache%s mtf %d @%d:", ra, c->page, i); - old = *c; - memmove(cache+1, cache, (c-cache)*sizeof cache[0]); - cache[0] = old; - if(chatty){ - for(i=0; i<nelem(cache); i++) - fprint(2, " %d", cache[i].page); - fprint(2, "\n"); - } - if(chatty) fprint(2, "cache%s return %d %p\n", ra, old.page, old.im); - return old.im; -} - -Image* -cachedpage(Document *doc, int angle, int page) -{ - static int lastpage = -1; - static int rabusy; - Image *im; - int ra; - - if(doc->npage < 1) - return display->white; - - im = _cachedpage(doc, angle, page, ""); - if(im == nil) - return nil; - - /* readahead */ - ra = -1; - if(!rabusy){ - if(page == lastpage+1) - ra = page+1; - else if(page == lastpage-1) - ra = page-1; - } - lastpage = page; - if(ra >= 0){ - rabusy = 1; - switch(rfork(RFPROC|RFMEM|RFNOWAIT)){ - case -1: - rabusy = 0; - break; - case 0: - lockdisplay(display); - _cachedpage(doc, angle, ra, "-ra"); - rabusy = 0; - unlockdisplay(display); - _exits(nil); - default: - break; - } - } - return im; -} diff --git a/sys/src/cmd/page/filter.c b/sys/src/cmd/page/filter.c deleted file mode 100644 index 07c3df2b2..000000000 --- a/sys/src/cmd/page/filter.c +++ /dev/null @@ -1,107 +0,0 @@ -#include <u.h> -#include <libc.h> -#include <draw.h> -#include <event.h> -#include <bio.h> -#include "page.h" - -Document* -initfilt(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf, char *type, char *cmd, int docopy) -{ - int ofd; - int p[2]; - char xbuf[8192]; - int n; - - if(argc > 1) { - fprint(2, "can only view one %s file at a time\n", type); - return nil; - } - - fprint(2, "converting from %s to postscript...\n", type); - - if(docopy){ - if(pipe(p) < 0){ - fprint(2, "pipe fails: %r\n"); - exits("Epipe"); - } - }else{ - p[0] = open("/dev/null", ORDWR); - p[1] = open("/dev/null", ORDWR); - } - - ofd = opentemp("/tmp/pagecvtXXXXXXXXX"); - switch(fork()){ - case -1: - fprint(2, "fork fails: %r\n"); - exits("Efork"); - default: - close(p[1]); - if(docopy){ - write(p[0], buf, nbuf); - if(b) - while((n = Bread(b, xbuf, sizeof xbuf)) > 0) - write(p[0], xbuf, n); - else - while((n = read(stdinfd, xbuf, sizeof xbuf)) > 0) - write(p[0], xbuf, n); - } - close(p[0]); - waitpid(); - break; - case 0: - close(p[0]); - dup(p[1], 0); - dup(ofd, 1); - /* stderr shines through */ - execl("/bin/rc", "rc", "-c", cmd, nil); - break; - } - - if(b) - Bterm(b); - seek(ofd, 0, 0); - b = emalloc(sizeof(Biobuf)); - Binit(b, ofd, OREAD); - - return initps(b, argc, argv, nil, 0); -} - -Document* -initdvi(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf) -{ - int fd; - char *name; - char cmd[256]; - char fdbuf[20]; - - /* - * Stupid DVIPS won't take standard input. - */ - if(b == nil){ /* standard input; spool to disk (ouch) */ - fd = spooltodisk(buf, nbuf, &name); - sprint(fdbuf, "/fd/%d", fd); - b = Bopen(fdbuf, OREAD); - if(b == nil){ - fprint(2, "cannot open disk spool file\n"); - wexits("Bopen temp"); - } - argv = &name; - argc = 1; - } - - snprint(cmd, sizeof cmd, "dvips -Pps -r0 -q1 -f1 '%s'", argv[0]); - return initfilt(b, argc, argv, buf, nbuf, "dvi", cmd, 0); -} - -Document* -inittroff(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf) -{ - return initfilt(b, argc, argv, buf, nbuf, "troff", "lp -dstdout", 1); -} - -Document* -initmsdoc(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf) -{ - return initfilt(b, argc, argv, buf, nbuf, "microsoft office", "doc2ps", 1); -} diff --git a/sys/src/cmd/page/gfx.c b/sys/src/cmd/page/gfx.c deleted file mode 100644 index 57ebc746b..000000000 --- a/sys/src/cmd/page/gfx.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - * graphics file reading for page - */ - -#include <u.h> -#include <libc.h> -#include <draw.h> -#include <event.h> -#include <bio.h> -#include "page.h" - -typedef struct Convert Convert; -typedef struct GfxInfo GfxInfo; -typedef struct Graphic Graphic; - -struct Convert { - char *name; - char *cmd; - char *truecmd; /* cmd for true color */ -}; - -struct GfxInfo { - Graphic *g; -}; - -struct Graphic { - int type; - char *name; - uchar *buf; /* if stdin */ - int nbuf; -}; - -enum { - Ipic, - Itiff, - Ijpeg, - Igif, - Iinferno, - Ifax, - Icvt2pic, - Iplan9bm, - Iccittg4, - Ippm, - Ipng, - Iyuv, - Ibmp, -}; - -/* - * N.B. These commands need to read stdin if %a is replaced - * with an empty string. - */ -Convert cvt[] = { -[Ipic] { "plan9", "fb/3to1 rgbv %a |fb/pcp -tplan9" }, -[Itiff] { "tiff", "fb/tiff2pic %a | fb/3to1 rgbv | fb/pcp -tplan9" }, -[Iplan9bm] { "plan9bm", nil }, -[Ijpeg] { "jpeg", "jpg -9 %a", "jpg -t9 %a" }, -[Igif] { "gif", "gif -9 %a", "gif -t9 %a" }, -[Iinferno] { "inferno", nil }, -[Ifax] { "fax", "aux/g3p9bit -g %a" }, -[Icvt2pic] { "unknown", "fb/cvt2pic %a |fb/3to1 rgbv" }, -[Ippm] { "ppm", "ppm -9 %a", "ppm -t9 %a" }, -/* ``temporary'' hack for hobby */ -[Iccittg4] { "ccitt-g4", "cat %a|rx nslocum /usr/lib/ocr/bin/bcp -M|fb/pcp -tcompressed -l0" }, -[Ipng] { "png", "png -9 %a", "png -t9 %a" }, -[Iyuv] { "yuv", "yuv -9 %a", "yuv -t9 %a" }, -[Ibmp] { "bmp", "bmp -9 %a", "bmp -t9 %a" }, -}; - -static Image* convert(Graphic*); -static Image* gfxdrawpage(Document *d, int page); -static char* gfxpagename(Document*, int); -static int spawnrc(char*, uchar*, int); -static void waitrc(void); -static int spawnpost(int); -static int addpage(Document*, char*); -static int rmpage(Document*, int); -static int genaddpage(Document*, char*, uchar*, int); - -static char* -gfxpagename(Document *doc, int page) -{ - GfxInfo *gfx = doc->extra; - return gfx->g[page].name; -} - -static Image* -gfxdrawpage(Document *doc, int page) -{ - GfxInfo *gfx = doc->extra; - return convert(gfx->g+page); -} - -Document* -initgfx(Biobuf*, int argc, char **argv, uchar *buf, int nbuf) -{ - GfxInfo *gfx; - Document *doc; - int i; - - doc = emalloc(sizeof(*doc)); - gfx = emalloc(sizeof(*gfx)); - gfx->g = nil; - - doc->npage = 0; - doc->drawpage = gfxdrawpage; - doc->pagename = gfxpagename; - doc->addpage = addpage; - doc->rmpage = rmpage; - doc->extra = gfx; - doc->fwdonly = 0; - - fprint(2, "reading through graphics...\n"); - if(argc==0 && buf) - genaddpage(doc, nil, buf, nbuf); - else{ - for(i=0; i<argc; i++) - if(addpage(doc, argv[i]) < 0) - fprint(2, "warning: not including %s: %r\n", argv[i]); - } - - return doc; -} - -static int -genaddpage(Document *doc, char *name, uchar *buf, int nbuf) -{ - Graphic *g; - GfxInfo *gfx; - Biobuf *b; - uchar xbuf[32]; - int i, l; - - l = 0; - gfx = doc->extra; - - assert((name == nil) ^ (buf == nil)); - assert(name != nil || doc->npage == 0); - - for(i=0; i<doc->npage; i++) - if(strcmp(gfx->g[i].name, name) == 0) - return i; - - if(name){ - l = strlen(name); - if((b = Bopen(name, OREAD)) == nil) { - werrstr("Bopen: %r"); - return -1; - } - - if(Bread(b, xbuf, sizeof xbuf) != sizeof xbuf) { - werrstr("short read: %r"); - return -1; - } - Bterm(b); - buf = xbuf; - nbuf = sizeof xbuf; - } - - - gfx->g = erealloc(gfx->g, (doc->npage+1)*(sizeof(*gfx->g))); - g = &gfx->g[doc->npage]; - - memset(g, 0, sizeof *g); - if(memcmp(buf, "GIF", 3) == 0) - g->type = Igif; - else if(memcmp(buf, "\111\111\052\000", 4) == 0) - g->type = Itiff; - else if(memcmp(buf, "\115\115\000\052", 4) == 0) - g->type = Itiff; - else if(memcmp(buf, "\377\330\377", 3) == 0) - g->type = Ijpeg; - else if(memcmp(buf, "\211PNG\r\n\032\n", 3) == 0) - g->type = Ipng; - else if(memcmp(buf, "compressed\n", 11) == 0) - g->type = Iinferno; - else if(memcmp(buf, "\0PC Research, Inc", 17) == 0) - g->type = Ifax; - else if(memcmp(buf, "TYPE=ccitt-g31", 14) == 0) - g->type = Ifax; - else if(memcmp(buf, "II*", 3) == 0) - g->type = Ifax; - else if(memcmp(buf, "TYPE=ccitt-g4", 13) == 0) - g->type = Iccittg4; - else if(memcmp(buf, "TYPE=", 5) == 0) - g->type = Ipic; - else if(buf[0] == 'P' && '0' <= buf[1] && buf[1] <= '9') - g->type = Ippm; - else if(memcmp(buf, "BM", 2) == 0) - g->type = Ibmp; - else if(memcmp(buf, " ", 10) == 0 && - '0' <= buf[10] && buf[10] <= '9' && - buf[11] == ' ') - g->type = Iplan9bm; - else if(strtochan((char*)buf) != 0) - g->type = Iplan9bm; - else if (l > 4 && strcmp(name + l -4, ".yuv") == 0) - g->type = Iyuv; - else - g->type = Icvt2pic; - - if(name) - g->name = estrdup(name); - else{ - g->name = estrdup("stdin"); /* so it can be freed */ - g->buf = buf; - g->nbuf = nbuf; - } - - if(chatty) fprint(2, "classified \"%s\" as \"%s\"\n", g->name, cvt[g->type].name); - return doc->npage++; -} - -static int -addpage(Document *doc, char *name) -{ - return genaddpage(doc, name, nil, 0); -} - -static int -rmpage(Document *doc, int n) -{ - int i; - GfxInfo *gfx; - - if(n < 0 || n >= doc->npage) - return -1; - - gfx = doc->extra; - doc->npage--; - free(gfx->g[n].name); - - for(i=n; i<doc->npage; i++) - gfx->g[i] = gfx->g[i+1]; - - if(n < doc->npage) - return n; - if(n == 0) - return 0; - return n-1; -} - - -static Image* -convert(Graphic *g) -{ - int fd; - Convert c; - char *cmd; - char *name, buf[1000]; - Image *im; - int rcspawned = 0; - Waitmsg *w; - - c = cvt[g->type]; - if(c.cmd == nil) { - if(chatty) fprint(2, "no conversion for bitmap \"%s\"...\n", g->name); - if(g->buf == nil){ /* not stdin */ - fd = open(g->name, OREAD); - if(fd < 0) { - fprint(2, "cannot open file: %r\n"); - wexits("open"); - } - }else - fd = stdinpipe(g->buf, g->nbuf); - } else { - cmd = c.cmd; - if(truecolor && c.truecmd) - cmd = c.truecmd; - - if(g->buf != nil) /* is stdin */ - name = ""; - else - name = g->name; - if(strlen(cmd)+strlen(name) > sizeof buf) { - fprint(2, "command too long\n"); - wexits("convert"); - } - snprint(buf, sizeof buf, cmd, name); - if(chatty) fprint(2, "using \"%s\" to convert \"%s\"...\n", buf, g->name); - fd = spawnrc(buf, g->buf, g->nbuf); - rcspawned++; - if(fd < 0) { - fprint(2, "cannot spawn converter: %r\n"); - wexits("convert"); - } - } - - im = readimage(display, fd, 0); - if(im == nil) { - fprint(2, "warning: couldn't read image: %r\n"); - } - close(fd); - - /* for some reason rx doesn't work well with wait */ - /* for some reason 3to1 exits on success with a non-null status of |3to1 */ - if(rcspawned && g->type != Iccittg4) { - if((w=wait())!=nil && w->msg[0] && !strstr(w->msg, "3to1")) - fprint(2, "slave wait error: %s\n", w->msg); - free(w); - } - return im; -} - -static int -spawnrc(char *cmd, uchar *stdinbuf, int nstdinbuf) -{ - int pfd[2]; - int pid; - - if(chatty) fprint(2, "spawning(%s)...", cmd); - - if(pipe(pfd) < 0) - return -1; - if((pid = fork()) < 0) - return -1; - - if(pid == 0) { - close(pfd[1]); - if(stdinbuf) - dup(stdinpipe(stdinbuf, nstdinbuf), 0); - else - dup(open("/dev/null", OREAD), 0); - dup(pfd[0], 1); - //dup(pfd[0], 2); - execl("/bin/rc", "rc", "-c", cmd, nil); - wexits("exec"); - } - close(pfd[0]); - return pfd[1]; -} - diff --git a/sys/src/cmd/page/gs.c b/sys/src/cmd/page/gs.c deleted file mode 100644 index 3ff04685b..000000000 --- a/sys/src/cmd/page/gs.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * gs interface for page. - * ps.c and pdf.c both use these routines. - * a caveat: if you run more than one gs, only the last - * one gets killed by killgs - */ -#include <u.h> -#include <libc.h> -#include <draw.h> -#include <event.h> -#include <bio.h> -#include "page.h" - -static int gspid; /* globals for atexit */ -static int gsfd; -static void killgs(void); - -static void -killgs(void) -{ - char tmpfile[100]; - - close(gsfd); - postnote(PNGROUP, getpid(), "die"); - - /* - * from ghostscript's use.txt: - * ``Ghostscript currently doesn't do a very good job of deleting temporary - * files when it exits; you may have to delete them manually from time to - * time.'' - */ - sprint(tmpfile, "/tmp/gs_%.5da", (gspid+300000)%100000); - if(chatty) fprint(2, "remove %s...\n", tmpfile); - remove(tmpfile); - sleep(100); - postnote(PNPROC, gspid, "die yankee pig dog"); -} - -int -spawnwriter(GSInfo *g, Biobuf *b) -{ - char buf[4096]; - int n; - int fd; - - switch(fork()){ - case -1: return -1; - case 0: break; - default: return 0; - } - - Bseek(b, 0, 0); - fd = g->gsfd; - while((n = Bread(b, buf, sizeof buf)) > 0) - write(fd, buf, n); - fprint(fd, "(/fd/3) (w) file dup (THIS IS NOT AN INFERNO BITMAP\\n) writestring flushfile\n"); - _exits(0); - return -1; -} - -int -spawnreader(int fd) -{ - int n, pfd[2]; - char buf[1024]; - - if(pipe(pfd)<0) - return -1; - switch(fork()){ - case -1: - return -1; - case 0: - break; - default: - close(pfd[0]); - return pfd[1]; - } - - close(pfd[1]); - switch(fork()){ - case -1: - wexits("fork failed"); - case 0: - while((n=read(fd, buf, sizeof buf)) > 0) { - write(1, buf, n); - write(pfd[0], buf, n); - } - break; - default: - while((n=read(pfd[0], buf, sizeof buf)) > 0) { - write(1, buf, n); - write(fd, buf, n); - } - break; - } - postnote(PNGROUP, getpid(), "i'm die-ing"); - _exits(0); - return -1; -} - -void -spawnmonitor(int fd) -{ - char buf[4096]; - char *xbuf; - int n; - int out; - int first; - - switch(rfork(RFFDG|RFNOTEG|RFPROC)){ - case -1: - default: - return; - - case 0: - break; - } - - out = open("/dev/cons", OWRITE); - if(out < 0) - out = 2; - - xbuf = buf; /* for ease of acid */ - first = 1; - while((n = read(fd, xbuf, sizeof buf)) > 0){ - if(first){ - first = 0; - fprint(2, "Ghostscript Error:\n"); - } - write(out, xbuf, n); - alarm(500); - } - _exits(0); -} - -int -spawngs(GSInfo *g, char *safer) -{ - char *args[16]; - char tb[32], gb[32]; - int i, nargs; - int devnull; - int stdinout[2]; - int dataout[2]; - int errout[2]; - - /* - * spawn gs - * - * gs's standard input is fed from stdinout. - * gs output written to fd-2 (i.e. output we generate intentionally) is fed to stdinout. - * gs output written to fd 1 (i.e. ouptut gs generates on error) is fed to errout. - * gs data output is written to fd 3, which is dataout. - */ - if(pipe(stdinout) < 0 || pipe(dataout)<0 || pipe(errout)<0) - return -1; - - nargs = 0; - args[nargs++] = "gs"; - args[nargs++] = "-dNOPAUSE"; - args[nargs++] = safer; - args[nargs++] = "-sDEVICE=plan9"; - args[nargs++] = "-sOutputFile=/fd/3"; - args[nargs++] = "-dQUIET"; - args[nargs++] = "-r100"; - sprint(tb, "-dTextAlphaBits=%d", textbits); - sprint(gb, "-dGraphicsAlphaBits=%d", gfxbits); - if(textbits) - args[nargs++] = tb; - if(gfxbits) - args[nargs++] = gb; - args[nargs++] = "-"; - args[nargs] = nil; - - gspid = fork(); - if(gspid == 0) { - close(stdinout[1]); - close(dataout[1]); - close(errout[1]); - - /* - * Horrible problem: we want to dup fd's 0-4 below, - * but some of the source fd's might have those small numbers. - * So we need to reallocate those. In order to not step on - * anything else, we'll dup the fd's to higher ones using - * dup(x, -1), but we need to use up the lower ones first. - */ - while((devnull = open("/dev/null", ORDWR)) < 5) - ; - - stdinout[0] = dup(stdinout[0], -1); - errout[0] = dup(errout[0], -1); - dataout[0] = dup(dataout[0], -1); - - dup(stdinout[0], 0); - dup(errout[0], 1); - dup(devnull, 2); /* never anything useful */ - dup(dataout[0], 3); - dup(stdinout[0], 4); - for(i=5; i<20; i++) - close(i); - exec("/bin/gs", args); - wexits("exec"); - } - close(stdinout[0]); - close(errout[0]); - close(dataout[0]); - atexit(killgs); - - if(teegs) - stdinout[1] = spawnreader(stdinout[1]); - - gsfd = g->gsfd = stdinout[1]; - g->gsdfd = dataout[1]; - g->gspid = gspid; - - spawnmonitor(errout[1]); - Binit(&g->gsrd, g->gsfd, OREAD); - - gscmd(g, "/PAGEOUT (/fd/4) (w) file def\n"); - gscmd(g, "/PAGE== { PAGEOUT exch write==only PAGEOUT (\\n) writestring PAGEOUT flushfile } def\n"); - waitgs(g); - - return 0; -} - -int -gscmd(GSInfo *gs, char *fmt, ...) -{ - char buf[1024]; - int n; - - va_list v; - va_start(v, fmt); - n = vseprint(buf, buf+sizeof buf, fmt, v) - buf; - if(n <= 0) - return n; - - if(chatty) { - fprint(2, "cmd: "); - write(2, buf, n); - } - - if(write(gs->gsfd, buf, n) != 0) - return -1; - - return n; -} - -/* - * set the dimensions of the bitmap we expect to get back from GS. - */ -void -setdim(GSInfo *gs, Rectangle bbox, int ppi, int landscape) -{ - Rectangle pbox; - - if(chatty) - fprint(2, "setdim: bbox=%R\n", bbox); - - if(ppi) - gs->ppi = ppi; - - gscmd(gs, "mark\n"); - if(ppi) - gscmd(gs, "/HWResolution [%d %d]\n", ppi, ppi); - - if(!Dx(bbox)) - bbox = Rect(0, 0, 612, 792); /* 8½×11 */ - - switch(landscape){ - case 0: - pbox = bbox; - break; - case 1: - pbox = Rect(bbox.min.y, bbox.min.x, bbox.max.y, bbox.max.x); - break; - } - gscmd(gs, "/PageSize [%d %d]\n", Dx(pbox), Dy(pbox)); - gscmd(gs, "/Margins [%d %d]\n", -pbox.min.x, -pbox.min.y); - gscmd(gs, "currentdevice putdeviceprops pop\n"); - gscmd(gs, "/#copies 1 store\n"); - - if(!eqpt(bbox.min, ZP)) - gscmd(gs, "%d %d translate\n", -bbox.min.x, -bbox.min.y); - - switch(landscape){ - case 0: - break; - case 1: - gscmd(gs, "%d 0 translate\n", Dy(bbox)); - gscmd(gs, "90 rotate\n"); - break; - } - - waitgs(gs); -} - -void -waitgs(GSInfo *gs) -{ - /* we figure out that gs is done by telling it to - * print something and waiting until it does. - */ - char *p; - Biobuf *b = &gs->gsrd; - uchar buf[1024]; - int n; - -// gscmd(gs, "(\\n**bstack\\n) print flush\n"); -// gscmd(gs, "stack flush\n"); -// gscmd(gs, "(**estack\\n) print flush\n"); - gscmd(gs, "(\\n//GO.SYSIN DD\\n) PAGE==\n"); - - alarm(300*1000); - for(;;) { - p = Brdline(b, '\n'); - if(p == nil) { - n = Bbuffered(b); - if(n <= 0) - break; - if(n > sizeof buf) - n = sizeof buf; - Bread(b, buf, n); - continue; - } - p[Blinelen(b)-1] = 0; - if(chatty) fprint(2, "p: "); - if(chatty) write(2, p, Blinelen(b)-1); - if(chatty) fprint(2, "\n"); - if(strstr(p, "Error:")) { - alarm(0); - fprint(2, "ghostscript error: %s\n", p); - wexits("gs error"); - } - - if(strstr(p, "//GO.SYSIN DD")) { - break; - } - } - alarm(0); -} diff --git a/sys/src/cmd/page/mkfile b/sys/src/cmd/page/mkfile deleted file mode 100644 index cbb8c9756..000000000 --- a/sys/src/cmd/page/mkfile +++ /dev/null @@ -1,36 +0,0 @@ -</$objtype/mkfile - -TARG=page - -HFILES=page.h -OFILES=\ - cache.$O\ - filter.$O\ - gfx.$O\ - gs.$O\ - page.$O\ - pdf.$O\ - ps.$O\ - rotate.$O\ - util.$O\ - view.$O\ - -LIB=/$objtype/lib/libdraw.a - -UPDATE=\ - mkfile\ - ${OFILES:%.$O=%.c}\ - pdfprolog.ps\ - $HFILES\ - /sys/man/1/page\ - /386/bin/page\ - -</sys/src/cmd/mkone - -BIN=/$objtype/bin - -pdfprolog.c: pdfprolog.ps - cat pdfprolog.ps | sed 's/.*/"&\\n"/g' >pdfprolog.c - -pdf.$O: pdfprolog.c - diff --git a/sys/src/cmd/page/nrotate.c b/sys/src/cmd/page/nrotate.c deleted file mode 100644 index 2225ec3f1..000000000 --- a/sys/src/cmd/page/nrotate.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Rotate an image 180° in O(log Dx + log Dy) - * draw calls, using an extra buffer the same size - * as the image. - * - * The basic concept is that you can invert an array by - * inverting the top half, inverting the bottom half, and - * then swapping them. - * - * This is usually overkill, but it speeds up slow remote - * connections quite a bit. - */ - -#include <u.h> -#include <libc.h> -#include <bio.h> -#include <draw.h> -#include <event.h> -#include "page.h" - -int ndraw = 0; - -enum { - Xaxis, - Yaxis, -}; - -static void reverse(Image*, Image*, int); -static void shuffle(Image*, Image*, int, int, Image*, int, int); -static void writefile(char *name, Image *im, int gran); -static void halvemaskdim(Image*); -static void swapranges(Image*, Image*, int, int, int, int); - -/* - * Rotate the image 180° by reflecting first - * along the X axis, and then along the Y axis. - */ -void -rot180(Image *img) -{ - Image *tmp; - - tmp = xallocimage(display, img->r, img->chan, 0, DNofill); - if(tmp == nil) - return; - - reverse(img, tmp, Xaxis); - reverse(img, tmp, Yaxis); - - freeimage(tmp); -} - -Image *mtmp; - -static void -reverse(Image *img, Image *tmp, int axis) -{ - Image *mask; - Rectangle r; - int i, d; - - /* - * We start by swapping large chunks at a time. - * The chunk size should be the largest power of - * two that fits in the dimension. - */ - d = axis==Xaxis ? Dx(img) : Dy(img); - for(i = 1; i*2 <= d; i *= 2) - ; - - r = axis==Xaxis ? Rect(0,0, i,100) : Rect(0,0, 100,i); - mask = xallocimage(display, r, GREY1, 1, DTransparent); - mtmp = xallocimage(display, r, GREY1, 1, DTransparent); - - /* - * Now color the bottom (or left) half of the mask opaque. - */ - if(axis==Xaxis) - r.max.x /= 2; - else - r.max.y /= 2; - - draw(mask, r, display->opaque, nil, ZP); - writefile("mask", mask, i); - - /* - * Shuffle will recur, shuffling the pieces as necessary - * and making the mask a finer and finer grating. - */ - shuffle(img, tmp, axis, d, mask, i, 0); - - freeimage(mask); -} - -/* - * Shuffle the image by swapping pieces of size maskdim. - */ -static void -shuffle(Image *img, Image *tmp, int axis, int imgdim, Image *mask, int maskdim) -{ - int slop; - - if(maskdim == 0) - return; - - /* - * Figure out how much will be left over that needs to be - * shifted specially to the bottom. - */ - slop = imgdim % maskdim; - - /* - * Swap adjacent grating lines as per mask. - */ - swapadjacent(img, tmp, axis, imgdim - slop, mask, maskdim); - - /* - * Calculate the mask with gratings half as wide and recur. - */ - halvemaskdim(mask, maskdim, axis); - writefile("mask", mask, maskdim/2); - - shuffle(img, tmp, axis, imgdim, mask, maskdim/2); - - /* - * Move the slop down to the bottom of the image. - */ - swapranges(img, tmp, 0, imgdim-slop, imgdim, axis); - moveup(im, tmp, lastnn, nn, n, axis); -} - -/* - * Halve the grating period in the mask. - * The grating currently looks like - * ####____####____####____####____ - * where #### is opacity. - * - * We want - * ##__##__##__##__##__##__##__##__ - * which is achieved by shifting the mask - * and drawing on itself through itself. - * Draw doesn't actually allow this, so - * we have to copy it first. - * - * ####____####____####____####____ (dst) - * + ____####____####____####____#### (src) - * in __####____####____####____####__ (mask) - * =========================================== - * ##__##__##__##__##__##__##__##__ - */ -static void -halvemaskdim(Image *m, int maskdim, int axis) -{ - Point δ; - - δ = axis==Xaxis ? Pt(maskdim,0) : Pt(0,maskdim); - draw(mtmp, mtmp->r, mask, nil, mask->r.min); - gendraw(mask, mask->r, mtmp, δ, mtmp, divpt(δ,2)); - writefile("mask", mask, maskdim/2); -} - -/* - * Swap the regions [a,b] and [b,c] - */ -static void -swapranges(Image *img, Image *tmp, int a, int b, int c, int axis) -{ - Rectangle r; - Point δ; - - if(a == b || b == c) - return; - - writefile("swap", img, 0); - draw(tmp, tmp->r, im, nil, im->r.min); - - /* [a,a+(c-b)] gets [b,c] */ - r = img->r; - if(axis==Xaxis){ - δ = Pt(1,0); - r.min.x = img->r.min.x + a; - r.max.x = img->r.min.x + a + (c-b); - }else{ - δ = Pt(0,1); - r.min.y = img->r.min.y + a; - r.max.y = img->r.min.y + a + (c-b); - } - draw(img, r, tmp, nil, addpt(tmp->r.min, mulpt(δ, b))); - - /* [a+(c-b), c] gets [a,b] */ - r = img->r; - if(axis==Xaxis){ - r.min.x = img->r.min.x + a + (c-b); - r.max.x = img->r.min.x + c; - }else{ - r.min.y = img->r.min.y + a + (c-b); - r.max.y = img->r.min.y + c; - } - draw(img, r, tmp, nil, addpt(tmp->r.min, mulpt(δ, a))); - writefile("swap", img, 1); -} - -/* - * Swap adjacent regions as specified by the grating. - * We do this by copying the image through the mask twice, - * once aligned with the grading and once 180° out of phase. - */ -static void -swapadjacent(Image *img, Image *tmp, int axis, int imgdim, Image *mask, int maskdim) -{ - Point δ; - Rectangle r0, r1; - - δ = axis==Xaxis ? Pt(1,0) : Pt(0,1); - - r0 = img->r; - r1 = img->r; - switch(axis){ - case Xaxis: - r0.max.x = imgdim; - r1.min.x = imgdim; - break; - case Yaxis: - r0.max.y = imgdim; - r1.min.y = imgdim; - } - - /* - * r0 is the lower rectangle, while r1 is the upper one. - */ - draw(tmp, tmp->r, img, nil, -} - -void -interlace(Image *im, Image *tmp, int axis, int n, Image *mask, int gran) -{ - Point p0, p1; - Rectangle r0, r1; - - r0 = im->r; - r1 = im->r; - switch(axis) { - case Xaxis: - r0.max.x = n; - r1.min.x = n; - p0 = (Point){gran, 0}; - p1 = (Point){-gran, 0}; - break; - case Yaxis: - r0.max.y = n; - r1.min.y = n; - p0 = (Point){0, gran}; - p1 = (Point){0, -gran}; - break; - } - - draw(tmp, im->r, im, display->black, im->r.min); - gendraw(im, r0, tmp, p0, mask, mask->r.min); - gendraw(im, r0, tmp, p1, mask, p1); -} - - -static void -writefile(char *name, Image *im, int gran) -{ - static int c = 100; - int fd; - char buf[200]; - - snprint(buf, sizeof buf, "%d%s%d", c++, name, gran); - fd = create(buf, OWRITE, 0666); - if(fd < 0) - return; - writeimage(fd, im, 0); - close(fd); -} - diff --git a/sys/src/cmd/page/page.c b/sys/src/cmd/page/page.c deleted file mode 100644 index 85e55586c..000000000 --- a/sys/src/cmd/page/page.c +++ /dev/null @@ -1,238 +0,0 @@ -#include <u.h> -#include <libc.h> -#include <draw.h> -#include <event.h> -#include <bio.h> -#include "page.h" - -int resizing; -int mknewwindow; -int doabort; -int chatty; -int reverse = -1; -int goodps = 1; -int ppi = 100; -int teegs = 0; -int truetoboundingbox; -int textbits=4, gfxbits=4; -int wctlfd = -1; -int stdinfd; -int truecolor; -int imagemode; -int notewatcher; -int notegp; - -int -watcher(void*, char *x) -{ - if(strcmp(x, "die") != 0) - postnote(PNGROUP, notegp, x); - _exits(0); - return 0; -} - -int -bell(void *u, char *x) -{ - if(x && strcmp(x, "hangup") == 0) - _exits(0); - - if(x && strstr(x, "die") == nil) - fprint(2, "postnote %d: %s\n", getpid(), x); - - /* alarms come from the gs monitor */ - if(x && strstr(x, "alarm")){ - postnote(PNGROUP, getpid(), "die (gs error)"); - postnote(PNPROC, notewatcher, "die (gs error)"); - } - - /* function mentions u so that it's in the stack trace */ - if((u == nil || u != x) && doabort) - abort(); - -/* fprint(2, "exiting %d\n", getpid()); */ - wexits("note"); - return 0; -} - -static int -afmt(Fmt *fmt) -{ - char *s; - - s = va_arg(fmt->args, char*); - if(s == nil || s[0] == '\0') - return fmtstrcpy(fmt, ""); - else - return fmtprint(fmt, "%#q", s); -} - -void -usage(void) -{ - fprint(2, "usage: page [-biRrw] [-p ppi] file...\n"); - exits("usage"); -} - -void -main(int argc, char **argv) -{ - Document *doc; - Biobuf *b; - enum { Ninput = 16 }; - uchar buf[Ninput+1]; - int readstdin; - - ARGBEGIN{ - /* "temporary" debugging options */ - case 'P': - goodps = 0; - break; - case 'v': - chatty++; - break; - case 'V': - teegs++; - break; - case 'a': - doabort++; - break; - case 'T': - textbits = atoi(EARGF(usage())); - gfxbits = atoi(EARGF(usage())); - break; - - /* real options */ - case 'R': - resizing = 1; - break; - case 'r': - reverse = 1; - break; - case 'p': - ppi = atoi(EARGF(usage())); - break; - case 'b': - truetoboundingbox = 1; - break; - case 'w': - mknewwindow = 1; - resizing = 1; - break; - case 'i': - imagemode = 1; - break; - default: - usage(); - }ARGEND; - - notegp = getpid(); - - switch(notewatcher = fork()){ - case -1: - sysfatal("fork"); - exits(0); - default: - break; - case 0: - atnotify(watcher, 1); - for(;;) - sleep(1000); - /* not reached */ - } - - rfork(RFNOTEG); - atnotify(bell, 1); - - readstdin = 0; - if(imagemode == 0 && argc == 0){ - readstdin = 1; - stdinfd = dup(0, -1); - close(0); - open("/dev/cons", OREAD); - } - - quotefmtinstall(); - fmtinstall('a', afmt); - - fmtinstall('R', Rfmt); - fmtinstall('P', Pfmt); - if(mknewwindow) - newwin(); - - if(readstdin){ - b = nil; - if(readn(stdinfd, buf, Ninput) != Ninput){ - fprint(2, "page: short read reading %s\n", argv[0]); - wexits("read"); - } - }else if(argc != 0){ - if(!(b = Bopen(argv[0], OREAD))) { - fprint(2, "page: cannot open \"%s\"\n", argv[0]); - wexits("open"); - } - - if(Bread(b, buf, Ninput) != Ninput) { - fprint(2, "page: short read reading %s\n", argv[0]); - wexits("read"); - } - }else - b = nil; - - buf[Ninput] = '\0'; - if(imagemode) - doc = initgfx(nil, 0, nil, nil, 0); - else if(strncmp((char*)buf, "%PDF-", 5) == 0) - doc = initpdf(b, argc, argv, buf, Ninput); - else if(strncmp((char*)buf, "\x04%!", 2) == 0) - doc = initps(b, argc, argv, buf, Ninput); - else if(buf[0] == '\x1B' && strstr((char*)buf, "@PJL")) - doc = initps(b, argc, argv, buf, Ninput); - else if(strncmp((char*)buf, "%!", 2) == 0) - doc = initps(b, argc, argv, buf, Ninput); - else if(strcmp((char*)buf, "\xF7\x02\x01\x83\x92\xC0\x1C;") == 0) - doc = initdvi(b, argc, argv, buf, Ninput); - else if(strncmp((char*)buf, "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1", 8) == 0) - doc = initmsdoc(b, argc, argv, buf, Ninput); - else if(strncmp((char*)buf, "x T ", 4) == 0) - doc = inittroff(b, argc, argv, buf, Ninput); - else { - if(ppi != 100) { - fprint(2, "page: you can't specify -p with graphic files\n"); - wexits("-p and graphics"); - } - doc = initgfx(b, argc, argv, buf, Ninput); - } - - if(doc == nil) { - fprint(2, "page: error reading file: %r\n"); - wexits("document init"); - } - - if(doc->npage < 1 && !imagemode) { - fprint(2, "page: no pages found?\n"); - wexits("pagecount"); - } - - if(reverse == -1) /* neither cmdline nor ps reader set it */ - reverse = 0; - - if(initdraw(0, 0, "page") < 0){ - fprint(2, "page: initdraw failed: %r\n"); - wexits("initdraw"); - } - display->locking = 1; - - truecolor = screen->depth > 8; - viewer(doc); - wexits(0); -} - -void -wexits(char *s) -{ - if(s && *s && strcmp(s, "note") != 0 && mknewwindow) - sleep(10*1000); - postnote(PNPROC, notewatcher, "die"); - exits(s); -} diff --git a/sys/src/cmd/page/page.h b/sys/src/cmd/page/page.h deleted file mode 100644 index ac66df6b1..000000000 --- a/sys/src/cmd/page/page.h +++ /dev/null @@ -1,85 +0,0 @@ -typedef struct Document Document; - -struct Document { - char *docname; - int npage; - int fwdonly; - char* (*pagename)(Document*, int); - Image* (*drawpage)(Document*, int); - int (*addpage)(Document*, char*); - int (*rmpage)(Document*, int); - Biobuf *b; - void *extra; -}; - -void *emalloc(int); -void *erealloc(void*, int); -char *estrdup(char*); -int spawncmd(char*, char **, int, int, int); - -int spooltodisk(uchar*, int, char**); -int stdinpipe(uchar*, int); -Document *initps(Biobuf*, int, char**, uchar*, int); -Document *initpdf(Biobuf*, int, char**, uchar*, int); -Document *initgfx(Biobuf*, int, char**, uchar*, int); -Document *inittroff(Biobuf*, int, char**, uchar*, int); -Document *initdvi(Biobuf*, int, char**, uchar*, int); -Document *initmsdoc(Biobuf*, int, char**, uchar*, int); - -void viewer(Document*); -extern Cursor reading; -extern int chatty; -extern int goodps; -extern int textbits, gfxbits; -extern int reverse; -extern int clean; -extern int ppi; -extern int teegs; -extern int truetoboundingbox; -extern int wctlfd; -extern int resizing; -extern int mknewwindow; - -void rot180(Image*); -Image *rot90(Image*); -Image *rot270(Image*); -Image *resample(Image*, Image*); - -/* ghostscript interface shared by ps, pdf */ -typedef struct GSInfo GSInfo; -struct GSInfo { - int gsfd; - Biobuf gsrd; - int gspid; - int gsdfd; - int ppi; -}; -void waitgs(GSInfo*); -int gscmd(GSInfo*, char*, ...); -int spawngs(GSInfo*, char*); -void setdim(GSInfo*, Rectangle, int, int); -int spawnwriter(GSInfo*, Biobuf*); -Rectangle screenrect(void); -void newwin(void); -void zerox(void); -Rectangle winrect(void); -void resize(int, int); -int max(int, int); -int min(int, int); -void wexits(char*); -Image* xallocimage(Display*, Rectangle, ulong, int, ulong); -int bell(void*, char*); -int opentemp(char *template); -Image* cachedpage(Document*, int, int); -void cacheflush(void); - -extern int stdinfd; -extern int truecolor; - -/* BUG BUG BUG BUG BUG: cannot use new draw operations in drawterm, - * or in vncs, and there is a bug in the kernel for copying images - * from cpu memory -> video memory (memmove is not being used). - * until all that is settled, ignore the draw operators. - */ -#define drawop(a,b,c,d,e,f) draw(a,b,c,d,e) -#define gendrawop(a,b,c,d,e,f,g) gendraw(a,b,c,d,e,f) diff --git a/sys/src/cmd/page/pdf.c b/sys/src/cmd/page/pdf.c deleted file mode 100644 index 5261eab59..000000000 --- a/sys/src/cmd/page/pdf.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * pdf.c - * - * pdf file support for page - */ - -#include <u.h> -#include <libc.h> -#include <draw.h> -#include <event.h> -#include <bio.h> -#include "page.h" - -typedef struct PDFInfo PDFInfo; -struct PDFInfo { - GSInfo; - Rectangle *pagebbox; -}; - -static Image* pdfdrawpage(Document *d, int page); -static char* pdfpagename(Document*, int); - -char *pdfprolog = -#include "pdfprolog.c" - ; - -Rectangle -pdfbbox(GSInfo *gs) -{ - char *p; - char *f[4]; - Rectangle r; - - r = Rect(0,0,0,0); - waitgs(gs); - gscmd(gs, "/CropBox knownoget {} {[0 0 0 0]} ifelse PAGE==\n"); - p = Brdline(&gs->gsrd, '\n'); - p[Blinelen(&gs->gsrd)-1] ='\0'; - if(p[0] != '[') - return r; - if(tokenize(p+1, f, 4) != 4) - return r; - r = Rect(atoi(f[0]), atoi(f[1]), atoi(f[2]), atoi(f[3])); - waitgs(gs); - return r; -} - -Document* -initpdf(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf) -{ - Document *d; - PDFInfo *pdf; - char *p; - char *fn; - char fdbuf[20]; - int fd; - int i, npage; - Rectangle bbox; - - if(argc > 1) { - fprint(2, "can only view one pdf file at a time\n"); - return nil; - } - - fprint(2, "reading through pdf...\n"); - if(b == nil){ /* standard input; spool to disk (ouch) */ - fd = spooltodisk(buf, nbuf, &fn); - sprint(fdbuf, "/fd/%d", fd); - b = Bopen(fdbuf, OREAD); - if(b == nil){ - fprint(2, "cannot open disk spool file\n"); - wexits("Bopen temp"); - } - }else - fn = argv[0]; - - /* sanity check */ - Bseek(b, 0, 0); - if(!(p = Brdline(b, '\n')) && !(p = Brdline(b, '\r'))) { - fprint(2, "cannot find end of first line\n"); - wexits("initps"); - } - if(strncmp(p, "%PDF-", 5) != 0) { - werrstr("not pdf"); - return nil; - } - - /* setup structures so one free suffices */ - p = emalloc(sizeof(*d) + sizeof(*pdf)); - d = (Document*) p; - p += sizeof(*d); - pdf = (PDFInfo*) p; - - d->extra = pdf; - d->b = b; - d->drawpage = pdfdrawpage; - d->pagename = pdfpagename; - d->fwdonly = 0; - - if(spawngs(pdf, "-dDELAYSAFER") < 0) - return nil; - - gscmd(pdf, "%s", pdfprolog); - waitgs(pdf); - - setdim(pdf, Rect(0,0,0,0), ppi, 0); - gscmd(pdf, "(%s) (r) file { DELAYSAFER { .setsafe } if } stopped pop pdfopen begin\n", fn); - gscmd(pdf, "pdfpagecount PAGE==\n"); - p = Brdline(&pdf->gsrd, '\n'); - npage = atoi(p); - if(npage < 1) { - fprint(2, "no pages?\n"); - return nil; - } - d->npage = npage; - d->docname = argv[0]; - - gscmd(pdf, "Trailer\n"); - bbox = pdfbbox(pdf); - - pdf->pagebbox = emalloc(sizeof(Rectangle)*npage); - for(i=0; i<npage; i++) { - gscmd(pdf, "%d pdfgetpage\n", i+1); - pdf->pagebbox[i] = pdfbbox(pdf); - if(Dx(pdf->pagebbox[i]) <= 0) - pdf->pagebbox[i] = bbox; - } - return d; -} - -static Image* -pdfdrawpage(Document *doc, int page) -{ - PDFInfo *pdf = doc->extra; - Image *im; - - gscmd(pdf, "%d DoPDFPage\n", page+1); - im = readimage(display, pdf->gsdfd, 0); - if(im == nil) { - fprint(2, "fatal: readimage error %r\n"); - wexits("readimage"); - } - waitgs(pdf); - return im; -} - -static char* -pdfpagename(Document*, int page) -{ - static char str[15]; - sprint(str, "p %d", page+1); - return str; -} diff --git a/sys/src/cmd/page/pdfprolog.ps b/sys/src/cmd/page/pdfprolog.ps deleted file mode 100644 index 681e0587a..000000000 --- a/sys/src/cmd/page/pdfprolog.ps +++ /dev/null @@ -1,20 +0,0 @@ -/Page null def -/Page# 0 def -/PDFSave null def -/DSCPageCount 0 def -/DoPDFPage {dup /Page# exch store pdfgetpage pdfshowpage } def - -/pdfshowpage_mysetpage { % <pagedict> pdfshowpage_mysetpage <pagedict> - dup /CropBox pget { - boxrect - 2 array astore /PageSize exch 4 2 roll - 4 index /Rotate pget { - dup 0 lt {360 add} if 90 idiv {exch neg} repeat - } if - exch neg exch 2 array astore /PageOffset exch - << 5 1 roll >> setpagedevice - } if -} bind def - -GS_PDF_ProcSet begin -pdfdict begin diff --git a/sys/src/cmd/page/ps.c b/sys/src/cmd/page/ps.c deleted file mode 100644 index f1e4cbf93..000000000 --- a/sys/src/cmd/page/ps.c +++ /dev/null @@ -1,450 +0,0 @@ -/* - * ps.c - * - * provide postscript file reading support for page - */ - -#include <u.h> -#include <libc.h> -#include <draw.h> -#include <event.h> -#include <bio.h> -#include <ctype.h> -#include "page.h" - -typedef struct PSInfo PSInfo; -typedef struct Page Page; - -struct Page { - char *name; - int offset; /* offset of page beginning within file */ -}; - -struct PSInfo { - GSInfo; - Rectangle bbox; /* default bounding box */ - Page *page; - int npage; - int clueless; /* don't know where page boundaries are */ - long psoff; /* location of %! in file */ - char ctm[256]; -}; - -static int pswritepage(Document *d, int fd, int page); -static Image* psdrawpage(Document *d, int page); -static char* pspagename(Document*, int); - -#define R(r) (r).min.x, (r).min.y, (r).max.x, (r).max.y -Rectangle -rdbbox(char *p) -{ - Rectangle r; - int a; - char *f[4]; - while(*p == ':' || *p == ' ' || *p == '\t') - p++; - if(tokenize(p, f, 4) != 4) - return Rect(0,0,0,0); - r = Rect(atoi(f[0]), atoi(f[1]), atoi(f[2]), atoi(f[3])); - r = canonrect(r); - if(Dx(r) <= 0 || Dy(r) <= 0) - return Rect(0,0,0,0); - - if(truetoboundingbox) - return r; - - /* initdraw not called yet, can't use %R */ - if(chatty) fprint(2, "[%d %d %d %d] -> ", R(r)); - /* - * attempt to sniff out A4, 8½×11, others - * A4 is 596×842 - * 8½×11 is 612×792 - */ - - a = Dx(r)*Dy(r); - if(a < 300*300){ /* really small, probably supposed to be */ - /* empty */ - } else if(Dx(r) <= 596 && r.max.x <= 596 && Dy(r) > 792 && Dy(r) <= 842 && r.max.y <= 842) /* A4 */ - r = Rect(0, 0, 596, 842); - else { /* cast up to 8½×11 */ - if(Dx(r) <= 612 && r.max.x <= 612){ - r.min.x = 0; - r.max.x = 612; - } - if(Dy(r) <= 792 && r.max.y <= 792){ - r.min.y = 0; - r.max.y = 792; - } - } - if(chatty) fprint(2, "[%d %d %d %d]\n", R(r)); - return r; -} - -#define RECT(X) X.min.x, X.min.y, X.max.x, X.max.y - -int -prefix(char *x, char *y) -{ - return strncmp(x, y, strlen(y)) == 0; -} - -/* - * document ps is really being printed as n-up pages. - * we need to treat every n pages as 1. - */ -void -repaginate(PSInfo *ps, int n) -{ - int i, np, onp; - Page *page; - - page = ps->page; - onp = ps->npage; - np = (ps->npage+n-1)/n; - - if(chatty) { - for(i=0; i<=onp+1; i++) - print("page %d: %d\n", i, page[i].offset); - } - - for(i=0; i<np; i++) - page[i] = page[n*i]; - - /* trailer */ - page[np] = page[onp]; - - /* EOF */ - page[np+1] = page[onp+1]; - - ps->npage = np; - - if(chatty) { - for(i=0; i<=np+1; i++) - print("page %d: %d\n", i, page[i].offset); - } - -} - -Document* -initps(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf) -{ - Document *d; - PSInfo *ps; - char *p; - char *q, *r; - char eol; - char *nargv[1]; - char fdbuf[20]; - char tmp[32]; - int fd; - int i; - int incomments; - int cantranslate; - int trailer=0; - int nesting=0; - int dumb=0; - int landscape=0; - long psoff; - long npage, mpage; - Page *page; - Rectangle bbox = Rect(0,0,0,0); - - if(argc > 1) { - fprint(2, "can only view one ps file at a time\n"); - return nil; - } - - fprint(2, "reading through postscript...\n"); - if(b == nil){ /* standard input; spool to disk (ouch) */ - fd = spooltodisk(buf, nbuf, nil); - sprint(fdbuf, "/fd/%d", fd); - b = Bopen(fdbuf, OREAD); - if(b == nil){ - fprint(2, "cannot open disk spool file\n"); - wexits("Bopen temp"); - } - nargv[0] = fdbuf; - argv = nargv; - } - - /* find %!, perhaps after PCL nonsense */ - Bseek(b, 0, 0); - psoff = 0; - eol = 0; - for(i=0; i<16; i++){ - psoff = Boffset(b); - if(!(p = Brdline(b, eol='\n')) && !(p = Brdline(b, eol='\r'))) { - fprint(2, "cannot find end of first line\n"); - wexits("initps"); - } - if(p[0]=='\x1B') - p++, psoff++; - if(p[0] == '%' && p[1] == '!') - break; - } - if(i == 16){ - werrstr("not ps"); - return nil; - } - - /* page counting */ - npage = 0; - mpage = 16; - page = emalloc(mpage*sizeof(*page)); - memset(page, 0, mpage*sizeof(*page)); - - cantranslate = goodps; - incomments = 1; -Keepreading: - while(p = Brdline(b, eol)) { - if(p[0] == '%') - if(chatty > 1) fprint(2, "ps %.*s\n", utfnlen(p, Blinelen(b)-1), p); - if(npage == mpage) { - mpage *= 2; - page = erealloc(page, mpage*sizeof(*page)); - memset(&page[npage], 0, npage*sizeof(*page)); - } - - if(p[0] != '%' || p[1] != '%') - continue; - - if(prefix(p, "%%BeginDocument")) { - nesting++; - continue; - } - if(nesting > 0 && prefix(p, "%%EndDocument")) { - nesting--; - continue; - } - if(nesting) - continue; - - if(prefix(p, "%%EndComment")) { - incomments = 0; - continue; - } - if(reverse == -1 && prefix(p, "%%PageOrder")) { - /* glean whether we should reverse the viewing order */ - p[Blinelen(b)-1] = 0; - if(strstr(p, "Ascend")) - reverse = 0; - else if(strstr(p, "Descend")) - reverse = 1; - else if(strstr(p, "Special")) - dumb = 1; - p[Blinelen(b)-1] = '\n'; - continue; - } else if(prefix(p, "%%Trailer")) { - incomments = 1; - page[npage].offset = Boffset(b)-Blinelen(b); - trailer = 1; - continue; - } else if(incomments && prefix(p, "%%Orientation")) { - if(strstr(p, "Landscape")) - landscape = 1; - } else if(incomments && Dx(bbox)==0 && prefix(p, q="%%BoundingBox")) { - bbox = rdbbox(p+strlen(q)+1); - if(chatty) - /* can't use %R because haven't initdraw() */ - fprint(2, "document bbox [%d %d %d %d]\n", - RECT(bbox)); - continue; - } - - /* - * If they use the initgraphics command, we can't play our translation tricks. - */ - p[Blinelen(b)-1] = 0; - if((q=strstr(p, "initgraphics")) && ((r=strchr(p, '%'))==nil || r > q)) - cantranslate = 0; - p[Blinelen(b)-1] = eol; - - if(!prefix(p, "%%Page:")) - continue; - - /* - * figure out of the %%Page: line contains a page number - * or some other page description to use in the menu bar. - * - * lines look like %%Page: x y or %%Page: x - * we prefer just x, and will generate our - * own if necessary. - */ - p[Blinelen(b)-1] = 0; - if(chatty) fprint(2, "page %s\n", p); - r = p+7; - while(*r == ' ' || *r == '\t') - r++; - q = r; - while(*q && *q != ' ' && *q != '\t') - q++; - free(page[npage].name); - if(*r) { - if(*r == '"' && *q == '"') - r++, q--; - if(*q) - *q = 0; - page[npage].name = estrdup(r); - *q = 'x'; - } else { - snprint(tmp, sizeof tmp, "p %ld", npage+1); - page[npage].name = estrdup(tmp); - } - - /* - * store the offset info for later viewing - */ - trailer = 0; - p[Blinelen(b)-1] = eol; - page[npage++].offset = Boffset(b)-Blinelen(b); - } - if(Blinelen(b) > 0){ - fprint(2, "page: linelen %d\n", Blinelen(b)); - Bseek(b, Blinelen(b), 1); - goto Keepreading; - } - - if(Dx(bbox) == 0 || Dy(bbox) == 0) - bbox = Rect(0,0,612,792); /* 8½×11 */ - /* - * if we didn't find any pages, assume the document - * is one big page - */ - if(npage == 0) { - dumb = 1; - if(chatty) fprint(2, "don't know where pages are\n"); - reverse = 0; - goodps = 0; - trailer = 0; - page[npage].name = "p 1"; - page[npage++].offset = 0; - } - - if(npage+2 > mpage) { - mpage += 2; - page = erealloc(page, mpage*sizeof(*page)); - memset(&page[mpage-2], 0, 2*sizeof(*page)); - } - - if(!trailer) - page[npage].offset = Boffset(b); - - Bseek(b, 0, 2); /* EOF */ - page[npage+1].offset = Boffset(b); - - d = emalloc(sizeof(*d)); - ps = emalloc(sizeof(*ps)); - ps->page = page; - ps->npage = npage; - ps->bbox = bbox; - ps->psoff = psoff; - - d->extra = ps; - d->npage = ps->npage; - d->b = b; - d->drawpage = psdrawpage; - d->pagename = pspagename; - - d->fwdonly = ps->clueless = dumb; - d->docname = argv[0]; - - if(spawngs(ps, "-dSAFER") < 0) - return nil; - - if(!cantranslate) - bbox.min = ZP; - setdim(ps, bbox, ppi, landscape); - - if(goodps){ - /* - * We want to only send the page (i.e. not header and trailer) information - * for each page, so initialize the device by sending the header now. - */ - pswritepage(d, ps->gsfd, -1); - waitgs(ps); - } - - if(dumb) { - fprint(ps->gsfd, "(%s) run\n", argv[0]); - fprint(ps->gsfd, "(/fd/3) (w) file dup (THIS IS NOT A PLAN9 BITMAP 01234567890123456789012345678901234567890123456789\\n) writestring flushfile\n"); - } - - ps->bbox = bbox; - - return d; -} - -static int -pswritepage(Document *d, int fd, int page) -{ - Biobuf *b = d->b; - PSInfo *ps = d->extra; - int t, n, i; - long begin, end; - char buf[8192]; - - if(page == -1) - begin = ps->psoff; - else - begin = ps->page[page].offset; - - end = ps->page[page+1].offset; - - if(chatty) { - fprint(2, "writepage(%d)... from #%ld to #%ld...\n", - page, begin, end); - } - Bseek(b, begin, 0); - - t = end-begin; - n = sizeof(buf); - if(n > t) n = t; - while(t > 0 && (i=Bread(b, buf, n)) > 0) { - if(write(fd, buf, i) != i) - return -1; - t -= i; - if(n > t) - n = t; - } - return end-begin; -} - -static Image* -psdrawpage(Document *d, int page) -{ - PSInfo *ps = d->extra; - Image *im; - - if(ps->clueless) - return readimage(display, ps->gsdfd, 0); - - waitgs(ps); - - if(goodps) - pswritepage(d, ps->gsfd, page); - else { - pswritepage(d, ps->gsfd, -1); - pswritepage(d, ps->gsfd, page); - pswritepage(d, ps->gsfd, d->npage); - } - /* - * If last line terminator is \r, gs will read ahead to check for \n - * so send one to avoid deadlock. - */ - write(ps->gsfd, "\n", 1); - im = readimage(display, ps->gsdfd, 0); - if(im == nil) { - fprint(2, "fatal: readimage error %r\n"); - wexits("readimage"); - } - waitgs(ps); - - return im; -} - -static char* -pspagename(Document *d, int page) -{ - PSInfo *ps = (PSInfo *) d->extra; - return ps->page[page].name; -} diff --git a/sys/src/cmd/page/rotate.c b/sys/src/cmd/page/rotate.c deleted file mode 100644 index 7f4083e8a..000000000 --- a/sys/src/cmd/page/rotate.c +++ /dev/null @@ -1,500 +0,0 @@ -/* - * rotate an image 180° in O(log Dx + log Dy) /dev/draw writes, - * using an extra buffer same size as the image. - * - * the basic concept is that you can invert an array by inverting - * the top half, inverting the bottom half, and then swapping them. - * the code does this slightly backwards to ensure O(log n) runtime. - * (If you do it wrong, you can get O(log² n) runtime.) - * - * This is usually overkill, but it speeds up slow remote - * connections quite a bit. - */ - -#include <u.h> -#include <libc.h> -#include <bio.h> -#include <draw.h> -#include <event.h> -#include "page.h" - -int ndraw = 0; -enum { - Xaxis = 0, - Yaxis = 1, -}; - -Image *mtmp; - -void -writefile(char *name, Image *im, int gran) -{ - static int c = 100; - int fd; - char buf[200]; - - snprint(buf, sizeof buf, "%d%s%d", c++, name, gran); - fd = create(buf, OWRITE, 0666); - if(fd < 0) - return; - writeimage(fd, im, 0); - close(fd); -} - -void -moveup(Image *im, Image *tmp, int a, int b, int c, int axis) -{ - Rectangle range; - Rectangle dr0, dr1; - Point p0, p1; - - if(a == b || b == c) - return; - - drawop(tmp, tmp->r, im, nil, im->r.min, S); - - switch(axis){ - case Xaxis: - range = Rect(a, im->r.min.y, c, im->r.max.y); - dr0 = range; - dr0.max.x = dr0.min.x+(c-b); - p0 = Pt(b, im->r.min.y); - - dr1 = range; - dr1.min.x = dr1.max.x-(b-a); - p1 = Pt(a, im->r.min.y); - break; - case Yaxis: - range = Rect(im->r.min.x, a, im->r.max.x, c); - dr0 = range; - dr0.max.y = dr0.min.y+(c-b); - p0 = Pt(im->r.min.x, b); - - dr1 = range; - dr1.min.y = dr1.max.y-(b-a); - p1 = Pt(im->r.min.x, a); - break; - } - drawop(im, dr0, tmp, nil, p0, S); - drawop(im, dr1, tmp, nil, p1, S); -} - -void -interlace(Image *im, Image *tmp, int axis, int n, Image *mask, int gran) -{ - Point p0, p1; - Rectangle r0, r1; - - r0 = im->r; - r1 = im->r; - switch(axis) { - case Xaxis: - r0.max.x = n; - r1.min.x = n; - p0 = (Point){gran, 0}; - p1 = (Point){-gran, 0}; - break; - case Yaxis: - r0.max.y = n; - r1.min.y = n; - p0 = (Point){0, gran}; - p1 = (Point){0, -gran}; - break; - } - - drawop(tmp, im->r, im, display->opaque, im->r.min, S); - gendrawop(im, r0, tmp, p0, mask, mask->r.min, S); - gendrawop(im, r0, tmp, p1, mask, p1, S); -} - -/* - * Halve the grating period in the mask. - * The grating currently looks like - * ####____####____####____####____ - * where #### is opacity. - * - * We want - * ##__##__##__##__##__##__##__##__ - * which is achieved by shifting the mask - * and drawing on itself through itself. - * Draw doesn't actually allow this, so - * we have to copy it first. - * - * ####____####____####____####____ (dst) - * + ____####____####____####____#### (src) - * in __####____####____####____####__ (mask) - * =========================================== - * ##__##__##__##__##__##__##__##__ - */ -int -nextmask(Image *mask, int axis, int maskdim) -{ - Point δ; - - δ = axis==Xaxis ? Pt(maskdim,0) : Pt(0,maskdim); - drawop(mtmp, mtmp->r, mask, nil, mask->r.min, S); - gendrawop(mask, mask->r, mtmp, δ, mtmp, divpt(δ,-2), S); -// writefile("mask", mask, maskdim/2); - return maskdim/2; -} - -void -shuffle(Image *im, Image *tmp, int axis, int n, Image *mask, int gran, - int lastnn) -{ - int nn, left; - - if(gran == 0) - return; - left = n%(2*gran); - nn = n - left; - - interlace(im, tmp, axis, nn, mask, gran); -// writefile("interlace", im, gran); - - gran = nextmask(mask, axis, gran); - shuffle(im, tmp, axis, n, mask, gran, nn); -// writefile("shuffle", im, gran); - moveup(im, tmp, lastnn, nn, n, axis); -// writefile("move", im, gran); -} - -void -rot180(Image *im) -{ - Image *tmp, *tmp0; - Image *mask; - Rectangle rmask; - int gran; - - if(chantodepth(im->chan) < 8){ - /* this speeds things up dramatically; draw is too slow on sub-byte pixel sizes */ - tmp0 = xallocimage(display, im->r, CMAP8, 0, DNofill); - drawop(tmp0, tmp0->r, im, nil, im->r.min, S); - }else - tmp0 = im; - - tmp = xallocimage(display, tmp0->r, tmp0->chan, 0, DNofill); - if(tmp == nil){ - if(tmp0 != im) - freeimage(tmp0); - return; - } - for(gran=1; gran<Dx(im->r); gran *= 2) - ; - gran /= 4; - - rmask.min = ZP; - rmask.max = (Point){2*gran, 100}; - - mask = xallocimage(display, rmask, GREY1, 1, DTransparent); - mtmp = xallocimage(display, rmask, GREY1, 1, DTransparent); - if(mask == nil || mtmp == nil) { - fprint(2, "out of memory during rot180: %r\n"); - wexits("memory"); - } - rmask.max.x = gran; - drawop(mask, rmask, display->opaque, nil, ZP, S); -// writefile("mask", mask, gran); - shuffle(im, tmp, Xaxis, Dx(im->r), mask, gran, 0); - freeimage(mask); - freeimage(mtmp); - - for(gran=1; gran<Dy(im->r); gran *= 2) - ; - gran /= 4; - rmask.max = (Point){100, 2*gran}; - mask = xallocimage(display, rmask, GREY1, 1, DTransparent); - mtmp = xallocimage(display, rmask, GREY1, 1, DTransparent); - if(mask == nil || mtmp == nil) { - fprint(2, "out of memory during rot180: %r\n"); - wexits("memory"); - } - rmask.max.y = gran; - drawop(mask, rmask, display->opaque, nil, ZP, S); - shuffle(im, tmp, Yaxis, Dy(im->r), mask, gran, 0); - freeimage(mask); - freeimage(mtmp); - freeimage(tmp); - if(tmp0 != im) - freeimage(tmp0); -} - -/* rotates an image 90 degrees clockwise */ -Image * -rot90(Image *im) -{ - Image *tmp; - int i, j, dx, dy; - - dx = Dx(im->r); - dy = Dy(im->r); - tmp = xallocimage(display, Rect(0, 0, dy, dx), im->chan, 0, DCyan); - if(tmp == nil) { - fprint(2, "out of memory during rot90: %r\n"); - wexits("memory"); - } - - for(j = 0; j < dx; j++) { - for(i = 0; i < dy; i++) { - drawop(tmp, Rect(i, j, i+1, j+1), im, nil, Pt(j, dy-(i+1)), S); - } - } - freeimage(im); - - return(tmp); -} - -/* rotates an image 270 degrees clockwise */ -Image * -rot270(Image *im) -{ - Image *tmp; - int i, j, dx, dy; - - dx = Dx(im->r); - dy = Dy(im->r); - tmp = xallocimage(display, Rect(0, 0, dy, dx), im->chan, 0, DCyan); - if(tmp == nil) { - fprint(2, "out of memory during rot270: %r\n"); - wexits("memory"); - } - - for(i = 0; i < dy; i++) { - for(j = 0; j < dx; j++) { - drawop(tmp, Rect(i, j, i+1, j+1), im, nil, Pt(dx-(j+1), i), S); - } - } - freeimage(im); - - return(tmp); -} - -/* from resample.c -- resize from → to using interpolation */ - - -#define K2 7 /* from -.7 to +.7 inclusive, meaning .2 into each adjacent pixel */ -#define NK (2*K2+1) -double K[NK]; - -double -fac(int L) -{ - int i, f; - - f = 1; - for(i=L; i>1; --i) - f *= i; - return f; -} - -/* - * i0(x) is the modified Bessel function, Σ (x/2)^2L / (L!)² - * There are faster ways to calculate this, but we precompute - * into a table so let's keep it simple. - */ -double -i0(double x) -{ - double v; - int L; - - v = 1.0; - for(L=1; L<10; L++) - v += pow(x/2., 2*L)/pow(fac(L), 2); - return v; -} - -double -kaiser(double x, double τ, double α) -{ - if(fabs(x) > τ) - return 0.; - return i0(α*sqrt(1-(x*x/(τ*τ))))/i0(α); -} - - -void -resamplex(uchar *in, int off, int d, int inx, uchar *out, int outx) -{ - int i, x, k; - double X, xx, v, rat; - - - rat = (double)inx/(double)outx; - for(x=0; x<outx; x++){ - if(inx == outx){ - /* don't resample if size unchanged */ - out[off+x*d] = in[off+x*d]; - continue; - } - v = 0.0; - X = x*rat; - for(k=-K2; k<=K2; k++){ - xx = X + rat*k/10.; - i = xx; - if(i < 0) - i = 0; - if(i >= inx) - i = inx-1; - v += in[off+i*d] * K[K2+k]; - } - out[off+x*d] = v; - } -} - -void -resampley(uchar **in, int off, int iny, uchar **out, int outy) -{ - int y, i, k; - double Y, yy, v, rat; - - rat = (double)iny/(double)outy; - for(y=0; y<outy; y++){ - if(iny == outy){ - /* don't resample if size unchanged */ - out[y][off] = in[y][off]; - continue; - } - v = 0.0; - Y = y*rat; - for(k=-K2; k<=K2; k++){ - yy = Y + rat*k/10.; - i = yy; - if(i < 0) - i = 0; - if(i >= iny) - i = iny-1; - v += in[i][off] * K[K2+k]; - } - out[y][off] = v; - } - -} - -Image* -resample(Image *from, Image *to) -{ - int i, j, bpl, nchan; - uchar **oscan, **nscan; - char tmp[20]; - int xsize, ysize; - double v; - Image *t1, *t2; - ulong tchan; - - for(i=-K2; i<=K2; i++){ - K[K2+i] = kaiser(i/10., K2/10., 4.); - } - - /* normalize */ - v = 0.0; - for(i=0; i<NK; i++) - v += K[i]; - for(i=0; i<NK; i++) - K[i] /= v; - - switch(from->chan){ - case GREY8: - case RGB24: - case RGBA32: - case ARGB32: - case XRGB32: - break; - - case CMAP8: - case RGB15: - case RGB16: - tchan = RGB24; - goto Convert; - - case GREY1: - case GREY2: - case GREY4: - tchan = GREY8; - Convert: - /* use library to convert to byte-per-chan form, then convert back */ - t1 = xallocimage(display, Rect(0, 0, Dx(from->r), Dy(from->r)), tchan, 0, DNofill); - if(t1 == nil) { - fprint(2, "out of memory for temp image 1 in resample: %r\n"); - wexits("memory"); - } - drawop(t1, t1->r, from, nil, ZP, S); - t2 = xallocimage(display, to->r, tchan, 0, DNofill); - if(t2 == nil) { - fprint(2, "out of memory temp image 2 in resample: %r\n"); - wexits("memory"); - } - resample(t1, t2); - drawop(to, to->r, t2, nil, ZP, S); - freeimage(t1); - freeimage(t2); - return to; - - default: - sysfatal("can't handle channel type %s", chantostr(tmp, from->chan)); - } - - xsize = Dx(to->r); - ysize = Dy(to->r); - oscan = malloc(Dy(from->r)*sizeof(uchar*)); - nscan = malloc(max(ysize, Dy(from->r))*sizeof(uchar*)); - if(oscan == nil || nscan == nil) - sysfatal("can't allocate: %r"); - - /* unload original image into scan lines */ - bpl = bytesperline(from->r, from->depth); - for(i=0; i<Dy(from->r); i++){ - oscan[i] = malloc(bpl); - if(oscan[i] == nil) - sysfatal("can't allocate: %r"); - j = unloadimage(from, Rect(from->r.min.x, from->r.min.y+i, from->r.max.x, from->r.min.y+i+1), oscan[i], bpl); - if(j != bpl) - sysfatal("unloadimage"); - } - - /* allocate scan lines for destination. we do y first, so need at least Dy(from->r) lines */ - bpl = bytesperline(Rect(0, 0, xsize, Dy(from->r)), from->depth); - for(i=0; i<max(ysize, Dy(from->r)); i++){ - nscan[i] = malloc(bpl); - if(nscan[i] == nil) - sysfatal("can't allocate: %r"); - } - - /* resample in X */ - nchan = from->depth/8; - for(i=0; i<Dy(from->r); i++){ - for(j=0; j<nchan; j++){ - if(j==0 && from->chan==XRGB32) - continue; - resamplex(oscan[i], j, nchan, Dx(from->r), nscan[i], xsize); - } - free(oscan[i]); - oscan[i] = nscan[i]; - nscan[i] = malloc(bpl); - if(nscan[i] == nil) - sysfatal("can't allocate: %r"); - } - - /* resample in Y */ - for(i=0; i<xsize; i++) - for(j=0; j<nchan; j++) - resampley(oscan, nchan*i+j, Dy(from->r), nscan, ysize); - - /* pack data into destination */ - bpl = bytesperline(to->r, from->depth); - for(i=0; i<ysize; i++){ - j = loadimage(to, Rect(0, i, xsize, i+1), nscan[i], bpl); - if(j != bpl) - sysfatal("loadimage: %r"); - } - - for(i=0; i<Dy(from->r); i++){ - free(oscan[i]); - free(nscan[i]); - } - free(oscan); - free(nscan); - - return to; -} diff --git a/sys/src/cmd/page/util.c b/sys/src/cmd/page/util.c deleted file mode 100644 index 3c27f9c03..000000000 --- a/sys/src/cmd/page/util.c +++ /dev/null @@ -1,131 +0,0 @@ -#include <u.h> -#include <libc.h> -#include <draw.h> -#include <event.h> -#include <bio.h> -#include "page.h" - -void* -emalloc(int sz) -{ - void *v; - v = malloc(sz); - if(v == nil) { - fprint(2, "out of memory allocating %d\n", sz); - wexits("mem"); - } - memset(v, 0, sz); - return v; -} - -void* -erealloc(void *v, int sz) -{ - v = realloc(v, sz); - if(v == nil) { - fprint(2, "out of memory allocating %d\n", sz); - wexits("mem"); - } - return v; -} - -char* -estrdup(char *s) -{ - char *t; - if((t = strdup(s)) == nil) { - fprint(2, "out of memory in strdup(%.10s)\n", s); - wexits("mem"); - } - return t; -} - -int -opentemp(char *template) -{ - int fd, i; - char *p; - - p = estrdup(template); - fd = -1; - for(i=0; i<10; i++){ - mktemp(p); - if(access(p, 0) < 0 && (fd=create(p, ORDWR|ORCLOSE, 0400)) >= 0) - break; - strcpy(p, template); - } - if(fd < 0){ - fprint(2, "couldn't make temporary file\n"); - wexits("Ecreat"); - } - strcpy(template, p); - free(p); - - return fd; -} - -/* - * spool standard input to /tmp. - * we've already read the initial in bytes into ibuf. - */ -int -spooltodisk(uchar *ibuf, int in, char **name) -{ - uchar buf[8192]; - int fd, n; - char temp[40]; - - strcpy(temp, "/tmp/pagespoolXXXXXXXXX"); - fd = opentemp(temp); - if(name) - *name = estrdup(temp); - - if(write(fd, ibuf, in) != in){ - fprint(2, "error writing temporary file\n"); - wexits("write temp"); - } - - while((n = read(stdinfd, buf, sizeof buf)) > 0){ - if(write(fd, buf, n) != n){ - fprint(2, "error writing temporary file\n"); - wexits("write temp0"); - } - } - seek(fd, 0, 0); - return fd; -} - -/* - * spool standard input into a pipe. - * we've already ready the first in bytes into ibuf - */ -int -stdinpipe(uchar *ibuf, int in) -{ - uchar buf[8192]; - int n; - int p[2]; - if(pipe(p) < 0){ - fprint(2, "pipe fails: %r\n"); - wexits("pipe"); - } - - switch(rfork(RFMEM|RFPROC|RFFDG)){ - case -1: - fprint(2, "fork fails: %r\n"); - wexits("fork"); - default: - close(p[1]); - return p[0]; - case 0: - break; - } - - close(p[0]); - write(p[1], ibuf, in); - while((n = read(stdinfd, buf, sizeof buf)) > 0) - write(p[1], buf, n); - - _exits(0); - return -1; /* not reached */ -} diff --git a/sys/src/cmd/page/view.c b/sys/src/cmd/page/view.c deleted file mode 100644 index 4a32916a9..000000000 --- a/sys/src/cmd/page/view.c +++ /dev/null @@ -1,1073 +0,0 @@ -/* - * the actual viewer that handles screen stuff - */ - -#include <u.h> -#include <libc.h> -#include <draw.h> -#include <cursor.h> -#include <event.h> -#include <bio.h> -#include <plumb.h> -#include <ctype.h> -#include <keyboard.h> -#include "page.h" - -Document *doc; -Image *im; -Image *tofree; -int page; -int angle = 0; -int showbottom = 0; /* on the next showpage, move the image so the bottom is visible. */ - -Rectangle ulrange; /* the upper left corner of the image must be in this rectangle */ -Point ul; /* the upper left corner of the image is at this point on the screen */ - -Point pclip(Point, Rectangle); -Rectangle mkrange(Rectangle screenr, Rectangle imr); -void redraw(Image*); - -Cursor reading={ - {-1, -1}, - {0xff, 0x80, 0xff, 0x80, 0xff, 0x00, 0xfe, 0x00, - 0xff, 0x00, 0xff, 0x80, 0xff, 0xc0, 0xef, 0xe0, - 0xc7, 0xf0, 0x03, 0xf0, 0x01, 0xe0, 0x00, 0xc0, - 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, }, - {0x00, 0x00, 0x7f, 0x00, 0x7e, 0x00, 0x7c, 0x00, - 0x7e, 0x00, 0x7f, 0x00, 0x6f, 0x80, 0x47, 0xc0, - 0x03, 0xe0, 0x01, 0xf0, 0x00, 0xe0, 0x00, 0x40, - 0x00, 0x00, 0x01, 0xb6, 0x01, 0xb6, 0x00, 0x00, } -}; - -Cursor query = { - {-7,-7}, - {0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, - 0x7c, 0x7e, 0x78, 0x7e, 0x00, 0xfc, 0x01, 0xf8, - 0x03, 0xf0, 0x07, 0xe0, 0x07, 0xc0, 0x07, 0xc0, - 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, }, - {0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xf8, 0x3c, 0x3c, - 0x38, 0x1c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, - 0x01, 0xe0, 0x03, 0xc0, 0x03, 0x80, 0x03, 0x80, - 0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, } -}; - -enum { - Left = 1, - Middle = 2, - Right = 4, - - RMenu = 3, -}; - -static void -delayfreeimage(Image *m) -{ - if(m == tofree) - return; - if(tofree) - freeimage(tofree); - tofree = m; -} - -void -unhide(void) -{ - static int wctl = -1; - - if(wctl < 0) - wctl = open("/dev/wctl", OWRITE); - if(wctl < 0) - return; - - write(wctl, "unhide", 6); -} - -int -max(int a, int b) -{ - return a > b ? a : b; -} - -int -min(int a, int b) -{ - return a < b ? a : b; -} - - -char* -menugen(int n) -{ - static char menustr[32]; - char *p; - int len; - - if(n == doc->npage) - return "exit"; - if(n > doc->npage) - return nil; - - if(reverse) - n = doc->npage-1-n; - - p = doc->pagename(doc, n); - len = (sizeof menustr)-2; - - if(strlen(p) > len && strrchr(p, '/')) - p = strrchr(p, '/')+1; - if(strlen(p) > len) - p = p+strlen(p)-len; - - strcpy(menustr+1, p); - if(page == n) - menustr[0] = '>'; - else - menustr[0] = ' '; - return menustr; -} - -void -showpage(int page, Menu *m) -{ - if(doc->fwdonly) - m->lasthit = 0; /* this page */ - else - m->lasthit = reverse ? doc->npage-1-page : page; - - esetcursor(&reading); - delayfreeimage(nil); - im = cachedpage(doc, angle, page); - if(im == nil) - wexits(0); - if(resizing) - resize(Dx(im->r), Dy(im->r)); - - esetcursor(nil); - if(showbottom){ - ul.y = screen->r.max.y - Dy(im->r); - showbottom = 0; - } - - redraw(screen); - flushimage(display, 1); -} - -char* -writebitmap(void) -{ - char basename[64]; - char name[64+30]; - static char result[200]; - char *p, *q; - int fd; - - if(im == nil) - return "no image"; - - memset(basename, 0, sizeof basename); - if(doc->docname) - strncpy(basename, doc->docname, sizeof(basename)-1); - else if((p = menugen(page)) && p[0] != '\0') - strncpy(basename, p+1, sizeof(basename)-1); - - if(basename[0]) { - if(q = strrchr(basename, '/')) - q++; - else - q = basename; - if(p = strchr(q, '.')) - *p = 0; - - memset(name, 0, sizeof name); - snprint(name, sizeof(name)-1, "%s.%d.bit", q, page+1); - if(access(name, 0) >= 0) { - strcat(name, "XXXX"); - mktemp(name); - } - if(access(name, 0) >= 0) - return "couldn't think of a name for bitmap"; - } else { - strcpy(name, "bitXXXX"); - mktemp(name); - if(access(name, 0) >= 0) - return "couldn't think of a name for bitmap"; - } - - if((fd = create(name, OWRITE, 0666)) < 0) { - snprint(result, sizeof result, "cannot create %s: %r", name); - return result; - } - - if(writeimage(fd, im, 0) < 0) { - snprint(result, sizeof result, "cannot writeimage: %r"); - close(fd); - return result; - } - close(fd); - - snprint(result, sizeof result, "wrote %s", name); - return result; -} - -static void translate(Point); - -static int -showdata(Plumbmsg *msg) -{ - char *s; - - s = plumblookup(msg->attr, "action"); - return s && strcmp(s, "showdata")==0; -} - -static int -plumbquit(Plumbmsg *msg) -{ - char *s; - - s = plumblookup(msg->attr, "action"); - return s && strcmp(s, "quit")==0; -} - -/* correspond to entries in miditems[] below, - * changing one means you need to change - */ -enum{ - Restore = 0, - Zin, - Fit, - Rot, - Upside, - Empty1, - Next, - Prev, - Zerox, - Empty2, - Reverse, - Del, - Write, - Empty3, - Exit, -}; - -void -viewer(Document *dd) -{ - int i, fd, n, oldpage; - int nxt; - Menu menu, midmenu; - Mouse m; - Event e; - Point dxy, oxy, xy0; - Rectangle r; - Image *tmp; - static char *fwditems[] = { "this page", "next page", "exit", 0 }; - static char *miditems[] = { - "orig size", - "zoom in", - "fit window", - "rotate 90", - "upside down", - "", - "next", - "prev", - "zerox", - "", - "reverse", - "discard", - "write", - "", - "quit", - 0 - }; - char *s; - enum { Eplumb = 4 }; - Plumbmsg *pm; - - doc = dd; /* save global for menuhit */ - ul = screen->r.min; - einit(Emouse|Ekeyboard); - if(doc->addpage != nil) - eplumb(Eplumb, "image"); - - esetcursor(&reading); - r.min = ZP; - - /* - * im is a global pointer to the current image. - * eventually, i think we will have a layer between - * the display routines and the ps/pdf/whatever routines - * to perhaps cache and handle images of different - * sizes, etc. - */ - im = 0; - page = reverse ? doc->npage-1 : 0; - - if(doc->fwdonly) { - menu.item = fwditems; - menu.gen = 0; - menu.lasthit = 0; - } else { - menu.item = 0; - menu.gen = menugen; - menu.lasthit = 0; - } - - midmenu.item = miditems; - midmenu.gen = 0; - midmenu.lasthit = Next; - - showpage(page, &menu); - esetcursor(nil); - - nxt = 0; - for(;;) { - /* - * throughout, if doc->fwdonly is set, we restrict the functionality - * a fair amount. we don't care about doc->npage anymore, and - * all that can be done is select the next page. - */ - unlockdisplay(display); - i = eread(Emouse|Ekeyboard|Eplumb, &e); - lockdisplay(display); - switch(i){ - case Ekeyboard: - if(e.kbdc <= 0xFF && isdigit(e.kbdc)) { - nxt = nxt*10+e.kbdc-'0'; - break; - } else if(e.kbdc != '\n') - nxt = 0; - switch(e.kbdc) { - case 'r': /* reverse page order */ - if(doc->fwdonly) - break; - reverse = !reverse; - menu.lasthit = doc->npage-1-menu.lasthit; - - /* - * the theory is that if we are reversing the - * document order and are on the first or last - * page then we're just starting and really want - * to view the other end. maybe the if - * should be dropped and this should happen always. - */ - if(page == 0 || page == doc->npage-1) { - page = doc->npage-1-page; - showpage(page, &menu); - } - break; - case 'w': /* write bitmap of current screen */ - esetcursor(&reading); - s = writebitmap(); - if(s) - string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP, - display->defaultfont, s); - esetcursor(nil); - flushimage(display, 1); - break; - case 'd': /* remove image from working set */ - if(doc->rmpage && page < doc->npage) { - if(doc->rmpage(doc, page) >= 0) { - if(doc->npage < 0) - wexits(0); - if(page >= doc->npage) - page = doc->npage-1; - showpage(page, &menu); - } - } - break; - case 'q': - case 0x04: /* ctrl-d */ - wexits(0); - case 'u': - if(im==nil) - break; - angle = (angle+180) % 360; - showpage(page, &menu); - break; - case '-': - case '\b': - case Kleft: - if(page > 0 && !doc->fwdonly) { - --page; - showpage(page, &menu); - } - break; - case '\n': - if(nxt) { - nxt--; - if(nxt >= 0 && nxt < doc->npage && !doc->fwdonly) - showpage(page=nxt, &menu); - nxt = 0; - break; - } - goto Gotonext; - case Kright: - case ' ': - Gotonext: - if(doc->npage && ++page >= doc->npage && !doc->fwdonly) - wexits(0); - showpage(page, &menu); - break; - - /* - * The upper y coordinate of the image is at ul.y in screen->r. - * Panning up means moving the upper left corner down. If the - * upper left corner is currently visible, we need to go back a page. - */ - case Kup: - if(screen->r.min.y <= ul.y && ul.y < screen->r.max.y){ - if(page > 0 && !doc->fwdonly){ - --page; - showbottom = 1; - showpage(page, &menu); - } - } else { - i = Dy(screen->r)/2; - if(i > 10) - i -= 10; - if(i+ul.y > screen->r.min.y) - i = screen->r.min.y - ul.y; - translate(Pt(0, i)); - } - break; - - /* - * If the lower y coordinate is on the screen, we go to the next page. - * The lower y coordinate is at ul.y + Dy(im->r). - */ - case Kdown: - i = ul.y + Dy(im->r); - if(screen->r.min.y <= i && i <= screen->r.max.y){ - ul.y = screen->r.min.y; - goto Gotonext; - } else { - i = -Dy(screen->r)/2; - if(i < -10) - i += 10; - if(i+ul.y+Dy(im->r) <= screen->r.max.y) - i = screen->r.max.y - Dy(im->r) - ul.y - 1; - translate(Pt(0, i)); - } - break; - default: - esetcursor(&query); - sleep(1000); - esetcursor(nil); - break; - } - break; - - case Emouse: - m = e.mouse; - switch(m.buttons){ - case Left: - oxy = m.xy; - xy0 = oxy; - do { - dxy = subpt(m.xy, oxy); - oxy = m.xy; - translate(dxy); - unlockdisplay(display); - m = emouse(); - lockdisplay(display); - } while(m.buttons == Left); - if(m.buttons) { - dxy = subpt(xy0, oxy); - translate(dxy); - } - break; - - case Middle: - if(doc->npage == 0) - break; - - unlockdisplay(display); - n = emenuhit(Middle, &m, &midmenu); - lockdisplay(display); - if(n == -1) - break; - switch(n){ - case Next: /* next */ - if(reverse) - page--; - else - page++; - if(page < 0) { - if(reverse) return; - else page = 0; - } - - if((page >= doc->npage) && !doc->fwdonly) - return; - - showpage(page, &menu); - nxt = 0; - break; - case Prev: /* prev */ - if(reverse) - page++; - else - page--; - if(page < 0) { - if(reverse) return; - else page = 0; - } - - if((page >= doc->npage) && !doc->fwdonly && !reverse) - return; - - showpage(page, &menu); - nxt = 0; - break; - case Zerox: /* prev */ - zerox(); - break; - case Zin: /* zoom in */ - { - double delta; - Rectangle r; - - r = egetrect(Middle, &m); - if((rectclip(&r, rectaddpt(im->r, ul)) == 0) || - Dx(r) == 0 || Dy(r) == 0) - break; - /* use the smaller side to expand */ - if(Dx(r) < Dy(r)) - delta = (double)Dx(im->r)/(double)Dx(r); - else - delta = (double)Dy(im->r)/(double)Dy(r); - - esetcursor(&reading); - tmp = xallocimage(display, - Rect(0, 0, (int)((double)Dx(im->r)*delta), (int)((double)Dy(im->r)*delta)), - im->chan, 0, DBlack); - if(tmp == nil) { - fprint(2, "out of memory during zoom: %r\n"); - wexits("memory"); - } - resample(im, tmp); - im = tmp; - delayfreeimage(tmp); - esetcursor(nil); - ul = screen->r.min; - redraw(screen); - flushimage(display, 1); - break; - } - case Fit: /* fit */ - { - double delta; - Rectangle r; - - delta = (double)Dx(screen->r)/(double)Dx(im->r); - if((double)Dy(im->r)*delta > Dy(screen->r)) - delta = (double)Dy(screen->r)/(double)Dy(im->r); - - r = Rect(0, 0, (int)((double)Dx(im->r)*delta), (int)((double)Dy(im->r)*delta)); - esetcursor(&reading); - tmp = xallocimage(display, r, im->chan, 0, DBlack); - if(tmp == nil) { - fprint(2, "out of memory during fit: %r\n"); - wexits("memory"); - } - resample(im, tmp); - im = tmp; - delayfreeimage(tmp); - esetcursor(nil); - ul = screen->r.min; - redraw(screen); - flushimage(display, 1); - break; - } - case Rot: /* rotate 90 */ - angle = (angle+90) % 360; - showpage(page, &menu); - break; - case Upside: /* upside-down */ - angle = (angle+180) % 360; - showpage(page, &menu); - break; - case Restore: /* restore */ - showpage(page, &menu); - break; - case Reverse: /* reverse */ - if(doc->fwdonly) - break; - reverse = !reverse; - menu.lasthit = doc->npage-1-menu.lasthit; - - if(page == 0 || page == doc->npage-1) { - page = doc->npage-1-page; - showpage(page, &menu); - } - break; - case Write: /* write */ - esetcursor(&reading); - s = writebitmap(); - if(s) - string(screen, addpt(screen->r.min, Pt(5,5)), display->black, ZP, - display->defaultfont, s); - esetcursor(nil); - flushimage(display, 1); - break; - case Del: /* delete */ - if(doc->rmpage && page < doc->npage) { - if(doc->rmpage(doc, page) >= 0) { - if(doc->npage < 0) - wexits(0); - if(page >= doc->npage) - page = doc->npage-1; - showpage(page, &menu); - } - } - break; - case Exit: /* exit */ - return; - case Empty1: - case Empty2: - case Empty3: - break; - - }; - - - - case Right: - if(doc->npage == 0) - break; - - oldpage = page; - unlockdisplay(display); - n = emenuhit(RMenu, &m, &menu); - lockdisplay(display); - if(n == -1) - break; - - if(doc->fwdonly) { - switch(n){ - case 0: /* this page */ - break; - case 1: /* next page */ - showpage(++page, &menu); - break; - case 2: /* exit */ - return; - } - break; - } - - if(n == doc->npage) - return; - else - page = reverse ? doc->npage-1-n : n; - - if(oldpage != page) - showpage(page, &menu); - nxt = 0; - break; - } - break; - - case Eplumb: - pm = e.v; - if(pm->ndata <= 0){ - plumbfree(pm); - break; - } - if(plumbquit(pm)) - exits(nil); - if(showdata(pm)) { - s = estrdup("/tmp/pageplumbXXXXXXX"); - fd = opentemp(s); - write(fd, pm->data, pm->ndata); - /* lose fd reference on purpose; the file is open ORCLOSE */ - } else if(pm->data[0] == '/') { - s = estrdup(pm->data); - } else { - s = emalloc(strlen(pm->wdir)+1+pm->ndata+1); - sprint(s, "%s/%s", pm->wdir, pm->data); - cleanname(s); - } - if((i = doc->addpage(doc, s)) >= 0) { - page = i; - unhide(); - showpage(page, &menu); - } - free(s); - plumbfree(pm); - break; - } - } -} - -Image *gray; - -/* - * A draw operation that touches only the area contained in bot but not in top. - * mp and sp get aligned with bot.min. - */ -static void -gendrawdiff(Image *dst, Rectangle bot, Rectangle top, - Image *src, Point sp, Image *mask, Point mp, int op) -{ - Rectangle r; - Point origin; - Point delta; - - USED(op); - - if(Dx(bot)*Dy(bot) == 0) - return; - - /* no points in bot - top */ - if(rectinrect(bot, top)) - return; - - /* bot - top ≡ bot */ - if(Dx(top)*Dy(top)==0 || rectXrect(bot, top)==0){ - gendrawop(dst, bot, src, sp, mask, mp, op); - return; - } - - origin = bot.min; - /* split bot into rectangles that don't intersect top */ - /* left side */ - if(bot.min.x < top.min.x){ - r = Rect(bot.min.x, bot.min.y, top.min.x, bot.max.y); - delta = subpt(r.min, origin); - gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); - bot.min.x = top.min.x; - } - - /* right side */ - if(bot.max.x > top.max.x){ - r = Rect(top.max.x, bot.min.y, bot.max.x, bot.max.y); - delta = subpt(r.min, origin); - gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); - bot.max.x = top.max.x; - } - - /* top */ - if(bot.min.y < top.min.y){ - r = Rect(bot.min.x, bot.min.y, bot.max.x, top.min.y); - delta = subpt(r.min, origin); - gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); - bot.min.y = top.min.y; - } - - /* bottom */ - if(bot.max.y > top.max.y){ - r = Rect(bot.min.x, top.max.y, bot.max.x, bot.max.y); - delta = subpt(r.min, origin); - gendrawop(dst, r, src, addpt(sp, delta), mask, addpt(mp, delta), op); - bot.max.y = top.max.y; - } -} - -static void -drawdiff(Image *dst, Rectangle bot, Rectangle top, Image *src, Image *mask, Point p, int op) -{ - gendrawdiff(dst, bot, top, src, p, mask, p, op); -} - -/* - * Translate the image in the window by delta. - */ -static void -translate(Point delta) -{ - Point u; - Rectangle r, or; - - if(im == nil) - return; - - u = pclip(addpt(ul, delta), ulrange); - delta = subpt(u, ul); - if(delta.x == 0 && delta.y == 0) - return; - - /* - * The upper left corner of the image is currently at ul. - * We want to move it to u. - */ - or = rectaddpt(Rpt(ZP, Pt(Dx(im->r), Dy(im->r))), ul); - r = rectaddpt(or, delta); - - drawop(screen, r, screen, nil, ul, S); - ul = u; - - /* fill in gray where image used to be but isn't. */ - drawdiff(screen, insetrect(or, -2), insetrect(r, -2), gray, nil, ZP, S); - - /* fill in black border */ - drawdiff(screen, insetrect(r, -2), r, display->black, nil, ZP, S); - - /* fill in image where it used to be off the screen. */ - if(rectclip(&or, screen->r)) - drawdiff(screen, r, rectaddpt(or, delta), im, nil, im->r.min, S); - else - drawop(screen, r, im, nil, im->r.min, S); - flushimage(display, 1); -} - -void -redraw(Image *screen) -{ - Rectangle r; - - if(im == nil) - return; - - ulrange.max = screen->r.max; - ulrange.min = subpt(screen->r.min, Pt(Dx(im->r), Dy(im->r))); - - ul = pclip(ul, ulrange); - drawop(screen, screen->r, im, nil, subpt(im->r.min, subpt(ul, screen->r.min)), S); - - if(im->repl) - return; - - /* fill in any outer edges */ - /* black border */ - r = rectaddpt(im->r, subpt(ul, im->r.min)); - border(screen, r, -2, display->black, ZP); - r.min = subpt(r.min, Pt(2,2)); - r.max = addpt(r.max, Pt(2,2)); - - /* gray for the rest */ - if(gray == nil) { - gray = xallocimage(display, Rect(0,0,1,1), RGB24, 1, 0x888888FF); - if(gray == nil) { - fprint(2, "g out of memory: %r\n"); - wexits("mem"); - } - } - border(screen, r, -4000, gray, ZP); -// flushimage(display, 0); -} - -void -eresized(int new) -{ - Rectangle r; - r = screen->r; - if(new && getwindow(display, Refnone) < 0) - fprint(2,"can't reattach to window"); - ul = addpt(ul, subpt(screen->r.min, r.min)); - redraw(screen); -} - -/* clip p to be in r */ -Point -pclip(Point p, Rectangle r) -{ - if(p.x < r.min.x) - p.x = r.min.x; - else if(p.x >= r.max.x) - p.x = r.max.x-1; - - if(p.y < r.min.y) - p.y = r.min.y; - else if(p.y >= r.max.y) - p.y = r.max.y-1; - - return p; -} - -/* - * resize is perhaps a misnomer. - * this really just grows the window to be at least dx across - * and dy high. if the window hits the bottom or right edge, - * it is backed up until it hits the top or left edge. - */ -void -resize(int dx, int dy) -{ - static Rectangle sr; - Rectangle r, or; - - dx += 2*Borderwidth; - dy += 2*Borderwidth; - if(wctlfd < 0){ - wctlfd = open("/dev/wctl", OWRITE); - if(wctlfd < 0) - return; - } - - r = insetrect(screen->r, -Borderwidth); - if(Dx(r) >= dx && Dy(r) >= dy) - return; - - if(Dx(sr)*Dy(sr) == 0) - sr = screenrect(); - - or = r; - - r.max.x = max(r.min.x+dx, r.max.x); - r.max.y = max(r.min.y+dy, r.max.y); - if(r.max.x > sr.max.x){ - if(Dx(r) > Dx(sr)){ - r.min.x = 0; - r.max.x = sr.max.x; - }else - r = rectaddpt(r, Pt(sr.max.x-r.max.x, 0)); - } - if(r.max.y > sr.max.y){ - if(Dy(r) > Dy(sr)){ - r.min.y = 0; - r.max.y = sr.max.y; - }else - r = rectaddpt(r, Pt(0, sr.max.y-r.max.y)); - } - - /* - * Sometimes we can't actually grow the window big enough, - * and resizing it to the same shape makes it flash. - */ - if(Dx(r) == Dx(or) && Dy(r) == Dy(or)) - return; - - fprint(wctlfd, "resize -minx %d -miny %d -maxx %d -maxy %d\n", - r.min.x, r.min.y, r.max.x, r.max.y); -} - -/* - * If we allocimage after a resize but before flushing the draw buffer, - * we won't have seen the reshape event, and we won't have called - * getwindow, and allocimage will fail. So we flushimage before every alloc. - */ -Image* -xallocimage(Display *d, Rectangle r, ulong chan, int repl, ulong val) -{ - flushimage(display, 0); - return allocimage(d, r, chan, repl, val); -} - -/* all code below this line should be in the library, but is stolen from colors instead */ -static char* -rdenv(char *name) -{ - char *v; - int fd, size; - - fd = open(name, OREAD); - if(fd < 0) - return 0; - size = seek(fd, 0, 2); - v = malloc(size+1); - if(v == 0){ - fprint(2, "page: can't malloc: %r\n"); - wexits("no mem"); - } - seek(fd, 0, 0); - read(fd, v, size); - v[size] = 0; - close(fd); - return v; -} - -void -newwin(void) -{ - char *srv, *mntsrv; - char spec[100]; - int srvfd, cons, pid; - - switch(rfork(RFFDG|RFPROC|RFNAMEG|RFENVG|RFNOTEG|RFNOWAIT)){ - case -1: - fprint(2, "page: can't fork: %r\n"); - wexits("no fork"); - case 0: - break; - default: - wexits(0); - } - - srv = rdenv("/env/wsys"); - if(srv == 0){ - mntsrv = rdenv("/mnt/term/env/wsys"); - if(mntsrv == 0){ - fprint(2, "page: can't find $wsys\n"); - wexits("srv"); - } - srv = malloc(strlen(mntsrv)+10); - sprint(srv, "/mnt/term%s", mntsrv); - free(mntsrv); - pid = 0; /* can't send notes to remote processes! */ - }else - pid = getpid(); - srvfd = open(srv, ORDWR); - if(srvfd == -1){ - fprint(2, "page: can't open %s: %r\n", srv); - wexits("no srv"); - } - free(srv); - sprint(spec, "new -pid %d", pid); - if(mount(srvfd, -1, "/mnt/wsys", 0, spec) == -1){ - fprint(2, "page: can't mount /mnt/wsys: %r (spec=%s)\n", spec); - wexits("no mount"); - } - close(srvfd); - unmount("/mnt/acme", "/dev"); - bind("/mnt/wsys", "/dev", MBEFORE); - cons = open("/dev/cons", OREAD); - if(cons==-1){ - NoCons: - fprint(2, "page: can't open /dev/cons: %r"); - wexits("no cons"); - } - dup(cons, 0); - close(cons); - cons = open("/dev/cons", OWRITE); - if(cons==-1) - goto NoCons; - dup(cons, 1); - dup(cons, 2); - close(cons); -// wctlfd = open("/dev/wctl", OWRITE); -} - -Rectangle -screenrect(void) -{ - int fd; - char buf[12*5]; - - fd = open("/dev/screen", OREAD); - if(fd == -1) - fd=open("/mnt/term/dev/screen", OREAD); - if(fd == -1){ - fprint(2, "page: can't open /dev/screen: %r\n"); - wexits("window read"); - } - if(read(fd, buf, sizeof buf) != sizeof buf){ - fprint(2, "page: can't read /dev/screen: %r\n"); - wexits("screen read"); - } - close(fd); - return Rect(atoi(buf+12), atoi(buf+24), atoi(buf+36), atoi(buf+48)); -} - -void -zerox(void) -{ - int pfd[2]; - - pipe(pfd); - switch(rfork(RFFDG|RFREND|RFPROC)) { - case -1: - wexits("cannot fork in zerox: %r"); - case 0: - dup(pfd[1], 0); - close(pfd[0]); - execl("/bin/page", "page", "-w", nil); - wexits("cannot exec in zerox: %r\n"); - default: - close(pfd[1]); - writeimage(pfd[0], im, 0); - close(pfd[0]); - break; - } -} |