replaceing page with npage

This commit is contained in:
cinap_lenrek 2011-09-15 20:59:31 +02:00
parent d02a0b7766
commit d9657f8274
16 changed files with 38 additions and 4020 deletions

View file

@ -80,27 +80,6 @@ The
.B -r
option reverses the order in which pages are displayed.
.PP
When viewing a document,
.I page
will try to guess the true bounding box, usually rounding up from
the file's bounding box to
×11 or A4 size.
The
.B -b
option causes it to respect the bounding box given in the file.
As a more general problem,
some PostScript files claim to conform to Adobe's
Document Structuring Conventions but do not.
The
.B -P
option enables a slightly slower and slightly more
skeptical version of the PostScript processing code.
Unfortunately, there are PostScript documents
that can only be viewed with the
.B -P
option, and there are PostScript documents that
can only be viewed without it.
.PP
When viewing images with
.IR page ,
it listens to the
@ -117,21 +96,6 @@ to not load any graphics files nor to read
from standard input but rather to listen
for ones to load from the plumbing channel.
.PP
The
.B -v
option turns on extra debugging output, and
the
.B -V
option turns on even more debugging output.
The
.B -a
option causes
.I page
to call
.IR abort (2)
rather than exit cleanly on errors,
to facilitate debugging.
.PP
Pressing and holding button 1 permits panning about the page.
.PP
Button 2 raises a menu of operations on the current image or the
@ -145,10 +109,9 @@ The button 2 menu operations are:
Restores the image to the original. All modifications are lost.
.TP
.B Zoom
Prompts the user to sweep a rectangle on the image which is
expanded proportionally to the rectangle.
controls magnification.
.TP
.B Fit window
.B Fit
Resizes the image so that it fits in the current window.
.TP
.B Rotate 90
@ -166,12 +129,6 @@ Displays the previous page.
.B Zerox
Displays the current image in a new page window.
Useful for selecting important pages from large documents.
.TP
.B Reverse
Reverses the order in which pages are displayed.
.TP
.B Write
Writes the image to file.
.PD
.PP
Button 3 raises a menu of the
@ -182,23 +139,6 @@ Typing a
.B q
or
control-D exits the program.
Typing a
.B u
toggles whether images are displayed upside-down.
(This is useful in the common case of mistransmitted upside-down faxes).
Typing a
.B r
reverses the order in which pages are displayed.
Typing a
.B w
will write the currently viewed page to a new file as a compressed
.IR image (6)
file.
When possible, the filename is of the form
.IR basename . pagenum . bit .
Typing a
.B d
removes an image from the working set.
.PP
To go to a specific page, one can type its number followed by enter.
Typing left arrow, backspace, or minus displays the previous page.
@ -238,34 +178,7 @@ Preview this manual in a new window.
.IR troff (1)
.SH SOURCE
.B /sys/src/cmd/page
.SH DIAGNOSTICS
The mouse cursor changes to an arrow and ellipsis
when
.I page
is reading or writing a file.
.SH BUGS
.I Page
supports reading of only one document
file at a time, and
the user interface is clumsy when viewing very large documents.
.PP
When viewing multipage PostScript files that do not contain
.RB `` %%Page ''
comments, the button 3 menu only contains
``this page'' and ``next page'':
correctly determining
page boundaries in Postscript code is not computable
in the general case.
.PP
If
.I page
has trouble viewing a Postscript file,
it might not be exactly conforming: try viewing it with the
.B -P
option.
.PP
The interface to the plumber is unsatisfactory. In particular,
document references cannot be sent
via plumbing messages.
.PP
There are too many keyboard commands.

View file

@ -872,6 +872,26 @@ translate(Page *p, Point d)
flushimage(display, 1);
}
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)
{
@ -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:

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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];
}

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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)

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 */
}

File diff suppressed because it is too large Load diff