Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * graphics file reading for page
3
 */
4
 
5
#include <u.h>
6
#include <libc.h>
7
#include <draw.h>
8
#include <event.h>
9
#include <bio.h>
10
#include "page.h"
11
 
12
typedef struct Convert	Convert;
13
typedef struct GfxInfo	GfxInfo;
14
typedef struct Graphic	Graphic;
15
 
16
struct Convert {
17
	char *name;
18
	char *cmd;
19
	char *truecmd;	/* cmd for true color */
20
};
21
 
22
struct GfxInfo {
23
	Graphic *g;
24
};
25
 
26
struct Graphic {
27
	int type;
28
	char *name;
29
	uchar *buf;	/* if stdin */
30
	int nbuf;
31
};
32
 
33
enum {
34
	Ipic,
35
	Itiff,
36
	Ijpeg,
37
	Igif,
38
	Iinferno,
39
	Ifax,
40
	Icvt2pic,
41
	Iplan9bm,
42
	Iccittg4,
43
	Ippm,
44
	Ipng,
45
	Iyuv,
46
	Ibmp,
47
};
48
 
49
/*
50
 * N.B. These commands need to read stdin if %a is replaced
51
 * with an empty string.
52
 */
53
Convert cvt[] = {
54
[Ipic]		{ "plan9",	"fb/3to1 rgbv %a |fb/pcp -tplan9" },
55
[Itiff]		{ "tiff",	"fb/tiff2pic %a | fb/3to1 rgbv | fb/pcp -tplan9" },
56
[Iplan9bm]	{ "plan9bm",	nil },
57
[Ijpeg]		{ "jpeg",	"jpg -9 %a", "jpg -t9 %a" },
58
[Igif]		{ "gif",	"gif -9 %a", "gif -t9 %a" },
59
[Iinferno]	{ "inferno",	nil },
60
[Ifax]		{ "fax",	"aux/g3p9bit -g %a" },
61
[Icvt2pic]	{ "unknown",	"fb/cvt2pic %a |fb/3to1 rgbv" },
62
[Ippm]		{ "ppm",	"ppm -9 %a", "ppm -t9 %a" },
63
/* ``temporary'' hack for hobby */
64
[Iccittg4]	{ "ccitt-g4",	"cat %a|rx nslocum /usr/lib/ocr/bin/bcp -M|fb/pcp -tcompressed -l0" },
65
[Ipng]		{ "png",	"png -9 %a", "png -t9 %a" },
66
[Iyuv]		{ "yuv",	"yuv -9 %a", "yuv -t9 %a"  },
67
[Ibmp]		{ "bmp",	"bmp -9 %a", "bmp -t9 %a"  },
68
};
69
 
70
static Image*	convert(Graphic*);
71
static Image*	gfxdrawpage(Document *d, int page);
72
static char*	gfxpagename(Document*, int);
73
static int	spawnrc(char*, uchar*, int);
74
static void	waitrc(void);
75
static int	spawnpost(int);
76
static int	addpage(Document*, char*);
77
static int	rmpage(Document*, int);
78
static int	genaddpage(Document*, char*, uchar*, int);
79
 
80
static char*
81
gfxpagename(Document *doc, int page)
82
{
83
	GfxInfo *gfx = doc->extra;
84
	return gfx->g[page].name;
85
}
86
 
87
static Image*
88
gfxdrawpage(Document *doc, int page)
89
{
90
	setlabel(gfxpagename(doc, page));
91
	GfxInfo *gfx = doc->extra;
92
	return convert(gfx->g+page);
93
}
94
 
