readpng.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. // work in progress... this version only good enough to read
  2. // non-interleaved, 24bit RGB images
  3. #include <u.h>
  4. #include <libc.h>
  5. #include <ctype.h>
  6. #include <bio.h>
  7. #include <flate.h>
  8. #include <draw.h>
  9. #include "imagefile.h"
  10. int debug;
  11. enum{ IDATSIZE=1000000,
  12. /* filtering algorithms, supposedly increase compression */
  13. FilterNone = 0, /* new[x][y] = buf[x][y] */
  14. FilterSub = 1, /* new[x][y] = buf[x][y] + new[x-1][y] */
  15. FilterUp = 2, /* new[x][y] = buf[x][y] + new[x][y-1] */
  16. FilterAvg = 3, /* new[x][y] = buf[x][y] + (new[x-1][y]+new[x][y-1])/2 */
  17. FilterPaeth= 4, /* new[x][y] = buf[x][y] + paeth(new[x-1][y],new[x][y-1],new[x-1][y-1]) */
  18. FilterLast = 5,
  19. PropertyBit = 1<<5,
  20. };
  21. typedef struct ZlibR{
  22. Biobuf *bi;
  23. uchar *buf;
  24. uchar *b; // next byte to decompress
  25. uchar *e; // past end of buf
  26. } ZlibR;
  27. typedef struct ZlibW{
  28. uchar *r, *g, *b; // Rawimage channels
  29. int chan; // next channel to write
  30. int col; // column index of current pixel
  31. // -1 = one-byte pseudo-column for filter spec
  32. int row; // row index of current pixel
  33. int ncol, nrow; // image width, height
  34. int filter; // algorithm for current scanline
  35. } ZlibW;
  36. static ulong *crctab;
  37. static uchar PNGmagic[] = {137,80,78,71,13,10,26,10};
  38. static char readerr[] = "ReadPNG: read error: %r";
  39. static char memerr[] = "ReadPNG: malloc failed: %r";
  40. static ulong
  41. get4(uchar *a)
  42. {
  43. return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
  44. }
  45. static
  46. void
  47. pnginit(void)
  48. {
  49. static int inited;
  50. if(inited)
  51. return;
  52. inited = 1;
  53. crctab = mkcrctab(0xedb88320);
  54. if(crctab == nil)
  55. sysfatal("mkcrctab error");
  56. inflateinit();
  57. }
  58. static
  59. void*
  60. pngmalloc(ulong n, int clear)
  61. {
  62. void *p;
  63. p = malloc(n);
  64. if(p == nil)
  65. sysfatal(memerr);
  66. if(clear)
  67. memset(p, 0, n);
  68. return p;
  69. }
  70. static int
  71. getchunk(Biobuf *b, char *type, uchar *d, int m)
  72. {
  73. uchar buf[8];
  74. ulong crc = 0, crc2;
  75. int n, nr;
  76. if(Bread(b, buf, 8) != 8)
  77. return -1;
  78. n = get4(buf);
  79. memmove(type, buf+4, 4);
  80. type[4] = 0;
  81. if(n > m)
  82. sysfatal("getchunk needed %d, had %d", n, m);
  83. nr = Bread(b, d, n);
  84. if(nr != n)
  85. sysfatal("getchunk read %d, expected %d", nr, n);
  86. crc = blockcrc(crctab, crc, type, 4);
  87. crc = blockcrc(crctab, crc, d, n);
  88. if(Bread(b, buf, 4) != 4)
  89. sysfatal("getchunk tlr failed");
  90. crc2 = get4(buf);
  91. if(crc != crc2)
  92. sysfatal("getchunk crc failed");
  93. return n;
  94. }
  95. static int
  96. zread(void *va)
  97. {
  98. ZlibR *z = va;
  99. char type[5];
  100. int n;
  101. if(z->b >= z->e){
  102. refill_buffer:
  103. z->b = z->buf;
  104. n = getchunk(z->bi, type, z->b, IDATSIZE);
  105. if(n < 0 || strcmp(type, "IEND") == 0)
  106. return -1;
  107. z->e = z->b + n;
  108. if(type[0] & PropertyBit)
  109. goto refill_buffer; /* skip auxiliary chunks for now */
  110. if(strcmp(type,"IDAT") != 0)
  111. sysfatal("unrecognized mandatory chunk %s", type);
  112. }
  113. return *z->b++;
  114. }
  115. static uchar
  116. paeth(uchar a, uchar b, uchar c)
  117. {
  118. int p, pa, pb, pc;
  119. p = (int)a + (int)b - (int)c;
  120. pa = abs(p - (int)a);
  121. pb = abs(p - (int)b);
  122. pc = abs(p - (int)c);
  123. if(pa <= pb && pa <= pc)
  124. return a;
  125. else if(pb <= pc)
  126. return b;
  127. return c;
  128. }
  129. static void
  130. unfilter(int alg, uchar *buf, uchar *ebuf, int up)
  131. {
  132. switch(alg){
  133. case FilterSub:
  134. while (++buf < ebuf)
  135. *buf += buf[-1];
  136. break;
  137. case FilterUp:
  138. if (up != 0)
  139. do
  140. *buf += buf[up];
  141. while (++buf < ebuf);
  142. break;
  143. case FilterAvg:
  144. if (up == 0)
  145. while (++buf < ebuf)
  146. *buf += buf[-1]/2;
  147. else{
  148. *buf += buf[up]/2;
  149. while (++buf < ebuf)
  150. *buf += (buf[-1]+buf[up])/2;
  151. }
  152. break;
  153. case FilterPaeth:
  154. if (up == 0)
  155. while (++buf < ebuf)
  156. *buf += buf[-1];
  157. else{
  158. *buf += paeth(0, buf[up], 0);
  159. while (++buf < ebuf)
  160. *buf += paeth(buf[-1], buf[up], buf[up-1]);
  161. }
  162. break;
  163. }
  164. }
  165. static int
  166. zwrite(void *va, void *vb, int n)
  167. {
  168. ZlibW *z = va;
  169. uchar *buf = vb;
  170. int i, up;
  171. for(i=0; i<n; i++){
  172. if(z->col == -1){
  173. // set filter byte
  174. z->filter = *buf++;
  175. if (z->filter >= FilterLast)
  176. sysfatal("unknown filter algorithm %d for row %d", z->row, z->filter);
  177. z->col++;
  178. continue;
  179. }
  180. switch(z->chan){
  181. case 0:
  182. *z->r++ = *buf++;
  183. z->chan = 1;
  184. break;
  185. case 1:
  186. *z->g++ = *buf++;
  187. z->chan = 2;
  188. break;
  189. case 2:
  190. *z->b++ = *buf++;
  191. z->chan = 0;
  192. z->col++;
  193. if(z->col == z->ncol){
  194. if (z->filter){
  195. if(z->row == 0)
  196. up = 0;
  197. else
  198. up = -z->ncol;
  199. unfilter(z->filter, z->r - z->col, z->r, up);
  200. unfilter(z->filter, z->g - z->col, z->g, up);
  201. unfilter(z->filter, z->b - z->col, z->b, up);
  202. }
  203. z->col = -1;
  204. z->row++;
  205. if((z->row >= z->nrow) && (i < n-1) )
  206. sysfatal("header said %d rows; data goes further", z->nrow);
  207. }
  208. break;
  209. }
  210. }
  211. return n;
  212. }
  213. static Rawimage*
  214. readslave(Biobuf *b)
  215. {
  216. ZlibR zr;
  217. ZlibW zw;
  218. Rawimage *image;
  219. char type[5];
  220. uchar *buf, *h;
  221. int k, n, nrow, ncol, err;
  222. buf = pngmalloc(IDATSIZE, 0);
  223. Bread(b, buf, sizeof PNGmagic);
  224. if(memcmp(PNGmagic, buf, sizeof PNGmagic) != 0)
  225. sysfatal("bad PNGmagic");
  226. n = getchunk(b, type, buf, IDATSIZE);
  227. if(n < 13 || strcmp(type,"IHDR") != 0)
  228. sysfatal("missing IHDR chunk");
  229. h = buf;
  230. ncol = get4(h); h += 4;
  231. nrow = get4(h); h += 4;
  232. if(ncol <= 0 || nrow <= 0)
  233. sysfatal("impossible image size nrow=%d ncol=%d", nrow, ncol);
  234. if(debug)
  235. fprint(2, "readpng nrow=%d ncol=%d\n", nrow, ncol);
  236. if(*h++ != 8)
  237. sysfatal("only 24 bit per pixel supported for now [%d]", h[-1]);
  238. if(*h++ != 2)
  239. sysfatal("only rgb supported for now [%d]", h[-1]);
  240. if(*h++ != 0)
  241. sysfatal("only deflate supported for now [%d]", h[-1]);
  242. if(*h++ != FilterNone)
  243. sysfatal("only FilterNone supported for now [%d]", h[-1]);
  244. if(*h != 0)
  245. sysfatal("only non-interlaced supported for now [%d]", h[-1]);
  246. image = pngmalloc(sizeof(Rawimage), 1);
  247. image->r = Rect(0, 0, ncol, nrow);
  248. image->cmap = nil;
  249. image->cmaplen = 0;
  250. image->chanlen = ncol*nrow;
  251. image->fields = 0;
  252. image->gifflags = 0;
  253. image->gifdelay = 0;
  254. image->giftrindex = 0;
  255. image->chandesc = CRGB;
  256. image->nchans = 3;
  257. for(k=0; k<3; k++)
  258. image->chans[k] = pngmalloc(ncol*nrow, 0);
  259. zr.bi = b;
  260. zr.buf = buf;
  261. zr.b = zr.e = buf + IDATSIZE;
  262. zw.r = image->chans[0];
  263. zw.g = image->chans[1];
  264. zw.b = image->chans[2];
  265. zw.chan = 0;
  266. zw.col = -1;
  267. zw.row = 0;
  268. zw.ncol = ncol;
  269. zw.nrow = nrow;
  270. err = inflatezlib(&zw, zwrite, &zr, zread);
  271. if(err)
  272. sysfatal("inflatezlib %s\n", flateerr(err));
  273. free(buf);
  274. return image;
  275. }
  276. Rawimage**
  277. Breadpng(Biobuf *b, int colorspace)
  278. {
  279. Rawimage *r, **array;
  280. char buf[ERRMAX];
  281. buf[0] = '\0';
  282. if(colorspace != CRGB){
  283. errstr(buf, sizeof buf); /* throw it away */
  284. werrstr("ReadPNG: unknown color space %d", colorspace);
  285. return nil;
  286. }
  287. pnginit();
  288. array = malloc(2*sizeof(*array));
  289. if(array==nil)
  290. return nil;
  291. errstr(buf, sizeof buf); /* throw it away */
  292. r = readslave(b);
  293. array[0] = r;
  294. array[1] = nil;
  295. return array;
  296. }
  297. Rawimage**
  298. readpng(int fd, int colorspace)
  299. {
  300. Rawimage** a;
  301. Biobuf b;
  302. if(Binit(&b, fd, OREAD) < 0)
  303. return nil;
  304. a = Breadpng(&b, colorspace);
  305. Bterm(&b);
  306. return a;
  307. }