writegif.c 11 KB

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