95
Document*
96
initgfx(Biobuf*, int argc, char **argv, uchar *buf, int nbuf)
97
{
98
	GfxInfo *gfx;
99
	Document *doc;
100
	int i;
101
 
102
	doc = emalloc(sizeof(*doc));
103
	gfx = emalloc(sizeof(*gfx));
104
	gfx->g = nil;
105
 
106
	doc->npage = 0;
107
	doc->drawpage = gfxdrawpage;
108
	doc->pagename = gfxpagename;
109
	doc->addpage = addpage;
110
	doc->rmpage = rmpage;
111
	doc->extra = gfx;
112
	doc->fwdonly = 0;
113
 
114
	fprint(2, "reading through graphics...\n");
115
	if(argc==0 && buf)
116
		genaddpage(doc, nil, buf, nbuf);
117
	else{
118
		for(i=0; i<argc; i++)
119
			if(addpage(doc, argv[i]) < 0)
120
				fprint(2, "warning: not including %s: %r\n", argv[i]);
121
	}
122
 
123
	return doc;
124
}
125
 
126
static int
127
genaddpage(Document *doc, char *name, uchar *buf, int nbuf)
128
{
129
	Graphic *g;
130
	GfxInfo *gfx;
131
	Biobuf *b;
132
	uchar xbuf[32];
133
	int i, l;
134
 
135
	l = 0;
136
	gfx = doc->extra;
137
 
138
	assert((name == nil) ^ (buf == nil));
139
	assert(name != nil || doc->npage == 0);
140
 
141
	for(i=0; i<doc->npage; i++)
142
		if(strcmp(gfx->g[i].name, name) == 0)
143
			return i;
144
 
145
	if(name){
146
		l = strlen(name);
147
		if((b = Bopen(name, OREAD)) == nil) {
148
			werrstr("Bopen: %r");
149
			return -1;
150
		}
151
 
152
		if(Bread(b, xbuf, sizeof xbuf) != sizeof xbuf) {
153
			werrstr("short read: %r");
154
			return -1;
155
		}
156
		Bterm(b);
157
		buf = xbuf;
158
		nbuf = sizeof xbuf;
159
	}
160
 
161
 
162
	gfx->g = erealloc(gfx->g, (doc->npage+1)*(sizeof(*gfx->g)));
163
	g = &gfx->g[doc->npage];
164
 
165
	memset(g, 0, sizeof *g);
166
	if(memcmp(buf, "GIF", 3) == 0)
167
		g->type = Igif;
168
	else if(memcmp(buf, "\111\111\052\000", 4) == 0) 
169
		g->type = Itiff;
170
	else if(memcmp(buf, "\115\115\000\052", 4) == 0)
171
		g->type = Itiff;
172
	else if(memcmp(buf, "\377\330\377", 3) == 0)
173
		g->type = Ijpeg;
174
	else if(memcmp(buf, "\211PNG\r\n\032\n", 3) == 0)
175
		g->type = Ipng;
176
	else if(memcmp(buf, "compressed\n", 11) == 0)
177
		g->type = Iinferno;
178
	else if(memcmp(buf, "\0PC Research, Inc", 17) == 0)
179
		g->type = Ifax;
180
	else if(memcmp(buf, "TYPE=ccitt-g31", 14) == 0)
181
		g->type = Ifax;
182
	else if(memcmp(buf, "II*", 3) == 0)
183
		g->type = Ifax;
184
	else if(memcmp(buf, "TYPE=ccitt-g4", 13) == 0)
185
		g->type = Iccittg4;
186
	else if(memcmp(buf, "TYPE=", 5) == 0)
187
		g->type = Ipic;
188
	else if(buf[0] == 'P' && '0' <= buf[1] && buf[1] <= '9')
189
		g->type = Ippm;
190
	else if(memcmp(buf, "BM", 2) == 0)
191
		g->type = Ibmp;
192
	else if(memcmp(buf, "          ", 10) == 0 &&
193
		'0' <= buf[10] && buf[10] <= '9' &&
194
		buf[11] == ' ')
195
		g->type = Iplan9bm;
196
	else if(strtochan((char*)buf) != 0)
197
		g->type = Iplan9bm;
198
	else if (l > 4 && strcmp(name + l -4, ".yuv") == 0)
199
		g->type = Iyuv;
200
	else
201
		g->type = Icvt2pic;
202
 
203
	if(name)
204
		g->name = estrdup(name);
205
	else{
206
		g->name = estrdup("stdin");	/* so it can be freed */
207
		g->buf = buf;
208
		g->nbuf = nbuf;
209
	}
210
 
211
	if(chatty) fprint(2, "classified \"%s\" as \"%s\"\n", g->name, cvt[g->type].name);
212
	return doc->npage++;
213
}
214
 
