2 * See PNG 1.2 spec, also RFC 2083.
11 #include "imagefile.h"
19 typedef struct ZlibR ZlibR;
20 typedef struct ZlibW ZlibW;
42 static uchar PNGmagic[] = { 137, 'P', 'N', 'G', '\r', '\n', 26, '\n'};
45 put4(uchar *a, ulong v)
54 chunk(Biobuf *bo, char *type, uchar *d, int n)
65 crc = blockcrc(crctab, crc, type, 4);
66 crc = blockcrc(crctab, crc, d, n);
72 zread(void *va, void *buf, int n)
74 int a, i, pixels, pixwid;
87 pixels = (e-b)/pixwid;
88 if(pixels > z->dx - z->x)
89 pixels = z->dx - z->x;
90 img = z->data + z->width*z->y + pixwid*z->x;
91 memmove(b, img, pixwid*pixels);
94 * Convert to non-premultiplied alpha.
96 for(i=0; i<pixels; i++, b+=4){
99 b[0] = b[1] = b[2] = 0;
121 return b - (uchar*)buf;
127 chunk(z->io, "IDAT", z->buf, z->b - z->buf);
132 zwrite(void *va, void *buf, int n)
163 * [A]BGR because we want R,G,B,[A] in big-endian order. Sigh.
165 chantostr(buf, i->chan);
174 ni = allocmemimage(i->r, dst);
177 memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);
182 memwritepng(Biobuf *io, Memimage *m, ImageInfo *II)
192 crctab = mkcrctab(0xedb88320);
194 sysfatal("mkcrctab error");
199 return "allocmemimage nil";
201 Bwrite(io, PNGmagic, sizeof PNGmagic);
205 put4(h, Dx(m->r)); h += 4;
206 put4(h, Dy(m->r)); h += 4;
207 *h++ = 8; /* 8 bits per channel */
208 if(rgb->chan == BGR24)
212 *h++ = 0; /* compression - deflate */
213 *h++ = 0; /* filter - none */
214 *h++ = 0; /* interlace - none */
215 chunk(io, "IHDR", buf, h-buf);
217 /* time - using now is suspect */
218 tm = gmtime(time(0));
220 *h++ = (tm->year + 1900)>>8;
221 *h++ = (tm->year + 1900)&0xff;
227 chunk(io, "tIME", buf, h-buf);
230 if(II->fields_set & II_GAMMA){
231 vgamma = II->gamma*100000;
233 chunk(io, "gAMA", buf, 4);
237 if(II->fields_set & II_COMMENT){
238 strncpy((char*)buf, "Comment", sizeof buf);
239 n = strlen((char*)buf)+1; // leave null between Comment and text
240 strncpy((char*)(buf+n), II->comment, sizeof buf - n);
241 chunk(io, "tEXt", buf, n+strlen((char*)buf+n));
247 zr.width = rgb->width * sizeof(ulong);
248 zr.data = rgb->data->bdata;
251 zr.pixwid = chantodepth(rgb->chan)/8;
253 zw.buf = malloc(IDATSIZE);
255 sysfatal("malloc: %r");
257 zw.e = zw.b + IDATSIZE;
258 if((err=deflatezlib(&zw, zwrite, &zr, zread, 6, 0)) < 0)
259 sysfatal("deflatezlib %s", flateerr(err));
263 chunk(io, "IEND", nil, 0);