14 typedef struct Entry Entry;
31 int nbits; /* bits in right side of shift register */
32 int sreg; /* shift register */
35 static Rectangle mainrect;
36 static Entry tbl[4096];
37 static uchar *colormap[5]; /* one for each ldepth: GREY1 GREY2 GREY4 CMAP8=rgbv plus GREY8 */
39 static int colormapsize[] = { 2, 4, 16, 256, 256 }; /* 2 for zero is an odd property of GIF */
41 static void writeheader(Biobuf*, Rectangle, int, ulong, int);
42 static void writedescriptor(Biobuf*, Rectangle);
43 static char* writedata(Biobuf*, Image*, Memimage*);
44 static void writetrailer(Biobuf *fd);
45 static void writecomment(Biobuf *fd, char*);
46 static void writegraphiccontrol(Biobuf *fd, int, int);
47 static void* gifmalloc(ulong);
48 static void encode(Biobuf*, Rectangle, int, uchar*, uint);
52 startgif0(Biobuf *fd, ulong chan, Rectangle r, int depth, int loopcount)
56 for(i=0; i<nelem(tbl); i++)
57 tbl[i] = (Entry){i, -1, i, nil};
67 return "WriteGIF: can't handle channel type";
71 writeheader(fd, r, depth, chan, loopcount);
76 startgif(Biobuf *fd, Image *image, int loopcount)
78 return startgif0(fd, image->chan, image->r, image->depth, loopcount);
82 memstartgif(Biobuf *fd, Memimage *memimage, int loopcount)
84 return startgif0(fd, memimage->chan, memimage->r, memimage->depth, loopcount);
89 writegif0(Biobuf *fd, Image *image, Memimage *memimage, ulong chan, Rectangle r, char *comment, int dt, int trans)
101 return "WriteGIF: can't handle channel type";
104 writecomment(fd, comment);
105 writegraphiccontrol(fd, dt, trans);
106 writedescriptor(fd, r);
108 err = writedata(fd, image, memimage);
116 writegif(Biobuf *fd, Image *image, char *comment, int dt, int trans)
118 return writegif0(fd, image, nil, image->chan, image->r, comment, dt, trans);
122 memwritegif(Biobuf *fd, Memimage *memimage, char *comment, int dt, int trans)
124 return writegif0(fd, nil, memimage, memimage->chan, memimage->r, comment, dt, trans);
128 * Write little-endian 16-bit integer
132 put2(Biobuf *fd, int i)
139 * Get color map for all ldepths, in format suitable for writing out
149 if(colormap[0] != nil)
151 for(i=0; i<nelem(colormap); i++)
152 colormap[i] = gifmalloc(3* colormapsize[i]);
153 c = colormap[GREYMAP]; /* GREY8 */
154 for(i=0; i<256; i++){
155 c[3*i+0] = i; /* red */
156 c[3*i+1] = i; /* green */
157 c[3*i+2] = i; /* blue */
159 c = colormap[3]; /* RGBV */
160 for(i=0; i<256; i++){
162 c[3*i+0] = (rgb>>16) & 0xFF; /* red */
163 c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
164 c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
166 c = colormap[2]; /* GREY4 */
170 c[3*i+0] = (rgb>>16) & 0xFF; /* red */
171 c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
172 c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
174 c = colormap[1]; /* GREY2 */
176 col = (i<<6)|(i<<4)|(i<<2)|i;
178 c[3*i+0] = (rgb>>16) & 0xFF; /* red */
179 c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
180 c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
182 c = colormap[0]; /* GREY1 */
189 c[3*i+0] = (rgb>>16) & 0xFF; /* red */
190 c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
191 c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
195 /* imported from libdraw/arith.c to permit an extern log2 function */
196 static int log2[] = {
197 -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4,
198 -1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5
202 * Write header, logical screen descriptor, and color map
206 writeheader(Biobuf *fd, Rectangle r, int depth, ulong chan, int loopcount)
209 Bprint(fd, "%s", "GIF89a");
211 /* Logical Screen Descriptor */
215 /* Color table present, 4 bits per color (for RGBV best case), size of color map */
216 Bputc(fd, (1<<7)|(3<<4)|(depth-1)); /* not right for GREY8, but GIF doesn't let us specify enough bits */
217 Bputc(fd, 0xFF); /* white background (doesn't matter anyway) */
218 Bputc(fd, 0); /* pixel aspect ratio - unused */
220 /* Global Color Table */
226 Bwrite(fd, colormap[depth], 3*colormapsize[depth]);
228 if(loopcount >= 0){ /* hard-to-discover way to force cycled animation */
229 /* Application Extension with (1 loopcountlo loopcounthi) as data */
233 Bwrite(fd, "NETSCAPE2.0", 11);
242 * Write optional comment block
246 writecomment(Biobuf *fd, char *comment)
250 if(comment==nil || comment[0]=='\0')
253 /* Comment extension and label */
262 Bwrite(fd, comment, n);
264 /* Block terminator */
269 * Write optional control block (sets Delay Time)
273 writegraphiccontrol(Biobuf *fd, int dt, int trans)
275 if(dt < 0 && trans < 0)
278 /* Comment extension and label and block size*/
283 /* Disposal method and other flags (none) */
289 /* Delay time, in centisec (argument is millisec for sanity) */
298 /* Transparency index */
303 /* Block terminator */
308 * Write image descriptor
312 writedescriptor(Biobuf *fd, Rectangle r)
314 /* Image Separator */
317 /* Left, top, width, height */
318 put2(fd, r.min.x-mainrect.min.x);
319 put2(fd, r.min.y-mainrect.min.y);
322 /* no special processing */
331 writedata(Biobuf *fd, Image *image, Memimage *memimage)
340 depth = memimage->depth;
343 depth = image->depth;
346 /* LZW Minimum code size */
353 * Read image data into memory
354 * potentially one extra byte on each end of each scan line
356 ndata = Dy(r)*(2+(Dx(r)>>(3-log2[depth])));
357 data = gifmalloc(ndata);
359 ndata = unloadmemimage(memimage, r, data, ndata);
361 ndata = unloadimage(image, r, data, ndata);
363 err = gifmalloc(ERRMAX);
364 snprint(err, ERRMAX, "WriteGIF: %r");
369 /* Encode and emit the data */
370 encode(fd, r, depth, data, ndata);
373 /* Block Terminator */
389 memendgif(Biobuf *fd)
395 * Put n bits of c into output at io.buf[i];
399 output(IO *io, int c, int n)
403 io->buf[io->i++] = io->sreg;
404 Bputc(io->fd, io->i);
405 Bwrite(io->fd, io->buf, io->i);
410 if(io->nbits+n >= 31){
411 fprint(2, "panic: WriteGIF sr overflow\n");
412 exits("WriteGIF panic");
414 io->sreg |= c<<io->nbits;
417 while(io->nbits >= 8){
418 io->buf[io->i++] = io->sreg;
425 Bwrite(io->fd, io->buf, 255);
426 memmove(io->buf, io->buf+255, io->i-255);
436 encode(Biobuf *fd, Rectangle r, int depth, uchar *data, uint ndata)
438 int i, c, h, csize, prefix, first, sreg, nbits, bitsperpixel;
439 int CTM, EOD, codesize, ld0, datai, x, ld, pm;
440 int nentry, maxentry, early;
447 /* ldepth 0 must generate codesize 2 with values 0 and 1 (see the spec.) */
455 io = gifmalloc(sizeof(IO));
459 bitsperpixel = 1<<ld;
460 pm = (1<<bitsperpixel)-1;
464 hash = gifmalloc(Nhash*sizeof(Entry*));
467 memset(hash, 0, Nhash*sizeof(Entry*));
470 maxentry = (1<<csize);
471 for(i = 0; i<nentry; i++){
473 h = (e->prefix<<24) | (e->exten<<8);
482 output(io, CTM, csize);
486 * Scan over pixels. Because of partially filled bytes on ends of scan lines,
487 * which must be ignored in the data stream passed to GIF, this is more
488 * complex than we'd like.
493 /* beginning of scan line is difficult; prime the shift register */
497 sreg = data[datai++];
498 nbits = 8-((x&(7>>ld))<<ld);
507 sreg = data[datai++];
510 nbits -= bitsperpixel;
511 c = sreg>>nbits & pm;
512 h = prefix<<24 | c<<8;
517 for(e = hash[h]; e!=nil; e=e->next){
518 if(e->prefix == prefix && e->exten == c){
530 output(io, prefix, csize);
531 early = 0; /* peculiar tiff feature here for reference */
532 if(nentry == maxentry-early){
534 nbits += bitsperpixel; /* unget pixel */
536 if(ld != 3 && x == r.min.x)
538 output(io, CTM, csize);
542 maxentry = (1<<csize);
555 output(io, prefix, csize);
556 output(io, EOD, csize);
557 output(io, -1, csize);
569 fprint(2, "WriteGIF: out of memory allocating %ld\n", sz);