writegif.c 11 KB

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