writegif.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <memdraw.h>
  5. #include <bio.h>
  6. #include "imagefile.h"
  7. enum
  8. {
  9. Nhash = 4001,
  10. Nbuf = 300,
  11. };
  12. typedef struct Entry Entry;
  13. typedef struct IO IO;
  14. struct Entry
  15. {
  16. int index;
  17. int prefix;
  18. int exten;
  19. Entry *next;
  20. };
  21. struct IO
  22. {
  23. Biobuf *fd;
  24. uchar buf[Nbuf];
  25. int i;
  26. int nbits; /* bits in right side of shift register */
  27. int sreg; /* shift register */
  28. };
  29. static Rectangle mainrect;
  30. static Entry tbl[4096];
  31. static uchar *colormap[5]; /* one for each ldepth: GREY1 GREY2 GREY4 CMAP8=rgbv plus GREY8 */
  32. #define GREYMAP 4
  33. static int colormapsize[] = { 2, 4, 16, 256, 256 }; /* 2 for zero is an odd property of GIF */
  34. static void writeheader(Biobuf*, Rectangle, int, ulong, int);
  35. static void writedescriptor(Biobuf*, Rectangle);
  36. static char* writedata(Biobuf*, Image*, Memimage*);
  37. static void writetrailer(Biobuf *fd);
  38. static void writecomment(Biobuf *fd, char*);
  39. static void writegraphiccontrol(Biobuf *fd, int, int);
  40. static void* gifmalloc(ulong);
  41. static void encode(Biobuf*, Rectangle, int, uchar*, uint);
  42. static
  43. char*
  44. startgif0(Biobuf *fd, ulong chan, Rectangle r, int depth, int loopcount)
  45. {
  46. int i;
  47. for(i=0; i<nelem(tbl); i++)
  48. tbl[i] = (Entry){i, -1, i, nil};
  49. switch(chan){
  50. case GREY1:
  51. case GREY2:
  52. case GREY4:
  53. case CMAP8:
  54. case GREY8:
  55. break;
  56. default:
  57. return "WriteGIF: can't handle channel type";
  58. }
  59. mainrect = r;
  60. writeheader(fd, r, depth, chan, loopcount);
  61. return nil;
  62. }
  63. char*
  64. startgif(Biobuf *fd, Image *image, int loopcount)
  65. {
  66. return startgif0(fd, image->chan, image->r, image->depth, loopcount);
  67. }
  68. char*
  69. memstartgif(Biobuf *fd, Memimage *memimage, int loopcount)
  70. {
  71. return startgif0(fd, memimage->chan, memimage->r, memimage->depth, loopcount);
  72. }
  73. static
  74. char*
  75. writegif0(Biobuf *fd, Image *image, Memimage *memimage, ulong chan, Rectangle r, char *comment, int dt, int trans)
  76. {
  77. char *err;
  78. switch(chan){
  79. case GREY1:
  80. case GREY2:
  81. case GREY4:
  82. case CMAP8:
  83. case GREY8:
  84. break;
  85. default:
  86. return "WriteGIF: can't handle channel type";
  87. }
  88. writecomment(fd, comment);
  89. writegraphiccontrol(fd, dt, trans);
  90. writedescriptor(fd, r);
  91. err = writedata(fd, image, memimage);
  92. if(err != nil)
  93. return err;
  94. return nil;
  95. }
  96. char*
  97. writegif(Biobuf *fd, Image *image, char *comment, int dt, int trans)
  98. {
  99. return writegif0(fd, image, nil, image->chan, image->r, comment, dt, trans);
  100. }
  101. char*
  102. memwritegif(Biobuf *fd, Memimage *memimage, char *comment, int dt, int trans)
  103. {
  104. return writegif0(fd, nil, memimage, memimage->chan, memimage->r, comment, dt, trans);
  105. }
  106. /*
  107. * Write little-endian 16-bit integer
  108. */
  109. static
  110. void
  111. put2(Biobuf *fd, int i)
  112. {
  113. Bputc(fd, i);
  114. Bputc(fd, i>>8);
  115. }
  116. /*
  117. * Get color map for all ldepths, in format suitable for writing out
  118. */
  119. static
  120. void
  121. getcolormap(void)
  122. {
  123. int i, col;
  124. ulong rgb;
  125. uchar *c;
  126. if(colormap[0] != nil)
  127. return;
  128. for(i=0; i<nelem(colormap); i++)
  129. colormap[i] = gifmalloc(3* colormapsize[i]);
  130. c = colormap[GREYMAP]; /* GREY8 */
  131. for(i=0; i<256; i++){
  132. c[3*i+0] = i; /* red */
  133. c[3*i+1] = i; /* green */
  134. c[3*i+2] = i; /* blue */
  135. }
  136. c = colormap[3]; /* RGBV */
  137. for(i=0; i<256; i++){
  138. rgb = cmap2rgb(i);
  139. c[3*i+0] = (rgb>>16) & 0xFF; /* red */
  140. c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
  141. c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
  142. }
  143. c = colormap[2]; /* GREY4 */
  144. for(i=0; i<16; i++){
  145. col = (i<<4)|i;
  146. rgb = cmap2rgb(col);
  147. c[3*i+0] = (rgb>>16) & 0xFF; /* red */
  148. c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
  149. c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
  150. }
  151. c = colormap[1]; /* GREY2 */
  152. for(i=0; i<4; i++){
  153. col = (i<<6)|(i<<4)|(i<<2)|i;
  154. rgb = cmap2rgb(col);
  155. c[3*i+0] = (rgb>>16) & 0xFF; /* red */
  156. c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
  157. c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
  158. }
  159. c = colormap[0]; /* GREY1 */
  160. for(i=0; i<2; i++){
  161. if(i == 0)
  162. col = 0;
  163. else
  164. col = 0xFF;
  165. rgb = cmap2rgb(col);
  166. c[3*i+0] = (rgb>>16) & 0xFF; /* red */
  167. c[3*i+1] = (rgb>> 8) & 0xFF; /* green */
  168. c[3*i+2] = (rgb>> 0) & 0xFF; /* blue */
  169. }
  170. }
  171. /*
  172. * Write header, logical screen descriptor, and color map
  173. */
  174. static
  175. void
  176. writeheader(Biobuf *fd, Rectangle r, int depth, ulong chan, int loopcount)
  177. {
  178. /* Header */
  179. Bprint(fd, "%s", "GIF89a");
  180. /* Logical Screen Descriptor */
  181. put2(fd, Dx(r));
  182. put2(fd, Dy(r));
  183. /* Color table present, 4 bits per color (for RGBV best case), size of color map */
  184. Bputc(fd, (1<<7)|(3<<4)|(depth-1)); /* not right for GREY8, but GIF doesn't let us specify enough bits */
  185. Bputc(fd, 0xFF); /* white background (doesn't matter anyway) */
  186. Bputc(fd, 0); /* pixel aspect ratio - unused */
  187. /* Global Color Table */
  188. getcolormap();
  189. if(chan == GREY8)
  190. depth = GREYMAP;
  191. else
  192. depth = log2[depth];
  193. Bwrite(fd, colormap[depth], 3*colormapsize[depth]);
  194. if(loopcount >= 0){ /* hard-to-discover way to force cycled animation */
  195. /* Application Extension with (1 loopcountlo loopcounthi) as data */
  196. Bputc(fd, 0x21);
  197. Bputc(fd, 0xFF);
  198. Bputc(fd, 11);
  199. Bwrite(fd, "NETSCAPE2.0", 11);
  200. Bputc(fd, 3);
  201. Bputc(fd, 1);
  202. put2(fd, loopcount);
  203. Bputc(fd, 0);
  204. }
  205. }
  206. /*
  207. * Write optional comment block
  208. */
  209. static
  210. void
  211. writecomment(Biobuf *fd, char *comment)
  212. {
  213. int n;
  214. if(comment==nil || comment[0]=='\0')
  215. return;
  216. /* Comment extension and label */
  217. Bputc(fd, 0x21);
  218. Bputc(fd, 0xFE);
  219. /* Comment data */
  220. n = strlen(comment);
  221. if(n > 255)
  222. n = 255;
  223. Bputc(fd, n);
  224. Bwrite(fd, comment, n);
  225. /* Block terminator */
  226. Bputc(fd, 0x00);
  227. }
  228. /*
  229. * Write optional control block (sets Delay Time)
  230. */
  231. static
  232. void
  233. writegraphiccontrol(Biobuf *fd, int dt, int trans)
  234. {
  235. if(dt < 0 && trans < 0)
  236. return;
  237. /* Comment extension and label and block size*/
  238. Bputc(fd, 0x21);
  239. Bputc(fd, 0xF9);
  240. Bputc(fd, 0x04);
  241. /* Disposal method and other flags (none) */
  242. if(trans >= 0)
  243. Bputc(fd, 0x01);
  244. else
  245. Bputc(fd, 0x00);
  246. /* Delay time, in centisec (argument is millisec for sanity) */
  247. if(dt < 0)
  248. dt = 0;
  249. else if(dt < 10)
  250. dt = 1;
  251. else
  252. dt = (dt+5)/10;
  253. put2(fd, dt);
  254. /* Transparency index */
  255. if(trans < 0)
  256. trans = 0;
  257. Bputc(fd, trans);
  258. /* Block terminator */
  259. Bputc(fd, 0x00);
  260. }
  261. /*
  262. * Write image descriptor
  263. */
  264. static
  265. void
  266. writedescriptor(Biobuf *fd, Rectangle r)
  267. {
  268. /* Image Separator */
  269. Bputc(fd, 0x2C);
  270. /* Left, top, width, height */
  271. put2(fd, r.min.x-mainrect.min.x);
  272. put2(fd, r.min.y-mainrect.min.y);
  273. put2(fd, Dx(r));
  274. put2(fd, Dy(r));
  275. /* no special processing */
  276. Bputc(fd, 0);
  277. }
  278. /*
  279. * Write data
  280. */
  281. static
  282. char*
  283. writedata(Biobuf *fd, Image *image, Memimage *memimage)
  284. {
  285. char *err;
  286. uchar *data;
  287. int ndata, depth;
  288. Rectangle r;
  289. if(memimage != nil){
  290. r = memimage->r;
  291. depth = memimage->depth;
  292. }else{
  293. r = image->r;
  294. depth = image->depth;
  295. }
  296. /* LZW Minimum code size */
  297. if(depth == 1)
  298. Bputc(fd, 2);
  299. else
  300. Bputc(fd, depth);
  301. /*
  302. * Read image data into memory
  303. * potentially one extra byte on each end of each scan line
  304. */
  305. ndata = Dy(r)*(2+(Dx(r)>>(3-log2[depth])));
  306. data = gifmalloc(ndata);
  307. if(memimage != nil)
  308. ndata = unloadmemimage(memimage, r, data, ndata);
  309. else
  310. ndata = unloadimage(image, r, data, ndata);
  311. if(ndata < 0){
  312. err = gifmalloc(ERRMAX);
  313. snprint(err, ERRMAX, "WriteGIF: %r");
  314. free(data);
  315. return err;
  316. }
  317. /* Encode and emit the data */
  318. encode(fd, r, depth, data, ndata);
  319. free(data);
  320. /* Block Terminator */
  321. Bputc(fd, 0);
  322. return nil;
  323. }
  324. /*
  325. * Write trailer
  326. */
  327. void
  328. endgif(Biobuf *fd)
  329. {
  330. Bputc(fd, 0x3B);
  331. Bflush(fd);
  332. }
  333. void
  334. memendgif(Biobuf *fd)
  335. {
  336. endgif(fd);
  337. }
  338. /*
  339. * Put n bits of c into output at io.buf[i];
  340. */
  341. static
  342. void
  343. output(IO *io, int c, int n)
  344. {
  345. if(c < 0){
  346. if(io->nbits != 0)
  347. io->buf[io->i++] = io->sreg;
  348. Bputc(io->fd, io->i);
  349. Bwrite(io->fd, io->buf, io->i);
  350. io->nbits = 0;
  351. return;
  352. }
  353. if(io->nbits+n >= 31){
  354. fprint(2, "panic: WriteGIF sr overflow\n");
  355. exits("WriteGIF panic");
  356. }
  357. io->sreg |= c<<io->nbits;
  358. io->nbits += n;
  359. while(io->nbits >= 8){
  360. io->buf[io->i++] = io->sreg;
  361. io->sreg >>= 8;
  362. io->nbits -= 8;
  363. }
  364. if(io->i >= 255){
  365. Bputc(io->fd, 255);
  366. Bwrite(io->fd, io->buf, 255);
  367. memmove(io->buf, io->buf+255, io->i-255);
  368. io->i -= 255;
  369. }
  370. }
  371. /*
  372. * LZW encoder
  373. */
  374. static
  375. void
  376. encode(Biobuf *fd, Rectangle r, int depth, uchar *data, uint ndata)
  377. {
  378. int i, c, h, csize, prefix, first, sreg, nbits, bitsperpixel;
  379. int CTM, EOD, codesize, ld0, datai, x, ld, pm;
  380. int nentry, maxentry, early;
  381. Entry *e, *oe;
  382. IO *io;
  383. Entry **hash;
  384. first = 1;
  385. ld = log2[depth];
  386. /* ldepth 0 must generate codesize 2 with values 0 and 1 (see the spec.) */
  387. ld0 = ld;
  388. if(ld0 == 0)
  389. ld0 = 1;
  390. codesize = (1<<ld0);
  391. CTM = 1<<codesize;
  392. EOD = CTM+1;
  393. io = gifmalloc(sizeof(IO));
  394. io->fd = fd;
  395. sreg = 0;
  396. nbits = 0;
  397. bitsperpixel = 1<<ld;
  398. pm = (1<<bitsperpixel)-1;
  399. datai = 0;
  400. x = r.min.x;
  401. hash = gifmalloc(Nhash*sizeof(Entry*));
  402. Init:
  403. memset(hash, 0, Nhash*sizeof(Entry*));
  404. csize = codesize+1;
  405. nentry = EOD+1;
  406. maxentry = (1<<csize);
  407. for(i = 0; i<nentry; i++){
  408. e = &tbl[i];
  409. h = (e->prefix<<24) | (e->exten<<8);
  410. h %= Nhash;
  411. if(h < 0)
  412. h += Nhash;
  413. e->next = hash[h];
  414. hash[h] = e;
  415. }
  416. prefix = -1;
  417. if(first)
  418. output(io, CTM, csize);
  419. first = 0;
  420. /*
  421. * Scan over pixels. Because of partially filled bytes on ends of scan lines,
  422. * which must be ignored in the data stream passed to GIF, this is more
  423. * complex than we'd like.
  424. */
  425. Next:
  426. for(;;){
  427. if(ld != 3){
  428. /* beginning of scan line is difficult; prime the shift register */
  429. if(x == r.min.x){
  430. if(datai == ndata)
  431. break;
  432. sreg = data[datai++];
  433. nbits = 8-((x&(7>>ld))<<ld);
  434. }
  435. x++;
  436. if(x == r.max.x)
  437. x = r.min.x;
  438. }
  439. if(nbits == 0){
  440. if(datai == ndata)
  441. break;
  442. sreg = data[datai++];
  443. nbits = 8;
  444. }
  445. nbits -= bitsperpixel;
  446. c = sreg>>nbits & pm;
  447. h = prefix<<24 | c<<8;
  448. h %= Nhash;
  449. if(h < 0)
  450. h += Nhash;
  451. oe = nil;
  452. for(e = hash[h]; e!=nil; e=e->next){
  453. if(e->prefix == prefix && e->exten == c){
  454. if(oe != nil){
  455. oe->next = e->next;
  456. e->next = hash[h];
  457. hash[h] = e;
  458. }
  459. prefix = e->index;
  460. goto Next;
  461. }
  462. oe = e;
  463. }
  464. output(io, prefix, csize);
  465. early = 0; /* peculiar tiff feature here for reference */
  466. if(nentry == maxentry-early){
  467. if(csize == 12){
  468. nbits += bitsperpixel; /* unget pixel */
  469. x--;
  470. if(ld != 3 && x == r.min.x)
  471. datai--;
  472. output(io, CTM, csize);
  473. goto Init;
  474. }
  475. csize++;
  476. maxentry = (1<<csize);
  477. }
  478. e = &tbl[nentry];
  479. e->prefix = prefix;
  480. e->exten = c;
  481. e->next = hash[h];
  482. hash[h] = e;
  483. prefix = c;
  484. nentry++;
  485. }
  486. output(io, prefix, csize);
  487. output(io, EOD, csize);
  488. output(io, -1, csize);
  489. free(io);
  490. free(hash);
  491. }
  492. static
  493. void*
  494. gifmalloc(ulong sz)
  495. {
  496. void *v;
  497. v = malloc(sz);
  498. if(v == nil) {
  499. fprint(2, "WriteGIF: out of memory allocating %ld\n", sz);
  500. abort();
  501. exits("mem");
  502. }
  503. memset(v, 0, sz);
  504. return v;
  505. }