215
static int 
216
addpage(Document *doc, char *name)
217
{
218
	return genaddpage(doc, name, nil, 0);
219
}
220
 
221
static int
222
rmpage(Document *doc, int n)
223
{
224
	int i;
225
	GfxInfo *gfx;
226
 
227
	if(n < 0 || n >= doc->npage)
228
		return -1;
229
 
230
	gfx = doc->extra;
231
	doc->npage--;
232
	free(gfx->g[n].name);
233
 
234
	for(i=n; i<doc->npage; i++)
235
		gfx->g[i] = gfx->g[i+1];
236
 
237
	if(n < doc->npage)
238
		return n;
239
	if(n == 0)
240
		return 0;
241
	return n-1;
242
}
243
 
244
 
245
static Image*
246
convert(Graphic *g)
247
{
248
	int fd;
249
	Convert c;
250
	char *cmd;
251
	char *name, buf[1000];
252
	Image *im;
253
	int rcspawned = 0;
254
	Waitmsg *w;
255
 
256
	c = cvt[g->type];
257
	if(c.cmd == nil) {
258
		if(chatty) fprint(2, "no conversion for bitmap \"%s\"...\n", g->name);
259
		if(g->buf == nil){	/* not stdin */
260
			fd = open(g->name, OREAD);
261
			if(fd < 0) {
262
				fprint(2, "cannot open file: %r\n");
263
				wexits("open");
264
			}
265
		}else
266
			fd = stdinpipe(g->buf, g->nbuf);	
267
	} else {
268
		cmd = c.cmd;
269
		if(truecolor && c.truecmd)
270
			cmd = c.truecmd;
271
 
272
		if(g->buf != nil)	/* is stdin */
273
			name = "";
274
		else
275
			name = g->name;
276
		if(strlen(cmd)+strlen(name) > sizeof buf) {
277
			fprint(2, "command too long\n");
278
			wexits("convert");
279
		}
280
		snprint(buf, sizeof buf, cmd, name);
281
		if(chatty) fprint(2, "using \"%s\" to convert \"%s\"...\n", buf, g->name);
282
		fd = spawnrc(buf, g->buf, g->nbuf);
283
		rcspawned++;
284
		if(fd < 0) {
285
			fprint(2, "cannot spawn converter: %r\n");
286
			wexits("convert");
287
		}	
288
	}
289
 
290
	im = readimage(display, fd, 0);
291
	if(im == nil) {
292
		fprint(2, "warning: couldn't read image: %r\n");
293
	}
294
	close(fd);
295
 
296
	/* for some reason rx doesn't work well with wait */
297
	/* for some reason 3to1 exits on success with a non-null status of |3to1 */
298
	if(rcspawned && g->type != Iccittg4) {
299
		if((w=wait())!=nil && w->msg[0] && !strstr(w->msg, "3to1"))
300
			fprint(2, "slave wait error: %s\n", w->msg);
301
		free(w);
302
	}
303
	return im;
304
}
305
 
306
static int
307
spawnrc(char *cmd, uchar *stdinbuf, int nstdinbuf)
308
{
309
	int pfd[2];
310
	int pid;
311
 
312
	if(chatty) fprint(2, "spawning(%s)...", cmd);
313
 
314
	if(pipe(pfd) < 0)
315
		return -1;
316
	if((pid = fork()) < 0)
317
		return -1;
318
 
319
	if(pid == 0) {
320
		close(pfd[1]);
321
		if(stdinbuf)
322
			dup(stdinpipe(stdinbuf, nstdinbuf), 0);
323
		else
324
			dup(open("/dev/null", OREAD), 0);
325
		dup(pfd[0], 1);
326
		//dup(pfd[0], 2);
327
		execl("/bin/rc", "rc", "-c", cmd, nil);
328
		wexits("exec");
329
	}
330
	close(pfd[0]);
331
	return pfd[1];
332
}
333