1 // based on PNG 1.2 specification, July 1999 (see also rfc2083)
2 // Alpha is not supported yet because of lack of industry acceptance and
3 // because Plan9 Image uses premultiplied alpha, so png can't be lossless.
4 // Only 24bit color supported, because 8bit may as well use GIF.
13 #include "imagefile.h"
15 enum{ IDATSIZE = 20000,
23 int row, col; // next pixel to send
29 uchar *b; // next place to write
30 uchar *e; // past end of buf
34 static uchar PNGmagic[] = {137,80,78,71,13,10,26,10};
37 put4(uchar *a, ulong v)
46 chunk(Biobuf *bo, char *type, uchar *d, int n)
57 crc = blockcrc(crctab, crc, type, 4);
58 crc = blockcrc(crctab, crc, d, n);
64 zread(void *va, void *buf, int n)
69 uchar *b = buf, *e = b+n, *img;
70 int i, pixels; // number of pixels in row that can be sent now
72 while(b+3 <= e){ // loop over image rows
78 if(pixels > ncol - z->col)
79 pixels = ncol - z->col;
80 img = z->data + z->width * z->row + 3 * z->col;
82 // Plan 9 image format is BGR?!!!
83 // memmove(b, img, 3*pixels);
85 for(i=0; i<pixels; i++, img += 3){
97 return b - (uchar*)buf;
103 chunk(z->bo, "IDAT", z->buf, z->b - z->buf);
108 zwrite(void *va, void *buf, int n)
111 uchar *b = buf, *e = b+n;
114 while(b < e){ // loop over IDAT chunks
135 ni = allocmemimage(i->r, RGB24);
138 memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);
143 memwritepng(Biobuf *bo, Memimage *r, ImageInfo *II)
150 int nrow = r->r.max.y - r->r.min.y;
151 int ncol = r->r.max.x - r->r.min.x;
157 return "allocmemimage nil";
158 crctab = mkcrctab(0xedb88320);
160 sysfatal("mkcrctab error");
163 Bwrite(bo, PNGmagic, sizeof PNGmagic);
166 put4(h, ncol); h += 4;
167 put4(h, nrow); h += 4;
168 *h++ = 8; // bit depth = 24 bit per pixel
169 *h++ = 2; // color type = rgb
170 *h++ = 0; // compression method = deflate
171 *h++ = 0; // filter method
172 *h++ = 0; // interlace method = no interlace
173 chunk(bo, "IHDR", buf, h-buf);
175 tm = gmtime(time(0));
177 *h++ = (tm->year + 1900)>>8;
178 *h++ = (tm->year + 1900)&0xff;
184 chunk(bo, "tIME", buf, h-buf);
186 if(II->fields_set & II_GAMMA){
187 vgamma = II->gamma*100000;
189 chunk(bo, "gAMA", buf, 4);
192 if(II->fields_set & II_COMMENT){
193 strncpy((char*)buf, "Comment", sizeof buf);
194 n = strlen((char*)buf)+1; // leave null between Comment and text
195 strncpy((char*)(buf+n), II->comment, sizeof buf - n);
196 chunk(bo, "tEXt", buf, n+strlen((char*)buf+n));
202 zr.width = rgb->width * sizeof(ulong);
203 zr.data = rgb->data->bdata;
206 zw.buf = malloc(IDATSIZE);
208 zw.e = zw.b + IDATSIZE;
209 err = deflatezlib(&zw, zwrite, &zr, zread, 6, 0);
214 sysfatal("deflatezlib %s\n", flateerr(err));
215 chunk(bo, "IEND", nil, 0);