1 // work in progress... this version only good enough to read
2 // non-interleaved, 24bit RGB images
10 #include "imagefile.h"
14 enum{ IDATSIZE=1000000,
15 /* filtering algorithms, supposedly increase compression */
16 FilterNone = 0, /* new[x][y] = buf[x][y] */
17 FilterSub = 1, /* new[x][y] = buf[x][y] + new[x-1][y] */
18 FilterUp = 2, /* new[x][y] = buf[x][y] + new[x][y-1] */
19 FilterAvg = 3, /* new[x][y] = buf[x][y] + (new[x-1][y]+new[x][y-1])/2 */
20 FilterPaeth= 4, /* new[x][y] = buf[x][y] + paeth(new[x-1][y],new[x][y-1],new[x-1][y-1]) */
28 uchar *b; // next byte to decompress
29 uchar *e; // past end of buf
33 uchar *r, *g, *b; // Rawimage channels
34 int chan; // next channel to write
35 int col; // column index of current pixel
36 // -1 = one-byte pseudo-column for filter spec
37 int row; // row index of current pixel
38 int ncol, nrow; // image width, height
39 int filter; // algorithm for current scanline
43 static uchar PNGmagic[] = {137,80,78,71,13,10,26,10};
44 static char memerr[] = "ReadPNG: malloc failed: %r";
49 return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
61 crctab = mkcrctab(0xedb88320);
63 sysfatal("mkcrctab error");
69 pngmalloc(ulong n, int clear)
82 getchunk(Biobuf *b, char *type, uchar *d, int m)
88 if(Bread(b, buf, 8) != 8)
91 memmove(type, buf+4, 4);
94 sysfatal("getchunk needed %d, had %d", n, m);
97 sysfatal("getchunk read %d, expected %d", nr, n);
98 crc = blockcrc(crctab, crc, type, 4);
99 crc = blockcrc(crctab, crc, d, n);
100 if(Bread(b, buf, 4) != 4)
101 sysfatal("getchunk tlr failed");
104 sysfatal("getchunk crc failed");
118 n = getchunk(z->bi, type, z->b, IDATSIZE);
119 if(n < 0 || strcmp(type, "IEND") == 0)
122 if(type[0] & PropertyBit)
123 goto refill_buffer; /* skip auxiliary chunks for now */
124 if(strcmp(type,"IDAT") != 0)
125 sysfatal("unrecognized mandatory chunk %s", type);
131 paeth(uchar a, uchar b, uchar c)
135 p = (int)a + (int)b - (int)c;
136 pa = abs(p - (int)a);
137 pb = abs(p - (int)b);
138 pc = abs(p - (int)c);
140 if(pa <= pb && pa <= pc)
148 unfilter(int alg, uchar *buf, uchar *ebuf, int up)
159 while (++buf < ebuf);
168 *buf += (buf[-1]+buf[up])/2;
176 *buf += paeth(0, buf[up], 0);
178 *buf += paeth(buf[-1], buf[up], buf[up-1]);
185 zwrite(void *va, void *vb, int n)
194 if (z->filter >= FilterLast)
195 sysfatal("unknown filter algorithm %d for row %d", z->row, z->filter);
212 if(z->col == z->ncol){
218 unfilter(z->filter, z->r - z->col, z->r, up);
219 unfilter(z->filter, z->g - z->col, z->g, up);
220 unfilter(z->filter, z->b - z->col, z->b, up);
224 if((z->row >= z->nrow) && (i < n-1) )
225 sysfatal("header said %d rows; data goes further", z->nrow);
241 int k, n, nrow, ncol, err;
243 buf = pngmalloc(IDATSIZE, 0);
244 Bread(b, buf, sizeof PNGmagic);
245 if(memcmp(PNGmagic, buf, sizeof PNGmagic) != 0)
246 sysfatal("bad PNGmagic");
248 n = getchunk(b, type, buf, IDATSIZE);
249 if(n < 13 || strcmp(type,"IHDR") != 0)
250 sysfatal("missing IHDR chunk");
252 ncol = get4(h); h += 4;
253 nrow = get4(h); h += 4;
254 if(ncol <= 0 || nrow <= 0)
255 sysfatal("impossible image size nrow=%d ncol=%d", nrow, ncol);
257 fprint(2, "readpng nrow=%d ncol=%d\n", nrow, ncol);
259 sysfatal("only 24 bit per pixel supported for now [%d]", h[-1]);
261 sysfatal("only rgb supported for now [%d]", h[-1]);
263 sysfatal("only deflate supported for now [%d]", h[-1]);
264 if(*h++ != FilterNone)
265 sysfatal("only FilterNone supported for now [%d]", h[-1]);
267 sysfatal("only non-interlaced supported for now [%d]", h[-1]);
269 image = pngmalloc(sizeof(Rawimage), 1);
270 image->r = Rect(0, 0, ncol, nrow);
273 image->chanlen = ncol*nrow;
277 image->giftrindex = 0;
278 image->chandesc = CRGB;
281 image->chans[k] = pngmalloc(ncol*nrow, 0);
284 zr.b = zr.e = buf + IDATSIZE;
285 zw.r = image->chans[0];
286 zw.g = image->chans[1];
287 zw.b = image->chans[2];
293 err = inflatezlib(&zw, zwrite, &zr, zread);
295 sysfatal("inflatezlib %s\n", flateerr(err));
301 Breadpng(Biobuf *b, int colorspace)
303 Rawimage *r, **array;
307 if(colorspace != CRGB){
308 errstr(buf, sizeof buf); /* throw it away */
309 werrstr("ReadPNG: unknown color space %d", colorspace);
313 array = malloc(2*sizeof(*array));
316 errstr(buf, sizeof buf); /* throw it away */
324 readpng(int fd, int colorspace)
329 if(Binit(&b, fd, OREAD) < 0)
331 a = Breadpng(&b, colorspace);