placeholder; does not yet build
This commit is contained in:
parent
d1e9002f81
commit
24c02865d8
13 changed files with 3661 additions and 0 deletions
107
src/cmd/page/filter.c
Normal file
107
src/cmd/page/filter.c
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
#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);
|
||||
}
|
||||
331
src/cmd/page/gfx.c
Normal file
331
src/cmd/page/gfx.c
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* 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 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 *b, int argc, char **argv, uchar *buf, int nbuf)
|
||||
{
|
||||
GfxInfo *gfx;
|
||||
Document *doc;
|
||||
int i;
|
||||
|
||||
USED(b);
|
||||
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];
|
||||
}
|
||||
|
||||
342
src/cmd/page/gs.c
Normal file
342
src/cmd/page/gs.c
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
* 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 *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++] = "-dSAFER";
|
||||
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);
|
||||
}
|
||||
23
src/cmd/page/mkfile
Normal file
23
src/cmd/page/mkfile
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<$PLAN9/src/mkhdr
|
||||
|
||||
TARG=page
|
||||
|
||||
HFILES=page.h
|
||||
OFILES=\
|
||||
filter.$O\
|
||||
gfx.$O\
|
||||
gs.$O\
|
||||
page.$O\
|
||||
pdf.$O\
|
||||
ps.$O\
|
||||
rotate.$O\
|
||||
util.$O\
|
||||
view.$O\
|
||||
|
||||
<$PLAN9/src//mkone
|
||||
|
||||
pdfprolog.c: pdfprolog.ps
|
||||
cat pdfprolog.ps | sed 's/.*/"&\\n"/g' >pdfprolog.c
|
||||
|
||||
pdf.$O: pdfprolog.c
|
||||
|
||||
277
src/cmd/page/nrotate.c
Normal file
277
src/cmd/page/nrotate.c
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
236
src/cmd/page/page.c
Normal file
236
src/cmd/page/page.c
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
#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 *v, char *x)
|
||||
{
|
||||
USED(v);
|
||||
|
||||
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\n");
|
||||
exits(0);
|
||||
default:
|
||||
break;
|
||||
case 0:
|
||||
atnotify(watcher, 1);
|
||||
for(;;)
|
||||
sleep(1000);
|
||||
_exits(0);
|
||||
}
|
||||
|
||||
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(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");
|
||||
}
|
||||
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);
|
||||
}
|
||||
84
src/cmd/page/page.h
Normal file
84
src/cmd/page/page.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
#include <cursor.h>
|
||||
|
||||
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 *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*);
|
||||
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);
|
||||
|
||||
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)
|
||||
155
src/cmd/page/pdf.c
Normal file
155
src/cmd/page/pdf.c
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* 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 gs;
|
||||
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->gs) < 0)
|
||||
return nil;
|
||||
|
||||
gscmd(&pdf->gs, "%s", pdfprolog);
|
||||
waitgs(&pdf->gs);
|
||||
|
||||
setdim(&pdf->gs, Rect(0,0,0,0), ppi, 0);
|
||||
gscmd(&pdf->gs, "(%s) (r) file pdfopen begin\n", fn);
|
||||
gscmd(&pdf->gs, "pdfpagecount PAGE==\n");
|
||||
p = Brdline(&pdf->gs.gsrd, '\n');
|
||||
npage = atoi(p);
|
||||
if(npage < 1) {
|
||||
fprint(2, "no pages?\n");
|
||||
return nil;
|
||||
}
|
||||
d->npage = npage;
|
||||
d->docname = argv[0];
|
||||
|
||||
gscmd(&pdf->gs, "Trailer\n");
|
||||
bbox = pdfbbox(&pdf->gs);
|
||||
|
||||
pdf->pagebbox = emalloc(sizeof(Rectangle)*npage);
|
||||
for(i=0; i<npage; i++) {
|
||||
gscmd(&pdf->gs, "%d pdfgetpage\n", i+1);
|
||||
pdf->pagebbox[i] = pdfbbox(&pdf->gs);
|
||||
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->gs, "%d DoPDFPage\n", page+1);
|
||||
im = readimage(display, pdf->gs.gsdfd, 0);
|
||||
if(im == nil) {
|
||||
fprint(2, "fatal: readimage error %r\n");
|
||||
wexits("readimage");
|
||||
}
|
||||
waitgs(&pdf->gs);
|
||||
return im;
|
||||
}
|
||||
|
||||
static char*
|
||||
pdfpagename(Document *d, int page)
|
||||
{
|
||||
static char str[15];
|
||||
USED(d);
|
||||
sprint(str, "p %d", page+1);
|
||||
return str;
|
||||
}
|
||||
29
src/cmd/page/pdfprolog.c
Normal file
29
src/cmd/page/pdfprolog.c
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
"/Page null def\n"
|
||||
"/Page# 0 def\n"
|
||||
"/PDFSave null def\n"
|
||||
"/DSCPageCount 0 def\n"
|
||||
"/DoPDFPage {dup /Page# exch store pdfgetpage mypdfshowpage } def\n"
|
||||
"\n"
|
||||
"/pdfshowpage_mysetpage { % <pagedict> pdfshowpage_mysetpage <pagedict>\n"
|
||||
" dup /CropBox pget {\n"
|
||||
" boxrect\n"
|
||||
" 2 array astore /PageSize exch 4 2 roll\n"
|
||||
" neg exch neg exch 2 array astore /PageOffset exch\n"
|
||||
" << 5 1 roll >> setpagedevice\n"
|
||||
" } if\n"
|
||||
"} bind def\n"
|
||||
"\n"
|
||||
"/mypdfshowpage % <pagedict> pdfshowpage -\n"
|
||||
" { dup /Page exch store\n"
|
||||
" pdfshowpage_init \n"
|
||||
" pdfshowpage_setpage \n"
|
||||
" pdfshowpage_mysetpage\n"
|
||||
" save /PDFSave exch store\n"
|
||||
" (before exec) VMDEBUG\n"
|
||||
" pdfshowpage_finish\n"
|
||||
" (after exec) VMDEBUG\n"
|
||||
" PDFSave restore\n"
|
||||
" } bind def\n"
|
||||
"\n"
|
||||
"GS_PDF_ProcSet begin\n"
|
||||
"pdfdict begin\n"
|
||||
450
src/cmd/page/ps.c
Normal file
450
src/cmd/page/ps.c
Normal file
|
|
@ -0,0 +1,450 @@
|
|||
/*
|
||||
* 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 gs;
|
||||
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) 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->gs) < 0)
|
||||
return nil;
|
||||
|
||||
if(!cantranslate)
|
||||
bbox.min = ZP;
|
||||
setdim(&ps->gs, 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->gs.gsfd, -1);
|
||||
waitgs(&ps->gs);
|
||||
}
|
||||
|
||||
if(dumb) {
|
||||
fprint(ps->gs.gsfd, "(%s) run\n", argv[0]);
|
||||
fprint(ps->gs.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->gs.gsdfd, 0);
|
||||
|
||||
waitgs(&ps->gs);
|
||||
|
||||
if(goodps)
|
||||
pswritepage(d, ps->gs.gsfd, page);
|
||||
else {
|
||||
pswritepage(d, ps->gs.gsfd, -1);
|
||||
pswritepage(d, ps->gs.gsfd, page);
|
||||
pswritepage(d, ps->gs.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->gs.gsfd, "\n", 1);
|
||||
im = readimage(display, ps->gs.gsdfd, 0);
|
||||
if(im == nil) {
|
||||
fprint(2, "fatal: readimage error %r\n");
|
||||
wexits("readimage");
|
||||
}
|
||||
waitgs(&ps->gs);
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
static char*
|
||||
pspagename(Document *d, int page)
|
||||
{
|
||||
PSInfo *ps = (PSInfo *) d->extra;
|
||||
return ps->page[page].name;
|
||||
}
|
||||
474
src/cmd/page/rotate.c
Normal file
474
src/cmd/page/rotate.c
Normal file
|
|
@ -0,0 +1,474 @@
|
|||
/*
|
||||
* 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 delta;
|
||||
|
||||
delta = axis==Xaxis ? Pt(maskdim,0) : Pt(0,maskdim);
|
||||
drawop(mtmp, mtmp->r, mask, nil, mask->r.min, S);
|
||||
gendrawop(mask, mask->r, mtmp, delta, mtmp, divpt(delta,-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);
|
||||
}
|
||||
|
||||
/* 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 tau, double alpha)
|
||||
{
|
||||
if(fabs(x) > tau)
|
||||
return 0.;
|
||||
return i0(alpha*sqrt(1-(x*x/(tau*tau))))/i0(alpha);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
131
src/cmd/page/util.c
Normal file
131
src/cmd/page/util.c
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#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(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 */
|
||||
}
|
||||
1022
src/cmd/page/view.c
Normal file
1022
src/cmd/page/view.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue