writegif.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  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. /* imported from libdraw/arith.c to permit an extern log2 function */
  172. static int log2[] = {
  173. -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4,
  174. -1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5
  175. };
  176. /*
  177. * Write header, logical screen descriptor, and color map
  178. */
  179. static
  180. void
  181. writeheader(Biobuf *fd, Rectangle r, int depth, ulong chan, int loopcount)
  182. {
  183. /* Header */
  184. Bprint(fd, "%s", "GIF89a");
  185. /* Logical Screen Descriptor */
  186. put2(fd, Dx(r));
  187. put2(fd, Dy(r));
  188. /* Color table present, 4 bits per color (for RGBV best case), size of color map */
  189. Bputc(fd, (1<<7)|(3<<4)|(depth-1)); /* not right for GREY8, but GIF doesn't let us specify enough bits */
  190. Bputc(fd, 0xFF); /* white background (doesn't matter anyway) */
  191. Bputc(fd, 0); /* pixel aspect ratio - unused */
  192. /* Global Color Table */
  193. getcolormap();
  194. if(chan == GREY8)
  195. depth = GREYMAP;
  196. else
  197. depth = log2[depth];
  198. Bwrite(fd, colormap[depth], 3*colormapsize[depth]);
  199. if(loopcount >= 0){ /* hard-to-discover way to force cycled animation */
  200. /* Application Extension with (1 loopcountlo loopcounthi) as data */
  201. Bputc(fd, 0x21);
  202. Bputc(fd, 0xFF);
  203. Bputc(fd, 11);
  204. Bwrite(fd, "NETSCAPE2.0", 11);
  205. Bputc(fd, 3);
  206. Bputc(fd, 1);
  207. put2(fd, loopcount);
  208. Bputc(fd, 0);
  209. }
  210. }
  211. /*
  212. * Write optional comment block
  213. */
  214. static
  215. void
  216. writecomment(Biobuf *fd, char *comment)
  217. {
  218. int n;
  219. if(comment==nil || comment[0]=='\0')
  220. return;
  221. /* Comment extension and label */
  222. Bputc(fd, 0x21);
  223. Bputc(fd, 0xFE);
  224. /* Comment data */
  225. n = strlen(comment);
  226. if(n > 255)
  227. n = 255;
  228. Bputc(fd, n);
  229. Bwrite(fd, comment, n);
  230. /* Block terminator */
  231. Bputc(fd, 0x00);
  232. }
  233. /*
  234. * Write optional control block (sets Delay Time)
  235. */
  236. static
  237. void
  238. writegraphiccontrol(Biobuf *fd, int dt, int trans)
  239. {
  240. if(dt < 0 && trans < 0)
  241. return;
  242. /* Comment extension and label and block size*/
  243. Bputc(fd, 0x21);
  244. Bputc(fd, 0xF9);
  245. Bputc(fd, 0x04);
  246. /* Disposal method and other flags (none) */
  247. if(trans >= 0)
  248. Bputc(fd, 0x01);
  249. else
  250. Bputc(fd, 0x00);
  251. /* Delay time, in centisec (argument is millisec for sanity) */
  252. if(dt < 0)
  253. dt = 0;
  254. else if(dt < 10)
  255. dt = 1;
  256. else
  257. dt = (dt+5)/10;
  258. put2(fd, dt);
  259. /* Transparency index */
  260. if(trans < 0)
  261. trans = 0;
  262. Bputc(fd, trans);
  263. /* Block terminator */
  264. Bputc(fd, 0x00);
  265. }
  266. /*
  267. * Write image descriptor
  268. */
  269. static
  270. void
  271. writedescriptor(Biobuf *fd, Rectangle r)
  272. {
  273. /* Image Separator */
  274. Bputc(fd, 0x2C);
  275. /* Left, top, width, height */
  276. put2(fd, r.min.x-mainrect.min.x);
  277. put2(fd, r.min.y-mainrect.min.y);
  278. put2(fd, Dx(r));
  279. put2(fd, Dy(r));
  280. /* no special processing */
  281. Bputc(fd, 0);
  282. }
  283. /*
  284. * Write data
  285. */
  286. static
  287. char*
  288. writedata(Biobuf *fd, Image *image, Memimage *memimage)
  289. {
  290. char *err;
  291. uchar *data;
  292. int ndata, depth;
  293. Rectangle r;
  294. if(memimage != nil){
  295. r = memimage->r;
  296. depth = memimage->depth;
  297. }else{
  298. r = image->r;
  299. depth = image->depth;
  300. }
  301. /* LZW Minimum code size */
  302. if(depth == 1)
  303. Bputc(fd, 2);
  304. else
  305. Bputc(fd, depth);
  306. /*
  307. * Read image data into memory
  308. * potentially one extra byte on each end of each scan line
  309. */
  310. ndata = Dy(r)*(2+(Dx(r)>>(3-log2[depth])));
  311. data = gifmalloc(ndata);
  312. if(memimage != nil)
  313. ndata = unloadmemimage(memimage, r, data, ndata);
  314. else
  315. ndata = unloadimage(image, r, data, ndata);
  316. if(ndata < 0){
  317. err = gifmalloc(ERRMAX);
  318. snprint(err, ERRMAX, "WriteGIF: %r");
  319. free(data);
  320. return err;
  321. }
  322. /* Encode and emit the data */
  323. encode(fd, r, depth, data, ndata);
  324. free(data);
  325. /* Block Terminator */
  326. Bputc(fd, 0);
  327. return nil;
  328. }
  329. /*
  330. * Write trailer
  331. */
  332. void
  333. endgif(Biobuf *fd)
  334. {
  335. Bputc(fd, 0x3B);
  336. Bflush(fd);
  337. }
  338. void
  339. memendgif(Biobuf *fd)
  340. {
  341. endgif(fd);
  342. }
  343. /*
  344. * Put n bits of c into output at io.buf[i];
  345. */
  346. static
  347. void
  348. output(IO *io, int c, int n)
  349. {
  350. if(c < 0){
  351. if(io->nbits != 0)
  352. io->buf[io->i++] = io->sreg;
  353. Bputc(io->fd, io->i);
  354. Bwrite(io->fd, io->buf, io->i);
  355. io->nbits = 0;
  356. return;
  357. }
  358. if(io->nbits+n >= 31){
  359. fprint(2, "panic: WriteGIF sr overflow\n");
  360. exits("WriteGIF panic");
  361. }
  362. io->sreg |= c<<io->nbits;
  363. io->nbits += n;
  364. while(io->nbits >= 8){
  365. io->buf[io->i++] = io->sreg;
  366. io->sreg >>= 8;
  367. io->nbits -= 8;
  368. }
  369. if(io->i >= 255){
  370. Bputc(io->fd, 255);
  371. Bwrite(io->fd, io->buf, 255);
  372. memmove(io->buf, io->buf+255, io->i-255);
  373. io->i -= 255;
  374. }
  375. }
  376. /*
  377. * LZW encoder
  378. */
  379. static
  380. void
  381. encode(Biobuf *fd, Rectangle r, int depth, uchar *data, uint ndata)
  382. {
  383. int i, c, h, csize, prefix, first, sreg, nbits, bitsperpixel;
  384. int CTM, EOD, codesize, ld0, datai, x, ld, pm;
  385. int nentry, maxentry, early;
  386. Entry *e, *oe;
  387. IO *io;
  388. Entry **hash;
  389. first = 1;
  390. ld = log2[depth];
  391. /* ldepth 0 must generate codesize 2 with values 0 and 1 (see the spec.) */
  392. ld0 = ld;
  393. if(ld0 == 0)
  394. ld0 = 1;
  395. codesize = (1<<ld0);
  396. CTM = 1<<codesize;
  397. EOD = CTM+1;
  398. io = gifmalloc(sizeof(IO));
  399. io->fd = fd;
  400. sreg = 0;
  401. nbits = 0;
  402. bitsperpixel = 1<<ld;
  403. pm = (1<<bitsperpixel)-1;
  404. datai = 0;
  405. x = r.min.x;
  406. hash = gifmalloc(Nhash*sizeof(Entry*));
  407. Init:
  408. memset(hash, 0, Nhash*sizeof(Entry*));
  409. csize = codesize+1;
  410. nentry = EOD+1;
  411. maxentry = (1<<csize);
  412. for(i = 0; i<nentry; i++){
  413. e = &tbl[i];
  414. h = (e->prefix<<24) | (e->exten<<8);
  415. h %= Nhash;
  416. if(h < 0)
  417. h += Nhash;
  418. e->next = hash[h];
  419. hash[h] = e;
  420. }
  421. prefix = -1;
  422. if(first)
  423. output(io, CTM, csize);
  424. first = 0;
  425. /*
  426. * Scan over pixels. Because of partially filled bytes on ends of scan lines,
  427. * which must be ignored in the data stream passed to GIF, this is more
  428. * complex than we'd like.
  429. */
  430. Next:
  431. for(;;){
  432. if(ld != 3){
  433. /* beginning of scan line is difficult; prime the shift register */
  434. if(x == r.min.x){
  435. if(datai == ndata)
  436. break;
  437. sreg = data[datai++];
  438. nbits = 8-((x&(7>>ld))<<ld);
  439. }
  440. x++;
  441. if(x == r.max.x)
  442. x = r.min.x;
  443. }
  444. if(nbits == 0){
  445. if(datai == ndata)
  446. break;
  447. sreg = data[datai++];
  448. nbits = 8;
  449. }
  450. nbits -= bitsperpixel;
  451. c = sreg>>nbits & pm;
  452. h = prefix<<24 | c<<8;
  453. h %= Nhash;
  454. if(h < 0)
  455. h += Nhash;
  456. oe = nil;
  457. for(e = hash[h]; e!=nil; e=e->next){
  458. if(e->prefix == prefix && e->exten == c){
  459. if(oe != nil){
  460. oe->next = e->next;
  461. e->next = hash[h];
  462. hash[h] = e;
  463. }
  464. prefix = e->index;
  465. goto Next;
  466. }
  467. oe = e;
  468. }
  469. output(io, prefix, csize);
  470. early = 0; /* peculiar tiff feature here for reference */
  471. if(nentry == maxentry-early){
  472. if(csize == 12){
  473. nbits += bitsperpixel; /* unget pixel */
  474. x--;
  475. if(ld != 3 && x == r.min.x)
  476. datai--;
  477. output(io, CTM, csize);
  478. goto Init;
  479. }
  480. csize++;
  481. maxentry = (1<<csize);
  482. }
  483. e = &tbl[nentry];
  484. e->prefix = prefix;
  485. e->exten = c;
  486. e->next = hash[h];
  487. hash[h] = e;
  488. prefix = c;
  489. nentry++;
  490. }
  491. output(io, prefix, csize);
  492. output(io, EOD, csize);
  493. output(io, -1, csize);
  494. free(io);
  495. free(hash);
  496. }
  497. static
  498. void*
  499. gifmalloc(ulong sz)
  500. {
  501. void *v;
  502. v = malloc(sz);
  503. if(v == nil) {
  504. fprint(2, "WriteGIF: out of memory allocating %ld\n", sz);
  505. abort();
  506. exits("mem");
  507. }
  508. memset(v, 0, sz);
  509. return v;
  510. }