writepng.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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. /*
  10. * See PNG 1.2 spec, also RFC 2083.
  11. */
  12. #include <u.h>
  13. #include <libc.h>
  14. #include <draw.h>
  15. #include <memdraw.h>
  16. #include <ctype.h>
  17. #include <bio.h>
  18. #include <flate.h>
  19. #include "imagefile.h"
  20. enum
  21. {
  22. IDATSIZE = 20000,
  23. FilterNone = 0,
  24. };
  25. typedef struct ZlibR ZlibR;
  26. typedef struct ZlibW ZlibW;
  27. struct ZlibR
  28. {
  29. uint8_t *data;
  30. int width;
  31. int dx;
  32. int dy;
  33. int x;
  34. int y;
  35. int pixwid;
  36. };
  37. struct ZlibW
  38. {
  39. Biobuf *io;
  40. uint8_t *buf;
  41. uint8_t *b;
  42. uint8_t *e;
  43. };
  44. static uint32_t *crctab;
  45. static uint8_t PNGmagic[] = { 137, 'P', 'N', 'G', '\r', '\n', 26, '\n'};
  46. static void
  47. put4(uint8_t *a, uint32_t v)
  48. {
  49. a[0] = v>>24;
  50. a[1] = v>>16;
  51. a[2] = v>>8;
  52. a[3] = v;
  53. }
  54. static void
  55. chunk(Biobuf *bo, char *type, uint8_t *d, int n)
  56. {
  57. uint8_t buf[4];
  58. uint32_t crc = 0;
  59. if(strlen(type) != 4)
  60. return;
  61. put4(buf, n);
  62. Bwrite(bo, buf, 4);
  63. Bwrite(bo, type, 4);
  64. Bwrite(bo, d, n);
  65. crc = blockcrc(crctab, crc, type, 4);
  66. crc = blockcrc(crctab, crc, d, n);
  67. put4(buf, crc);
  68. Bwrite(bo, buf, 4);
  69. }
  70. static int
  71. zread(void *va, void *buf, int n)
  72. {
  73. int a, i, pixels, pixwid;
  74. uint8_t *b, *e, *img;
  75. ZlibR *z;
  76. z = va;
  77. pixwid = z->pixwid;
  78. b = buf;
  79. e = b+n;
  80. while(b+pixwid < e){ /* one less for filter alg byte */
  81. if(z->y >= z->dy)
  82. break;
  83. if(z->x == 0)
  84. *b++ = FilterNone;
  85. pixels = (e-b)/pixwid;
  86. if(pixels > z->dx - z->x)
  87. pixels = z->dx - z->x;
  88. img = z->data + z->width*z->y + pixwid*z->x;
  89. memmove(b, img, pixwid*pixels);
  90. if(pixwid == 4){
  91. /*
  92. * Convert to non-premultiplied alpha.
  93. */
  94. for(i=0; i<pixels; i++, b+=4){
  95. a = b[3];
  96. if(a == 0)
  97. b[0] = b[1] = b[2] = 0;
  98. else if(a != 255){
  99. if(b[0] >= a)
  100. b[0] = a;
  101. b[0] = (b[0]*255)/a;
  102. if(b[1] >= a)
  103. b[1] = a;
  104. b[1] = (b[1]*255)/a;
  105. if(b[2] >= a)
  106. b[2] = a;
  107. b[2] = (b[2]*255)/a;
  108. }
  109. }
  110. }else
  111. b += pixwid*pixels;
  112. z->x += pixels;
  113. if(z->x >= z->dx){
  114. z->x = 0;
  115. z->y++;
  116. }
  117. }
  118. return b - (uint8_t*)buf;
  119. }
  120. static void
  121. IDAT(ZlibW *z)
  122. {
  123. chunk(z->io, "IDAT", z->buf, z->b - z->buf);
  124. z->b = z->buf;
  125. }
  126. static int
  127. zwrite(void *va, void *buf, int n)
  128. {
  129. int m;
  130. uint8_t *b, *e;
  131. ZlibW *z;
  132. z = va;
  133. b = buf;
  134. e = b+n;
  135. while(b < e){
  136. m = z->e - z->b;
  137. if(m > e - b)
  138. m = e - b;
  139. memmove(z->b, b, m);
  140. z->b += m;
  141. b += m;
  142. if(z->b >= z->e)
  143. IDAT(z);
  144. }
  145. return n;
  146. }
  147. static Memimage*
  148. memRGBA(Memimage *i)
  149. {
  150. Memimage *ni;
  151. char buf[32];
  152. uint32_t dst;
  153. /*
  154. * [A]BGR because we want R,G,B,[A] in big-endian order. Sigh.
  155. */
  156. chantostr(buf, i->chan);
  157. if(strchr(buf, 'a'))
  158. dst = ABGR32;
  159. else
  160. dst = BGR24;
  161. if(i->chan == dst)
  162. return i;
  163. ni = allocmemimage(i->r, dst);
  164. if(ni == nil)
  165. return ni;
  166. memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);
  167. return ni;
  168. }
  169. char*
  170. memwritepng(Biobuf *io, Memimage *m, ImageInfo *II)
  171. {
  172. int err, n;
  173. uint8_t buf[200], *h;
  174. uint32_t vgamma;
  175. Tm *tm;
  176. Memimage *rgb;
  177. ZlibR zr;
  178. ZlibW zw;
  179. crctab = mkcrctab(0xedb88320);
  180. if(crctab == nil)
  181. sysfatal("mkcrctab error");
  182. deflateinit();
  183. rgb = memRGBA(m);
  184. if(rgb == nil)
  185. return "allocmemimage nil";
  186. Bwrite(io, PNGmagic, sizeof PNGmagic);
  187. /* IHDR chunk */
  188. h = buf;
  189. put4(h, Dx(m->r)); h += 4;
  190. put4(h, Dy(m->r)); h += 4;
  191. *h++ = 8; /* 8 bits per channel */
  192. if(rgb->chan == BGR24)
  193. *h++ = 2; /* RGB */
  194. else
  195. *h++ = 6; /* RGBA */
  196. *h++ = 0; /* compression - deflate */
  197. *h++ = 0; /* filter - none */
  198. *h++ = 0; /* interlace - none */
  199. chunk(io, "IHDR", buf, h-buf);
  200. /* time - using now is suspect */
  201. tm = gmtime(time(0));
  202. h = buf;
  203. *h++ = (tm->year + 1900)>>8;
  204. *h++ = (tm->year + 1900)&0xff;
  205. *h++ = tm->mon + 1;
  206. *h++ = tm->mday;
  207. *h++ = tm->hour;
  208. *h++ = tm->min;
  209. *h++ = tm->sec;
  210. chunk(io, "tIME", buf, h-buf);
  211. /* gamma */
  212. if(II->fields_set & II_GAMMA){
  213. vgamma = II->gamma*100000;
  214. put4(buf, vgamma);
  215. chunk(io, "gAMA", buf, 4);
  216. }
  217. /* comment */
  218. if(II->fields_set & II_COMMENT){
  219. strncpy((char*)buf, "Comment", sizeof buf);
  220. n = strlen((char*)buf)+1; // leave null between Comment and text
  221. strncpy((char*)(buf+n), II->comment, sizeof buf - n);
  222. chunk(io, "tEXt", buf, n+strlen((char*)buf+n));
  223. }
  224. /* image data */
  225. zr.dx = Dx(m->r);
  226. zr.dy = Dy(m->r);
  227. zr.width = rgb->width * sizeof(uint32_t);
  228. zr.data = rgb->data->bdata;
  229. zr.x = 0;
  230. zr.y = 0;
  231. zr.pixwid = chantodepth(rgb->chan)/8;
  232. zw.io = io;
  233. zw.buf = malloc(IDATSIZE);
  234. if(zw.buf == nil)
  235. sysfatal("malloc: %r");
  236. zw.b = zw.buf;
  237. zw.e = zw.b + IDATSIZE;
  238. if((err=deflatezlib(&zw, zwrite, &zr, zread, 6, 0)) < 0)
  239. sysfatal("deflatezlib %s", flateerr(err));
  240. if(zw.b > zw.buf)
  241. IDAT(&zw);
  242. free(zw.buf);
  243. chunk(io, "IEND", nil, 0);
  244. if(m != rgb)
  245. freememimage(rgb);
  246. return nil;
  247. }