1 28994509 2004-04-21 devnull #include <u.h>
2 28994509 2004-04-21 devnull #include <libc.h>
3 28994509 2004-04-21 devnull #include <bio.h>
4 28994509 2004-04-21 devnull #include <draw.h>
5 28994509 2004-04-21 devnull #include <event.h>
6 28994509 2004-04-21 devnull #include "imagefile.h"
8 28994509 2004-04-21 devnull int cflag = 0;
9 28994509 2004-04-21 devnull int dflag = 0;
10 28994509 2004-04-21 devnull int eflag = 0;
11 28994509 2004-04-21 devnull int nineflag = 0;
12 28994509 2004-04-21 devnull int threeflag = 0;
13 28994509 2004-04-21 devnull int output = 0;
14 28994509 2004-04-21 devnull ulong outchan = CMAP8;
15 28994509 2004-04-21 devnull Image **allims;
16 28994509 2004-04-21 devnull Image **allmasks;
17 28994509 2004-04-21 devnull int which;
18 28994509 2004-04-21 devnull int defaultcolor = 1;
21 28994509 2004-04-21 devnull Border = 2,
25 28994509 2004-04-21 devnull char *show(int, char*);
27 28994509 2004-04-21 devnull Rectangle
28 28994509 2004-04-21 devnull imager(void)
30 28994509 2004-04-21 devnull Rectangle r;
32 28994509 2004-04-21 devnull if(allims==nil || allims[0]==nil)
33 28994509 2004-04-21 devnull return screen->r;
34 28994509 2004-04-21 devnull r = insetrect(screen->clipr, Edge+Border);
35 28994509 2004-04-21 devnull r.max.x = r.min.x+Dx(allims[0]->r);
36 28994509 2004-04-21 devnull r.max.y = r.min.y+Dy(allims[0]->r);
37 28994509 2004-04-21 devnull return r;
41 28994509 2004-04-21 devnull eresized(int new)
43 28994509 2004-04-21 devnull Rectangle r;
45 28994509 2004-04-21 devnull if(new && getwindow(display, Refnone) < 0){
46 28994509 2004-04-21 devnull fprint(2, "gif: can't reattach to window\n");
47 28994509 2004-04-21 devnull exits("resize");
49 28994509 2004-04-21 devnull if(allims==nil || allims[which]==nil)
51 846ec3d2 2006-02-15 devnull r = rectaddpt(allims[0]->r, subpt(screen->r.min, allims[0]->r.min));
52 28a8042c 2006-03-19 devnull if(!new && !winsize)
53 846ec3d2 2006-02-15 devnull drawresizewindow(r);
54 846ec3d2 2006-02-15 devnull r = rectaddpt(r, subpt(allims[which]->r.min, allims[0]->r.min));
55 28994509 2004-04-21 devnull drawop(screen, r, allims[which], allmasks[which], allims[which]->r.min, S);
56 28994509 2004-04-21 devnull flushimage(display, 1);
60 be36ff68 2004-04-29 devnull usage(void)
62 be36ff68 2004-04-29 devnull fprint(2, "usage: gif -39cdektv -W winsize [file.gif ...]\n");
63 be36ff68 2004-04-29 devnull exits("usage");
68 28994509 2004-04-21 devnull main(int argc, char *argv[])
70 28994509 2004-04-21 devnull int fd, i;
71 28994509 2004-04-21 devnull char *err;
73 28994509 2004-04-21 devnull ARGBEGIN{
74 be36ff68 2004-04-29 devnull case 'W':
75 be36ff68 2004-04-29 devnull winsize = EARGF(usage());
77 28994509 2004-04-21 devnull case '3': /* produce encoded, compressed, three-color bitmap file; no display by default */
78 28994509 2004-04-21 devnull threeflag++;
79 28994509 2004-04-21 devnull /* fall through */
80 28994509 2004-04-21 devnull case 't': /* produce encoded, compressed, true-color bitmap file; no display by default */
83 28994509 2004-04-21 devnull output++;
84 28994509 2004-04-21 devnull defaultcolor = 0;
85 28994509 2004-04-21 devnull outchan = RGB24;
87 28994509 2004-04-21 devnull case 'c': /* produce encoded, compressed, bitmap file; no display by default */
90 28994509 2004-04-21 devnull output++;
91 28994509 2004-04-21 devnull if(defaultcolor)
92 28994509 2004-04-21 devnull outchan = CMAP8;
94 28994509 2004-04-21 devnull case 'd': /* suppress display of image */
97 28994509 2004-04-21 devnull case 'e': /* disable floyd-steinberg error diffusion */
100 28994509 2004-04-21 devnull case 'k': /* force black and white */
101 28994509 2004-04-21 devnull defaultcolor = 0;
102 28994509 2004-04-21 devnull outchan = GREY8;
104 28994509 2004-04-21 devnull case 'v': /* force RGBV */
105 28994509 2004-04-21 devnull defaultcolor = 0;
106 28994509 2004-04-21 devnull outchan = CMAP8;
108 28994509 2004-04-21 devnull case '9': /* produce plan 9, uncompressed, bitmap file; no display by default */
109 28994509 2004-04-21 devnull nineflag++;
110 28994509 2004-04-21 devnull dflag++;
111 28994509 2004-04-21 devnull output++;
112 28994509 2004-04-21 devnull if(defaultcolor)
113 28994509 2004-04-21 devnull outchan = CMAP8;
115 28994509 2004-04-21 devnull default:
116 be36ff68 2004-04-29 devnull usage();
117 28994509 2004-04-21 devnull }ARGEND;
119 28994509 2004-04-21 devnull err = nil;
120 28994509 2004-04-21 devnull if(argc == 0)
121 28994509 2004-04-21 devnull err = show(0, "<stdin>");
123 28994509 2004-04-21 devnull for(i=0; i<argc; i++){
124 28994509 2004-04-21 devnull fd = open(argv[i], OREAD);
125 28994509 2004-04-21 devnull if(fd < 0){
126 28994509 2004-04-21 devnull fprint(2, "gif: can't open %s: %r\n", argv[i]);
127 28994509 2004-04-21 devnull err = "open";
129 28994509 2004-04-21 devnull err = show(fd, argv[i]);
130 28994509 2004-04-21 devnull close(fd);
132 28994509 2004-04-21 devnull if(output && argc>1 && err==nil){
133 28994509 2004-04-21 devnull fprint(2, "gif: exiting after one file\n");
138 28994509 2004-04-21 devnull exits(err);
142 28994509 2004-04-21 devnull transparency(Rawimage *r, char *name)
144 28994509 2004-04-21 devnull Image *i;
145 28994509 2004-04-21 devnull int j, index;
146 28994509 2004-04-21 devnull uchar *pic, *mpic, *mask;
148 28994509 2004-04-21 devnull if((r->gifflags&TRANSP) == 0)
149 28994509 2004-04-21 devnull return nil;
150 28994509 2004-04-21 devnull i = allocimage(display, r->r, GREY8, 0, 0);
151 28994509 2004-04-21 devnull if(i == nil){
152 28994509 2004-04-21 devnull fprint(2, "gif: allocimage for mask of %s failed: %r\n", name);
153 28994509 2004-04-21 devnull return nil;
155 28994509 2004-04-21 devnull pic = r->chans[0];
156 28994509 2004-04-21 devnull mask = malloc(r->chanlen);
157 28994509 2004-04-21 devnull if(mask == nil){
158 28994509 2004-04-21 devnull fprint(2, "gif: malloc for mask of %s failed: %r\n", name);
159 28994509 2004-04-21 devnull freeimage(i);
160 28994509 2004-04-21 devnull return nil;
162 28994509 2004-04-21 devnull index = r->giftrindex;
163 28994509 2004-04-21 devnull mpic = mask;
164 28994509 2004-04-21 devnull for(j=0; j<r->chanlen; j++)
165 28994509 2004-04-21 devnull if(*pic++ == index)
166 28994509 2004-04-21 devnull *mpic++ = 0;
168 28994509 2004-04-21 devnull *mpic++ = 0xFF;
169 28994509 2004-04-21 devnull if(loadimage(i, i->r, mask, r->chanlen) < 0){
170 28994509 2004-04-21 devnull fprint(2, "gif: loadimage for mask of %s failed: %r\n", name);
171 28994509 2004-04-21 devnull free(mask);
172 28994509 2004-04-21 devnull freeimage(i);
173 28994509 2004-04-21 devnull return nil;
175 28994509 2004-04-21 devnull free(mask);
176 28994509 2004-04-21 devnull return i;
179 28994509 2004-04-21 devnull /* interleave alpha values of 0xFF in data stream. alpha value comes first, then b g r */
181 28994509 2004-04-21 devnull expand(uchar *u, int chanlen, int nchan)
183 28994509 2004-04-21 devnull int j, k;
184 28994509 2004-04-21 devnull uchar *v, *up, *vp;
186 28994509 2004-04-21 devnull v = malloc(chanlen*(nchan+1));
187 28994509 2004-04-21 devnull if(v == nil){
188 28994509 2004-04-21 devnull fprint(2, "gif: malloc fails: %r\n");
189 28994509 2004-04-21 devnull exits("malloc");
193 28994509 2004-04-21 devnull for(j=0; j<chanlen; j++){
194 28994509 2004-04-21 devnull *vp++ = 0xFF;
195 28994509 2004-04-21 devnull for(k=0; k<nchan; k++)
196 28994509 2004-04-21 devnull *vp++ = *up++;
198 28994509 2004-04-21 devnull return v;
202 28994509 2004-04-21 devnull addalpha(Rawimage *i)
204 28994509 2004-04-21 devnull char buf[32];
206 28994509 2004-04-21 devnull switch(outchan){
207 28994509 2004-04-21 devnull case CMAP8:
208 28994509 2004-04-21 devnull i->chans[0] = expand(i->chans[0], i->chanlen/1, 1);
209 28994509 2004-04-21 devnull i->chanlen = 2*(i->chanlen/1);
210 28994509 2004-04-21 devnull i->chandesc = CRGBVA16;
211 28994509 2004-04-21 devnull outchan = CHAN2(CMap, 8, CAlpha, 8);
214 28994509 2004-04-21 devnull case GREY8:
215 28994509 2004-04-21 devnull i->chans[0] = expand(i->chans[0], i->chanlen/1, 1);
216 28994509 2004-04-21 devnull i->chanlen = 2*(i->chanlen/1);
217 28994509 2004-04-21 devnull i->chandesc = CYA16;
218 28994509 2004-04-21 devnull outchan = CHAN2(CGrey, 8, CAlpha, 8);
221 28994509 2004-04-21 devnull case RGB24:
222 28994509 2004-04-21 devnull i->chans[0] = expand(i->chans[0], i->chanlen/3, 3);
223 28994509 2004-04-21 devnull i->chanlen = 4*(i->chanlen/3);
224 28994509 2004-04-21 devnull i->chandesc = CRGBA32;
225 28994509 2004-04-21 devnull outchan = RGBA32;
228 28994509 2004-04-21 devnull default:
229 28994509 2004-04-21 devnull chantostr(buf, outchan);
230 28994509 2004-04-21 devnull fprint(2, "gif: can't add alpha to type %s\n", buf);
231 28994509 2004-04-21 devnull exits("err");
236 28994509 2004-04-21 devnull * Called only when writing output. If the output is RGBA32,
237 28994509 2004-04-21 devnull * we must write four bytes per pixel instead of two.
238 28994509 2004-04-21 devnull * There's always at least two: data plus alpha.
239 28994509 2004-04-21 devnull * r is used only for reference; the image is already in c.
242 4e247f10 2011-05-17 rsc blackout(Rawimage *r, Rawimage *c)
244 28994509 2004-04-21 devnull int i, trindex;
245 28994509 2004-04-21 devnull uchar *rp, *cp;
247 28994509 2004-04-21 devnull rp = r->chans[0];
248 28994509 2004-04-21 devnull cp = c->chans[0];
249 28994509 2004-04-21 devnull trindex = r->giftrindex;
250 28994509 2004-04-21 devnull if(outchan == RGBA32)
251 28994509 2004-04-21 devnull for(i=0; i<r->chanlen; i++){
252 28994509 2004-04-21 devnull if(*rp == trindex){
253 28994509 2004-04-21 devnull *cp++ = 0x00;
254 4e247f10 2011-05-17 rsc *cp++ = 0x00;
255 4e247f10 2011-05-17 rsc *cp++ = 0x00;
256 4e247f10 2011-05-17 rsc *cp++ = 0x00;
258 28994509 2004-04-21 devnull *cp++ = 0xFF;
259 28994509 2004-04-21 devnull cp += 3;
264 28994509 2004-04-21 devnull for(i=0; i<r->chanlen; i++){
265 28994509 2004-04-21 devnull if(*rp == trindex){
266 28994509 2004-04-21 devnull *cp++ = 0x00;
267 4e247f10 2011-05-17 rsc *cp++ = 0x00;
269 28994509 2004-04-21 devnull *cp++ = 0xFF;
277 28994509 2004-04-21 devnull init(void)
279 28994509 2004-04-21 devnull static int inited;
281 28994509 2004-04-21 devnull if(inited == 0){
282 28994509 2004-04-21 devnull if(initdraw(0, 0, 0) < 0){
283 28994509 2004-04-21 devnull fprint(2, "gif: initdraw failed: %r\n");
284 28994509 2004-04-21 devnull return -1;
286 28994509 2004-04-21 devnull einit(Ekeyboard|Emouse);
287 28994509 2004-04-21 devnull inited++;
289 28994509 2004-04-21 devnull return 1;
293 28994509 2004-04-21 devnull show(int fd, char *name)
295 28994509 2004-04-21 devnull Rawimage **images, **rgbv;
296 28994509 2004-04-21 devnull Image **ims, **masks;
297 28994509 2004-04-21 devnull int j, k, n, ch, nloop, loopcount, dt;
298 28994509 2004-04-21 devnull char *err;
299 28994509 2004-04-21 devnull char buf[32];
301 28994509 2004-04-21 devnull err = nil;
302 28994509 2004-04-21 devnull images = readgif(fd, CRGB);
303 28994509 2004-04-21 devnull if(images == nil){
304 28994509 2004-04-21 devnull fprint(2, "gif: decode %s failed: %r\n", name);
305 28994509 2004-04-21 devnull return "decode";
307 28994509 2004-04-21 devnull for(n=0; images[n]; n++)
309 28994509 2004-04-21 devnull ims = malloc((n+1)*sizeof(Image*));
310 28994509 2004-04-21 devnull masks = malloc((n+1)*sizeof(Image*));
311 28994509 2004-04-21 devnull rgbv = malloc((n+1)*sizeof(Rawimage*));
312 28994509 2004-04-21 devnull if(masks==nil || rgbv==nil || ims==nil){
313 28994509 2004-04-21 devnull fprint(2, "gif: malloc of masks for %s failed: %r\n", name);
314 28994509 2004-04-21 devnull err = "malloc";
315 28994509 2004-04-21 devnull goto Return;
317 28994509 2004-04-21 devnull memset(masks, 0, (n+1)*sizeof(Image*));
318 28994509 2004-04-21 devnull memset(ims, 0, (n+1)*sizeof(Image*));
319 28994509 2004-04-21 devnull memset(rgbv, 0, (n+1)*sizeof(Rawimage*));
320 28994509 2004-04-21 devnull if(!dflag){
321 28994509 2004-04-21 devnull if(init() < 0){
322 28994509 2004-04-21 devnull err = "initdraw";
323 28994509 2004-04-21 devnull goto Return;
325 28994509 2004-04-21 devnull if(defaultcolor && screen->depth>8)
326 28994509 2004-04-21 devnull outchan = RGB24;
329 28994509 2004-04-21 devnull for(k=0; k<n; k++){
330 28994509 2004-04-21 devnull if(outchan == CMAP8)
331 28994509 2004-04-21 devnull rgbv[k] = torgbv(images[k], !eflag);
333 28994509 2004-04-21 devnull if(outchan==GREY8 || (images[k]->chandesc==CY && threeflag==0))
334 28994509 2004-04-21 devnull rgbv[k] = totruecolor(images[k], CY);
336 28994509 2004-04-21 devnull rgbv[k] = totruecolor(images[k], CRGB24);
338 28994509 2004-04-21 devnull if(rgbv[k] == nil){
339 28994509 2004-04-21 devnull fprint(2, "gif: converting %s to local format failed: %r\n", name);
340 28994509 2004-04-21 devnull err = "torgbv";
341 28994509 2004-04-21 devnull goto Return;
343 28994509 2004-04-21 devnull if(!dflag){
344 28994509 2004-04-21 devnull masks[k] = transparency(images[k], name);
345 28994509 2004-04-21 devnull if(rgbv[k]->chandesc == CY)
346 28994509 2004-04-21 devnull ims[k] = allocimage(display, rgbv[k]->r, GREY8, 0, 0);
348 28994509 2004-04-21 devnull ims[k] = allocimage(display, rgbv[k]->r, outchan, 0, 0);
349 28994509 2004-04-21 devnull if(ims[k] == nil){
350 28994509 2004-04-21 devnull fprint(2, "gif: allocimage %s failed: %r\n", name);
351 28994509 2004-04-21 devnull err = "allocimage";
352 28994509 2004-04-21 devnull goto Return;
354 28994509 2004-04-21 devnull if(loadimage(ims[k], ims[k]->r, rgbv[k]->chans[0], rgbv[k]->chanlen) < 0){
355 28994509 2004-04-21 devnull fprint(2, "gif: loadimage %s failed: %r\n", name);
356 28994509 2004-04-21 devnull err = "loadimage";
357 28994509 2004-04-21 devnull goto Return;
362 28994509 2004-04-21 devnull allims = ims;
363 28994509 2004-04-21 devnull allmasks = masks;
364 28994509 2004-04-21 devnull loopcount = images[0]->gifloopcount;
365 28994509 2004-04-21 devnull if(!dflag){
366 28994509 2004-04-21 devnull nloop = 0;
368 28994509 2004-04-21 devnull for(k=0; k<n; k++){
369 28994509 2004-04-21 devnull which = k;
370 28994509 2004-04-21 devnull eresized(0);
371 28994509 2004-04-21 devnull dt = images[k]->gifdelay*10;
372 28994509 2004-04-21 devnull if(dt < 50)
373 28994509 2004-04-21 devnull dt = 50;
374 28994509 2004-04-21 devnull while(n==1 || ecankbd()){
375 28994509 2004-04-21 devnull if((ch=ekbd())=='q' || ch==0x7F || ch==0x04) /* an odd, democratic list */
376 28994509 2004-04-21 devnull exits(nil);
377 28994509 2004-04-21 devnull if(ch == '\n')
378 28994509 2004-04-21 devnull goto Out;
379 28994509 2004-04-21 devnull }sleep(dt);
381 28994509 2004-04-21 devnull /* loopcount -1 means no loop (this code's rule), loopcount 0 means loop forever (netscape's rule)*/
382 28994509 2004-04-21 devnull }while(loopcount==0 || ++nloop<loopcount);
383 28994509 2004-04-21 devnull /* loop count has run out */
386 28994509 2004-04-21 devnull drawop(screen, screen->clipr, display->white, nil, ZP, S);
388 28994509 2004-04-21 devnull if(n>1 && output)
389 28994509 2004-04-21 devnull fprint(2, "gif: warning: only writing first image in %d-image GIF %s\n", n, name);
390 28994509 2004-04-21 devnull if(nineflag){
391 28994509 2004-04-21 devnull if(images[0]->gifflags&TRANSP){
392 28994509 2004-04-21 devnull addalpha(rgbv[0]);
393 4e247f10 2011-05-17 rsc blackout(images[0], rgbv[0]);
395 28994509 2004-04-21 devnull chantostr(buf, outchan);
396 28994509 2004-04-21 devnull print("%11s %11d %11d %11d %11d ", buf,
397 28994509 2004-04-21 devnull rgbv[0]->r.min.x, rgbv[0]->r.min.y, rgbv[0]->r.max.x, rgbv[0]->r.max.y);
398 28994509 2004-04-21 devnull if(write(1, rgbv[0]->chans[0], rgbv[0]->chanlen) != rgbv[0]->chanlen){
399 28994509 2004-04-21 devnull fprint(2, "gif: %s: write error %r\n", name);
400 28994509 2004-04-21 devnull return "write";
402 28994509 2004-04-21 devnull }else if(cflag){
403 28994509 2004-04-21 devnull if(images[0]->gifflags&TRANSP){
404 28994509 2004-04-21 devnull addalpha(rgbv[0]);
405 4e247f10 2011-05-17 rsc blackout(images[0], rgbv[0]);
407 28994509 2004-04-21 devnull if(writerawimage(1, rgbv[0]) < 0){
408 28994509 2004-04-21 devnull fprint(2, "gif: %s: write error: %r\n", name);
409 28994509 2004-04-21 devnull return "write";
414 28994509 2004-04-21 devnull allims = nil;
415 28994509 2004-04-21 devnull allmasks = nil;
416 28994509 2004-04-21 devnull for(k=0; images[k]; k++){
417 28994509 2004-04-21 devnull for(j=0; j<images[k]->nchans; j++)
418 28994509 2004-04-21 devnull free(images[k]->chans[j]);
419 28994509 2004-04-21 devnull free(images[k]->cmap);
420 28994509 2004-04-21 devnull if(rgbv[k])
421 28994509 2004-04-21 devnull free(rgbv[k]->chans[0]);
422 28994509 2004-04-21 devnull freeimage(ims[k]);
423 28994509 2004-04-21 devnull freeimage(masks[k]);
424 28994509 2004-04-21 devnull free(images[k]);
425 28994509 2004-04-21 devnull free(rgbv[k]);
427 28994509 2004-04-21 devnull free(images);
428 28994509 2004-04-21 devnull free(masks);
429 28994509 2004-04-21 devnull free(ims);
430 28994509 2004-04-21 devnull return err;