png.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. #include "stdinc.h"
  2. #include "dat.h"
  3. #include "fns.h"
  4. enum
  5. {
  6. IDATSIZE = 20000,
  7. FilterNone = 0
  8. };
  9. typedef struct ZlibR ZlibR;
  10. typedef struct ZlibW ZlibW;
  11. struct ZlibR
  12. {
  13. uchar *data;
  14. int width;
  15. int dx;
  16. int dy;
  17. int x;
  18. int y;
  19. int pixwid;
  20. };
  21. struct ZlibW
  22. {
  23. Hio *io;
  24. uchar *buf;
  25. uchar *b;
  26. uchar *e;
  27. };
  28. static ulong *crctab;
  29. static uchar PNGmagic[] = { 137, 'P', 'N', 'G', '\r', '\n', 26, '\n'};
  30. static void
  31. put4(uchar *a, ulong v)
  32. {
  33. a[0] = v>>24;
  34. a[1] = v>>16;
  35. a[2] = v>>8;
  36. a[3] = v;
  37. }
  38. static void
  39. chunk(Hio *io, char *type, uchar *d, int n)
  40. {
  41. uchar buf[4];
  42. ulong crc = 0;
  43. if(strlen(type) != 4)
  44. return;
  45. put4(buf, n);
  46. hwrite(io, buf, 4);
  47. hwrite(io, type, 4);
  48. hwrite(io, d, n);
  49. crc = blockcrc(crctab, crc, type, 4);
  50. crc = blockcrc(crctab, crc, d, n);
  51. put4(buf, crc);
  52. hwrite(io, buf, 4);
  53. }
  54. static int
  55. zread(void *va, void *buf, int n)
  56. {
  57. int a, i, pixels, pixwid;
  58. uchar *b, *e, *img;
  59. ZlibR *z;
  60. z = va;
  61. pixwid = z->pixwid;
  62. b = buf;
  63. e = b+n;
  64. while(b+pixwid <= e){
  65. if(z->y >= z->dy)
  66. break;
  67. if(z->x == 0)
  68. *b++ = FilterNone;
  69. pixels = (e-b)/pixwid;
  70. if(pixels > z->dx - z->x)
  71. pixels = z->dx - z->x;
  72. img = z->data + z->width*z->y + pixwid*z->x;
  73. memmove(b, img, pixwid*pixels);
  74. if(pixwid == 4){
  75. /*
  76. * Convert to non-premultiplied alpha.
  77. */
  78. for(i=0; i<pixels; i++, b+=4){
  79. a = b[3];
  80. if(a != 0 && a != 255){
  81. if(b[0] >= a)
  82. b[0] = a;
  83. b[0] = (b[0]*255)/a;
  84. if(b[1] >= a)
  85. b[1] = a;
  86. b[1] = (b[1]*255)/a;
  87. if(b[2] >= a)
  88. b[2] = a;
  89. b[2] = (b[2]*255)/a;
  90. }
  91. }
  92. }else
  93. b += pixwid*pixels;
  94. z->x += pixels;
  95. if(z->x >= z->dx){
  96. z->x = 0;
  97. z->y++;
  98. }
  99. }
  100. return b - (uchar*)buf;
  101. }
  102. static void
  103. IDAT(ZlibW *z)
  104. {
  105. chunk(z->io, "IDAT", z->buf, z->b - z->buf);
  106. z->b = z->buf;
  107. }
  108. static int
  109. zwrite(void *va, void *buf, int n)
  110. {
  111. int m;
  112. uchar *b, *e;
  113. ZlibW *z;
  114. z = va;
  115. b = buf;
  116. e = b+n;
  117. while(b < e){
  118. m = z->e - z->b;
  119. if(m > e - b)
  120. m = e - b;
  121. memmove(z->b, b, m);
  122. z->b += m;
  123. b += m;
  124. if(z->b >= z->e)
  125. IDAT(z);
  126. }
  127. return n;
  128. }
  129. static Memimage*
  130. memRGBA(Memimage *i)
  131. {
  132. Memimage *ni;
  133. char buf[32];
  134. ulong dst;
  135. /*
  136. * [A]BGR because we want R,G,B,[A] in big-endian order. Sigh.
  137. */
  138. chantostr(buf, i->chan);
  139. if(strchr(buf, 'a'))
  140. dst = ABGR32;
  141. else
  142. dst = BGR24;
  143. if(i->chan == dst)
  144. return i;
  145. qlock(&memdrawlock);
  146. ni = allocmemimage(i->r, dst);
  147. if(ni)
  148. memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);
  149. qunlock(&memdrawlock);
  150. return ni;
  151. }
  152. int
  153. writepng(Hio *io, Memimage *m)
  154. {
  155. static int first = 1;
  156. static QLock lk;
  157. uchar buf[200], *h;
  158. Memimage *rgb;
  159. ZlibR zr;
  160. ZlibW zw;
  161. if(first){
  162. qlock(&lk);
  163. if(first){
  164. deflateinit();
  165. crctab = mkcrctab(0xedb88320);
  166. first = 0;
  167. }
  168. qunlock(&lk);
  169. }
  170. rgb = memRGBA(m);
  171. if(rgb == nil)
  172. return -1;
  173. hwrite(io, PNGmagic, sizeof PNGmagic);
  174. /* IHDR chunk */
  175. h = buf;
  176. put4(h, Dx(m->r)); h += 4;
  177. put4(h, Dy(m->r)); h += 4;
  178. *h++ = 8; /* 8 bits per channel */
  179. if(rgb->chan == BGR24)
  180. *h++ = 2; /* RGB */
  181. else
  182. *h++ = 6; /* RGBA */
  183. *h++ = 0; /* compression - deflate */
  184. *h++ = 0; /* filter - none */
  185. *h++ = 0; /* interlace - none */
  186. chunk(io, "IHDR", buf, h-buf);
  187. /* image data */
  188. zr.dx = Dx(m->r);
  189. zr.dy = Dy(m->r);
  190. zr.width = rgb->width * sizeof(ulong);
  191. zr.data = rgb->data->bdata;
  192. zr.x = 0;
  193. zr.y = 0;
  194. zr.pixwid = chantodepth(rgb->chan)/8;
  195. zw.io = io;
  196. zw.buf = vtmalloc(IDATSIZE);
  197. zw.b = zw.buf;
  198. zw.e = zw.b + IDATSIZE;
  199. if(deflatezlib(&zw, zwrite, &zr, zread, 6, 0) < 0){
  200. free(zw.buf);
  201. return -1;
  202. }
  203. if(zw.b > zw.buf)
  204. IDAT(&zw);
  205. free(zw.buf);
  206. chunk(io, "IEND", nil, 0);
  207. if(m != rgb){
  208. qlock(&memdrawlock);
  209. freememimage(rgb);
  210. qunlock(&memdrawlock);
  211. }
  212. return 0;
  213. }