Blob


1 /*
2 * graphics file reading for page
3 */
5 #include <u.h>
6 #include <libc.h>
7 #include <draw.h>
8 #include <thread.h>
9 #include <bio.h>
10 #include <cursor.h>
11 #include "page.h"
13 typedef struct Convert Convert;
14 typedef struct GfxInfo GfxInfo;
16 struct Convert {
17 char *name;
18 char *cmd;
19 char *truecmd; /* cmd for true color */
20 };
22 struct GfxInfo {
23 Graphic *g;
24 };
26 /*
27 * N.B. These commands need to read stdin if %a is replaced
28 * with an empty string.
29 */
30 Convert cvt[] = {
31 { "plan9", "fb/3to1 rgbv %a |fb/pcp -tplan9" },
32 { "tiff", "fb/tiff2pic %a | fb/3to1 rgbv | fb/pcp -tplan9" },
33 { "jpeg", "jpg -9 %a", "jpg -t9 %a" },
34 { "gif", "gif -9 %a", "gif -t9 %a" },
35 { "inferno", nil },
36 { "fax", "aux/g3p9bit -g %a" },
37 { "unknown", "fb/cvt2pic %a |fb/3to1 rgbv" },
38 { "plan9bm", nil },
39 { "ppm", "ppm -9 %a", "ppm -t9 %a" },
40 { "png", "png -9 %a", "png -t9 %a" },
41 { "yuv", "yuv -9 %a", "yuv -t9 %a" },
42 { "bmp", "bmp -9 %a", "bmp -t9 %a" },
43 };
45 static Image* gfxdrawpage(Document *d, int page);
46 static char* gfxpagename(Document*, int);
47 static int spawnrc(char*, Graphic*);
48 //static void waitrc(void);
49 //static int spawnpost(int);
50 static int addpage(Document*, char*);
51 static int rmpage(Document*, int);
52 static int genaddpage(Document*, char*, uchar*, int);
54 static char*
55 gfxpagename(Document *doc, int page)
56 {
57 GfxInfo *gfx = doc->extra;
58 return gfx->g[page].name;
59 }
61 static Image*
62 gfxdrawpage(Document *doc, int page)
63 {
64 GfxInfo *gfx = doc->extra;
65 return convert(gfx->g+page);
66 }
68 Document*
69 initgfx(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
70 {
71 GfxInfo *gfx;
72 Document *doc;
73 int i;
75 USED(b);
77 doc = emalloc(sizeof(*doc));
78 gfx = emalloc(sizeof(*gfx));
79 gfx->g = nil;
81 doc->npage = 0;
82 doc->drawpage = gfxdrawpage;
83 doc->pagename = gfxpagename;
84 doc->addpage = addpage;
85 doc->rmpage = rmpage;
86 doc->extra = gfx;
87 doc->fwdonly = 0;
88 doc->type = Tgfx;
90 fprint(2, "reading through graphics...\n");
91 if(argc==0 && buf)
92 genaddpage(doc, nil, buf, nbuf);
93 else{
94 for(i=0; i<argc; i++)
95 if(addpage(doc, argv[i]) < 0)
96 fprint(2, "warning: not including %s: %r\n", argv[i]);
97 }
99 return doc;
102 static int
103 genaddpage(Document *doc, char *name, uchar *buf, int nbuf)
105 Graphic *g;
106 GfxInfo *gfx;
107 Biobuf *b;
108 uchar xbuf[32];
109 int i, l;
111 l = 0;
112 gfx = doc->extra;
114 assert((name == nil) ^ (buf == nil));
115 assert(name != nil || doc->npage == 0);
117 for(i=0; i<doc->npage; i++)
118 if(strcmp(gfx->g[i].name, name) == 0)
119 return i;
121 if(name){
122 l = strlen(name);
123 if((b = Bopen(name, OREAD)) == nil) {
124 werrstr("Bopen: %r");
125 return -1;
128 if(Bread(b, xbuf, sizeof xbuf) != sizeof xbuf) {
129 werrstr("short read: %r");
130 return -1;
132 Bterm(b);
133 buf = xbuf;
134 nbuf = sizeof xbuf;
138 gfx->g = erealloc(gfx->g, (doc->npage+1)*(sizeof(*gfx->g)));
139 g = &gfx->g[doc->npage];
141 memset(g, 0, sizeof *g);
142 if(memcmp(buf, "GIF", 3) == 0)
143 g->type = Igif;
144 else if(memcmp(buf, "\111\111\052\000", 4) == 0)
145 g->type = Itiff;
146 else if(memcmp(buf, "\115\115\000\052", 4) == 0)
147 g->type = Itiff;
148 else if(memcmp(buf, "\377\330\377", 3) == 0)
149 g->type = Ijpeg;
150 else if(memcmp(buf, "\211PNG\r\n\032\n", 3) == 0)
151 g->type = Ipng;
152 else if(memcmp(buf, "compressed\n", 11) == 0)
153 g->type = Iinferno;
154 else if(memcmp(buf, "\0PC Research, Inc", 17) == 0)
155 g->type = Ifax;
156 else if(memcmp(buf, "TYPE=ccitt-g31", 14) == 0)
157 g->type = Ifax;
158 else if(memcmp(buf, "II*", 3) == 0)
159 g->type = Ifax;
160 else if(memcmp(buf, "TYPE=", 5) == 0)
161 g->type = Ipic;
162 else if(buf[0] == 'P' && '0' <= buf[1] && buf[1] <= '9')
163 g->type = Ippm;
164 else if(memcmp(buf, "BM", 2) == 0)
165 g->type = Ibmp;
166 else if(memcmp(buf, " ", 10) == 0 &&
167 '0' <= buf[10] && buf[10] <= '9' &&
168 buf[11] == ' ')
169 g->type = Iplan9bm;
170 else if(strtochan((char*)buf) != 0)
171 g->type = Iplan9bm;
172 else if (l > 4 && strcmp(name + l -4, ".yuv") == 0)
173 g->type = Iyuv;
174 else
175 g->type = Icvt2pic;
177 if(name){
178 g->name = estrdup(name);
179 g->fd = -1;
180 }else{
181 g->name = estrdup("stdin"); /* so it can be freed */
182 g->fd = stdinpipe(buf, nbuf);
185 if(chatty) fprint(2, "classified \"%s\" as \"%s\"\n", g->name, cvt[g->type].name);
186 return doc->npage++;
189 static int
190 addpage(Document *doc, char *name)
192 return genaddpage(doc, name, nil, 0);
195 static int
196 rmpage(Document *doc, int n)
198 int i;
199 GfxInfo *gfx;
201 if(n < 0 || n >= doc->npage)
202 return -1;
204 gfx = doc->extra;
205 doc->npage--;
206 free(gfx->g[n].name);
208 for(i=n; i<doc->npage; i++)
209 gfx->g[i] = gfx->g[i+1];
211 if(n < doc->npage)
212 return n;
213 if(n == 0)
214 return 0;
215 return n-1;
219 Image*
220 convert(Graphic *g)
222 int fd;
223 Convert c;
224 char *cmd;
225 char *name, buf[1000];
226 Image *im;
227 int rcspawned = 0;
229 c = cvt[g->type];
230 if(c.cmd == nil) {
231 if(chatty) fprint(2, "no conversion for bitmap \"%s\"...\n", g->name);
232 if(g->fd < 0){ /* not stdin */
233 fd = open(g->name, OREAD);
234 if(fd < 0) {
235 fprint(2, "cannot open file: %r\n");
236 wexits("open");
238 }else
239 fd = g->fd;
240 } else {
241 cmd = c.cmd;
242 if(truecolor && c.truecmd)
243 cmd = c.truecmd;
245 if(g->fd >= 0) /* is pipe */
246 name = "";
247 else
248 name = g->name;
249 if(strlen(cmd)+strlen(name) > sizeof buf) {
250 fprint(2, "command too long\n");
251 wexits("convert");
253 snprint(buf, sizeof buf, cmd, name);
254 if(chatty) fprint(2, "using \"%s\" to convert \"%s\"...\n", buf, g->name);
255 fd = spawnrc(buf, g);
256 rcspawned++;
257 if(fd < 0) {
258 fprint(2, "cannot spawn converter: %r\n");
259 wexits("convert");
263 im = readimage(display, fd, 0);
264 if(im == nil) {
265 fprint(2, "warning: couldn't read image: %r\n");
268 close(fd);
269 return im;
272 static int
273 spawnrc(char *cmd, Graphic *g)
275 int pfd[2];
276 int fd[3];
278 if(chatty) fprint(2, "spawning(%s)...", cmd);
280 if(pipe(pfd) < 0)
281 return -1;
283 if(g->fd > 0)
284 fd[0] = dup(g->fd, -1);
285 else
286 fd[0] = open("/dev/null", OREAD);
287 fd[1] = pfd[1];
288 fd[2] = dup(2, -1);
290 if(threadspawnl(fd, "rc", "rc", "-c", cmd, nil) == -1)
291 return -1;
293 return pfd[0];